From 621422cb3914228f8477c32f1ebb4972c31eac49 Mon Sep 17 00:00:00 2001 From: Sebastian Lund Date: Thu, 1 Sep 2022 19:04:59 +0200 Subject: [PATCH 1/8] Change all Federations to EDBM Federations, removing the dependency on UDBM (and C/C++) entirely --- Cargo.toml | 8 +- README.md | 30 +- dbm/CMakeLists.txt | 24 - dbm/DBMAlloc.patch | 13 - dbm/include/base/DataAllocator.h | 175 - dbm/include/base/Enumerator.h | 87 - dbm/include/base/ItemAllocator.h | 158 - dbm/include/base/Timer.h | 66 - dbm/include/base/array_t.h | 130 - dbm/include/base/bitstring.h | 224 - dbm/include/base/c_allocator.h | 84 - dbm/include/base/doubles.h | 83 - dbm/include/base/exceptions.h | 58 - dbm/include/base/inttypes.h | 50 - dbm/include/base/intutils.h | 75 - dbm/include/base/linkable.h | 165 - dbm/include/base/memory.hpp | 104 - dbm/include/base/pointer.h | 176 - dbm/include/base/relation.h | 66 - dbm/include/base/stats.h | 74 - dbm/include/config.h | 20 - dbm/include/dbm/ClockAccessor.h | 35 - dbm/include/dbm/Valuation.h | 187 - dbm/include/dbm/constraints.h | 360 - dbm/include/dbm/dbm.h | 911 --- dbm/include/dbm/fed.h | 1681 ----- dbm/include/dbm/gen.h | 129 - dbm/include/dbm/inline_fed.h | 2217 ------ dbm/include/dbm/mingraph.h | 438 -- dbm/include/dbm/partition.h | 318 - dbm/include/dbm/pfed.h | 648 -- dbm/include/dbm/priced.h | 795 --- dbm/include/dbm/print.h | 197 - dbm/include/debug/macros.h | 222 - dbm/include/debug/malloc.h | 60 - dbm/include/debug/monitor.h | 82 - dbm/include/debug/new.h | 67 - dbm/include/debug/utils.h | 291 - dbm/include/doctest.h | 6580 ------------------ dbm/include/hash/compute.h | 156 - dbm/include/hash/tables.h | 387 - dbm/include/io/FileStreamBuffer.h | 58 - dbm/recompile.sh | 42 - dbm/toolchain-x86_64-w64-mingw32.cmake | 25 - dbm/wrapper.cpp | 220 - dbm/wrapper.h | 90 - src/DBMLib/dbm.rs | 596 -- src/DBMLib/lib_dbm.rs | 442 -- src/DBMLib/lib_stub.rs | 529 -- src/DBMLib/mod.rs | 11 - src/DataReader/parse_edge.rs | 5 +- src/DataReader/serialization.rs | 5 +- src/DataReader/xml_parser.rs | 5 +- src/DataTypes/statepair_list.rs | 59 +- src/EdgeEval/constraint_applyer.rs | 82 +- src/EdgeEval/updater.rs | 21 +- src/ModelObjects/component.rs | 405 +- src/ModelObjects/representations.rs | 185 +- src/ModelObjects/state.rs | 2 +- src/ModelObjects/statepair.rs | 40 +- src/System/extract_system_rep.rs | 9 +- src/System/input_enabler.rs | 38 +- src/System/local_consistency.rs | 25 +- src/System/pruning.rs | 185 +- src/System/refine.rs | 67 +- src/System/save_component.rs | 27 +- src/TransitionSystems/common.rs | 17 +- src/TransitionSystems/compiled_component.rs | 22 +- src/TransitionSystems/composition.rs | 10 +- src/TransitionSystems/conjunction.rs | 10 +- src/TransitionSystems/location_tuple.rs | 23 +- src/TransitionSystems/quotient.rs | 77 +- src/TransitionSystems/transition_system.rs | 6 +- src/build.rs | 80 - src/main.rs | 1 - src/tests/ModelObjects/max_bounds.rs | 59 - src/tests/ModelObjects/mod.rs | 1 - src/tests/dbm/federation.rs | 124 - src/tests/dbm/mod.rs | 1 - src/tests/mod.rs | 1 - src/tests/save_component/save_comp_helper.rs | 3 +- 81 files changed, 673 insertions(+), 20566 deletions(-) delete mode 100644 dbm/CMakeLists.txt delete mode 100644 dbm/DBMAlloc.patch delete mode 100644 dbm/include/base/DataAllocator.h delete mode 100644 dbm/include/base/Enumerator.h delete mode 100644 dbm/include/base/ItemAllocator.h delete mode 100644 dbm/include/base/Timer.h delete mode 100644 dbm/include/base/array_t.h delete mode 100644 dbm/include/base/bitstring.h delete mode 100644 dbm/include/base/c_allocator.h delete mode 100644 dbm/include/base/doubles.h delete mode 100644 dbm/include/base/exceptions.h delete mode 100644 dbm/include/base/inttypes.h delete mode 100644 dbm/include/base/intutils.h delete mode 100644 dbm/include/base/linkable.h delete mode 100644 dbm/include/base/memory.hpp delete mode 100644 dbm/include/base/pointer.h delete mode 100644 dbm/include/base/relation.h delete mode 100644 dbm/include/base/stats.h delete mode 100644 dbm/include/config.h delete mode 100644 dbm/include/dbm/ClockAccessor.h delete mode 100644 dbm/include/dbm/Valuation.h delete mode 100644 dbm/include/dbm/constraints.h delete mode 100644 dbm/include/dbm/dbm.h delete mode 100644 dbm/include/dbm/fed.h delete mode 100644 dbm/include/dbm/gen.h delete mode 100644 dbm/include/dbm/inline_fed.h delete mode 100644 dbm/include/dbm/mingraph.h delete mode 100644 dbm/include/dbm/partition.h delete mode 100644 dbm/include/dbm/pfed.h delete mode 100644 dbm/include/dbm/priced.h delete mode 100644 dbm/include/dbm/print.h delete mode 100644 dbm/include/debug/macros.h delete mode 100644 dbm/include/debug/malloc.h delete mode 100644 dbm/include/debug/monitor.h delete mode 100644 dbm/include/debug/new.h delete mode 100644 dbm/include/debug/utils.h delete mode 100644 dbm/include/doctest.h delete mode 100644 dbm/include/hash/compute.h delete mode 100644 dbm/include/hash/tables.h delete mode 100644 dbm/include/io/FileStreamBuffer.h delete mode 100755 dbm/recompile.sh delete mode 100644 dbm/toolchain-x86_64-w64-mingw32.cmake delete mode 100644 dbm/wrapper.cpp delete mode 100644 dbm/wrapper.h delete mode 100644 src/DBMLib/dbm.rs delete mode 100644 src/DBMLib/lib_dbm.rs delete mode 100644 src/DBMLib/lib_stub.rs delete mode 100644 src/DBMLib/mod.rs delete mode 100644 src/tests/ModelObjects/max_bounds.rs delete mode 100644 src/tests/dbm/federation.rs delete mode 100644 src/tests/dbm/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 5447718c..a5d92c0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,11 +32,15 @@ simple-error = "0.2.3" force_graph = "0.3.2" rand = "0.8.5" futures = "0.3.21" +# edbm = {git = "https://github.com/Ecdar/EDBM"} +edbm = {path = "../EDBM"} +# Enable optimizations for EDBM in debug mode, but not for our code: +[profile.dev.package.edbm] +opt-level = 3 + [build-dependencies] -bindgen = "0.60.0" -cc = "1.0.73" tonic-build = "0.5.*" diff --git a/README.md b/README.md index 66fcf90b..da59bf0a 100644 --- a/README.md +++ b/README.md @@ -3,38 +3,22 @@ ## About This is a model checking engine for ECDAR (Environment for Compositional Design and Analysis of Real Time Systems) written in rust. +#### DBM Library +The engine uses the ECDAR DBM Library for operations on zones of time (https://www.github.com/ECDAR/EDBM). + ## Prerequisites -- A rust compiler and C++ compiler installed (https://www.rust-lang.org/learn/get-started) -- [clang](https://clang.llvm.org/) for compiling the library (for the Ubuntu linux distribution, run the command ```apt install llvm-dev libclang-dev clang``` to properly install the clang dependencies) +- A rust compiler installed (https://www.rust-lang.org/learn/get-started) - A folder containing the model components to check - ProtoBuf compiler protoc (for the Ubuntu linux distribution ```apt install protobuf-compiler```) - Download ProtoBuf definitions with ```git submodule update --init --recursive``` -## Building the DBM library - -Navigate into the dbm folder and make sure no build folder already exists. Then use cmake to build the dbm library, the files should be created in a `out` folder where Reveaal use them from. - -```bash -cd dbm -cmake -B build/ -cmake --build build/ -``` - ## Building the project - Build the project using `cargo build` - Optionally run the tests using `cargo test` -## Cross compiling from Linux to Windows -Build the DBM library using the x86_64-w64-mingw32 toolchain: - -```bash -cd dbm -cmake -B buildw/ -D CMAKE_TOOLCHAIN_FILE=toolchain-x86_64-w64-mingw32.cmake -cmake --build buildw/ -``` +## Cross compiling +The project is pure just so one should be able to crosscompile to any platform with a rust target. +### Compiling to Windows Ensure that the rustc windows target is installed with `rustup target add x86_64-pc-windows-gnu` and build with cargo: - `cargo build --target x86_64-pc-windows-gnu` - -The rust compiler is configured to pick the library for the current target, so you dont have to recompile the dbm library when switching compile target. diff --git a/dbm/CMakeLists.txt b/dbm/CMakeLists.txt deleted file mode 100644 index f63aefcd..00000000 --- a/dbm/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.16.3) -include(ExternalProject) - -project(dbm_wrapper) - - -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/out/${triple}) -message(Compiling to output directory ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) - -set(dbm_patch ${CMAKE_SOURCE_DIR}/DBMAlloc.patch) - - -ExternalProject_Add(udbm PREFIX UDBM/ - GIT_REPOSITORY https://github.com/UPPAALModelChecker/UDBM - GIT_TAG v2.0.10 - GIT_PROGRESS true - PATCH_COMMAND git apply ${dbm_patch} - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory udbm/lib ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} - CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -) - -include_directories(include/) -add_library(udbmwrapper STATIC wrapper.cpp) -add_dependencies(udbmwrapper udbm) \ No newline at end of file diff --git a/dbm/DBMAlloc.patch b/dbm/DBMAlloc.patch deleted file mode 100644 index d4236636..00000000 --- a/dbm/DBMAlloc.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/dbm/DBMAllocator.h b/dbm/DBMAllocator.h -index d2d2e50..4510a0e 100644 ---- a/dbm/DBMAllocator.h -+++ b/dbm/DBMAllocator.h -@@ -29,7 +29,7 @@ namespace dbm - { - public: - ///< Default constructor -- DBMAllocator(): freeList(16), dbm1x1(1) -+ DBMAllocator(): freeList(256), dbm1x1(1) - { - raw_t lezero = dbm_LE_ZERO; - dbm1x1.newCopy(&lezero, 1); diff --git a/dbm/include/base/DataAllocator.h b/dbm/include/base/DataAllocator.h deleted file mode 100644 index c62a13be..00000000 --- a/dbm/include/base/DataAllocator.h +++ /dev/null @@ -1,175 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : DataAllocator.h (base) -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: DataAllocator.h,v 1.15 2005/04/22 15:20:10 adavid Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_DATAALLOCATOR_H -#define INCLUDE_BASE_DATAALLOCATOR_H - -#include "base/array_t.h" -#include "base/c_allocator.h" -#include -#include - -/** C wrapper function for DataAllocator. - * @see dbm/mingraph.h - * @param size: size in int to allocate. - * @param allocator: a pointer to DataAllocator - */ -int32_t* base_allocate(size_t size, void* allocator); - -/** C wrapper function for DataAllocator. - * @see base/c_allocator.h - * @param mem: memory to deallocate - * @param intSize: size in int to deallocate - * @param allocator: DataAllocator object - * @pre memory was allocated with base_allocate and intSize corresponds - * to the allocated size. - */ -void base_deallocate(void* mem, size_t intSize, void* allocator); - -/** C wrapper function for new. - * @see dbm/mingraph.h, base/c_allocator.h - * @param size: size in int to allocate. - * @param unused: unused. - */ -int32_t* base_new(size_t size, void* unused); - -/** C wrapper function for delete. - * @see base/c_allocator.h - * @param mem: memory to deallocate. - * @param unused1, unused2: unused parameters. - */ -void base_delete(void* mem, size_t unused1, void* unused2); - -/** C wrapper allocator instance for new. - */ -extern allocator_t base_newallocator; - -namespace base -{ - /** Fast chunk allocator. - * Has the ability to deallocate all data at once. - */ - class DataAllocator; - typedef std::shared_ptr DataAllocator_ptr; - - class DataAllocator final : public std::enable_shared_from_this - { - public: - DataAllocator(); - virtual ~DataAllocator() noexcept; - - /** Allocate memory. - * @param intSize: size in int units - * @return a int32[intSize] allocated - * memory area. - * If ALIGN_WORD64 is defined then the result is aligned - * on 64 bits. It is the responsability of the developper - * to use the flag. It is possible to skip the flag on - * Intel architecture that can cope with non aligned - * addresses. - * @pre intSize <= CHUNK_SIZE - */ - void* allocate(size_t intSize); - - /** Deallocate memory. - * @pre - * - memory was allocated with allocate - * - size allocated was intSize - * @param data: memory to deallocate - * @param intSize: size in int units of the - * allocated memory. - */ - void deallocate(void* data, size_t intSize); - - /** Reset the allocator: deallocate all - * memory allocated by this allocator! - */ - void reset(); - - /** Print statistics, C style. - * @param out: where to print. - */ - void printStats(FILE* out) const; - - /** Print statistics, C++ style. - * @param out: where to print. - * @return the ostream. - */ - std::ostream& printStats(std::ostream& out) const; - - /** C wrapper allocator - * @return C wrapper allocator_t - */ - allocator_t getCAllocator() - { - allocator_t c_alloc = {.allocData = this, - .allocFunction = base_allocate, - .deallocFunction = base_deallocate}; - return c_alloc; - } - - private: - /** Memory is allocated internally by - * chunks. This controls the size of - * these chunks. - */ - enum { CHUNK_SIZE = (1 << 22) }; - - /** Table of free memory lists. - * freeMem[i] starts a list of free - * memory blocks of i INT size - */ - array_t freeMem; - - /** An entry in the freeMem table - * at i gives a free memory block - * of size i ints. If there are other - * such blocks, then this memory block - * contains the pointer to the next - * free block. - * This function is a convenience cast - * for this case. - */ - static inline uintptr_t* getNext(uintptr_t data) { return (uintptr_t*)data; } - static inline uintptr_t getNext(uintptr_t* data) { return (uintptr_t)data; } - - /** Check that a given address belongs to a pool or the free list. - * Used for debugging, this is not a performance critical method. - * @param data: memory to check, - * @param intSize: size of the memory to check. - * @return true if the memory belongs to a pool. - */ - bool hasInPools(const uintptr_t* data, size_t intSize) const; - - /** Memory pool. - */ - struct Pool_t - { - Pool_t* next; - uintptr_t mem[CHUNK_SIZE]; - uintptr_t end[]; /**< only to mark the end, no data */ - }; - - Pool_t* memPool; /**< current pool in use */ - uintptr_t* freePtr; /**< current free mem position */ - uintptr_t* endFree; /**< end of current chunk */ - }; - -} // namespace base - -static inline std::ostream& operator<<(std::ostream& os, const base::DataAllocator& alloc) -{ - return alloc.printStats(os); -} - -#endif // INCLUDE_ALLOCATOR_DATAALLOCATOR_H diff --git a/dbm/include/base/Enumerator.h b/dbm/include/base/Enumerator.h deleted file mode 100644 index 815fbb07..00000000 --- a/dbm/include/base/Enumerator.h +++ /dev/null @@ -1,87 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : Enumerator.h (base) -// -// LinkableEnumerator -// | -// +-Enumerator -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: Enumerator.h,v 1.5 2005/01/25 18:30:22 adavid Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_ENUMERATOR_H -#define INCLUDE_BASE_ENUMERATOR_H - -#include "base/inttypes.h" -#include "base/linkable.h" - -#include - -namespace base -{ - /** Generic enumerator for linkables: enumerate on a - * table of linkables. Typically, this is used in - * hash tables. - */ - class LinkableEnumerator - { - public: - /** Constructor: - * @param sizeOfTable: size of the table - * of linkables - * @param theTable: table of linkables - * @pre theTable is a Linkable_t*[sizeOfTable] - */ - LinkableEnumerator(size_t sizeOfTable, SingleLinkable_t** theTable): - size(sizeOfTable), table(theTable), current(*theTable) - {} - - /** Enumerate all the nodes in the table. The - * order is not specified. In practice we start - * from the beginning of the table and we enumerate - * all nodes in natural order. - * @return next linkable, or NULL if there are no - * linkable left. - * @post internal state is changed to return the - * next linkable everytime the method is called. - */ - SingleLinkable_t* getNextLinkable(); - - private: - size_t size; /**< size of the table */ - SingleLinkable_t** table; /**< table of linkables */ - SingleLinkable_t* current; /**< current node in enumeration */ - }; - - /** Template for typed enumerators: - * assume T is a kind of SingleLinkable_t. - * This is basically a wrapper for typed - * linkables. - */ - template - class Enumerator : public LinkableEnumerator - { - public: - /** Constructor: - * @see LinkableEnumerator - */ - Enumerator(size_t sizeOfTable, T** theTable): - LinkableEnumerator(sizeOfTable, reinterpret_cast(theTable)) - {} - - /** Enumeration: - * Enumerates all nodes in the table in an unspecified order. - * @return next node or NULL if there are no nodes left. - * @see LinkableEnumerator - */ - T* getNext() { return static_cast(getNextLinkable()); } - }; -} // namespace base - -#endif // INCLUDE_BASE_ENUMERATOR_H diff --git a/dbm/include/base/ItemAllocator.h b/dbm/include/base/ItemAllocator.h deleted file mode 100644 index de6efa91..00000000 --- a/dbm/include/base/ItemAllocator.h +++ /dev/null @@ -1,158 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : ItemAllocator.h (base) -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// Copyright (c) 2020, Aalborg University. -// All right reserved. -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_ITEMALLOCATOR_H -#define INCLUDE_BASE_ITEMALLOCATOR_H - -#include -#include - -namespace base -{ - /** Simple (and fast) item allocator. - * The interest of it, compared - * to DataAllocator is to have a different memory area (and thus - * avoid messing up with the pages) for another kind of data. This - * is particularly fitted to the waiting queue vs explored states - * stored. - * - * Working of ItemAllocator: it allocates a - * continuous chunk of numberOfItems items (=pool) and - * initializes the list of free items. Allocation - * and deallocation just pop and push items on - * this list. When the list is empty, a new pool - * of items is allocated. - * Template arguments: - * @param ITEM: type of object to allocate - * Default = 128k items - * @pre ITEM size is at least 1 int. - */ - template - class ItemAllocator - { - public: - /** Default number of items. - */ - enum { NB_ITEMS = (1 << 17) }; - - /** Constructor: check precondition & init to nullptr - * @param nbItems: number of items per pool. - * @pre nbItems > 1 - */ - ItemAllocator(std::uintptr_t nbItems = NB_ITEMS): - numberOfItems{nbItems}, pool{nullptr}, freeItem{nullptr} - { - assert(sizeof(ITEM) >= sizeof(void*)); - assert(nbItems > 1); - } - - /** Destructor = reset - */ - ~ItemAllocator() { reset(); } - - /** Allocate a new item. - * @return new allocated item. - * @post result != nullptr - */ - ITEM* allocate() - { - if (!freeItem) - addPool(); - AllocCell_t* cell = freeItem; - freeItem = cell->next; - return &cell->item; - } - - /** Deallocate an item. - * @param item: item to deallocate. - * @pre - * - item allocated with this allocator - * - item != nullptr - */ - void deallocate(ITEM* item) - { - assert(item); - AllocCell_t* cell = (AllocCell_t*)item; - cell->next = freeItem; - freeItem = cell; - } - - /** Reset the allocator: free all pools - * and reset the list of free items. - */ - void reset() - { - AllocPool_t* p = pool; - pool = nullptr; - freeItem = nullptr; - while (p) { - AllocPool_t* next = p->next; - delete[](char*) p; - p = next; - } - } - - private: - /** Add a new pool of items. - */ - void addPool() - { - // Add new pool to list of pools - AllocPool_t* newPool = - (AllocPool_t*)new char[sizeof(AllocPool_t) + sizeof(AllocCell_t) * numberOfItems]; - newPool->next = pool; - pool = newPool; - - // Init beginning of the list of free items - // Also, do not try this at home kids. - AllocCell_t* item = &(newPool->items); - assert(!freeItem); - freeItem = item; - - // Init list of free items - auto n = numberOfItems - 1; - assert(numberOfItems > 1); - do { - item[0].next = &item[1]; - item++; - } while (--n); - item[0].next = nullptr; // last item: no next - } - - /** UNION to manage list of - * free items (next) and allocation - * of items (item). - * Guarantee at compile time that - * ITEM does not have a constructor. - */ - union AllocCell_t - { - AllocCell_t* next; - ITEM item; - }; - - /** Pool of items. - */ - struct AllocPool_t - { - AllocPool_t* next; - AllocCell_t items; - }; - - std::uintptr_t numberOfItems; /**< number of items per pool */ - AllocPool_t* pool; /**< allocated pools */ - AllocCell_t* freeItem; /**< list of free items */ - }; - -} // namespace base - -#endif // INCLUDE_BASE_ITEMALLOCATOR_H diff --git a/dbm/include/base/Timer.h b/dbm/include/base/Timer.h deleted file mode 100644 index bb5f2981..00000000 --- a/dbm/include/base/Timer.h +++ /dev/null @@ -1,66 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : Timer.h (base) -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// v 1.3 reviewed. -// $Id: Timer.h,v 1.6 2004/04/02 22:50:43 behrmann Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_TIMER_H -#define INCLUDE_BASE_TIMER_H - -#include -#include - -namespace base -{ - /** A simple timer to measure CPU time. - */ - class Timer - { - public: - explicit Timer(bool running = true); - - /** - * Access to CPU time. Returns the CPU time consumed since the - * last call of this method or since initialization of the - * object if the method has not been called before. - * - * @returns CPU time in seconds. - */ - double getElapsed(); - - void pause(); - void start(); - - class AutoStartStop - { - public: - explicit AutoStartStop(Timer&); - ~AutoStartStop(); - - private: - Timer& timer; - }; - - private: - std::chrono::nanoseconds nanoseconds{0}; - bool paused = false; - std::chrono::system_clock::time_point timer; - }; -} // namespace base - -/** - * Output operator for Timer class. Writes the consumed CPU time to \a - * out. Calls \c getElapsed() internally, so the timer is reset. Up - * to 3 decimals are printed. - */ -std::ostream& operator<<(std::ostream& out, base::Timer& t); - -#endif // INCLUDE_BASE_TIMER_H diff --git a/dbm/include/base/array_t.h b/dbm/include/base/array_t.h deleted file mode 100644 index db2f59ff..00000000 --- a/dbm/include/base/array_t.h +++ /dev/null @@ -1,130 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : array.h (base) -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: array.h,v 1.6 2005/01/25 18:30:22 adavid Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_ARRAY_H -#define INCLUDE_BASE_ARRAY_H - -#include "base/pointer.h" - -namespace base -{ - /** This defines a simple array template that will work on scalar - * types only. The idea is to be able to access the array randomly - * even on non predefined position. The array will grow automatically. - * This is not possible with std::vector: you have to define a loop and - * use push_back() to fill the gaps. Besides, reading outside the - * vector will seg-fault. - * - * Lower case name: basic template on basic scalar types only - * this class is not supposed to have sub-classes - * - * This class is highly obsolete. - */ - template - class array_t : public pointer_t - { - public: - /** increase size step: at least 1 - */ - enum { INC = 8 }; - - /** constructor: alloc and init the array to 0 - * always at least 1 element. - * @param initSize: initial size - */ - array_t(size_t initSize = 4): - pointer_t(new T[initSize == 0 ? 1 : initSize], initSize == 0 ? 1 : initSize) - { - assert(INC > 0); - pointer_t::reset(); - } - - /** destructor: free the array - */ - ~array_t() { delete[] pointer_t::data; } - - /** Copy constructor - */ - array_t(const array_t& arr): pointer_t(new T[arr.capa], arr.capa) { copyFrom(arr); } - - /** copy operator - */ - array_t& operator=(array_t& arr) - { - if (pointer_t::capa != arr.capa) { - pointer_t::data = std::make_unique(arr.capa); - pointer_t::capa = arr.capa; - } - copyFrom(arr); - } - - /** data read: test if outside bounds - * @param at: where to read. - * if at is outside limits then return 0. - */ - T get(size_t at) const { return at < pointer_t::capa ? pointer_t::data[at] : 0; } - - /** data write: may increase array - * @param at: where to write. - * @param value: what to write. - * if at is outside limits then the array is - * increased. - */ - void set(size_t at, T value) - { - ensurePos(at); - pointer_t::data[at] = value; - } - - /** data read/write: may increase array - * @param at: where to read and write. - * @param value: what to write. - * @return original value at position at. - */ - T replace(size_t at, T value) - { - ensurePos(at); - T res = pointer_t::data[at]; - pointer_t::data[at] = value; - return res; - } - - /** addition with the given argument - * @param at: where to add value - * @param value: what to add - */ - void add(size_t at, T value) - { - ensurePos(at); - pointer_t::data[at] += value; - } - - private: - /** make sure position at may be accessed - * @param at: position to be able to read. - * @post data[at] is valid. - */ - void ensurePos(size_t at) - { - if (at >= pointer_t::capa) { - auto newData = new T[at + INC]; - std::copy(pointer_t::data, pointer_t::data + pointer_t::capa, newData); - pointer_t::data = newData; - pointer_t::capa = at + INC; - } - } - }; - -} // namespace base - -#endif // INCLUDE_BASE_ARRAY_H diff --git a/dbm/include/base/bitstring.h b/dbm/include/base/bitstring.h deleted file mode 100644 index 260cbbd1..00000000 --- a/dbm/include/base/bitstring.h +++ /dev/null @@ -1,224 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : bitstring.h (base) - * C/C++ header. - * - * Basic operations on bits and strings of bits + BitString & Bit classes. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * v 1.1 reviewed. - * $Id: bitstring.h,v 1.17 2005/05/14 16:57:34 behrmann Exp $ - * - *********************************************************************/ - -#ifndef INCLUDE_BASE_BIT_H -#define INCLUDE_BASE_BIT_H - -#include -#include - -#include "base/intutils.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Type to ensure correct arguments. - */ -typedef enum { ZERO = 0, ONE = 1 } bit_t; - -/** Bit counting function. - * @return: the number of 1s in a given int - * @param x: the int to examine. - */ -static inline uint32_t base_countBits(uint32_t x) -{ - /* algorithm: count bits in parallel (hack) */ - x -= (x & 0xaaaaaaaa) >> 1; - x = ((x >> 2) & 0x33333333L) + (x & 0x33333333L); - x = ((x >> 4) + x) & 0x0f0f0f0fL; - x = ((x >> 8) + x); - x = ((x >> 16) + x) & 0xff; - return x; -} - -/** Bit counting function. - * @return: the number of 1s in a given string of bits - * @param bitString: the string of bits to examine - * @param n: number of ints to read. - */ -static inline uint32_t base_countBitsN(const uint32_t* bitString, size_t n) -{ - uint32_t cnt; - assert(n == 0 || bitString); - for (cnt = 0; n != 0; --n) - cnt += base_countBits(*bitString++); - return cnt; -} - -/** Reset of bits (to 0). - * memset could be used but for strings of - * bits of length 3-4 ints max, it is overkill. - * Conversely, for larger arrays, don't use this - * function. - * @param bits: the string to reset - * @param n: number of ints to write. - */ -static inline void base_resetBits(uint32_t* bits, size_t n) -{ - assert(n == 0 || bits); - for (; n != 0; --n) - *bits++ = 0; -} - -/** Equality test to 0. Optimistic - * implementation: works best when == 0. - * @param bits: the string to test - * @param n: n number of ints to test - * @return true if all bits[0..n-1] == 0 - */ -static inline bool base_areBitsReset(const uint32_t* bits, size_t n) -{ - uint32_t diff = 0; /* accumulate the difference to 0 */ - assert(n == 0 || bits); - for (; n != 0; --n) - diff |= *bits++; - return (diff == 0); -} - -/** Wrapper to base_areBitsResets - */ -static inline bool base_areIBitsReset(const int32_t* bits, size_t n) -{ - return base_areBitsReset((uint32_t*)bits, n); -} - -/** Comparison of bits. - * Same comment as for resetBits: better - * to inline this simple code for small - * arrays, ie, bit arrays. Optimistic implementation. - * @param bits1,bits2: arrays to compare - * @param n: number of ints to read - * @return true if array contents are the same - */ -static inline bool base_areBitsEqual(const uint32_t* bits1, const uint32_t* bits2, size_t n) -{ - uint32_t diff = 0; - assert(n == 0 || (bits1 && bits2)); - for (; n != 0; --n) - diff |= *bits1++ ^ *bits2++; - return (diff == 0); -} - -/** Set bit to 1 at position i in a table of bits. - * @param bits: the table of *int* - * @param i: the position of the bit - * Bit position in a table of int = - * int position at i/32 == i >> 5 - * bit position at i%32 == i & 31 - * NOTE: we don't use setBit and resetBit - * as names because they are too close to - * resetBits that is already used. - * @pre valid pointer and no out of bounds. - */ -static inline void base_setOneBit(uint32_t* bits, size_t i) -{ - assert(bits); - bits[i >> 5] |= 1u << (i & 31); -} - -/** Reset bit to 0 at position i in a table of bits. - * @param bits: the table of *int* - * @param i: the position of the bit - * Bit position in a table of int = - * int position at i/32 == i >> 5 - * bit position at i%32 == i & 31 - * NOTE: don't use setBit and resetBit - * as names because they are too close to - * resetBits that is already used. - * @pre valid pointer and not out of bounds. - */ -static inline void base_resetOneBit(uint32_t* bits, size_t i) -{ - assert(bits); - bits[i >> 5] &= ~(1u << (i & 31)); -} - -/** Toggle bit at position i in a table of bits. - * @param bits: the table of *int* - * @param i: the position of the bit - * Bit position in a table of int = - * int position at i/32 == i >> 5 - * bit position at i%32 == i & 31 - * @pre valid pointer and not out of bounds. - */ -static inline void base_toggleOneBit(uint32_t* bits, size_t i) -{ - assert(bits); - bits[i >> 5] ^= 1u << (i & 31); -} - -/** Test for a set bit in a bit-string. - * Can be used in the following way. Instead of: - * \code - * if (base_getOneBit(a,n)) c++; - * \endcode - * you can write: - * \code - * c += base_getOneBit(a,n); - * \endcode - * @returns ONE if \a i'th bit is set, ZERO otherwise. - * @pre valid pointer and not out of bounds. - */ -static inline bit_t base_getOneBit(const uint32_t* bits, size_t i) -{ - assert(bits); - return (bit_t)((bits[i >> 5] >> (i & 31)) & 1); -} - -/** Test for a set bit in a bit-string. This function is not the same - * as \c base_getOneBit(). This function returns an integer with all - * other bits except the \a i'th bit masked out. I.e. it returns 0 if - * the bit is not set, and a power of 2 if it is set. - * - * @returns the bit as it is in the int, ie, shifted. - * @pre valid pointer and not out of bounds. - */ -static inline uint32_t base_readOneBit(const uint32_t* bits, size_t i) -{ - assert(bits); - return bits[i >> 5] & (1u << (i & 31)); -} - -/** Unpack a bit table to an index table. - * Useful when loading a DBM and computing initial - * redirection table. May be used for other things - * than DBMs, e.g., variables. - * @param table: index redirection table - * @param bits: bit array - * @param n: size in int of the bit array - * @return number of bits in bits - * @pre - * - table is large enough: at least - * uint32_t[size] where size = index of the highest bit - * in the bitstring bits. - * - bits is at least a uint32_t[n] - * @post - * - returned value == number of bits in bits - * - for all bits set in bits at position i, - * then table[i] is defined and gives the - * proper indirection ; for other bits, table[i] - * is untouched. - */ -size_t base_bits2indexTable(const uint32_t* bits, size_t n, cindex_t* table); - -#ifdef __cplusplus -} - -#endif /* __cplusplus */ - -#endif /* INCLUDE_BASE_BITSTRING_H */ diff --git a/dbm/include/base/c_allocator.h b/dbm/include/base/c_allocator.h deleted file mode 100644 index 7f8bbe2b..00000000 --- a/dbm/include/base/c_allocator.h +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : c_allocator.h (base) - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * $Id: c_allocator.h,v 1.2 2004/06/14 07:36:53 adavid Exp $ - * - *********************************************************************/ - -#ifndef INCLUDE_BASE_C_ALLOCATOR_H -#define INCLUDE_BASE_C_ALLOCATOR_H - -#include "base/inttypes.h" -#include - -/** - * @file - * Definition of the allocator function type - * and declaration of a default function based - * on malloc. - * In different places where C libraries need - * memory management, we want to stay independent - * from particular needs. A generic allocator function - * is declared for this purpose. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** Allocator function. - * @param intSize: size to allocate in ints - * @param data: custom data for the allocator - * (ignored for malloc, for example, important - * for a custom allocator) - * @return int32_t[intSize] - */ -typedef int32_t* (*allocator_f)(size_t intSize, void* data); - -/** Deallocator function. - * @param mem: memory to deallocate - * @param intSize: size to deallocate in ints - * @param data: custom data for the allocator - * @pre intSize must correspond to the allocated - * size, mem != NULL. - */ -typedef void (*deallocator_f)(void* mem, size_t intSize, void* data); - -/** Allocator = allocator function + custom data. - */ -typedef struct -{ - void* allocData; - allocator_f allocFunction; - deallocator_f deallocFunction; -} allocator_t; - -/** Default allocator function based on malloc. - * @param intSize: size to allocate in ints - * @param unused: not used, only to comply with allocator_f - * @return int32_t[intSize] allocated by malloc - */ -int32_t* base_malloc(size_t intSize, void* unused); - -/** Default deallocator function based on free. - * @param mem: memory to deallocate - * @param unused1,unused2: unused parameters, only to comply - * with deallocator_f. - */ -void base_free(void* mem, size_t unused1, void* unused2); - -/** Default allocator type based on malloc. - */ -extern allocator_t base_mallocator; - -#ifdef __cplusplus -} -#endif - -#endif /* INCLUDE_BASE_C_ALLOCATOR_H */ diff --git a/dbm/include/base/doubles.h b/dbm/include/base/doubles.h deleted file mode 100644 index 16692862..00000000 --- a/dbm/include/base/doubles.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : doubles.h - * - * Basic stuff on doubles. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * $Id: doubles.h,v 1.2 2005/06/20 16:27:03 adavid Exp $ - * - *********************************************************************/ - -#ifndef INCLUDE_BASE_DOUBLES_H -#define INCLUDE_BASE_DOUBLES_H - -#include - -/* Epsilon */ -/* #define base_EPSILON (DBL_EPSILON*10) - * BigDecimal in the GUI is lost beyond - * 1e-6. In addition, the GUI computes middle - * interval points so 2e-6 is the smallest - * value compatible with the GUI. There is - * an unavoidable problem if the user can - * recursively choose middle points. - * If the epsilon is too big then the point - * inclusion check may fail. - */ -#define base_EPSILON 2e-6 - -#ifdef __cplusplus -extern "C" { -#endif - -/* Add/subtract epsilon to/from value and - * make sure the result is different from - * the original (except if too big or too - * small). - */ -double base_addEpsilon(double value, double epsilon); -double base_subtractEpsilon(double value, double epsilon); - -#ifdef __cplusplus -} -#endif - -/* Comparisons between doubles. */ - -/* -#define IS_GT(X,Y) ((X) > (Y)+DBL_EPSILON) -#define IS_LT(X,Y) ((X) < (Y)-DBL_EPSILON) -#define IS_GE(X,Y) ((X) > (Y)-DBL_EPSILON) -#define IS_LE(X,Y) ((X) < (Y)+DBL_EPSILON) -*/ -#define IS_GT(X, Y) ((X) - (Y) >= 1e-14) -#define IS_LT(X, Y) IS_GT(Y, X) -#define IS_GE(X, Y) ((Y) - (X) <= 1e-14) -#define IS_LE(X, Y) IS_GE(Y, X) - -#define IS_EQ(X, Y) (IS_GE(X, Y) && IS_LE(X, Y)) - -/* - -Justification of 1e-14: - -irb -irb(main):001:0> 7.613442-(8.613442-1) -=> 8.88178419700125e-16 - -1e-15 would be the immediate reasonable -choice, we take 1e-14 to be a little safer. - -Of course that doesn't guarantee it will be -fine for all the other cases but it seems a -reasonable choice given the precision of the -points handled by the GUI. - -*/ - -#endif // INCLUDE_BASE_DOUBLES_H diff --git a/dbm/include/base/exceptions.h b/dbm/include/base/exceptions.h deleted file mode 100644 index a6d54775..00000000 --- a/dbm/include/base/exceptions.h +++ /dev/null @@ -1,58 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2006, Uppsala University and Aalborg University. -// All right reserved. -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_EXCEPTIONS_H -#define INCLUDE_BASE_EXCEPTIONS_H - -#include - -// Common base class. - -class UppaalException : public std::exception -{ -protected: - char _what[256]; - -public: - const char* what() const noexcept override; -}; - -// Specialized exceptions. Unfortunately -// it is difficult to factorize the code -// in the constructor due to the varying -// number of arguments. - -class SystemException : public UppaalException -{ -public: - SystemException(const char* fmt, ...); -}; - -class InvalidOptionsException : public UppaalException -{ -public: - InvalidOptionsException(const char* fmt, ...); -}; - -class RuntimeException : public UppaalException -{ -public: - RuntimeException(const char* fmt, ...); -}; - -class SuccessorException : public RuntimeException -{ -public: - const char* state; - const char* channel; - SuccessorException(const char* state, const char* channel, const char* message); - virtual ~SuccessorException(); -}; - -#endif // INCLUDE_BASE_EXCEPTIONS_H diff --git a/dbm/include/base/inttypes.h b/dbm/include/base/inttypes.h deleted file mode 100644 index 5466fced..00000000 --- a/dbm/include/base/inttypes.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : inttypes.h (base) - * C header. - * - * Definition of integer types. Basically a wrapper for different - * includes + basic size computation in int units. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * v 1.2 reviewed. - * $Id: inttypes.h,v 1.11 2005/04/22 15:20:10 adavid Exp $ - * - *********************************************************************/ - -#ifndef INCLUDE_BASE_INTTYPES_H -#define INCLUDE_BASE_INTTYPES_H - -#include "config.h" - -// use .h here as this file is BOTH c and c++ (i.e. cinttypes is only c++) -#include -#include -#include - -/** Size computation in "int" units to avoid any alignment problem. - * intsizeof : as sizeof but result in "int" units - * bits2intsize : convert # of bits to # of int (size+31)/32 - * bytes2intsize: convert # of bytes to # of int (size+3)/4 - */ - -#define bits2intsize(X) (((X) + 31u) >> 5u) -#define bytes2intsize(X) (((X) + 3u) >> 2u) -#define intSizeOf(X) bytes2intsize(sizeof(X)) -#define intSizeOfA(X, N) bytes2intsize(sizeof(X) * N) - -/* Define ARCH_APPLE_DARWIN on Mac OS X. - */ -#if defined(__APPLE__) && defined(__MACH__) -#define ARCH_APPLE_DARWIN -#endif - -/** Type for indices (variables and clocks). - */ -typedef uint32_t cindex_t; - -#endif /* INCLUDE_BASE_INTTYPES_H */ diff --git a/dbm/include/base/intutils.h b/dbm/include/base/intutils.h deleted file mode 100644 index b82b9ae1..00000000 --- a/dbm/include/base/intutils.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : intutils.h (base) - * - * Utility functions for integers. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * $Id: intutils.h,v 1.13 2005/04/22 15:20:10 adavid Exp $ - * - **********************************************************************/ - -#ifndef INCLUDE_BASE_INTUTILS_H -#define INCLUDE_BASE_INTUTILS_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include "base/inttypes.h" - -/** - * Check if an unsigned integer is a power of two - * @param v: the value to check - * @return true if power of two, else false - */ -static inline bool base_isPowerOfTwo(size_t v) { return v && !(v & (v - 1)); } - -/** Check if memory differs with a given value. - * @param mem: memory to check - * @param intSize: size in int to fill - * @param intValue: value to check - * @return 0 if mem[0..intSize-1] == intValue, - * or !=0 otherwise. - */ -uint32_t base_diff(const void* mem, size_t intSize, uint32_t intValue); - -/** Fill memory with a given value. - * @param from: memory to fill - * @param to: ptr after last element to fill - * @param intval: value to use to fill - * @post from[i] == inval for 0 <= i < (to - from). - */ -void base_fill(int32_t* from, int32_t* to, uint32_t intval); - -/** Test equality. (optimistic implementation) - * @param data1,data2: data to be compared. - * @param intSize: size in int to compare. - * @return true if the contents are the same. - * @pre data1 and data2 are of size int32_t[intSize] - * null pointers are accepted as argument - */ -bool base_areEqual(const void* data1, const void* data2, size_t intSize); - -/** @return (x < 0 ? ~x : x) without a jump! - * @param x: int to test. - */ -static inline int32_t base_absNot(int32_t x) -{ - /* Algo: see base_abs - */ - uint32_t sign = ((uint32_t)x) >> 31; - return (x ^ -sign); -} - -#ifdef __cplusplus -} -#endif - -#endif /* INCLUDE_BASE_INTUTILS_H */ diff --git a/dbm/include/base/linkable.h b/dbm/include/base/linkable.h deleted file mode 100644 index e3b268e6..00000000 --- a/dbm/include/base/linkable.h +++ /dev/null @@ -1,165 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : linkable.h (base) -// -// SingleLinkable_t -// | -// +-SingleLinkable -// | -// +-DoubleLinkable_t -// | -// +-DoubleLinkable -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: linkable.h,v 1.6 2004/04/19 14:47:40 adavid Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_LINKABLE_H -#define INCLUDE_BASE_LINKABLE_H - -#include - -/** - * @file - * - * Defines base linkable structures for single and double linked lists. - * struct is used (instead of class) for style reasons (though it's the - * same conceptually): class refers to an object, struct refers to a - * simple data structure made to be stored. - * These structures are defined because it is far more readable to - * have bla->link(somewhere) than the manual pointer link stuff every - * time. This reduces errors. Furthermore the default lists of the - * STL are double linked. - */ - -namespace base -{ - /** Generic untyped structure - * for generic manipulation. - */ - struct SingleLinkable_t - { - SingleLinkable_t* next; - }; - - /** Generic untyped structure - * for generic manipulation. - */ - struct DoubleLinkable_t : public SingleLinkable_t - { - DoubleLinkable_t** previous; - }; - - /** Template for typed manipulation. - */ - template - struct SingleLinkable : public SingleLinkable_t - { - /** Link this linkable node from a given root. - * @pre struct your_struct : publid SingleLinkable - * @param fromWhere: from where the node - * should be linked. - */ - void link(T** fromWhere) - { - assert(fromWhere); - - next = *fromWhere; - *fromWhere = static_cast(this); - } - - /** Unlink this linkable node from a given root. - * @pre struct your_struct : publid SingleLinkable - * @param fromWhere: from where the node - * should be unlinked. - */ - void unlink(T** fromWhere) - { - assert(fromWhere && *fromWhere == static_cast(this)); - - *fromWhere = getNext(); - } - - /** Access to the (typed) next linkable element. - * @return pointer to next element - */ - T* getNext() const { return static_cast(next); } - - /** Access to the address of the next pointed element. - * @return address of the pointer to the next element. - */ - T** getAtNext() { return reinterpret_cast(&next); } - }; - - /** Template for typed manipulation. - */ - template - struct DoubleLinkable : public DoubleLinkable_t - { - /** Link this linkable node from a given root. - * @pre struct your_struct : publid DoubleLinkable - * @param fromWhere: from where the node - * should be linked. - */ - void link(T** fromWhere) - { - assert(fromWhere); - - previous = reinterpret_cast(fromWhere); - next = *fromWhere; - if (next) - getNext()->previous = reinterpret_cast(&next); - *fromWhere = static_cast(this); - } - - /** Unlink this linkable node from a - * given root. We do not need the argument - * for the root since it is a double linked - * node. - * @pre struct your_struct : publid DoubleLinkable - */ - void unlink() - { - assert(previous && *previous == static_cast(this)); - - *previous = getNext(); - if (next) - getNext()->previous = previous; - } - - /** Access to the (typed) next linkable element. - * @return pointer to next element - */ - T* getNext() const { return static_cast(next); } - - /** Access to the address of the next pointed element. - * @return address of the pointer to the next element. - */ - T** getAtNext() { return reinterpret_cast(&next); } - - /** Access to the previous element. - * @pre there is a previous element: previous != NULL - * @return address of previous element. - */ - T* getPrevious() const - { - /* the structure has next* and previous** - * where previous is the address of the previous - * next* == beginning of the previous element. - */ - return reinterpret_cast(previous); - } - - /** Cast access to previous. - * @return typed previous. - */ - T** getPreviousPtr() const { return reinterpret_cast(previous); } - }; -} // namespace base - -#endif // INCLUDE_BASE_LINKABLE_H diff --git a/dbm/include/base/memory.hpp b/dbm/include/base/memory.hpp deleted file mode 100644 index 2356eb6f..00000000 --- a/dbm/include/base/memory.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * Functions for safe and direct memory access. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 2012 - 2019, Aalborg University. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - **********************************************************************/ - -#ifndef INCLUDE_BASE_MEMORY_HPP -#define INCLUDE_BASE_MEMORY_HPP - -#include // conditional_t -#include // memcpy -#include // uint8_t - -/** - * A few notes on low-level memory manipulation: - * 1) Arbitrary pointer type-casting is UB and poor alignment triggers UB sanitizer. - * 2) Some architectures may not support instructions when the data type is not properly aligned. - * The supporting ones (e.g. Intel) may perform slower on non-aligned data. - * Therefore avoid performing direct operations and use it for storage (compression, encoding - * etc). 3) The safe way is to perform byte-wise operations (which are many and potentially slower). - * 4) Templated operations are most likely to be inlined and optimized. - * 5) GCC and Clang recognize memcpy and -O2 use appropriate move instructions. - * 6) arguments, internal variables, return values are mapped to registers - * 7) there are only "move reg, mem" and "move mem,reg" instructions thus the code below is optimal. - */ - -/** - * Reads the specified type at arbitrary memory position. - * @param address the location of the memory - * @return a copy of memory content - */ -template -Data mem_get(const void* address) -{ - Data res; - std::memcpy(&res, address, sizeof(Data)); - return res; // C++17 guarantees Return-Value-Optimization -} - -/** - * Read arbitrary type value from the specified memory location (disregarding the alignment). - * @param value the data location - * @param mem the memory place - */ -template -void mem_get(Data& value, const void* address) -{ - std::memcpy(&value, address, sizeof(Data)); // -O2: "mov rax,[xx]; mov [yy],rax;" -} - -/** - * Copies arbitrary type value into specified memory location (disregarding the alignment). - * @param address the memory place - * @param value the data (passed-by-value, likely via register, enabling single instruction - * optimaztion) - */ -template -void mem_set(void* address, const Data value) -{ - static_assert(sizeof(Data) <= 16, "only up to 16byte=128bit data types are expected"); - std::memcpy(address, &value, sizeof(Data)); // -O2: "movq [xx],xmm0;" -} - -template -using uint_equivalent_t = std::conditional_t< - sizeof(T) == 1, uint8_t, - std::conditional_t>>>; - -/** - * Computes in-place bit-wise OR on the specified memory with the given mask. - * @param address the place in memory - * @param mask the binary mask of arbitrary type - */ -template -void mem_or(void* address, const Mask mask) -{ - static_assert(sizeof(Mask) * 8 <= 64, "only up to 64bit types are supported"); - using Data = uint_equivalent_t; - Data d = mem_get(address) | mem_get(&mask); // bitwise ops result in int(!) - mem_set(address, d); -} - -/** - * Computes in-place bit-wise AND on the specified memory with the given mask. - * @param mem the place in memory - * @param mask the binary mask of arbitrary type - */ -template -void mem_and(void* address, const Mask mask) -{ - static_assert(sizeof(Mask) * 8 <= 64, "only up to 64bit types are supported"); - using Data = uint_equivalent_t; - Data d = mem_get(address) & mem_get(&mask); // bitwise ops result in int(!) - mem_set(address, d); -} - -#endif /* INCLUDE_BASE_MEMORY_HPP */ diff --git a/dbm/include/base/pointer.h b/dbm/include/base/pointer.h deleted file mode 100644 index 6e5a97b4..00000000 --- a/dbm/include/base/pointer.h +++ /dev/null @@ -1,176 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : pointer.h (base) -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2000, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: pointer.h,v 1.7 2005/04/22 15:20:10 adavid Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_POINTER_H -#define INCLUDE_BASE_POINTER_H - -#include "base/intutils.h" -#include "hash/compute.h" - -#include -#include -#include - -namespace base -{ - /** A simple reference with maximal capacity for access checks. - * This is a pointer to some bounded memory. array_t is defined - * too, but pointer_t has no memory management, it is only a reference. - * Accesses ptr[i] are checked. Main purpose is debugging + simple - * iteration. std::vector does not provide these debugging capabilities. - * Everything is assumed to be 32 bits aligned - * so this wrapper is obviously not designed - * for int8 or int16 types. - */ - template - class pointer_t - { - // check assumption on valid data types - static_assert((sizeof(T) & 3) == 0 && sizeof(T) > 0); - - protected: - T* data{nullptr}; /**< data pointed */ - size_t capa{0}; /**< size of data, important for checks */ - public: - /** Default constructor - */ - pointer_t() = default; - - /** Constructor: - * @param ptr: pointer to wrap. - * @param max: number of elements - * pointed by ptr. - */ - pointer_t(T* ptr, size_t max): data{ptr}, capa{max} {} - - /** Pointer equality testing. - * It is ambiguous to define a == operator since - * it could be interpreted as pointer or content testing. - */ - bool isSamePointerAs(const pointer_t& other) const - { - return begin() == other.begin() && size() == other.size(); - } - - /** wrap and check ptr[at] - */ - T& operator[](size_t at) - { - assert(at < capa); - assert(data); - return data[at]; - } - - /** wrap and check read only ptr[at] - */ - const T& operator[](size_t at) const - { - assert(at < capa); - assert(data); - return data[at]; - } - - /** wrap and check ptr->something - */ - T* operator->() - { - assert(data); - return data; - } - - /** wrap and check *ptr - */ - T& operator*() - { - assert(data); - return *data; - } - - /** size of pointed area in T nb of elements - */ - size_t size() const { return capa; } - - /** reset all pointed elements - */ - void reset() - { - assert(capa == 0 || data); - std::fill(begin(), end(), T{}); - } - - /** @return a hash value. - */ - uint32_t hash() const - { - return hash_computeU32((uint32_t*)data, intSizeOfA(T, capa), capa); - } - - /** copy all pointed elements from a pointer. - * @param src: compatible pointer - * @pre sizes are the same. - */ - void copyFrom(const pointer_t& src) - { - assert(capa == src.capa); - assert(capa == 0 || (data && src.data)); - std::copy(src.begin(), src.end(), data); - } - - void setData(T* data, size_t capa) - { - this->data = data; - this->capa = capa; - } - - /** Simple iteration. - */ - const T* begin() const - { - assert(capa == 0 || data); - return data; - } - const T* end() const - { - assert(capa == 0 || data); - return data + capa; - } - T* begin() - { - assert(capa == 0 || data); - return data; - } - T* end() - { - assert(capa == 0 || data); - return data + capa; - } - - /** Reading data. - */ - const T* operator()() const { return data; } - }; - - /// Overload ostream <<. - template - std::ostream& operator<<(std::ostream& os, const pointer_t& p) - { - os << '(' << p.size() << ")["; - for (const T* i = p.begin(); i != p.end(); ++i) { - os << ' ' << *i; - } - return os << " ]"; - } - -} // namespace base - -#endif diff --git a/dbm/include/base/relation.h b/dbm/include/base/relation.h deleted file mode 100644 index 7f7c6ae7..00000000 --- a/dbm/include/base/relation.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : relation.h (base) - * - * Definition of partial order relations between sets or other. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * $Id: relation.h,v 1.2 2005/04/22 15:20:10 adavid Exp $ - * - *********************************************************************/ - -#ifndef INCLUDE_BASE_RELATION_H -#define INCLUDE_BASE_RELATION_H - -/** Partial order relations between two sets: - * the values depend on "exactness" of relations. - */ -typedef enum { /* EXACT relation | NON EXACT relation */ - /*--------------------|--------------------*/ - base_DIFFERENT = 0, /**< incomparable | not (set1 <= set2) */ - base_SUPERSET = 1, /**< set1 > set2 | not used */ - base_GREATER = 1, /**< same as superset | */ - base_SUBSET = 2, /**< set1 < set2 | set1 <= set2 */ - base_LESS = 2, /**< same as subset | */ - base_EQUAL = 3 /**< set1 == set2 | not used */ -} relation_t; - -/* Note: testing <=, ie, relation == base_EQUAL || relation == base_SUBSET - * is equivalent to testing (relation & base_SUBSET). The same applies to - * >=. It is also a good practice to use parenthesis since '&' has a low - * precedence. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** @return the symmetric relation (useful when - * swapping arguments for a relation): - * different -> different - * superset -> subset - * subset -> superset - * equal -> equal - * Implementation: invert the superset and subset bits. - * @param rel: relation to invert. - */ -static inline relation_t base_symRelation(relation_t rel) -{ - return (relation_t)(((rel >> 1) | (rel << 1)) & 3); -} - -/** Convertion from subset to superset */ -static inline relation_t base_sub2super(relation_t rel) { return (relation_t)(rel >> 1); } - -/** Conversion from superset to subset */ -static inline relation_t base_super2sub(relation_t rel) { return (relation_t)((rel & 1) << 1); } - -#ifdef __cplusplus -} -#endif - -#endif // INCLUDE_BASE_RELATION_H diff --git a/dbm/include/base/stats.h b/dbm/include/base/stats.h deleted file mode 100644 index cce7d3ae..00000000 --- a/dbm/include/base/stats.h +++ /dev/null @@ -1,74 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : stats.h -// -// General statistics meant for experiments but not in the release -// version of UPPAAL. -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_STATS_H -#define INCLUDE_BASE_STATS_H - -#ifdef SHOW_STATS - -#include "hash/tables.h" - -namespace base -{ - class Stats - { - public: - Stats() {} - ~Stats(); - - void count(const char* statName, const char* subStat = NULL); - - struct stat_t - { - stat_t(const char* statName, stat_t* nxt): name(statName), counter(1), next(nxt) {} - ~stat_t() { delete next; } - - const char* name; - int64_t counter; - stat_t* next; - }; - - struct entry_t : public uhash::TableSingle::Bucket_t - { - entry_t(const char* name, stat_t* next = NULL): stat(name, next) {} - - stat_t stat; // Main stat, with list of sub-stats. - }; - - private: - uhash::TableSingle table; - }; - - extern Stats stats; -} // namespace base - -// Typical way of using stats: - -#define RECORD_STAT() base::stats.count(__PRETTY_FUNCTION__, NULL) -#define RECORD_SUBSTAT(NAME) base::stats.count(__PRETTY_FUNCTION__, NAME) -#define RECORD_NSTAT(ROOT, NAME) \ - base::stats.count(ROOT, NULL); \ - base::stats.count(ROOT, NAME) - -#else - -#define RECORD_STAT() -#define RECORD_SUBSTAT(NAME) -#define RECORD_NSTAT(ROOT, NAME) - -#endif // SHOW_STATS - -#endif // INCLUDE_BASE_STATS_H diff --git a/dbm/include/config.h b/dbm/include/config.h deleted file mode 100644 index 289faa96..00000000 --- a/dbm/include/config.h +++ /dev/null @@ -1,20 +0,0 @@ -#define HAVE_INTTYPES_H 1 -#define HAVE_STDINT_H 1 -#define HAVE_SSTREAM 1 - -#define PACKAGE_STRING "UDBM 2.0.10" -#define PACKAGE_VERSION "2.0.10" -#define VERSION "2.0.10" -#define DBM_VERSION "2.0.8" -#define PACKAGE_REVISION "rev. CBB68A4A47C04F7E" - -#define PACKAGE_YEAR "2021" -#define PACKAGE_MONTH "August" - -#define PACKAGE_NAME "UDBM" -#define PACKAGE_TARNAME "UDBM" -#define PACKAGE_URL "https://www.uppaal.org/" -#define PACKAGE_BUGREPORT "uppaal@cs.aau.dk" -#define COMPILER_STRING "Compiled using -DISABLE_ASSERTX" - -//#define ENABLE_DBM_NEW 1 diff --git a/dbm/include/dbm/ClockAccessor.h b/dbm/include/dbm/ClockAccessor.h deleted file mode 100644 index 7cf16cdc..00000000 --- a/dbm/include/dbm/ClockAccessor.h +++ /dev/null @@ -1,35 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2006, Uppsala University and Aalborg University. -// All right reserved. -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_DBM_CLOCKACCESSOR_H -#define INCLUDE_DBM_CLOCKACCESSOR_H - -#include "base/inttypes.h" - -#include -#include - -namespace dbm -{ - class ClockAccessor; - typedef std::unique_ptr ClockAccessor_uptr; - // Class to access clock names in an abstract way. - class ClockAccessor - { - public: - virtual ~ClockAccessor() = default; - - /// @return the name of a given clock (index). - /// The reference clock corresponds to index 0. - virtual const std::string& getClockName(cindex_t index) const = 0; - }; - -} // namespace dbm - -#endif // INCLUDE_DBM_CLOCKACCESSOR_H diff --git a/dbm/include/dbm/Valuation.h b/dbm/include/dbm/Valuation.h deleted file mode 100644 index 1f5490cb..00000000 --- a/dbm/include/dbm/Valuation.h +++ /dev/null @@ -1,187 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : Valuation.h -// -// IntValuation & DoubleValuation -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: Valuation.h,v 1.2 2005/04/25 16:38:27 behrmann Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_DBM_VALUATION_H -#define INCLUDE_DBM_VALUATION_H - -#include "dbm/ClockAccessor.h" -#include "base/pointer.h" -#include "debug/utils.h" - -#include -#include -#include - -namespace dbm -{ - /** Valuation: like a fixed vector of scalars S with - * some basic operations on it. - * We don't use array_t because we don't want to - * resize but we need basic memory alloc/dealloc. - */ - template - class Valuation : public base::pointer_t - { - private: - size_t dynamicSize; - size_t staticSize; - // S* dynamic; - public: - /** Constructor - * @param size: size of the S valuation vector, - * or dimension. - */ - Valuation(size_t size, size_t dyn = 0): - base::pointer_t(new S[size + dyn], dyn + size), dynamicSize(dyn), staticSize(size) - { - base::pointer_t::reset(); - } - /** Copy constructor - * @param original: vector to copy - */ - Valuation(const Valuation& original): - base::pointer_t(new S[original.staticSize + original.dynamicSize], - original.staticSize + original.dynamicSize), - dynamicSize(original.dynamicSize), staticSize(original.staticSize) - { - this->copyFrom(original); - } - - ~Valuation() { delete[] this->data; } - - /** - * Copy the elements of the original vector. - * It is dangerous not to have this operator. - * @pre original.size() == size(). - */ - Valuation& operator=(const Valuation& original) - { - base::pointer_t::copyFrom(original); - return *this; - } - - /** Add value to all the elements of this vector - * EXCEPT element 0 (reference clock). - * @param value: element to add. - */ - Valuation& operator+=(S value) - { - if (value != 0) { - for (S* i = this->begin() + 1; i < this->end(); ++i) { - *i += value; - } - } - return *this; - } - void reset() { std::fill(this->begin(), this->end(), 0); } - S last() const - { - assert(base::pointer_t::size() > 0); - return (*this)[base::pointer_t::size() - 1]; - } - - S lastStatic() const - { - assert(staticSize > 0); - return (*this)[staticSize - 1]; - } - - /** Subtract value to all the elements of this vector. - * @param value: element to subtract. - */ - Valuation& operator-=(S value) { return *this += -value; } - - /** @return the delay between this point and the - * argument point. This has any sense iff - * argument point = this point + some delay. - */ - S getDelayTo(const Valuation& arg) const - { - if (base::pointer_t::size() <= 1) { - return 0; // Only ref clock. - } - S delay = arg[1] - (*this)[1]; // Get delay. -#ifndef NDEBUG // Check consistency. - size_t n = base::pointer_t::size(); - for (size_t i = 1; i < n; ++i) { - assert(arg[i] - (*this)[i] == delay); - } -#endif - return delay; - } - - std::ostream& print(std::ostream& os, const ClockAccessor& a) const - { - os << "[ " << std::setprecision(std::numeric_limits::digits10 + 1); - cindex_t id = 0; - for (auto& v : *this) { - auto name = a.getClockName(id++); - if (name[0] != '#') - os << name << "=" << v << " "; - } - return os << "]"; - } - - /** String representation of the valuation in a more - * user friendly manner than just a vector of numbers. - */ - std::string toString(const ClockAccessor& a) const - { - std::ostringstream os; - print(os, a); - return os.str(); - } - - void copyFrom(const Valuation& src) - { - assert(src.staticSize == staticSize); - assert(src.dynamicSize <= dynamicSize); - // Copy the dynamic parts in common - std::copy(src.begin(), src.end(), this->begin()); - for (size_t i = src.dynamicSize; i < dynamicSize; ++i) { - (*this)[staticSize + i] = 0; - } - } - - bool extend(size_t n) - { - S* buf = new S[n + dynamicSize + staticSize]; - - std::copy(base::pointer_t::begin(), base::pointer_t::end(), buf); - delete[] base::pointer_t::data; - // dynamicSize += n; - std::fill_n(buf + staticSize + dynamicSize, n, 0); - dynamicSize += n; - this->setData(buf, dynamicSize + staticSize); - return true; - } - }; - - using IntValuation = Valuation; - using DoubleValuation = Valuation; - - /** Overload += for automatic cast. */ - /* static inline - DoubleValuation& operator += (DoubleValuation& d, int32_t v) { - return d += (double)v; - } - - static inline - DoubleValuation& operator += (DoubleValuation& d, double v) { - return d += v; - }*/ -} // namespace dbm - -#endif // INCLUDE_DBM_VALUATION_H diff --git a/dbm/include/dbm/constraints.h b/dbm/include/dbm/constraints.h deleted file mode 100644 index 49864f0d..00000000 --- a/dbm/include/dbm/constraints.h +++ /dev/null @@ -1,360 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : constraints.h (dbm) - * C header. - * - * Definition of type, constants, and basic operations for constraints. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * v 1.2 reviewed. - * $Id: constraints.h,v 1.20 2005/09/15 12:39:22 adavid Exp $ - * - *********************************************************************/ - -#ifndef INCLUDE_DBM_CONSTRAINTS_H -#define INCLUDE_DBM_CONSTRAINTS_H - -#include "base/inttypes.h" - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** To distinguish normal integers and those - * representing constraints. "raw" is used - * because it represents an encoding and this - * is the raw representation of it. - */ -typedef int32_t raw_t; - -/** Basic clock constraint representation. - * xi-xj <= value (with the special encoding) - */ -#ifdef __cplusplus -// C++ version: constructors -struct constraint_t -{ - constraint_t() = default; - constraint_t(const constraint_t& c) = default; - constraint_t(cindex_t ci, cindex_t cj, raw_t vij): i(ci), j(cj), value{vij} {} - constraint_t(cindex_t ci, cindex_t cj, int32_t bound, bool isStrict): - i(ci), j(cj), value{(bound * 2) | (not isStrict)} - {} - - bool operator==(const constraint_t& b) const; - - cindex_t i, j; - raw_t value; -}; -#else -typedef struct -{ - cindex_t i, j; /**< indices for xi and xj */ - raw_t value; -} constraint_t; -#endif - -/** *Bound* constants. - */ -enum { - dbm_INFINITY = INT_MAX >> 1, /**< infinity */ - dbm_OVERFLOW = INT_MAX >> 2 /**< to detect overflow on computations */ -}; - -/** Bound *strictness*. Vital constant values *DO NOT CHANGE*. - */ -typedef enum { - dbm_STRICT = 0, /**< strict less than constraints: < x */ - dbm_WEAK = 1 /**< less or equal constraints : <= x */ -} strictness_t; - -/** *Raw* encoded constants. - */ -enum { - dbm_LE_ZERO = 1, /**< Less Equal Zero */ - dbm_LS_INFINITY = (dbm_INFINITY << 1), /**< Less Strict than infinity */ - dbm_LE_OVERFLOW = dbm_LS_INFINITY >> 1 /**< to detect overflow on computations */ -}; - -/** Encoding of bound into (strict) less or less equal. - * @param bound,strict: the bound to encode with the strictness. - * @return encoded constraint ("raw"). - */ -static inline raw_t dbm_bound2raw(int32_t bound, strictness_t strict) -{ - return (bound * 2) | strict; -} - -/** Encoding of bound into (strict) less or less equal. - * @param bound,isStrict: the bound to encode with a flag - * telling if the bound is strict or not. - * if isStrict is true then dbm_STRICT is taken, - * otherwise dbm_WEAK. - * @return encoded constraint ("raw"). - */ -#ifdef __cplusplus -static inline raw_t dbm_boundbool2raw(int32_t bound, bool isStrict) -{ - return (bound * 2) | (isStrict ^ 1); -} -#else -static inline raw_t dbm_boundbool2raw(int32_t bound, bool isStrict) -{ - return (bound * 2) | (isStrict ^ 1); -} -#endif - -/** Decoding of raw representation: bound. - * @param raw: encoded constraint (bound + strictness). - * @return the decoded bound value. - */ -static inline int32_t dbm_raw2bound(raw_t raw) { return (raw >> 1); } - -/** Make an encoded constraint weak. - * @param raw: bound to make weak. - * @pre raw != dbm_LS_INFINITY because <= infinity - * is wrong. - * @return weak raw. - */ -static inline raw_t dbm_weakRaw(raw_t raw) -{ - assert(dbm_WEAK == 1); - assert(raw != dbm_LS_INFINITY); - return raw | dbm_WEAK; // set bit -} - -/** Make an encoded constraint strict. - * @param raw: bound to make strict. - * @return strict raw. - */ -static inline raw_t dbm_strictRaw(raw_t raw) -{ - assert(dbm_WEAK == 1); - return raw & ~dbm_WEAK; // set bit -} - -/** Decoding of raw representation: strictness. - * @param raw: encoded constraint (bound + strictness). - * @return the decoded strictness. - */ -static inline strictness_t dbm_raw2strict(raw_t raw) { return (strictness_t)(raw & 1); } - -/** Tests of strictness. - * @param raw: encoded constraint (bound + strictness). - * @return true if the constraint is strict. - * dbm_rawIsStrict(x) == !dbm_rawIsEq(x) - */ -static inline bool dbm_rawIsStrict(raw_t raw) { return ((raw & 1) ^ dbm_WEAK); } - -/** Tests of non strictness. - * @param raw: encoded constraint (bound + strictness). - * @return true if the constraint is not strict. - * dbm_rawIsStrict(x) == !dbm_rawIsEq(x) - */ -static inline bool dbm_rawIsWeak(raw_t raw) { return ((raw & 1) ^ dbm_STRICT); } - -/** Negate the strictness of a constraint. - * @param strictness: the flag to negate. - */ -static inline strictness_t dbm_negStrict(strictness_t strictness) -{ - return (strictness_t)(strictness ^ 1); -} - -/** Negate a constraint: - * neg( ASSUME dimension > 0 - * - * Format of a dbm of dimension dim: - * dbm[i,j] = dbm[i*dim+j] - * where dbm[i,j] = constraint xi-xj < or <= c_ij - * The constraint encoding is described in constraints.h - * - * The API does not support indirection table for clocks. - * Dynamic mappings must be resolved before calling these - * functions. Be careful when dealing with operation that - * involve arrays of constraints (e.g. kExtrapolate). - * As a common assumption for all operations on DBM: - * dim > 0, which means at least the reference clock is - * in the DBM. - * DBM non empty means the represented zone is non empty, - * which is, for a closed dbm the diagonal elements are =0. - * - * Common pre-condition: DBMs are always of dimension >= 1. - */ - -/** Initialize a DBM with: - * - <= 0 on the diagonal and the 1st row if CLOCKS_POSITIVE - * - <= infinity elsewhere - * @param dbm: DBM to initialize. - * @param dim: dimension. - * @return initialized DBM. - * @post DBM is closed. - */ -void dbm_init(raw_t* dbm, cindex_t dim); - -/** Set the DBM so that it contains only 0. - * @param dbm: DBM to set to 0 - * @param dim: dimension - * @return zeroed DBM - * @post DBM is closed - */ -static inline void dbm_zero(raw_t* dbm, cindex_t dim) -{ - base_fill(dbm, dbm + (dim * dim), dbm_LE_ZERO); -} - -/** Equality test with trivial dbm as obtained from - * dbm_init(dbm, dim). - * @param dbm: DBM to test - * @param dim: dimension. - */ -bool dbm_isEqualToInit(const raw_t* dbm, cindex_t dim); - -/** Test if a DBM contains the zero point of not. - * @param dbm: DBM to test. - * @param dim: dimension. - * @return true if the DBM contains the origin 0, false otherwise. - */ -bool dbm_hasZero(const raw_t* dbm, cindex_t dim); - -/** Equality test with dbm as obtained from dbm_zero(dbm, dim, tauClock) - * @param dbm: DBM to test - * @param tauClock: clock that should not be set to 0. - * @param dim: dimension - * @return zeroed DBM - * @post DBM is closed - * @pre - * - tauClock > 0 (not reference clock) - */ -static inline bool dbm_isEqualToZero(const raw_t* dbm, cindex_t dim) -{ - return (base_diff(dbm, dim * dim, dbm_LE_ZERO) == 0); -} - -/** Convex hull union between 2 DBMs. - * @param dbm1,dbm2: DBMs. - * @param dim: dimension - * @pre - * - both DBMs have the same dimension - * - both DBMs are closed and non empty - * @return dbm1 = dbm1 U dbm2 - * @post dbm1 is closed. - */ -void dbm_convexUnion(raw_t* dbm1, const raw_t* dbm2, cindex_t dim); - -/** Intersection of 2 DBMs. - * @param dbm1,dbm2: DBMs. - * @param dim: dimension. - * @pre - * - both DBMs have the same dimension - * - both DBMs are closed and non empty - * @return dbm1 = dbm1 intersected with dbm2 and - * true if dbm1 is non empty. - * @post dbm1 is closed and non empty OR dbm1 is empty. - */ -bool dbm_intersection(raw_t* dbm1, const raw_t* dbm2, cindex_t dim); - -/** Relaxed intersection of 2 DBMs. - * @param dbm1,dbm2: DBMs. - * @param dim: dimension. - * @pre - * - both DBMs have the same dimension - * - both DBMs are closed and non empty - * - dim > 0 - * @return dst = relaxed(dbm1) intersected with relaxed(dbm2) and - * true if dst is non empty. - * @post dst is closed and non empty OR dst is empty. - */ -bool dbm_relaxedIntersection(raw_t* dst, const raw_t* dbm1, const raw_t* dbm2, cindex_t dim); - -/** Test if 2 DBMs have an intersection. - * @param dbm1,dbm2: DBMs to test. - * @param dim: dimension of both DBMs. - * @return false if dbm1 intersection dbm2 is empty - * and true if it *may* be non empty (not guaranteed). - */ -bool dbm_haveIntersection(const raw_t* dbm1, const raw_t* dbm2, cindex_t dim); - -/** Constrain a DBM with a constraint. - * USAGE: - * -# dbm must be closed. - * -# reset touched: base_resetBits(touched, size) - * -# apply constraints: dbm_constrain(...) - * -# if not empty dbm_close(dbm, dim, touched) - * @param dbm: DBM. - * @param dim: dimension. - * @param i,j,constraint: the clock constraint xi-xj <= constraint - * (or < constraint) according to the clock constraint encoding. - * @param touched: bit table to keep track of modified clocks. - * @return: false if the DBM is empty, true otherwise, the constrained - * DBM, and which clocks were modified (touched). - * It is not guaranteed that the DBM is non empty, but - * if false is returned then the DBM is guaranteed to be empty. - * @pre - * - touched is at least a uint32_t[bits2intsize(dim)] - * - constraint is finite - * - dim > 1 induced by i < dim & j < dim & i != j - * - i < dim, j < dim, i != j - * @post THE RESULTING DBM MAY NOT BE CLOSED, calls to isEmpty - * can return erroneous results. - */ -bool dbm_constrain(raw_t* dbm, cindex_t dim, cindex_t i, cindex_t j, raw_t constraint, - uint32_t* touched); - -/** Constrain a DBM with several constraints. - * USAGE: - * @param dbm: DBM - * @param dim: dimension. - * @param constraints, n: the n constraints to use. - * @pre - * - DBM closed and non empty. - * - valid constraint: not of the form xi-xi <= something - * - dim > 1 induced by i < dim & j < dim & i != j - * - constraints[*].{i,j} < dim - * @return true if the DBM is non empty, the constrained - * DBM - * @post the resulting DBM is closed if it is non empty. - */ -bool dbm_constrainN(raw_t* dbm, cindex_t dim, const constraint_t* constraints, size_t n); - -/** Constrain a DBM with several constraints using a table for - * index translation (translates absolute clock indices to - * local clock indices for this DBM). - * USAGE: - * @param dbm: DBM - * @param dim: dimension. - * @param indexTable: table for index translation - * @param constraints, n: the n constraints to use. - * @pre - * - DBM closed and non empty. - * - valid constraint: not of the form xi-xi <= something - * - dim > 1 induced by i < dim & j < dim & i != j - * - constraints[*].{i,j} < dim - * @return true if the DBM is non empty, the constrained - * DBM - * @post the resulting DBM is closed if it is non empty. - */ -bool dbm_constrainIndexedN(raw_t* dbm, cindex_t dim, const cindex_t* indexTable, - const constraint_t* constraints, size_t n); - -/** Constrain a DBM with one constraint. - * If you have several constraints, it may be better to - * use the previous functions. - * @param dbm: DBM, ASSUME: closed. - * @param dim: dimension. - * @param i,j,constraint: constraint for xi-xj to use - * @pre - * - DBM is closed and non empty - * - dim > 1 induced by i < dim & j < dim & i != j - * - as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 - * and dim > (i or j) > 0 => dim > 1 - * - i < dim, j < dim, i != j - * @return true if the DBM is non empty and the constrained - * DBM. - * @post the resulting DBM is closed if it is non empty. - */ -bool dbm_constrain1(raw_t* dbm, cindex_t dim, cindex_t i, cindex_t j, raw_t constraint); - -/** Wrapper for constrain1. - * @param dbm: DBM, assume closed - * @param dim: dimension - * @param c: the constraint to apply - * @return true if the DBM is non empty - * @post the resulting DBM is closed if it is non empty - */ -static inline bool dbm_constrainC(raw_t* dbm, cindex_t dim, constraint_t c) -{ - return dbm_constrain1(dbm, dim, c.i, c.j, c.value); -} - -/** Delay operation. - * Remove constraints of the form xi-x0 <= ci - * and replace them by xi-x0 < infinity. - * It is also called strongest post-condition. - * @param dbm: DBM. - * @param dim: dimension. - * @pre - * - DBM closed and non empty - * @post DBM is closed. - */ -void dbm_up(raw_t* dbm, cindex_t dim); - -/** Delay operation with stopped clocks. - * Apply delay except for a number of stopped clocks. The - * constraints of the form xi-x0 <= ci are replaced by - * xi-x0 <= infinity for the "running" clocks xi and the - * constraints xj-xi <= cji are replaced by xj-xi <= infinity - * for xj "running" and xi stopped (j > 0). - * @param dbm: DBM. - * @param dim: dimension. - * @pre - * - DBM closed and non empty - * - stopped != NULL and stopped is a uint32_t[bits2intsize(dim)] - * @post DBM is closed - */ -void dbm_up_stop(raw_t* dbm, cindex_t dim, const uint32_t* stopped); - -/** Internal dbm_down, don't use directly */ -void dbm_downFrom(raw_t* dbm, cindex_t dim, cindex_t j0); - -/** Inverse delay operation. - * Also called weakest pre-condition. - * @param dbm: DBM. - * @param dim: dimension. - * @pre - * - DBM closed and non empty - * @post DBM is closed. - */ -static inline void dbm_down(raw_t* dbm, cindex_t dim) { dbm_downFrom(dbm, dim, 1); } - -/** Inverse delay operation with stopped clocks. - * This one is more tricky: 1) It lowers the lower - * bounds of the clocks to 0 or the minimum it can - * be (due to other constraints) *for the clocks - * that are running*. 2) It recomputes the lower - * diagonal constraints between running and stopped - * clocks. - * @param dbm: DBM. - * @param dim: dimension. - * @pre - * - DBM clocsed and non empty. - * - stopped != NULL and stopped is a uint32_t[bits2intsize(dim)] - * @post DBM is closed. - */ -void dbm_down_stop(raw_t* dbm, cindex_t dim, const uint32_t* stopped); - -/** Former "reset" operation, properly called update. - * Implement the operation x := v, where x is a clock and v - * a positive integer. - * @param dbm: DBM - * @param dim: dimension. - * @param index: clock index. - * @param value: value to reset to (may be non null), must be >=0.. - * @pre - * - DBM closed and non empty - * - dim > 1 induced by index > 0 and index < dim - * - index > 0: never reset reference clock, index < dim - * - value is finite and not an encoded clock constraint - * - value >= 0 (int used for type convenience and compatibility). - * @post DBM is closed. - */ -void dbm_updateValue(raw_t* dbm, cindex_t dim, cindex_t index, int32_t value); - -/** Free operation. Remove all constraints (lower and upper - * bounds) for a given clock, i.e., set them to infinity, - * except for x0-xk <= 0 if CLOCKS_POSITIVE is true. - * @param dbm: DBM. - * @param dim: dimension. - * @param index: the clock to free. - * @pre - * - DBM is closed and non empty - * - dim > 1 induced by index > 0 && index < dim - * - index > 0, index < dim - * @post DBM is closed. - */ -void dbm_freeClock(raw_t* dbm, cindex_t dim, cindex_t index); - -/** Free all upper bounds for a given clock. - * @param dbm: DBM. - * @param dim: dimension. - * @param index: the concerned clock. - * @pre DBM closed and non empty and 0 < index < dim - * @post DBM is closed and non empty. - */ -void dbm_freeUp(raw_t* dbm, cindex_t dim, cindex_t index); - -/** Free all upper bounds for all clocks. - * @param dbm: DBM. - * @param dim: dimension. - * @pre DBM closed and non empty. - * @post DBM closed and non empty. - */ -void dbm_freeAllUp(raw_t* dbm, cindex_t dim); - -/** @return true if dbm_freeAllUp(dbm,dim) has - * no effect on dbm. - * @param dbm,dim: DBM of dimension dim to test. - */ -bool dbm_isFreedAllUp(const raw_t* dbm, cindex_t dim); - -/** @return 0 if dbm_freeAllDown(dbm,dim) has - * no effect on dbm, or (j << 16)|i otherwise - * where i and j are the indices from where dbm - * differs from its expected result. - * @param dbm,dim: DBM of dimension dim to test. - */ -uint32_t dbm_testFreeAllDown(const raw_t* dbm, cindex_t dim); - -/** Free all lower bounds for a given clock. - * @param dbm: DBM. - * @param dim: dimension. - * @param index: index of the clock to "down-free" - * @pre - * - dim > 1 induced by index > 0 && index < dim - * - index > 0, index < dim - * - DBM closed and non empty - * @post DBM is closed and non empty. - */ -void dbm_freeDown(raw_t* dbm, cindex_t dim, cindex_t index); - -/** Free all lower bounds for all clocks. - * @param dbm: DBM. - * @param dim: dimension. - * @pre DBM closed and non empty. - * @post DBM closed and non empty. - */ -void dbm_freeAllDown(raw_t* dbm, cindex_t dim); - -/** Clock copy operation = update clock: - * xi := xj, where xi and xj are clocks. - * @param dbm: DBM. - * @param dim: dimension. - * @param i,j: indices of the clocks. - * @pre - * - DBM closed and non empty. - * - dim > 1 induced by i > 0 & i < dim - * - i > 0, j > 0, i < dim, j < dim - * @post DBM is closed. - */ -void dbm_updateClock(raw_t* dbm, cindex_t dim, cindex_t i, cindex_t j); - -/** Increment operation: xi := xi + value, where xi is a clock. - * WARNING: if offset is negative it may be incorrect to use this. - * @param dbm: DBM. - * @param dim: dimension. - * @param i: index of the clock. - * @param value: the increment. - * @pre - * - DBM closed and non empty. - * - dim > 1 induced by i > 0 && i < dim - * - i > 0, i < dim - * - if value < 0, then |value| <= min bound of clock i - * @post DBM is closed. - */ -void dbm_updateIncrement(raw_t* dbm, cindex_t dim, cindex_t i, int32_t value); - -/** More general update operation: xi := xj + value, - * where xi and yi are clocks. - * WARNING: if offset is negative it may be incorrect to use this. - * @param dbm: DBM. - * @param dim: dimension. - * @param i,j: indices of the clocks. - * @param value: the increment. - * @pre - * - DBM is closed and non empty. - * - dim > 1 induced by i > 0 && i < dim - * - i > 0, j > 0, j < dim, i < dim - * - if value < 0 then |value| <= min bound of clock j - * @post DBM is closed. - */ -void dbm_update(raw_t* dbm, cindex_t dim, cindex_t i, cindex_t j, int32_t value); - -/** @return constraint clock to == value, and return - * if the result is non empty. - * @param dbm,dim: DBM of dimension dim - * @param clock: clock index for the reset - * @param value: reset value to apply - * @pre clock != 0 (not ref clock) && clock < dim - */ -bool dbm_constrainClock(raw_t* dbm, cindex_t dim, cindex_t clock, int32_t value); - -/** Satisfy operation. - * Check if a DBM satisfies a constraint. The DBM is not modified. - * WARNING: using this for conjunction of constraints is incorrect - * because the DBM is not modified. - * @param dbm: DBM. - * @param dim: dimension. - * @param i,j: indices of clocks for the clock constraint. - * @param constraint: the encoded constraint. - * @pre - * - DBM is closed and non empty. - * - dim > 0 - * - i != j (don't touch the diagonal) - * - i < dim, j < dim - * @return true if the DBM satisfies the constraint. - */ -static inline bool dbm_satisfies(const raw_t* dbm, cindex_t dim, cindex_t i, cindex_t j, - raw_t constraint) -{ - assert(dbm && dim && i < dim && j < dim && dim > 0); - return !(dbm[i * dim + j] > constraint && /* tightening ? */ - dbm_negRaw(constraint) >= dbm[j * dim + i]); /* too tight ? */ -} - -/** Check if a DBM is empty by looking - * at its diagonal. There should be only == 0 - * constraints. - * NOTE: one should never need to call this function - * manually, unless for debugging. - * @param dbm: DBM. - * @param dim: dimension. - * @pre - * - the close function was run before on the dbm - * @return: true if empty, false otherwise. - */ -bool dbm_isEmpty(const raw_t* dbm, cindex_t dim); - -/** Close operation. Complexity: cubic in dim. - * Apply Floyd's shortest path algorithm. - * @param dbm: DBM. - * @param dim: dimension. - * @return true if the DBM is non empty. - * @post DBM is closed *if* non empty. - * @pre if dim == 1 then *dbm==dbm_LE_ZERO: close has - * not sense and will not work for dim == 1. - */ -bool dbm_close(raw_t* dbm, cindex_t dim); - -/** Check that a DBM is closed. This test is as - * expensive as dbm_close! It is there mainly for - * testing/debugging purposes. - * @param dbm: DBM to check. - * @param dim: dimension. - * @return true if DBM is closed and non empty, - * false otherwise. - */ -bool dbm_isClosed(const raw_t* dbm, cindex_t dim); - -/** Close operation. Complexity: custom*dim*dim, - * where custom is the number of clocks to look at. - * @param dbm: DBM. - * @param dim: dimension. - * @param touched: bit table that tells which clocks - * to look at. - * @pre - * - touched is at least a uint32_t[bit2intsize(dim)] - * - if there is no bit set (nothing to do) then - * the input DBM is non empty. - * @return true if the dbm is non empty. - */ -bool dbm_closex(raw_t* dbm, cindex_t dim, const uint32_t* touched); - -/** Close operation for 1 clock. Complexity: dim*dim. - * @param dbm: DBM. - * @param dim: dimension. - * @param k: the clock for which the closure applies. - * @pre - * - k < dim - * @return true if the DBM is non empty. - */ -bool dbm_close1(raw_t* dbm, cindex_t dim, cindex_t k); - -/** Specialization of close valid if only one - * constraint cij is tightened, ie, DBM is closed, - * you tighten DBM[i,j] only, then this function - * recomputes the closure more efficiently than - * calling close1(i) and close1(j). - * @param dbm: DBM - * @param dim: dimension - * @param i,j: the constraint that was tightened - * @see Rokicki's thesis page 171. - * @pre - * - dim > 1 induced by i!=j & i < dim & j < dim - * - i != j, i < dim, j < dim - * - DBM non empty: - * DBM[i,j] + DBM[j,i] >= 0, ie, the tightening - * still results in a non empty DBM. If we have - * < 0 then this close should not be called - * at all because we know the DBM is empty. - * @post DBM is not empty - */ -void dbm_closeij(raw_t* dbm, cindex_t dim, cindex_t i, cindex_t j); - -/** Tighten with a constraint c and maintain the closed form. - * @param dbm,dim DBM of dimension dim - * @param i,j,c constraint c_ij to tighten - * @pre c_ij < dbm[i,j] (it is a tightening) and -c_ij < dbm[j,i] - * (it does not tighten too much, ie, to an empty DBM). - * @post dbm is not empty. - */ -static inline void dbm_tighten(raw_t* dbm, cindex_t dim, cindex_t i, cindex_t j, raw_t c) -{ - // it is a tightening and it does not tighten too much - assert(dbm[i * dim + j] > c && dbm_negRaw(c) < dbm[j * dim + i]); - dbm[i * dim + j] = c; - dbm_closeij(dbm, dim, i, j); - assert(!dbm_isEmpty(dbm, dim)); -} - -/** Check if a DBM is unbounded, i.e., if one point - * can delay infinitely. - * @param dbm: DBM. - * @param dim: dimension. - * @return true if unbounded, false otherwise. - * @pre - * - dbm_isValid(dbm, dim) - */ -bool dbm_isUnbounded(const raw_t* dbm, cindex_t dim); - -/** Relation between 2 dbms. - * See relation_t. - * @param dbm1,dbm2: DBMs to be tested. - * @param dim: dimension of the DBMS. - * @pre - * - dbm1 and dbm2 have the same dimension - * - dbm_isValid for both DBMs - * @return: exact relation result, @see relation_t. - */ -relation_t dbm_relation(const raw_t* dbm1, const raw_t* dbm2, cindex_t dim); - -/** Test only if dbm1 <= dbm2. - * @param dbm1,dbm2: DBMs to be tested. - * @param dim: dimension of the DBMs. - * @pre - * - dbm1 and dbm2 have the same dimension - * - dbm_isValid for both DBMs - * @return true if dbm1 <= dbm2, false otherwise. - */ -bool dbm_isSubsetEq(const raw_t* dbm1, const raw_t* dbm2, cindex_t dim); - -/** Symmetric relation, just for completeness. - * @return true if dbm1 >= dbm2, false otherwise. - */ -static inline bool dbm_isSupersetEq(const raw_t* dbm1, const raw_t* dbm2, cindex_t dim) -{ - return dbm_isSubsetEq(dbm2, dbm1, dim); -} - -/** Relax upper bounds of a given clocks, ie, make them weak. - * @param dbm, dim: DBM of dimension dim - * @param clock: clock to relax. - * @pre (dim > 0 induced by) clock >= 0 && clock < dim - * && dbm_isValid(dbm,dim) - * @post DBM is closed and non empty - */ -void dbm_relaxUpClock(raw_t* dbm, cindex_t dim, cindex_t clock); - -/** Relax lower bounds of a given clocks, ie, make them weak. - * @param dbm, dim: DBM of dimension dim - * @param clock: clock to relax. - * @pre (dim > 0 induced by) clock >= 0 && clock < dim - * && dbm_isValid(dbm,dim) - * @post DBM is closed and non empty - */ -void dbm_relaxDownClock(raw_t* dbm, cindex_t dim, cindex_t clock); - -/** Relax all bounds so that they are non strict (except - * for infinity). - * @param dbm,dim: DBM of dimension dim. - * @pre dbm_isValid(dbm, dim) - * @post dbm_isValid(dbm, dim) - */ -void dbm_relaxAll(raw_t* dbm, cindex_t dim); - -/** Smallest possible delay. Render upper bounds xi-x0 <= ci0 - * non strict if possible. - * @param dbm: DBM. - * @param dim: dimension. - * @pre - * - dbm_isValid(dbm, dim) - * @post DBM is closed and non empty (if dim > 0) - */ -static inline void dbm_relaxUp(raw_t* dbm, cindex_t dim) -{ - // down of the ref clock == up of all other clocks - dbm_relaxDownClock(dbm, dim, 0); -} - -/** Smallest possible inverse delay. Render lower bounds x0-xi <= c0i - * non strict if possible. - * @param dbm: DBM. - * @param dim: dimension. - * @pre - * - dbm_isValid(dbm, dim) - * @post DBM is closed and non empty (if dim > 0) - */ -static inline void dbm_relaxDown(raw_t* dbm, cindex_t dim) -{ - // up of the ref clock == down of all other clocks - dbm_relaxUpClock(dbm, dim, 0); -} - -/** Constrain all lower bounds to be strict. - * @param dbm: DBM. - * @param dim: dimension. - * @pre dbm_isValid(dbm,dim) - * @return true if the DBM is non empty and closed, 0 otherwise. - */ -bool dbm_tightenDown(raw_t* dbm, cindex_t dim); - -/** Constrain all upper bounds to be strict. - * @param dbm: DBM. - * @param dim: dimension. - * @pre dbm_isValid(dbm,dim) - * @return true if the DBM is non empty and closed, 0 otherwise. - */ -bool dbm_tightenUp(raw_t* dbm, cindex_t dim); - -/** Copy DBMs. - * @param src: source. - * @param dst: destination. - * @param dim: dimension. - * @pre src and dst are raw_t[dim*dim] - */ -static inline void dbm_copy(raw_t* dst, const raw_t* src, cindex_t dim) -{ - memcpy(dst, src, dim * dim * sizeof(raw_t)); -} - -/** Test equality. - * @param dbm1,dbm2: DBMs to compare. - * @param dim: dimension. - * @pre dbm1 and dbm2 are raw_t[dim*dim] - * @return true if dbm1 == dbm2 - */ -static inline bool dbm_areEqual(const raw_t* dbm1, const raw_t* dbm2, cindex_t dim) -{ - return base_areEqual(dbm1, dbm2, dim * dim); -} - -/** Compute a hash value for a DBM. - * @param dbm: input DBM. - * @param dim: dimension. - * @pre dbm is a raw_t[dim*dim] - * @return hash value. - */ -static inline uint32_t dbm_hash(const raw_t* dbm, cindex_t dim) -{ - return hash_computeI32(dbm, dim * dim, dim); -} - -/** Test if a (discrete) point is included in the - * zone represented by the DBM. - * @param pt: the point - * @param dbm: DBM - * @param dim: dimension - * @pre - * - pt is a int32_t[dim] - * - dbm is a raw_t[dim*dim] - * - dbm is closed - * @return true if the pt satisfies the constraints of dbm - */ -bool dbm_isPointIncluded(const int32_t* pt, const raw_t* dbm, cindex_t dim); - -/** Test if a (real) point is included in the - * zone represented by the DBM. - * @param pt: the point - * @param dbm: DBM - * @param dim: dimension - * @pre - * - pt is a int32_t[dim] - * - dbm is a raw_t[dim*dim] - * - dbm is closed - * @return true if the pt satisfies the constraints of dbm - */ -bool dbm_isRealPointIncluded(const double* pt, const raw_t* dbm, cindex_t dim); - -/** Classical extrapolation based on maximal bounds, - * formerly called k-normalization. - * - * Extrapolate the zone using maximal constants: - * - if dbm[i,j] > max_xi then set it to infinity - * - if dbm[i,j] < -max_xj then set it to < -max_xj - * - otherwise don't touch dbm[i,j] - * - * @param dbm: DBM. - * @param dim: dimension. - * @param max: table of maximal constants to use for the clocks. - * @pre - * - DBM is closed and non empty - * - max is a int32_t[dim] - * - max[0] = 0 (reference clock) - * @post DBM is closed - */ -void dbm_extrapolateMaxBounds(raw_t* dbm, cindex_t dim, const int32_t* max); - -/** Diagonal extrapolation based on maximal bounds. - * - * Update dbm[i,j] with - * - infinity if dbm[i,j] > max_xi - * - infinity if dbm[0,i] < -max_xi - * - infinity if dbm[0,j] < -max_xj, i != 0 - * - <-max_xj if dbm[i,j] < -max_xj, i == 0 - * - dbm[i,j] otherwise - * - * @param dbm: DBM. - * @param dim: dimension. - * @param max: table of maximal constants. - * @pre - * - DBM is closed and non empty - * - max is a int32_t[dim] - * - max[0] = 0 (reference clock) - * @post DBM is closed. - */ -void dbm_diagonalExtrapolateMaxBounds(raw_t* dbm, cindex_t dim, const int32_t* max); - -/** Extrapolation based on lower-upper bounds. - * - * - if dbm[i,j] > lower_xi then dbm[i,j] = infinity - * - if dbm[i,j] < -upper_xj then dbm[i,j] = < -upper_xj - * - * @param dbm: DBM. - * @param dim: dimension. - * @param lower: lower bounds. - * @param upper: upper bounds. - * @pre - * - DBM is closed - * - lower and upper are int32_t[dim] - * - lower[0] = upper[0] = 0 (reference clock) - * @post DBM is closed. - */ -void dbm_extrapolateLUBounds(raw_t* dbm, cindex_t dim, const int32_t* lower, const int32_t* upper); - -/** Diagonal extrapolation based on lower-upper bounds. - * Most general approximation. - * - * Update dbm[i,j] with - * - infinity if dbm[i,j] > lower_xi - * - infinity if dbm[0,i] < -lower_xi - * - infinity if dbm[0,j] < -upper_xj for i != 0 - * - <-upper_xj if dbm[0,j] < -upper_xj for i = 0 - * - dbm[i,j] otherwise - * - * @param dbm: DBM. - * @param dim: dimension. - * @param lower: lower bounds. - * @param upper: upper bounds. - * @pre - * - DBM is closed and non empty - * - lower and upper are int32_t[dim] - * - lower[0] = upper[0] = 0 (reference clock) - * @post DBM is closed. - */ -void dbm_diagonalExtrapolateLUBounds(raw_t* dbm, cindex_t dim, const int32_t* lower, - const int32_t* upper); - -/** Shrink and expand a DBM: - * - takes 2 bit arrays: the source array marks which - * clocks are used in the source DBM, and the - * destination array marks the clocks in the destination - * DBM - * - removes clock constraints in source and not - * in destination - * - adds clock constraints not in source and in - * destination - * - leaves clock constraints that are in source - * and in destination - * - * @param dbmSrc: source DBM - * @param dimSrc: dimension of dbmSrc - * @param dbmDst: destination DBM - * @param bitSrc: source bit array - * @param bitDst: destination bit array - * @param bitSize: size in int of the bit arrays \a bitSrc and \a bitDst - * @param table: where to write the indirection table for the - * destination DBM, \a dbmDst. If bit \a i is set in the bitDst, then - * table[i] gives the index used in the \a dbmDst. - * - * @return dimDst = dimension of dbmDst. - * @pre let maxDim = bitSize * 32: - * - dbmDst is at least a raw_t[resultDim*resultDim] where - * resultDim = base_countBitsN(bitDst, bitSize) - * - dimSrc = number of bits set in bitSrc - * - bitSrc and bitDst are uint32_t[bitSize] - * - table is at least a uint32_t[maxDim] - * - bitSize <= bits2intsize(maxDim) - * - dimSrc > 0 - * - first bit in bitSrc is set - * - first bit in bitDst is set - * - bitSrc and bitDst are different (contents): - * the function is supposed to be called only - * if there is work to do - * - dbmSrc != dbmDst (pointers): we do not - * modify the source DBM - * - bitSize > 0 because at least ref clock - * @post - * - dimDst (returned) == number of bits in bitDst - * - for all bits set in bitDst at positions i, - * then table[i] is defined and gives the proper - * indirection ; for other bits, table[i] is - * untouched. - */ -cindex_t dbm_shrinkExpand(const raw_t* dbmSrc, raw_t* dbmDst, cindex_t dimSrc, - const uint32_t* bitSrc, const uint32_t* bitDst, size_t bitSize, - cindex_t* table); - -/** Variant of dbm_shrinkExpand: Instead of giving - * bit arrays, you provide one array of the clocks - * you want in the destination. - * @param dbmDst, dimDst: destination DBM of dimension dimDst - * @param dbmSrc, dimSrc: source DBM of dimension dimSrc - * @param cols: indirection table to copy the DBM, ie, - * rows (and columns) i of the destination come from - * cols[i] in the source if ~cols[i] (ie != ~0). - * @pre cols is a cindex_t[dimDst], cols[0] is ignored - * since the ref clock is always at 0, and - * for all i < dimDst: cols[i] < dimSrc. - */ -void dbm_updateDBM(raw_t* dbmDst, const raw_t* dbmSrc, cindex_t dimDst, cindex_t dimSrc, - const cindex_t* cols); - -/** Swap clocks. - * @param dbm,dim: DBM of dimension dim. - * @param x,y: clocks to swap. - */ -void dbm_swapClocks(raw_t* dbm, cindex_t dim, cindex_t x, cindex_t y); - -/** Test if the diagonal is correct. - * Constraints on the diagonal should be <0 if the - * DBM is empty or <=0 for non empty DBMs. Positive - * constraints are allowed in principle but such DBMs - * are not canonical. - * @param dbm: DBM. - * @param dim: dimension. - * @return true if the diagonal <=0. - */ -bool dbm_isDiagonalOK(const raw_t* dbm, cindex_t dim); - -/** Test if - * - dbm is closed - * - dbm is not empty - * - constraints in the 1st row are at most <=0 - */ -bool dbm_isValid(const raw_t* dbm, cindex_t dim); - -/** Convert code to string. - * @param rel: relation result to translate. - * @return string to print. - * DO NOT deallocate or touch the result string. - */ -const char* dbm_relation2string(relation_t rel); - -/** Go through a DBM (dim*dim) and - * compute the max range needed to store - * the constraints, excluding infinity. - * @param dbm: DBM. - * @param dim: dimension. - * @return max range, positive value. - */ -raw_t dbm_getMaxRange(const raw_t* dbm, cindex_t dim); - -#ifdef __cplusplus -} -#endif - -#endif /* INCLUDE_DBM_DBM_H */ diff --git a/dbm/include/dbm/fed.h b/dbm/include/dbm/fed.h deleted file mode 100644 index c234a255..00000000 --- a/dbm/include/dbm/fed.h +++ /dev/null @@ -1,1681 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : fed.h -// -// C++ federation & DBMs -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2018, Uppsala University and Aalborg University. -// All right reserved. -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_DBM_FED_H -#define INCLUDE_DBM_FED_H - -#include "base/pointer.h" -#include "dbm/dbm.h" -#include "dbm/mingraph.h" -#include "dbm/ClockAccessor.h" - -#include -#include - -/** @file - * This API offers access to DBMs and federations - * (of DBMs) through 2 classes: dbm_t and fed_t. - * These classes hide memory management and reference - * counting. Copy-on-write semantics is implemented. - */ -namespace dbm -{ - // internal classes - class idbm_t; - class ifed_t; - class fdbm_t; - class dbmlist_t; - - // public classes - class dbm_t; - class fed_t; - - /// Wrapper class for clock operations, @see dbm_t - template - class ClockOperation - { - public: - /// Clock increment and decrement. - ClockOperation &operator+(int32_t val); - ClockOperation &operator-(int32_t val); - ClockOperation &operator+=(int32_t val); - ClockOperation &operator-=(int32_t val); - - /// Execute(update) clock (+value ignored) = clock + value. - /// @pre this->dbm == op.dbm - ClockOperation &operator=(const ClockOperation &op); - - /// Execute(updateValue) clock = value. - ClockOperation &operator=(int32_t val); - - /// Check if clock constraints are satisfied. - /// Semantics: does there exist a point such that it - /// satisfies the constraint. - /// @pre we are using the same dbm_t (or fed_t) - - bool operator<(const ClockOperation &x) const; - bool operator<=(const ClockOperation &x) const; - bool operator>(const ClockOperation &x) const; - bool operator>=(const ClockOperation &x) const; - bool operator==(const ClockOperation &x) const; - bool operator<(int32_t v) const; - bool operator<=(int32_t v) const; - bool operator>(int32_t v) const; - bool operator>=(int32_t v) const; - bool operator==(int32_t v) const; - - /// The constructor should be used only by dbm_t or fed_t - /// since ClockOperation is a convenience class. - /// @param d: dbm that generated this clock operation. - /// @param c: index of the clock to manipulate. - /// @pre c < d->getDimension() - ClockOperation(TYPE *d, cindex_t c); - - /// Access to the arguments of the operation. - TYPE *getPtr() const { return ptr; } - cindex_t getClock() const { return clock; } - int32_t getVal() const { return incVal; } - - private: - TYPE *ptr; /// related dbm_t or fed_t, no reference count - cindex_t clock; /// clock to read/write - int32_t incVal; /// increment value to apply - }; - - /*********************************************************************** - * dbm_t: DBM type. A DBM is basically a matrix of dimension >= 1, - * ALWAYS >= 1. - * - * Special features: - * - * - sharing of DBMs (intern()): a cheap way to save memory - * for DBMs that are to be kept but not modified is to share - * identical DBMs (by using a hash table internally). Different - * dbm_t may point to the same idbm_t data. Another effect of - * this call is that if 2 dbm_t have had their intern() methods - * called, then test for equality is reduced to pointer testing, - * which is provided by the sameAs method. - * - * - direct access to the DBM matrix: read-only access is - * straight-forward (with the () operator). Read-write access - * (getDBM()) is more subtle because there may be no DBM allocated or - * the internal DBM may be shared with another dbm_t. Furthermore, - * the invariant of dbm_t is that it has a DBM matrix iff it is - * closed and non empty. Thus, when asking for a read-write - * direct access, we may need to allocate and copy internally. - * After the direct access, the invariant must also hold. - * Direct access must not be mixed with accessing the original - * dbm_t in case the matrix is deallocated for some reason. - * - * - relation with fed_t (the federation type): relation(xx) and - * the operators == != < > ... have the semantics of set inclusion - * check with DBMs pair-wise. These relations are exact when a - * dbm_t is compared with a dbm_t but are approximate when a dbm_t - * is compared with a fed_t, since the semantics is DBM inclusion - * check! We do not detect if a union of DBM is equal (semantically - * with respect to sets) to another DBM with the relation(xx) methods - * and < > <= .. operators. The (semantic) exact relation is provided - * by the exactRelation(xx) and le lt ge.. methods. The results from - * the approximate relations are safe, in the sense that EQUAL, SUBSET, - * and SUPERSET are reliable. However, DIFFERENT could be refined, we - * don't know. This is enough for most cases. The special case - * dbm_t >= fed_t is an exact comparison. - * - * - the closed form is maintained internally. - * - * - interaction with "raw matrices" is supported, ie, it is possible - * to use DBMs as arrays raw_t[dim*dim] where dim is the dimension - * of the DBMs. However, in these cases, it is assumed that these - * DBMs are valid, which is, dbm_isValid(dbm, dim) holds. - * - * - convenient operations: - * Assume you have declared dbm_t a,b; - * then you can write the following expressions: - * a(2) = a(3) + 3; is the clock update x2 = x3 + 3 for the DBM a - * a(1) = 0; is the clock update value (also called reset) x1 = 0 - * a(1) += 3; is the clock increment x1 += 3 - * b &= dbm_t(a(2) + 2); is the intersection of the result of - * x2 += 2 in for the DBM a and b (though a is not changed). - * if (a(2) < a(1) + 2) tests if the clock constraint x2 < x1 + 2 holds - * with respect to the DBM a. - * See the interface of ClockOperation. - * IMPORTANT: YOU ARE NOT SUPPOSED TO USE dbm_t::ClockOperation EXPLICITELY - * like declaring dbm_t::ClockOperation = .. and hack with it: this would - * give wrong results because of how + and - are implemented. This - * is kept simple here for efficiency and simplicity and - * let the compiler do its magic and optimize the final compiled - * inlined expressions! - * - ************************************************************************/ - - class dbm_t - { - friend class fed_t; - friend class dbmlist_t; - - public: - // Define maximal dimension as a bit mask. - // 2^15-1 means trouble anyway (2^15-1)^2 bytes per DBM! - enum - { - MAX_DIM_POWER = 15, - MAX_DIM = ((1 << MAX_DIM_POWER) - 1), - }; - - /// Initialize a dbm_t to empty DBM of a given dimension. - /// @param dim: dimension of the DBM. - /// @post isEmpty() - explicit dbm_t(cindex_t dim = 1); - - /// Standard copy constructor. - dbm_t(const dbm_t &arg); - - /// Copy constructor from a DBM matrix. - /// @post isEmpty() iff dim == 0 - dbm_t(const raw_t *arg, cindex_t dim); - - ~dbm_t(); - - /// @return the dimension of this DBM. - cindex_t getDimension() const; - - /// @return string representation of the - /// constraints of this DBM. A clock - /// is always positive, so "true" simply means - /// all clocks positive. - std::string toString(const ClockAccessor &, bool full = false) const; - - /** Make an unbounded DBM with the lower bounds set to low - * (strict constraints). - */ - static dbm_t makeUnbounded(const int32_t *low, cindex_t dim); - - /** Wrapper for dbm_getSizeOfMinDBM. Here for other compatibility reasons. - * @pre dimension == getDimension() - */ - static size_t getSizeOfMinDBM(cindex_t dim, mingraph_t); - - /** Construct a dbm_t from a mingraph_t. Not as a constructor - * for other compatibility reasons. - * @pre dimension == getDimension() - */ - static dbm_t readFromMinDBM(cindex_t dim, mingraph_t); - - /// Change the dimension of this DBM. - /// The resulting DBM is empty. @post isEmpty() - void setDimension(cindex_t dim); - - /// @return true if it is empty. - bool isEmpty() const; - - /// Empty this DBM. - void setEmpty(); - - /// Short for setDimension(1), has the effect of deallocating the DBM. - void nil(); - - /// @return true if this DBM contains the zero point. - bool hasZero() const; - - /// @return true if a point in the DBM can delay. - bool canDelay() const; - - /// @return a hash value. - uint32_t hash(uint32_t seed = 0) const; - - /// @return true if arg has the same internal idbmPtr. - bool sameAs(const dbm_t &arg) const; - - /// Try to share the DBM. - void intern(); - - /// Copy from a DBM. - void copyFrom(const raw_t *src, cindex_t dim); - - /// Copy to a DBM. - /// @pre dbm_isValid(dst, dim) and dim == getDimension() - void copyTo(raw_t *dst, cindex_t dim) const; - - // Overload of operators () and []: - // dbm_t::() -> DBM matrix - // dbm_t::(i) -> Clock access for clock i - // dbm_t::(i,j) -> read contraint DBM[i,j] - // dbm_t::[i] -> return matrix row i. - - /// @return read-only pointer to the internal DBM matrix. - /// @post non null pointer iff !isEmpty() - const raw_t *operator()() const; - - /// @return DBM[i,j] - /// @pre !isEmpty() && i < getDimension() && j < getDimension() otherwise segfault. - raw_t operator()(cindex_t i, cindex_t j) const; - - /// @return row DBM[i] - /// @pre !isEmpty() && i < getDimension() - const raw_t *operator[](cindex_t i) const; - - /// @return a read-write access pointer to the internal DBM. - /// @post return non null pointer iff getDimension() > 0 - raw_t *getDBM(); - - /** Compute the minimal set of constraints to represent - * this DBM. - * @see dbm_analyzeForMinDBM. - * @return the number of constraints of the set. - * @pre bitMatrix is a uint32_t[bits2intsize(dim*dim)] and !isEmpty() - */ - size_t analyzeForMinDBM(uint32_t *bitMatrix) const; - - /** Compute & save the minimal set of constraints. - * @param tryConstraints16: flag to try to save - * constraints on 16 bits, will cost dim*dim time. - * @param c_alloc: C allocator wrapper - * @param offset: offset for allocation. - * @return allocated memory. - * @pre !isEmpty(). - */ - int32_t *writeToMinDBMWithOffset(bool minimizeGraph, bool tryConstraints16, - allocator_t c_alloc, size_t offset) const; - - /** Similar to writeToMinDBMWithOffset but works with - * a pre-analyzed DBM. - * @pre !isEmpty() and bitMatrix corresponds to its - * analysis (otherwise nonsense will be written). - * @see dbm_writeAnalyzedDBM. - * @post bitMatrix is cleaned from the constraints xi>=0. - */ - int32_t *writeAnalyzedDBM(uint32_t *bitMatrix, size_t nbConstraints, bool tryConstraints16, - allocator_t c_alloc, size_t offset) const; - -#ifdef ENABLE_STORE_MINGRAPH - /** @return its minimal set of constraints. - * The result is cached, so consecutive calls are - * very cheap unless the DBM is changed in-between. - * The bit matrix returned is an uint32_t[bits2intsize(dim*dim)]. - * WARNING: You are not supposed to read anything from this - * pointer when the DBM changes in any way (deallocation too). - * @param size is the number of constraints in the graph. - * @pre !isEmpty() - */ - const uint32_t *getMinDBM(size_t *size) const; -#endif - - /** Relation with a mingraph_t, @see dbm_relationWithMinDBM. - * @pre unpackBuffer is a raw_t[dim*dim]. - */ - relation_t relation(mingraph_t ming, raw_t *unpackBuffer) const; - - /// Overload of standard operators. - /// The raw_t* arguments are assumed to be matrices of the same - /// dimension of this dbm_t (and dbm_isValid also holds). - - dbm_t &operator=(const dbm_t &); - dbm_t &operator=(const raw_t *); - - /// Comparisons have the semantics of set inclusion. - /// Equality of dimensions is checked. - /// Comparisons agains fed_t are approximate and cheap - /// since done between DBMs pair-wise. See the header. - - bool operator==(const dbm_t &) const; - bool operator==(const fed_t &) const; - bool operator==(const raw_t *) const; - bool operator!=(const dbm_t &) const; - bool operator!=(const fed_t &) const; - bool operator!=(const raw_t *) const; - bool operator<(const dbm_t &) const; - bool operator<(const fed_t &) const; - bool operator<(const raw_t *) const; - bool operator>(const dbm_t &) const; - bool operator>(const fed_t &) const; - bool operator>(const raw_t *) const; - bool operator<=(const dbm_t &) const; - bool operator<=(const fed_t &) const; - bool operator<=(const raw_t *) const; - bool operator>=(const dbm_t &) const; - bool operator>=(const fed_t &) const; // exact - bool operator>=(const raw_t *) const; - - /// Relation (wrt inclusion, approximate only for fed_t). - /// @return this (relation) arg. - - relation_t relation(const dbm_t &arg) const; - relation_t relation(const fed_t &arg) const; - relation_t relation(const raw_t *arg, cindex_t dim) const; - - /// Exact (expensive) relations (for fed_t only). - - bool lt(const fed_t &arg) const; // this less than arg - bool gt(const fed_t &arg) const; // this greater than arg - bool le(const fed_t &arg) const; // this less (than) or equal arg - bool ge(const fed_t &arg) const; // this greater (than) or equal arg - bool eq(const fed_t &arg) const; // this equal arg - relation_t exactRelation(const fed_t &arg) const; - - /// Set this zone to zero (origin). - /// @param tau: tau clock, @see dbm.h - /// @post !isEmpty() iff dim > 0. - dbm_t &setZero(); - - /// (re-)initialize the DBM with no constraint. - /// @post !isEmpty() iff dim > 0. - dbm_t &setInit(); - - /// @return dbm_isEqualToInit(DBM), @see dbm.h - bool isInit() const; - - /// @return dbm_isEqualToZero(DBM), @see dbm.h - bool isZero() const; - - /** Computes the biggest lower cost in the zone. - * This corresponds to the value - * \f$\sup\{ c \mid \exists v \in Z : c = - * \inf \{ c' \mid v[cost\mapsto c'] \in Z \} \}\f$ - */ - int32_t getUpperMinimumCost(int32_t cost) const; - - /// Only for compatibility with priced DBMs. - int32_t getInfimum() const { return 0; } - - /// Convex union operator (+). - /// @pre same dimension. - - dbm_t &operator+=(const dbm_t &); - dbm_t &operator+=(const fed_t &); // += argument.convexHull() - dbm_t &operator+=(const raw_t *); - - /// Intersection and constraint operator (&). - /// @pre same dimension, compatible indices, - /// and i != j for the constraints. - - dbm_t &operator&=(const dbm_t &); - dbm_t &operator&=(const raw_t *); - dbm_t &operator&=(const constraint_t &); - dbm_t &operator&=(const base::pointer_t &); - dbm_t &operator&=(const std::vector &); - - /// Compute the intersection with the axis of a given clock. - /// @return !isEmpty() - bool intersectionAxis(cindex_t); - - /** Methods for constraining: with one or more constraints. - * Variants with @param table: indirection table for the indices. - * - clock xi == value - * - clocks xi-xj < cij or <= cij (constraint = c) - * - clocks xi-xj < or <= b depending on strictness (strictness_t or bool). - * - or several constraints at once. - * @pre compatible indices, i != j for the constraints, and - * table is an cindex_t[getDimension()] - * @return !isEmpty() - */ - bool constrain(cindex_t i, int32_t value); - bool constrain(cindex_t i, cindex_t j, raw_t c); - bool constrain(cindex_t i, cindex_t j, int32_t b, strictness_t s); - bool constrain(cindex_t i, cindex_t j, int32_t b, bool isStrict); - bool constrain(const constraint_t &c); - bool constrain(const constraint_t *c, size_t n); - bool constrain(const cindex_t *table, const constraint_t *c, size_t n); - bool constrain(const cindex_t *table, const base::pointer_t &); - bool constrain(const cindex_t *table, const std::vector &); - - /// @return false if there is no intersection with the argument - /// or true if there *may* be an intersection. - /// @pre same dimension. - - bool intersects(const dbm_t &) const; - bool intersects(const fed_t &) const; - bool intersects(const raw_t *, cindex_t dim) const; // dim here for safety check - - /// Delay (strongest post-condition). Remove upper bounds. - /// @return this - dbm_t &up(); - - /// Delay, except for stopped clocks. - /// @param stopped is a bit array marking which clocks are stopped. - /// @pre if stopped != NULL then it is a uint32_t[bits2intsize(getDimension())]. - dbm_t &upStop(const uint32_t *stopped); - - /// Inverse delay (weakest pre-condition). Remove lower bounds. - /// @return this - dbm_t &down(); - - /// Similar to upStop but for inverse delay. - dbm_t &downStop(const uint32_t *stopped); - - /// Free clock (unconstrain). Remove constraints on a particular - /// clock, both upper and lower bounds. - /// @return this. @post freeClock(c) == freeUp(c).freeDown(c) - dbm_t &freeClock(cindex_t clock); - - /// Free upper or lower bounds only for a particular clock or - /// for all clocks. @pre 0 < clock < getDimension() - /// @return this. @see dbm.h - - dbm_t &freeUp(cindex_t clock); - dbm_t &freeDown(cindex_t clock); - dbm_t &freeAllUp(); - dbm_t &freeAllDown(); - - /** Update methods where x & y are clocks, v an integer value. - * x := v -> updateValue - * x := y -> updateClock - * x := x + v -> updateIncrement - * x := y + v -> update - * @pre 0 < x and y < getDimension(), v < infinity, and v is - * s.t. the clocks stay positive. - */ - void updateValue(cindex_t x, int32_t v); - void updateClock(cindex_t x, cindex_t y); - void updateIncrement(cindex_t x, int32_t v); - void update(cindex_t x, cindex_t y, int32_t v); - - /// Check if the DBM satisfies a constraint c_ij. - /// @pre i != j, i and j < getDimension() - - bool satisfies(cindex_t i, cindex_t j, raw_t c) const; - bool satisfies(const constraint_t &c) const; - bool operator&&(const constraint_t &c) const; - - /// @return true if this DBM contains points that can delay arbitrarily. - bool isUnbounded() const; - - /// Make upper or lower finite bounds non strict. - /// @see dbm.h. - /// @return this. - dbm_t &relaxUp(); - dbm_t &relaxDown(); - - /// Make lower bounds strict. - /// @return this. - dbm_t &tightenDown(); - - /// Make upper bounds strict. - /// @return this. - dbm_t &tightenUp(); - - /// Similar for all bounds of a particular clock. - /// @see dbm.h. Special for clock == 0: - /// relaxUp(0) = relaxDown() and relaxDown(0) = relaxUp(). - dbm_t &relaxUpClock(cindex_t clock); - dbm_t &relaxDownClock(cindex_t clock); - - /// Make all constraints (except infinity) non strict. - dbm_t &relaxAll(); - - /// Test point inclusion. - /// @pre same dimension. - - bool contains(const int32_t *point, cindex_t dim) const; - bool contains(const double *point, cindex_t dim) const; - - /** Compute the 'almost min' necessary delay from - * a point to enter this federation. If this point - * is already contained in this federation, 0.0 is - * returned. The result is 'almost min' since we - * want a discrete value, which is not possible in - * case of strict constraints. - * @pre dim == getDimension() and point[0] == 0.0 - * otherwise the computation will not work. - * @return true if it is possible to reach this DBM - * by delaying, or false if this DBM is empty or it - * is not possible to reach it by delaying. - * The delay is written in t. - * @param minVal,minStrict: another (optional) output - * is provided in the form of a delay value and a - * flag telling if the delay is strict, e.g., - * wait >= 2.1 or wait > 2.1. - * @pre minVal and minStrict are both NULL or non NULL. - */ - bool getMinDelay(const double *point, cindex_t dim, double *t, double *minVal = NULL, - bool *minStrict = NULL, const uint32_t *stopped = NULL) const; - - /** - * Compute the max delay from a point such that it respects the - * upper bound constraints of the DBM. - * @return true if the delay is possible, false otherwise. - */ - bool getMaxDelay(const double *point, cindex_t dim, double *t, double *minVal = NULL, - bool *minStrict = NULL, const uint32_t *stopped = NULL) const; - - /** Similarly for the past. - * The returned value (in t) is <= max. - * @pre max > 0 otherwise this is meaningless. - */ - bool getMaxBackDelay(const double *point, cindex_t dim, double *t, double max) const; - - bool isConstrainedBy(cindex_t, cindex_t, raw_t) const; - - /// Extrapolations: @see dbm_##method functions in dbm.h. - /// @pre max, lower, and upper are int32_t[getDimension()] - - void extrapolateMaxBounds(const int32_t *max); - void diagonalExtrapolateMaxBounds(const int32_t *max); - void extrapolateLUBounds(const int32_t *lower, const int32_t *upper); - void diagonalExtrapolateLUBounds(const int32_t *lower, const int32_t *upper); - - /** Resize this DBM: bitSrc marks the subset of clocks (out from - * a larger total set) that are in this DBM and bitDst marks the - * subset of clocks we want to change to. Resizing means keep the - * constraints of the clocks that are kept, remove the constraints - * of the clocks that are removed, and add free constraints (infinity) - * for the new clocks. - * @see dbm_shrinkExpand in dbm.h. - * @param bitSrc,bitDst,bitSize: bit strings of (int) size bitSize - * that mark the source and destination active clocks. - * @param table: redirection table to write. - * @pre bitSrc & bitDst are uint32_t[bitSize] and - * table is a uint32_t[32*bitSize] - * @post the indirection table is written. - */ - void resize(const uint32_t *bitSrc, const uint32_t *bitDst, size_t bitSize, - cindex_t *table); - - /** Resize and change clocks of this DBM. - * The updated DBM will have its clocks i coming from target[i] - * in the original DBM. - * @param target is the table that says where to put the current - * clocks in the target DBM. If target[i] = ~0 then a new free - * clock is inserted. - * @pre newDim > 0, target is a cindex_t[newDim], and - * for all i < newDim, target[i] < getDimension(). - */ - void changeClocks(const cindex_t *target, cindex_t newDim); - - /// Swap clocks x and y. - void swapClocks(cindex_t x, cindex_t y); - - /** Get a clock valuation and change only the clocks - * that are marked free. - * @param cval: clock valuation to write. - * @param freeC: free clocks to write. If freeC = NULL then all - * clocks are considered free. - * @return cval - * @throw std::out_of_range if the generation fails - * if isEmpty() or cval too constrained. - * @post if freeC != NULL, forall i < dim: freeC[i] = false - */ - void getValuation(double *cval, cindex_t dimen, bool *freeC = NULL) const; - - /// Special constructor to copy the result of a pending operation. - /// @param op: clock operation. - dbm_t(const ClockOperation &op); - - /// @see ClockOperation for more details. - /// @pre clk > 0 except for clock constraint tests - /// and clk < getDimension() - ClockOperation operator()(cindex_t clk); - - /** @return (this-arg).isEmpty() but it is able to - * stop the subtraction early if it is not empty and - * it does not modify itself. - * @pre same dimension. - */ - bool isSubtractionEmpty(const raw_t *arg, cindex_t dim) const; - bool isSubtractionEmpty(const fed_t &arg) const; - bool isSubtractionEmpty(const dbm_t &arg) const; - - /************************ - * Low-level operations * - ************************/ - - /// Simplified copy with @pre isEmpty() - void newCopy(const raw_t *arg, cindex_t dim); - - /// Simplified copy with @pre isEmpty() && !arg.isEmpty() - void newCopy(const dbm_t &arg); - - /// Simplified copy with @pre !isEmpty() - void updateCopy(const raw_t *arg, cindex_t dim); - - /// Simplified copy with @pre !isEmpty() && !arg.isEmpty() - void updateCopy(const dbm_t &arg); - - /// Const access to its idbm_t, @pre !isEmpty() - const idbm_t *const_idbmt() const; - - /// @return idbmPtr as a pointer @pre !isEmpty() - idbm_t *idbmt(); - - /// Explicit const access to the DBM matrix. - /// Note: const_dbm() and dbm() have different assertions. - /// @pre !isEmpty() - const raw_t *const_dbm() const; - - /// Mutable access to the DBM matrix. - /// @pre isMutable() - raw_t *dbm(); - - /// @return dimension with @pre isEmpty() - cindex_t edim() const; - - /// @return dimension with @pre !isEmpty() - cindex_t pdim() const; - - /// @return true if this fed_t can be modified, @pre isPointer() - bool isMutable() const; - - /// Set and return a new writable DBM, @pre !isEmpty() - raw_t *getNew(); - - /// Set and return a writable copy of this DBM, @pre !isEmpty() - raw_t *getCopy(); - - private: - /// @return idbmPtr as an int. - uintptr_t uval() const; - - /// Wrapper for idbmPtr. - void incRef() const; - - /// Wrapper for idbmPtr. - void decRef() const; - - /// Specialized versions to remove idbmPtr and setEmpty(dim), @pre !isEmpty() - void empty(cindex_t dim); - void emptyImmutable(cindex_t dim); - void emptyMutable(cindex_t dim); - - /// Set idbmPtr to empty with dimension dim. - void setEmpty(cindex_t dim); - - /// Set a pointer for idbmPtr. - void setPtr(idbm_t *ptr); - - /// Check and try to make idbmPtr mutable cheaply (eg if reference - /// counter is equal to 1 and the DBM is in the hash, then it is cheap). - /// @pre !isEmpty() - bool tryMutable(); - - /// Set idbmPtr to a newly allocated DBM with explicit dimension. - /// @pre getDimension() > 0 - raw_t *setNew(cindex_t dim); - - /// Allocate new DBM and return the matrix. - /// @pre !isEmpty() && !tryMutable() - raw_t *inew(cindex_t dim); - - /// Copy its DBM and return the matrix. - /// @pre !isEmpty() && !tryMutable() - raw_t *icopy(cindex_t dim); - - /// Widen a DBM w.r.t. drift, see fed_t. - dbm_t &driftWiden(); - - /// Implementations of previous methods with @pre isPointer() - /// useful for fed_t since the invariant states that there is - /// no empty dbm_t in fed_t. - - void ptr_intern(); - dbm_t &ptr_convexUnion(const raw_t *arg, cindex_t dim); - bool ptr_intersectionIsArg(const raw_t *arg, cindex_t dim); - bool ptr_constrain(cindex_t i, cindex_t j, raw_t c); // pre i != j - bool ptr_constrain(cindex_t k, int32_t value); // pre k != 0 - bool ptr_constrain(const constraint_t *cnstr, size_t n); - bool ptr_constrain(const cindex_t *table, const constraint_t *cnstr, size_t n); - void ptr_up(); - void ptr_upStop(const uint32_t *stopped); - void ptr_downStop(const uint32_t *stopped); - void ptr_down(); - void ptr_freeClock(cindex_t k); // pre k != 0 - void ptr_updateValue(cindex_t i, int32_t v); // pre i != 0 - void ptr_updateClock(cindex_t i, cindex_t j); // pre i != j, i !=0, j != 0 - void ptr_update(cindex_t i, cindex_t j, int32_t v); // pre i != 0, j != 0 - void ptr_freeUp(cindex_t k); // pre k != 0 - void ptr_freeDown(cindex_t k); // pre k != 0 - void ptr_freeAllUp(); - void ptr_freeAllDown(); - void ptr_relaxDownClock(cindex_t k); - void ptr_relaxUpClock(cindex_t k); - void ptr_relaxAll(); - void ptr_tightenDown(); - void ptr_tightenUp(); - bool ptr_getValuation(double *cval, cindex_t dimen, bool *freeC) const; - void ptr_swapClocks(cindex_t x, cindex_t y); - - // Coding of dimPtr: - // - if dbm_t is empty, idbmPtr = (dim << 1) | 1 - // - if dbm_t is not empty idbmPtr = pointer to idbm_t and (idbmPtr & 3) == 0 - - /// Internal pointer or special coding for empty. - idbm_t *idbmPtr; - }; - - /*************************************************************** - * fed_t: federation type. - * - * Special features: - * - * - direct reference transfer: similarly to dbm_t. - * - * - sharing of DBMs: this is a call-back for dbm_t. - * - * - raw_t* argument must satisfy dbm_isValid(..) - * - * - relations: see dbm_t, the exact relation operations (wrt - * set inclusion) are exactRelation and the methods le lt gt ge eq. - * Approximate relations are relation, < > <= >= == !=. - * - * - convenient operations: like dbm_t but for all the internal - * DBMs. This is a call-back for all the dbm_t that are in fed_t. - * - * - methods marked as dummy wrappers: these are for copy arguments. - * In the cases where the compiler wants a fed_t&, it - * won't be happy to find a fed_t, so we define a number of - * dummy wrappers to make it understand that the thing on the - * stack may be taken as a reference argument too. - * - ***************************************************************/ - - class fed_t - { - public: - /// Initialize a fed_t to empty federation of a given dimension. - /// @param dim: dimension of the federation. - /// @post isEmpty() - explicit fed_t(cindex_t dim = 1); - - /// Standard copy constructor. - fed_t(const fed_t &arg); - - /// Wrap a DBM in a federation. - fed_t(const dbm_t &arg); - - /// Copy a DBM matrix in a federation. - fed_t(const raw_t *arg, cindex_t dim); - - ~fed_t(); - - /// @return the number of DBMs in this federation. - size_t size() const; - - /// @return the dimension of this federation. - cindex_t getDimension() const; - - /// Change the dimension of this federation. - /// The resulting federation is empty. @post isEmpty() - void setDimension(cindex_t dim); - - /// @return true if it is empty. - bool isEmpty() const; - - /// Empty this federation. - void setEmpty(); - - /// Short for setDimension(1), has the effect of deallocating the DBMs. - void nil(); - - /// @return true if this DBM contains the zero point. - bool hasZero() const; - - /// @return true if a point in the federation can delay. - bool canDelay() const; - - /// @return string representation of the - /// constraints of this federation. A clock - /// is always positive, so "true" simply means - /// all clocks positive. - std::string toString(const ClockAccessor &, bool full = false) const; - - /** Computes the biggest lower cost in the zone. - * This corresponds to the value - * \f$\sup\{ c \mid \exists v \in Z : c = - * \inf \{ c' \mid v[cost\mapsto c'] \in Z \} \}\f$ - */ - int32_t getUpperMinimumCost(int cost) const; - - /// Only for compatibility with priced federations. - int32_t getInfimum() const { return 0; } - - /// Compute the intersection with the axis on clock and returns the upper bound. - /// Returns 0 if empty intersection. - int32_t maxOnZero(cindex_t clock); - - /// @return a hash value that does not depend on the order of the DBMs - /// but call reduce before to get a reliable value. - uint32_t hash(uint32_t seed = 0) const; - - /// @return true if arg has the same internal ifedPtr. - bool sameAs(const fed_t &arg) const; - - /// Try to share the DBMs. Side-effect: affects all copies of this fed_t. - void intern(); - - /// Overload of standard operators. - /// The raw_t* arguments are assumed to be matrices of the same - /// dimension of this dbm_t (and dbm_isValid also holds). - - fed_t &operator=(const fed_t &); - fed_t &operator=(const dbm_t &); - fed_t &operator=(const raw_t *); - - /// Comparisons have the semantics of set inclusion. - /// Comparisons agains fed_t are approximate and cheap - /// since done between DBMs pair-wise. See dbm_t. - /// @pre same dimension for the operators < > <= >=, use - /// relation if you don't know. - - bool operator==(const fed_t &) const; - bool operator==(const dbm_t &) const; - bool operator==(const raw_t *) const; - bool operator!=(const fed_t &) const; - bool operator!=(const dbm_t &) const; - bool operator!=(const raw_t *) const; - bool operator<(const fed_t &) const; - bool operator<(const dbm_t &) const; - bool operator<(const raw_t *) const; - bool operator>(const fed_t &) const; - bool operator>(const dbm_t &) const; - bool operator>(const raw_t *) const; - bool operator<=(const fed_t &) const; - bool operator<=(const dbm_t &) const; // exact - bool operator<=(const raw_t *) const; // exact - bool operator>=(const fed_t &) const; - bool operator>=(const dbm_t &) const; - bool operator>=(const raw_t *) const; - - /// Relation (wrt inclusion, approximate). - /// @return this (relation) arg. - - relation_t relation(const fed_t &arg) const; - relation_t relation(const dbm_t &arg) const; - relation_t relation(const raw_t *arg, cindex_t dim) const; - - /// Specialized relation test: >= arg (approximate). - bool isSupersetEq(const raw_t *arg, cindex_t dim) const; - - /// Exact (expensive) relations. See comments on dbm_t. eq: equal, - /// lt: less than, gt: greater than, le: less or equal, ge: greater or equal. - /// @pre same dimension for eq,lt,le,gt,ge - - bool eq(const fed_t &arg) const; - bool eq(const dbm_t &arg) const; - bool eq(const raw_t *arg, cindex_t dim) const; - bool lt(const fed_t &arg) const; - bool lt(const dbm_t &arg) const; - bool lt(const raw_t *arg, cindex_t dim) const; - bool gt(const fed_t &arg) const; - bool gt(const dbm_t &arg) const; - bool gt(const raw_t *arg, cindex_t dim) const; - bool le(const fed_t &arg) const; - bool le(const dbm_t &arg) const; - bool le(const raw_t *arg, cindex_t dim) const; - bool ge(const fed_t &arg) const; - bool ge(const dbm_t &arg) const; - bool ge(const raw_t *arg, cindex_t dim) const; - - relation_t exactRelation(const fed_t &arg) const; - relation_t exactRelation(const dbm_t &arg) const; - relation_t exactRelation(const raw_t *arg, cindex_t dim) const; - - /// Set this federation to zero (origin). - /// @post size() == 1 if dim > 1, 0 otherwise. - fed_t &setZero(); - - /// (re-)initialize the federation with no constraint. - /// @post size() == 1 if dim > 1, 0 otherwise. - fed_t &setInit(); - - /// Convex union of its DBMs. - fed_t &convexHull(); - - /** Similar to dbm_t::makeUnbounded but only w.r.t. the future - * of this DBM, i.e., take max(c[i],max all lower bounds[i]) - * as lower bounds (and keep strictness). - */ - dbm_t makeUnboundedFrom(const int32_t *c) const; - - /// Widen with respect to a small drift. This is to implement - /// drift w.r.t. Mani's semantics. The operation consists of - /// - widening the closed contraints by 1 and make them open, - /// - make all lower bounds strict, - /// - return a union with the original federation. - /// @pre up() was called before, namely this makes sense only - /// after delay and it is correct w.r.t. the algorithm only - /// if the upper bounds are removed. - fed_t &driftWiden(); - - /// (Set) union operator (|). Inclusion is checked and the - /// operation has the effect of reduce() on the argument. - /// @pre same dimension. - - fed_t &operator|=(const fed_t &); - fed_t &operator|=(const dbm_t &); - fed_t &operator|=(const raw_t *); - - /// Union of 2 fed_t. @post arg.isEmpty() - fed_t &unionWith(fed_t &arg); - fed_t &unionWithC(fed_t arg); // dummy wrapper - - /// Simply add (list concatenation) DBMs to this federation. - /// @pre same dimension. - - fed_t &add(const fed_t &arg); - fed_t &add(const dbm_t &arg); - fed_t &add(const raw_t *arg, cindex_t dim); - - /// Append arg to 'this', @post arg.isEmpty() - fed_t &append(fed_t &arg); - fed_t &appendC(fed_t arg); // dummy wrapper - void append(fdbm_t *arg); // low level - - /// Like append but guarantee where the argument is - /// inserted (beginning or end). - fed_t &appendBegin(fed_t &arg); - fed_t &appendEnd(fed_t &arg); - - /// Combination of appendEnd + incremental mergeReduce. - fed_t &steal(fed_t &arg); - fed_t &stealC(fed_t arg); // dummy wrapper - - /// Swap this federation with another. - void swap(fed_t &); - - /// Convex union operator (+). Every DBM of the federation - /// is unified with the argument. To get the convex hull of - /// everything, call this->convexHull() += arg; - /// @pre same dimension. - - fed_t &operator+=(const fed_t &); - fed_t &operator+=(const dbm_t &); - fed_t &operator+=(const raw_t *); - - /// Intersection and constraint operator (&). - /// @pre same dimension, compatible indices, - /// and i != j for the constraints. - - fed_t &operator&=(const fed_t &); - fed_t &operator&=(const dbm_t &); - fed_t &operator&=(const raw_t *); - fed_t &operator&=(const constraint_t &); - fed_t &operator&=(const base::pointer_t &); - fed_t &operator&=(const std::vector &); - - /// (Set) subtraction operator (-). - /// @pre same dimension. - - fed_t &operator-=(const fed_t &); - fed_t &operator-=(const dbm_t &); - fed_t &operator-=(const raw_t *); - - /// Compute (*this -= arg).down(). The interest of this - /// call is that some subtractions can be avoided if the - /// following down() negates their effects. - - fed_t &subtractDown(const fed_t &); - fed_t &subtractDown(const dbm_t &); - fed_t &subtractDown(const raw_t *); - - /// Methods for constraining: with one or more constraints. - /// Variants with @param table: indirection table for the indices. - /// @pre compatible indices, i != j for the constraints, and - /// table is an cindex_t[getDimension()]. @see dbm_t. - - bool constrain(cindex_t i, int32_t value); - bool constrain(cindex_t i, cindex_t j, raw_t c); - bool constrain(cindex_t i, cindex_t j, int32_t b, strictness_t s); - bool constrain(cindex_t i, cindex_t j, int32_t b, bool isStrict); - bool constrain(const constraint_t &c); - bool constrain(const constraint_t *c, size_t n); - bool constrain(const cindex_t *table, const constraint_t *c, size_t n); - bool constrain(const cindex_t *table, const base::pointer_t &); - bool constrain(const cindex_t *table, const std::vector &); - - /// @return false if there is no intersection with the argument - /// or true if there *may* be an intersection. - /// @pre same dimensions. - - bool intersects(const fed_t &) const; - bool intersects(const dbm_t &) const; - bool intersects(const raw_t *, cindex_t dim) const; - - /// Delay (strongest post-condition) for all the DBMs. - fed_t &up(); - - /// Delay, except for stopped clocks. - /// @param stopped is a bit array marking which clocks are stopped. - /// @pre if stopped != NULL then it is a uint32_t[bits2intsize(getDimension())]. - fed_t &upStop(const uint32_t *stopped); - - /// Inverse delay (weakest pre-condition) for all the DBMs. - fed_t &down(); - - /// Similar to upStop but for inverse delay. - fed_t &downStop(const uint32_t *stopped); - - /// Free clock (unconstraint) for all the DBMs. - fed_t &freeClock(cindex_t clock); - - /// Free upper or lower bounds only for a particular clock or - /// for all clocks. @pre 0 < clock < getDimension() - /// @return this. @see dbm.h - - fed_t &freeUp(cindex_t clock); - fed_t &freeDown(cindex_t clock); - fed_t &freeAllUp(); - fed_t &freeAllDown(); - - /// Update methods where x & y are clocks, v an integer value. - /// x := v -> updateValue - /// x := y -> updateClock - /// x := x + v -> updateIncrement - /// x := y + v -> update - /// @pre 0 < x and y < getDimension(), v < infinity, and v is - /// s.t. the clocks stay positive. - - void updateValue(cindex_t x, int32_t v); - void updateClock(cindex_t x, cindex_t y); - void updateIncrement(cindex_t x, int32_t v); - void update(cindex_t x, cindex_t y, int32_t v); - - /// @return true if this federation satisfies a constraint c_ij. - /// @pre i != j, i and j < getDimension() - - bool satisfies(cindex_t i, cindex_t j, raw_t c) const; - bool satisfies(const constraint_t &c) const; - bool operator&&(const constraint_t &c) const; - - /// @return true if this federation has points that can delay infinitely. - bool isUnbounded() const; - - /// @return the part of the federation that is unbounded (maybe empty). - fed_t getUnbounded() const; - - /// @return the part of the federation that is bounded (maybe empty). - fed_t getBounded() const; - - /// Make upper or lower finite bounds non strict for all the DBMs. - /// @see dbm.h. - /// @return this. - fed_t &relaxUp(); - fed_t &relaxDown(); - - fed_t &enlargeUp(); - - /// Make lower bounds strict. - /// @return this. - fed_t &tightenDown(); - - /// Make upper bounds strict. - /// @return this. - fed_t &tightenUp(); - - /// Similar for all bounds of a particular clock for all the DBMs. - /// @see dbm.h. Special for clock == 0: - /// relaxUp(0) = relaxDown() and relaxDown(0) = relaxUp(). - fed_t &relaxUpClock(cindex_t clock); - fed_t &relaxDownClock(cindex_t clock); - - /// Make all constraints (except infinity) non strict for all the DBMs. - fed_t &relaxAll(); - - /// Remove redundant DBMs (if included in ONE other DBM). - /// @post side effect: all copies of this fed_t are affected so - /// do not mix iterators and reduce(). - /// @return this. - fed_t &reduce(); - - /// This method is useful only for experiments. - fed_t &noReduce() { return *this; } - - /// Remove redundant DBMs (if included in the UNION of the other DBMs). - /// @post same side effect as reduce(). - /// @return this. - fed_t &expensiveReduce(); - - /// Try to merge DBMs by pairs. - /// @post same side effect as reduce(). - /// @param skip is the number of DBMs to skip for the - /// reduction, useful for incremental reductions. - /// @param level is how expensive it can be: 0=default, - /// 1=more expensive (more effective), 2=much more expensive - /// (hopefully even more effective). - /// @return this. - fed_t &mergeReduce(size_t skip = 0, int level = 0); - - /// The mergeReduce implementation uses a heuristic - /// to avoid computing (possibly) useless subtractions. - /// It is activated by default but it may miss reductions. - /// If you want to spend more time but get a better result - /// set it to false. - static void heuristicMergeReduce(bool active); - - /// Use a heuristic to recompute parts of the federation as - /// part=convexHull(part)-(convexHull(part)-part) - /// @return this. - fed_t &convexReduce(); - - /// Try to replace this by convexHull(this)-(convexHull(this)-this) - /// @return this. - fed_t &expensiveConvexReduce(); - - /// Find partitions in the federation and reduce them separately. - /// @return this. - fed_t &partitionReduce(); - - /// @return true if a point (discrete or "real") is included - /// in this federation (ie in one of its DBMs). - /// @pre same dimension. - - bool contains(const int32_t *point, cindex_t dim) const; - bool contains(const double *point, cindex_t dim) const; - - /** @return the 'almost max' possible delay backward from - * a point while still staying inside the federation. It - * is 'almost max' since we want a discrete value, which - * cannot me the max when we have strict constraints. - * The precision is 0.5. 0.0 may be returned if the point - * is too close to a border. - * @param point: the point to go backward from. - * @pre dim = getDimension() && contains(point) - */ - double possibleBackDelay(const double *point, cindex_t dim) const; - - /** Compute the 'almost min' necessary delay from - * a point to enter this federation. If this point - * is already contained in this federation, 0.0 is - * returned. The result is 'almost min' since we - * want a discrete value, which is not possible in - * case of strict constraints. - * @pre dim == getDimension() and point[0] == 0.0 - * otherwise the computation will not work. - * @return true if it is possible to reach this federation - * by delaying, or false if this federation is empty or it - * is not possible to reach it by delaying. - * The delay is written in t. - * @param minVal,minStrict: another (optional) output - * is provided in the form of a delay value and a - * flag telling if the delay is strict, e.g., - * wait >= 2.1 or wait > 2.1. - * @pre minVal and minStrict are both NULL or non NULL. - */ - bool getMinDelay(const double *point, cindex_t dim, double *t, double *minVal = NULL, - bool *minStrict = NULL, const uint32_t *stopped = NULL) const; - - /** Similarly for the past. - * The returned value (in t) is <= max, where max. - * @pre max > 0 otherwise this is meaningless. - */ - bool getMaxBackDelay(const double *point, cindex_t dim, double *t, double max) const; - - /** Compute the approximate interval delay from - * a point to enter this federation and to stay - * inside continuously. - * @return true if it is possible to reach this federation - * by delaying, false otherwise. - * @param min and max give the interval, max can be - * HUGE_VAL to mean infinity. - */ - bool getDelay(const double *point, cindex_t dim, double *min, double *max, - double *minVal = NULL, bool *minStrict = NULL, double *maxVal = NULL, - bool *maxStrict = NULL, const uint32_t *stopped = NULL) const; - - bool isConstrainedBy(cindex_t, cindex_t, raw_t) const; - - /// Extrapolations: @see dbm_##method functions in dbm.h. - /// @pre max, lower, and upper are int32_t[getDimension()] - - void extrapolateMaxBounds(const int32_t *max); - void diagonalExtrapolateMaxBounds(const int32_t *max); - void extrapolateLUBounds(const int32_t *lower, const int32_t *upper); - void diagonalExtrapolateLUBounds(const int32_t *lower, const int32_t *upper); - - /** "Split-extrapolation". Split the DBMs with the diagonal - * constraints given in argument, apply extrapolateMaxBounds - * on the result, and make sure that the resulting DBMs are - * still constrained by these diagonals. - * @param begin .. end give the diagonal constraints for - * splitting (from begin (inclusive) to end (exclusive)). - * @param max is the array of maximal bounds. - */ - void splitExtrapolate(const constraint_t *begin, const constraint_t *end, - const int32_t *max); - - /** Resize all the DBMs of this federation, @see dbm_t. - * @see dbm_shrinkExpand in dbm.h. - * @param bitSrc,bitDst,bitSize: bit strings of (int) size bitSize - * that mark the source and destination active clocks. - * @param table: redirection table to write. - * @pre bitSrc & bitDst are uint32_t[bitSize] and - * table is a uint32_t[32*bitSize] - * @post the indirection table is written. - */ - void resize(const uint32_t *bitSrc, const uint32_t *bitDst, size_t bitSize, - cindex_t *table); - - /** Resize and change clocks of all the DBMs of this federation. - * The updated DBMs will have its clocks i coming from target[i] - * in the original DBM. - * @param target is the table that says where to put the current - * clocks in the target DBMs. If target[i] = ~0 then a new free - * clock is inserted. - * @pre newDim > 0, target is a cindex_t[newDim], and - * for all i < newDim, target[i] < getDimension(). - */ - void changeClocks(const cindex_t *target, cindex_t newDim); - - /// Swap clocks x and y. - void swapClocks(cindex_t x, cindex_t y); - - /** Get a clock valuation and change only the clocks - * that are marked free. The point will belong to one - * DBM of this federation, it is unspecified which one. - * @param cval: clock valuation to write. - * @param freeC: free clocks to write, if freeC == NULL, then - * all clocks are considered free. - * @return cval - * @throw std::out_of_range if the generation fails - * if isEmpty() or cval too constrained. - * @post if freeC != NULL, forall i < dim: freeC[i] = false - * @pre same dimension. - */ - void getValuation(double *cval, cindex_t dimen, bool *freeC = NULL) const; - - /** predt operation: temporal predecessor of this federation - * avoiding 'bad'. The extra argument 'restrict' is to apply - * intersection (thus restricting) to the result, which *may* - * improve the algorithm. The argument is optional and its - * dimension must match getDimension(). - * @post the points in the resulting federation may delay - * (and stay in the result) until they belong to this federation - * without entering bad. - * @pre same dimension. - */ - fed_t &predt(const fed_t &bad, const raw_t *restrict = NULL); - fed_t &predt(const dbm_t &bad, const raw_t *restrict = NULL); - fed_t &predt(const raw_t *bad, cindex_t dim, const raw_t *restrict = NULL); - - /** succt operation: symmetric to predt except that lower2upper(bad) is - * added to the result (this is used for urgent action in strategies). - * Furthermore if lower2upper(bad) fails when needed then false is - * returned and this federation is undefined. - */ - bool succt(const fed_t &bad); - - /// @return true if this fed_t is included in predt(good,bad) - /// This test may terminate earlier than calling le(predt(good,bad)) - /// because predt does not have to be computed in full sometimes. - bool isIncludedInPredt(const fed_t &good, const fed_t &bad) const; - - /// Identify test to know if this federation has a specific DBM. - /// If (dbm_t) arg is empty, then it is trivially true (if same dimension). - bool has(const dbm_t &arg) const; - bool has(const raw_t *arg, cindex_t dim) const; - - /// Similar but test with exact same dbm_t. Note: an empty federation - /// is an empty list and an empty DBM is an empty zone. Both are - /// compatible since they contain no point but empty_fed.hasSame(empty_dbm) - /// will return false even if the dimensions are the same since an empty - /// fed_t contains no dbm_t at all. - bool hasSame(const dbm_t &arg) const; - - /** Remove the DBMs that are included in DBMs of arg (pair-wise - * inclusion checking). WARNING: If sameAs(arg) then you will - * empty this federation *and* the argument. - * @pre same dimension. - * @return !(arg <= *this) if arg is a dbm_t. - */ - void removeIncludedIn(const fed_t &arg); - bool removeIncludedIn(const dbm_t &arg); - bool removeIncludedIn(const raw_t *arg, cindex_t dim); - - /// Special constructor to copy the result of a pending operation. - /// @param op: clock operation. - fed_t(const ClockOperation &op); - - /** Overload of operator (): () or (i,j) make no sense here. - * fed_t::(i) -> clock access for clock i. - * @see ClockOperation for more details. - * @pre clk > 0 except for clock constraint tests - * and clk < getDimension(). - */ - ClockOperation operator()(cindex_t clk); - - /** @return (this-arg).isEmpty() but it is able to - * stop the subtraction early if it is not empty and - * it does not modify itself. - * @pre dbm_isValid(arg, dim) and dim == getDimension() - */ - bool isSubtractionEmpty(const raw_t *arg, cindex_t dim) const; - bool isSubtractionEmpty(const dbm_t &arg) const; - bool isSubtractionEmpty(const fed_t &arg) const; - static bool isSubtractionEmpty(const raw_t *dbm, cindex_t dim, const fed_t &fed); - - /// Subtract DBM arg1 - DBM arg2 wrapper functions. - static fed_t subtract(const raw_t *arg1, const raw_t *arg2, cindex_t dim); - static fed_t subtract(const dbm_t &arg1, const raw_t *arg2); - static fed_t subtract(const dbm_t &arg1, const dbm_t &arg2); - - /** @return a new fed_t made of all the (weak) lower bounds of the original - * fed_t (i.e. no diagonals) but without overlapping. - */ - fed_t toLowerBounds() const; - - /// Similar but for upper bounds. - fed_t toUpperBounds() const; - - /** @return a new fed_t made of upper bounds derived from the - * lower bounds from the original federation. If some lower - * bounds are strict, then this cannot be done and an empty - * federation is returned. Result = union down(this intersec weakNegRaw(dbm[i])) - */ - fed_t lower2upper() const; - - /** @return the max upper bound (raw) of a clock. - */ - raw_t getMaxUpper(cindex_t) const; - - /** @return the max lower bound (raw) of a clock. - */ - raw_t getMaxLower(cindex_t) const; - - /** Clean-up the federation of its empty dbm_t. - * Normally this is never needed except if the mutable - * iterator is used and makes some dbm_t empty. - */ - void removeEmpty(); - - /** @return true if this fed_t has an empty dbm_t in its list. - * Normally this should never occur, unless you play with dbm_t - * manually with the iterator. This is used mainly for testing. - */ - bool hasEmpty() const; - - /// Mutable iterator -> iterate though dbm_t - class iterator - { - public: - /// End of list. - static const fdbm_t *ENDF; - - /// Special constructor to end iterations. - iterator(); - - /// Initialize the iterator of a federation. - /// @param fed: federation. - iterator(ifed_t *fed); - - /// Dereference to dbm_t, @pre !null() - dbm_t &operator*() const; - - /// Dereference to dbm_t*, @pre !null() - dbm_t *operator->() const; - - /// Mutable access to the matrix as for fed_t, @pre !null() - raw_t *operator()() const; - raw_t operator()(cindex_t i, cindex_t j) const; - - /// Increment iterator, @pre !null() - iterator &operator++(); - - /// Test if there are DBMs left on the list. - bool null() const; - - /// @return true if there is another DBM after, @pre !null() - bool hasNext() const; - - /// Equality test of the internal fdbm_t* - bool operator==(const iterator &arg) const; - bool operator!=(const iterator &arg) const; - - /// Remove (and deallocate) current dbm_t. - void remove(); - - /// Remove (and deallocate) current empty dbm_t. - void removeEmpty(); - - /// Extract the current DBM from the list. - /// The result->getNext() points to the rest of the list. - fdbm_t *extract(); - - /// Insert a DBM in the list at the current position. - void insert(fdbm_t *dbm); - - private: - fdbm_t **fdbm; /// list of DBMs - ifed_t *ifed; /// to update the size - }; - - /// Const iterator -> iterate though dbm_t - class const_iterator - { - public: - /// Const iterator for end of list. - static const const_iterator ENDI; - - /// Constructor: @param fed: federation. - const_iterator(const fdbm_t *fed); - const_iterator(const fed_t &fed); - const_iterator(); - - /// Dereference to dbm_t - const dbm_t &operator*() const; - - /// Dereference to dbm_t*, @pre !null() - const dbm_t *operator->() const; - - /// Access to the matrix as for fed_t - const raw_t *operator()() const; - raw_t operator()(cindex_t i, cindex_t j) const; - - /// Increment iterator, @pre !null() - const_iterator &operator++(); - - /// Test if there are DBMs left on the list. - bool null() const; - - /// @return true if there is another DBM after, @pre !null() - bool hasNext() const; - - /// Equality test of the internal fdbm_t* - bool operator==(const const_iterator &arg) const; - bool operator!=(const const_iterator &arg) const; - - private: - const fdbm_t *fdbm; /// list of DBMs - }; - - /// Access to iterators. Limitation: you cannot modify the original - /// fed_t object otherwise the iterator will be invalidated. In - /// addition, you cannot copy the original either if the non const - /// iterator is used. - - const_iterator begin() const; - const const_iterator end() const; - iterator beginMutable(); - const iterator endMutable() const; - - // Standard erase method for the iterator. - iterator erase(iterator &iter); - - /** Dump its list of ifed_t and reload them. This is - * useful for testing mainly but can be extended later - * for saving or loading a fed_t. - * @param mem: a ifed_t[size()] - * @post isEmpty() - * @return size() - */ - size_t write(fdbm_t **mem); - - /** Symmetric: read. - * @param fed,size: a ifed_t[size] - * @post the ifed list is re-linked and belongs to this fed_t. - */ - void read(fdbm_t **fed, size_t size); - - /// @return its first dbm_t, @pre size() > 0 - const dbm_t &const_dbmt() const; - - /// @return its dbm_t, @pre size() >= 1 - /// This is a dangerous access, whatever you do - /// with this dbm_t *never* have it empty. - dbm_t &dbmt(); - - /// Remove a dbm_t from this fed_t. The match uses dbm_t::sameAs(..) - /// @return true if arg was removed, false otherwise. - bool removeThisDBM(const dbm_t &dbm); - - /// Ensure this ifed_t is mutable. - void setMutable(); - - /// @return ifedPtr with basic checks. - ifed_t *ifed(); - const ifed_t *ifed() const; - - private: - // You are not supposed to read this part :) - - // Internal constructor. - fed_t(ifed_t *ifed); - - /// Call-backs to ifed_t. - bool isMutable() const; - bool isOK() const; - void incRef() const; - void decRef() const; - void decRefImmutable() const; - - /// Convert its linked list to an array. - /// @pre ar is of size size() - void toArray(const raw_t **ar) const; - - /// Internal subtraction implemention (*this - arg). - /// @pre !isEmpty() && isMutable() - void ptr_subtract(const raw_t *arg, cindex_t dim); - -#ifdef ENABLE_STORE_MINGRAPH - /// Internal subtraction implemention (*this - arg). - /// @pre !isEmpty() && isMutable() && !arg.isEmpty() - void ptr_subtract(const dbm_t &arg); -#endif - - /// Similarly with a DBM. @pre isPointer() - relation_t ptr_relation(const raw_t *arg, cindex_t dim) const; - - /// @return true if this DBM can be ignored in subtractDown. - bool canSkipSubtract(const raw_t *, cindex_t) const; - - ifed_t *ifedPtr; - }; - - /********************************************** - * Operator overloads with const arguments. - * + : convex union (result = always DBM) - * & : intersection/constraining - * | : set union - * - : set subtraction - * @pre same dimension for the arguments! - * @see dbm_t and fed_t - **********************************************/ - - dbm_t operator+(const dbm_t &a, const raw_t *b); - dbm_t operator+(const fed_t &a, const raw_t *b); - dbm_t operator+(const dbm_t &a, const dbm_t &b); - dbm_t operator+(const dbm_t &a, const fed_t &b); - dbm_t operator+(const fed_t &a, const dbm_t &b); - dbm_t operator+(const fed_t &a, const fed_t &b); - - dbm_t operator&(const dbm_t &a, const raw_t *b); - fed_t operator&(const fed_t &a, const raw_t *b); - dbm_t operator&(const dbm_t &a, const dbm_t &b); - fed_t operator&(const dbm_t &a, const fed_t &b); - fed_t operator&(const fed_t &a, const dbm_t &b); - fed_t operator&(const fed_t &a, const fed_t &b); - - dbm_t operator&(const dbm_t &a, const constraint_t &c); - dbm_t operator&(const constraint_t &c, const dbm_t &a); - fed_t operator&(const fed_t &a, const constraint_t &c); - fed_t operator&(const constraint_t &c, const fed_t &a); - - dbm_t operator&(const dbm_t &a, const base::pointer_t &c); - dbm_t operator&(const base::pointer_t &c, const dbm_t &a); - fed_t operator&(const fed_t &a, const base::pointer_t &c); - fed_t operator&(const base::pointer_t &c, const fed_t &a); - - dbm_t operator&(const dbm_t &a, const std::vector &vec); - dbm_t operator&(const std::vector &vec, const dbm_t &a); - fed_t operator&(const fed_t &a, const std::vector &vec); - fed_t operator&(const std::vector &vec, const fed_t &a); - - fed_t operator|(const dbm_t &a, const raw_t *b); - fed_t operator|(const fed_t &a, const raw_t *b); - fed_t operator|(const dbm_t &a, const dbm_t &b); - fed_t operator|(const fed_t &a, const dbm_t &b); - fed_t operator|(const dbm_t &a, const fed_t &b); - fed_t operator|(const fed_t &a, const fed_t &b); - - fed_t operator-(const dbm_t &a, const raw_t *b); - fed_t operator-(const fed_t &a, const raw_t *b); - fed_t operator-(const dbm_t &a, const dbm_t &b); - fed_t operator-(const fed_t &a, const dbm_t &b); - fed_t operator-(const dbm_t &a, const fed_t &b); - fed_t operator-(const fed_t &a, const fed_t &b); - - fed_t operator!(const dbm_t &); - fed_t operator!(const fed_t &); - - /// Create zero or init dbm_t with a given dimension. - - dbm_t zero(cindex_t dim); - dbm_t init(cindex_t dim); - - /// Straight-forward wrapper functions: - /// @return dbm_t(arg).function(other arguments) - - dbm_t up(const dbm_t &arg); - dbm_t down(const dbm_t &arg); - dbm_t freeClock(const dbm_t &arg, cindex_t clock); - dbm_t freeUp(const dbm_t &arg, cindex_t k); - dbm_t freeDown(const dbm_t &arg, cindex_t k); - dbm_t freeAllUp(const dbm_t &arg); - dbm_t freeAllDown(const dbm_t &arg); - dbm_t relaxUp(const dbm_t &arg); - dbm_t relaxDown(const dbm_t &arg); - dbm_t relaxUpClock(const dbm_t &arg, cindex_t k); - dbm_t relaxDownClock(const dbm_t &arg, cindex_t k); - - /// Straight-forward wrapper functions: - /// @return fed_t(arg).function(other arguments) - - fed_t up(const fed_t &arg); - fed_t down(const fed_t &arg); - fed_t freeClock(const fed_t &arg, cindex_t x); - fed_t freeUp(const fed_t &arg, cindex_t k); - fed_t freeDown(const fed_t &arg, cindex_t x); - fed_t freeAllUp(const fed_t &arg); - fed_t freeAllDown(const fed_t &arg); - fed_t relaxUp(const fed_t &arg); - fed_t relaxDown(const fed_t &arg); - fed_t relaxUpClock(const fed_t &arg, cindex_t k); - fed_t relaxDownClock(const fed_t &arg, cindex_t k); - fed_t reduce(const fed_t &arg); - fed_t expensiveReduce(const fed_t &arg); - fed_t predt(const fed_t &good, const fed_t &bad); - fed_t predt(const fed_t &good, const dbm_t &bad); - fed_t predt(const fed_t &good, const raw_t *bad, cindex_t dim); - fed_t predt(const dbm_t &good, const fed_t &bad); - fed_t predt(const dbm_t &good, const dbm_t &bad); - fed_t predt(const dbm_t &good, const raw_t *bad, cindex_t dim); - fed_t predt(const raw_t *good, cindex_t dim, const fed_t &bad); - fed_t predt(const raw_t *good, cindex_t dim, const dbm_t &bad); - fed_t predt(const raw_t *good, const raw_t *bad, cindex_t dim); - -#ifndef ENABLE_DBM_NEW - /// Clean-up function useful for testing. Deallocate internally - /// allocated DBMs that are currently free. - void cleanUp(); -#endif // ENABLE_DBM_NEW -} // namespace dbm - -#include "dbm/inline_fed.h" - -#endif // INCLUDE_DBM_FED_H diff --git a/dbm/include/dbm/gen.h b/dbm/include/dbm/gen.h deleted file mode 100644 index 8a3798a6..00000000 --- a/dbm/include/dbm/gen.h +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : gen.h (dbm) - * C header. - * - * Generation of DBMs and points. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * $Id: gen.h,v 1.1 2005/04/22 15:20:10 adavid Exp $ - * - **********************************************************************/ - -#ifndef INCLUDE_DBM_GEN_H -#define INCLUDE_DBM_GEN_H - -#include "dbm/constraints.h" -#include // size_t - -#ifdef __cplusplus -extern "C" { -#endif - -/** Generate a random closed and non empty DBM. - * @param dbm: where to write the DBM. - * @param dim: dimension. - * @param range: approximate range for the values. - * @return true if it is a non trivial one (sometimes - * the generation may fail and fall back to a trivial - * DBM). A trivial DBM is created by dbm_init. - * @pre dbm is a raw_t[dim*dim] - */ -bool dbm_generate(raw_t* dbm, cindex_t dim, raw_t range); - -/** Generate a random closed and non empty DBM - * that satisfy a number of constraints. - * @param dbm: where to write the DBM. - * @param dim: dimension. - * @param range: approximate range for the values. - * @param constraints,n: the n constraints the DBM - * has to satisfy. - * @pre constraints[n] do not result in an empty DBM - * dbm is a raw_t[dim*dim], dim > 0 - * @post the result is non empty - * @return true if generation succeeded, false if it failed. - */ -bool dbm_generateConstrained(raw_t* dbm, cindex_t dim, raw_t range, const constraint_t* constraints, - size_t n); - -/** Constrain randomly an already constrained DBM. - * @param dbm,dim: DBM of dimension dim to constrain. - * @param range: maximal range for the generated valued. - * @param bitMatrix: bit matrix marking the constraints that - * should be kept. - * @pre dbm is closed and non empty, dim > 0. - * @post dbm is closed and non empty. - */ -void dbm_generatePreConstrained(raw_t* dbm, cindex_t dim, raw_t range, const uint32_t* bitMatrix); - -/** Generate 2nd DBM argument for intersection/substraction - * with a first DBM. - * @param dbm,dim: first DBM of dimension dim to generate - * a second DBM argument from. - * @param arg: where to generate a DBM of dimension dim - * to test for intersection or substraction. - * @pre dbm closed and not empty, arg is a raw_t[dim*dim] - * @post arg is closed and not empty - */ -void dbm_generateArgDBM(raw_t* arg, const raw_t* dbm, cindex_t dim); - -/** Generate a superset DBM. - * @param src: the original DBM. - * @param dst: where to write superset. - * @param dim: dimension. - * @pre - * - src and dst are raw_t[dim*dim] - * - src is non empty and closed - * @post - * - dst is non empty and closed - * - dst >= src - */ -void dbm_generateSuperset(raw_t* dst, const raw_t* src, cindex_t dim); - -/** Generate a subset DBM. - * @param src: the original DBM. - * @param dst: where to write subset. - * @param dim: dimension. - * @pre - * - src and dst are raw_t[dim*dim] - * - src is non empty and closed - * @post - * - dst is non empty and closed - * - dst >= src - * @return true if the subset is strict - */ -bool dbm_generateSubset(raw_t* dst, const raw_t* src, cindex_t dim); - -/** Generate a random discrete point that belongs to the zone. - * @param pt: memory where to write the point (x0,x1,x2..) - * @param dbm: DBM. - * @param dim: dimension. - * @pre - * - dbm is a raw_t[dim*dim] and ptr is a int32_t[dim] - * - dbm is closed and non empty, dim > 0 - * @return true if generated point is included in the DBM. - */ -bool dbm_generatePoint(int32_t* pt, const raw_t* dbm, cindex_t dim); - -/** Generate a random real point that belongs to the zone. - * Always succeeds if zone is not empty (pre-condition). - * @param pt: memory where to write the point (x0,x1,x2..) - * @param dbm: DBM. - * @param dim: dimension. - * @pre - * - dbm is a raw_t[dim*dim] and ptr is a int32_t[dim] - * - dbm is closed and non empty, dim > 0 - * @return true if generation succeeded - * @post pt is valid only if the generation succeeded - */ -bool dbm_generateRealPoint(double* pt, const raw_t* dbm, cindex_t dim); - -#ifdef __cplusplus -} -#endif - -#endif /* INCLUDE_DBM_GEN_H */ diff --git a/dbm/include/dbm/inline_fed.h b/dbm/include/dbm/inline_fed.h deleted file mode 100644 index f20d544f..00000000 --- a/dbm/include/dbm/inline_fed.h +++ /dev/null @@ -1,2217 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : inline_fed.h (dbm) -// -// Internal classes and inlined implementation of fed.h -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: inline_fed.h,v 1.34 2005/10/24 18:34:09 adavid Exp $ -// -/////////////////////////////////////////////////////////////////// - -#if defined(INCLUDE_DBM_INLINE_FED_H) || !defined(INCLUDE_DBM_FED_H) -#error "dbm/inline_fed.h wrongly included!" -#endif -#define INCLUDE_DBM_INLINE_FED_H - -#include "base/exceptions.h" -#include "base/ItemAllocator.h" -#include "base/stats.h" -#include "hash/tables.h" -#include "debug/macros.h" - -/** @file - * This file contains internal classes and inlined implementation of fed.h. - */ -namespace dbm -{ - /// @return true if ptr is a non null pointer, mainly for debugging. - static inline bool isPointer(const void *ptr) - { - return (((uintptr_t)ptr) & 3) == 0 && ptr != nullptr; - } - - /******************************************************** - * DBMTable : hash table of idbm_t to internalize them. * - ********************************************************/ - - class DBMTable : public uhash::TableDouble - { - public: - /// Default constructor, @see table.h - DBMTable() : uhash::TableDouble(dbm_t::MAX_DIM_POWER, false) {} - -#if defined(ENABLE_MONITOR) || !defined(NDEBUG) - /// this hash table should be empty now unless there have been leaks - ~DBMTable() - { - if (nbBuckets) - { - std::cerr << RED(BOLD) << nbBuckets << (nbBuckets > 1 ? " DBMs are" : " DBM is") - << " left in the internal hash table!" NORMAL "\n"; - } - } -#endif - }; - - /// One instance for the DBM table. - extern DBMTable dbm_table; - - /**************************************************** - * Allocation of DBMs: by new or internal allocator * - ****************************************************/ - -#ifdef ENABLE_DBM_NEW - - /// Clean-up function does nothing - static void cleanUp(); - - /** Allocate memory with new. - * @param dim: dimension of the idbm_t to allocate. - */ - static void *dbm_new(cindex_t dim); - - /** Deallocate memory as allocated by dbm_new. - * @param dbm: idbm_t to deallocate. - * @pre dbm != NULL - */ - static void dbm_delete(idbm_t *dbm); - -#else // ifndef ENABLE_DBM_NEW - - /** Allocate memory with a local allocator. - * @param dim: dimension of the idbm_t to allocate. - * DON'T INLINE because array_t will expand - * every call too badly. - */ - void *dbm_new(cindex_t dim); - - /** Deallocate memory as allocated by dbm_new. - * @param dbm: idbm_t to deallocate. - * @pre dbm != NULL - * DON'T INLINE because array_t will expand - * every call too badly. - */ - void dbm_delete(idbm_t *dbm); - -#endif // ENABLE_DBM_NEW - - /************************************************** - * idbm_t: internal DBM -- to be used in DBMTable * - **************************************************/ - - class idbm_t : public uhash::TableDouble::Bucket_t - { - public: - /** Maximal dimension == 2^15-1 - * because (2^15)^2 == 2^30 constraints == 2^32 bytes - * and we are in big big trouble then. - * MAX_DIM is the maximum dimension *and* the access mask. - * HASH_MASK contains the remaining bits for the hash value - * HASHED_BIT mark if this DBM is in a hash tabled (hashed). - */ - enum - { - HASHED_BIT = (1 << 31), - HASH_MASK = ~(HASHED_BIT | dbm_t::MAX_DIM), - DIM_MASK = dbm_t::MAX_DIM - }; - - /// @return dimension of this DBM. - cindex_t getDimension() const { return info & DIM_MASK; } - - /// @return a freshly computed hash value - uint32_t hash(uint32_t seed = 0) const - { - uint32_t dim = getDimension(); - return hash_computeI32(matrix, dim * dim, seed); - } - - /// @return true if this DBM is in a hash table - bool isHashed() const { return (info & HASHED_BIT) != 0; } - -#ifdef ENABLE_STORE_MINGRAPH - /// Invalidate its mingraph. - void invalidate() { minSize = SIZE_MAX; } - - /// Test if the mingraph is valid. - bool isValid() const { return minSize != SIZE_MAX; } - - /// Compute/update the mingraph. - const uint32_t *getMinGraph(size_t *size); - - /// Copy its mingraph. - /// @pre isValid() && !arg->isValid() && same DBMs. - void copyMinGraphTo(idbm_t *arg); -#endif - - /// @return true if this dbm can be modified. - bool isMutable() const - { - assert(refCounter > 0); - return refCounter == 1 && !isHashed(); - } - - /// Check if this dimPtr is mutable and try to make it so cheaply. - bool tryMutable() - { - assert(refCounter > 0); - if (refCounter > 1) - return false; -#ifdef ENABLE_STORE_MINGRAPH - invalidate(); // We're going to change this DBM. -#endif - if (isHashed()) - unhash(); - return true; - } - - /// Unhash itself. - /// @pre refCounter == 1 && isHashed() - void unhash() - { - assert(refCounter == 1 && isHashed()); - dbm_table.remove(this); - unmarkHashed(); - } - - /// @return recomputed hash value for this DBM - /// and save it partially. - uint32_t updateHash(uint32_t seed = 0) - { - uint32_t hashValue = hash(seed); - info = (info & ~HASH_MASK) | (hashValue & HASH_MASK); - return hashValue; - } - - /// Mark 'this' as hashed - void markHashed() - { - assert(!isHashed()); - info |= HASHED_BIT; - } - - /// Unmark 'this' as hashed - void unmarkHashed() - { - assert(isHashed()); - info &= ~HASHED_BIT; - } - - /// Increment reference counter. - void incRef() { refCounter++; } - - /// Decrement reference counter. - /// @post 'this' may be deallocated. - void decRef() - { - assert(refCounter > 0); - if (--refCounter == 0) - remove(); - } - - /// Simple decRef without remove() @pre refCounter > 1 - void decRefImmutable() - { - assert(refCounter > 1); - refCounter--; - } - - /// Simple remove for mutable idbm_t. @pre isMutable() - void removeMutable() - { - assert(isMutable()); - dbm_delete(this); - } - - /** Deallocate this idbm_t. - * @pre refCounter == 0 - * Not inlined since the call is present very often - * for every decRef, where decRef is called for - * garbage collection. - */ - void remove(); - - /// @return writable DBM matrix, @pre isMutable() - raw_t *dbm() - { - assert(isMutable()); - return matrix; - } - - /// @return read-only DBM matrix. - const raw_t *const_dbm() const { return matrix; } - - /// @return DBM matrix without pre-condition, careful... - raw_t *getMatrix() { return matrix; } - - /// @return newly allocated idbm_t, @param dim: DBM dimension. - static idbm_t *create(cindex_t dim) - { - return new (dbm_new(dim)) idbm_t(dim); // placement constructor - } - - /// @return newly allocated idbm_t, @param arg: original to copy. - static idbm_t *create(const idbm_t &arg) - { - return new (dbm_new(arg.getDimension())) idbm_t(arg); // placement constructor - } - - /** Constructor: use placement constructor - * to instantiate. - * @param dim: dimension of the DBM. - * @pre dim < 2^16, reasonable since such a - * DBM would have 2^32 elements and we cannot - * use a single such DBM. - * @post DBM is not initialized! - */ - idbm_t(cindex_t dim) : refCounter{1} - { - assert(dim > 0 && dim <= DIM_MASK); - info = dim; -#ifdef ENABLE_STORE_MINGRAPH - invalidate(); -#endif - } - - /** Constructor by copy: useful to get a mutable copy - * of this DBM. - * @param original: DBM to copy. - */ - idbm_t(const idbm_t &other) : refCounter{1} - { - info = other.getDimension(); -#ifdef ENABLE_STORE_MINGRAPH - invalidate(); -#endif - dbm_copy(matrix, other.matrix, info); - } - - private: - /// Must never be called - ~idbm_t() = delete; - - /* Inherited variables from parent class: - * idbm_t **previous, *next: for collision list of - * the internal hash table. - * uint32_t info: special coding is as follows - * info & 0x80000000 = mutable bit = is not hashed - * info & 0x7fff8000 = higher bits of hash value - * info & 0x00007fff = dimension (default DBM_MAX_DIM) - */ - uint32_t refCounter; //< reference counter -#ifdef ENABLE_STORE_MINGRAPH - size_t minSize; -#endif - raw_t matrix[]; //< DBM matrix - }; - -#ifdef ENABLE_DBM_NEW - - /// Clean-up function does nothing - static inline void cleanUp() {} - - /** Allocate memory with new. - * @param dim: dimension of the idbm_t to allocate. - */ - static inline void *dbm_new(cindex_t dim) - { -#ifdef ENABLE_STORE_MINGRAPH - return new int32_t[intSizeOf(idbm_t) + dim * dim + bits2intsize(dim * dim)]; -#else - return new int32_t[intSizeOf(idbm_t) + dim * dim]; -#endif - } - - /** Deallocate memory as allocated by dbm_new. - * @param dbm: idbm_t to deallocate. - * @pre dbm != NULL - */ - static inline void dbm_delete(idbm_t *dbm) - { - assert(dbm); - delete[] reinterpret_cast(dbm); - } - -#endif // ENABLE_DBM_NEW - - /********************************* - * Allocation of fdbm_t & ifed_t * - *********************************/ - - /// Use a struct here to instantiate an ItemAllocator (and - /// cheat gravely with the allocator). fdbm_t has a dbm_t as - /// member, which implies a constructor, which bugs us very much. - struct alloc_fdbm_t - { - ifed_t *next; //< list of DBMs for the federation - idbm_t *idbm; //< DBM itself - }; - - /// Similarly for ifed_t - struct alloc_ifed_t - { - size_t fedSize; - fdbm_t *fhead; - uint32_t refCounter; - cindex_t dim; - }; - - /// Allocator instance. - extern base::ItemAllocator fdbm_allocator; - extern base::ItemAllocator ifed_allocator; - - /******************************************************** - * Federation of DBMs: list containing individual DBMs. * - ********************************************************/ - - class fdbm_t - { - public: - /// Copy a DBM into a newly created fdbm_t. - /// @param adbm: the DBM to copy. - /// @param nxt: list of DBMs to append. - static fdbm_t *create(const raw_t *adbm, cindex_t dim, fdbm_t *nxt = NULL) - { - fdbm_t *fdbm = create(nxt); - fdbm->idbm.newCopy(adbm, dim); - return fdbm; - } - static fdbm_t *create(const dbm_t &adbm, fdbm_t *nxt = NULL) - { - fdbm_t *fdbm = create(nxt); - fdbm->idbm.newCopy(adbm); - return fdbm; - } - - /// Copy start and append end to the copy. - static fdbm_t *copy(const fdbm_t *start, fdbm_t *end = NULL); - - /// Wrapper methods. - fdbm_t *copy() const { return copy(this); } - bool isEmpty() const { return idbm.isEmpty(); } - cindex_t getDimension() const { return idbm.getDimension(); } - - /// Remove the list starting at fhead. - static void removeAll(fdbm_t *fhead); - - /// Remove this fdbm_t and its DBM. - void remove() - { - idbm.nil(); - fdbm_allocator.deallocate(reinterpret_cast(this)); - } - - /// Remove this fdbm_t with @pre isEmpty() - void removeEmpty() - { - assert(isEmpty()); - fdbm_allocator.deallocate(reinterpret_cast(this)); - } - - /// Compute list size. - size_t size() const - { - const fdbm_t *f = this; - size_t s = 0; - do - { - f = f->next; - ++s; - } while (f); - return s; - } - - /// @return the internal DBM. - const dbm_t &const_dbmt() const - { - assert(!idbm.isEmpty()); - return idbm; - } - dbm_t &dbmt() { return idbm; } - - /// Unchecked access. - raw_t *getMatrix() { return idbm.idbmt()->getMatrix(); } - - /// @return start appended with end. - static fdbm_t *append(fdbm_t *start, fdbm_t *end); - - /// @return next for iterations. - fdbm_t **getNextMutable() { return &next; } - const fdbm_t *getNext() const { return next; } - fdbm_t *getNext() { return next; } - - /// Test its next pointer. - bool hasNext(fdbm_t **nxt) const { return &next == nxt; } - - /// Change next for iterations. - void setNext(fdbm_t *nxt) { next = nxt; } - - /// Remove this and return next; - fdbm_t *removeAndNext() - { - fdbm_t *nxt = next; - remove(); - return nxt; - } - /// Remove this and return next; - fdbm_t *removeEmptyAndNext() - { - fdbm_t *nxt = next; - removeEmpty(); - return nxt; - } - - private: - /// Creation of fdbm_t using an allocator. - static fdbm_t *create(fdbm_t *nxt = NULL); - - /// Must never be called - ~fdbm_t() = delete; - - fdbm_t *next; //< next DBM in the list. - dbm_t idbm; //< (internal) DBM. - }; - - /*************************************** - * ifed_t: head of the federation list * - ***************************************/ - - /// Simple list of DBMs for light-weight computations. - class dbmlist_t - { - public: - dbmlist_t() : fedSize(0), fhead(NULL) {} - dbmlist_t(size_t size, fdbm_t *flist) : fedSize(size), fhead(flist) {} - dbmlist_t(const raw_t *arg, cindex_t dim) : fedSize(1), fhead(fdbm_t::create(arg, dim)) {} - dbmlist_t(const dbm_t &arg) : fedSize(1), fhead(fdbm_t::create(arg)) {} - - /// Append a list of fdbm_t. - dbmlist_t &append(dbmlist_t &arg) - { - fhead = fedSize > arg.fedSize ? fdbm_t::append(arg.fhead, fhead) - : fdbm_t::append(fhead, arg.fhead); - fedSize += arg.fedSize; - return *this; - } - dbmlist_t &appendBegin(dbmlist_t &arg) - { - fhead = fdbm_t::append(arg.fhead, fhead); - fedSize += arg.fedSize; - return *this; - } - dbmlist_t &appendEnd(dbmlist_t &arg) - { - fhead = fdbm_t::append(fhead, arg.fhead); - fedSize += arg.fedSize; - return *this; - } - /// Append just one fdbm_t, not the whole list! - dbmlist_t &append(fdbm_t *arg) - { - assert(arg); - arg->setNext(fhead); - fhead = arg; - fedSize++; - return *this; - } - /// Append a copy of arg, @pre dimension is the same as the other DBMs. - raw_t *append(const raw_t *arg, cindex_t dim) - { - fhead = fdbm_t::create(arg, dim, fhead); - fedSize++; - return fhead->getMatrix(); - } - - /// Remove DBMs of 'this' that are included in arg - /// and DBMs of arg that are included in 'this'. - void removeIncluded(dbmlist_t &arg); - - /// Union of arg with this dbmlist_t, does inclusion checking - /// @post dbmlist_t arg is invalid. - dbmlist_t &unionWith(dbmlist_t &arg) - { - removeIncluded(arg); - append(arg); - return *this; - } - - /// Simple reduction by inclusion check of DBMs. - void reduce(cindex_t dim); - - /// Reduction by inclusion check + merge (by pairs) of DBMs. - void mergeReduce(cindex_t dim, size_t jumpj = 0, int expensiveTry = 0); - - /// @return the federation size. - size_t size() const - { - assert((fedSize == 0) == (fhead == NULL)); - assert(fhead == NULL || fedSize == fhead->size()); - return fedSize; - } - - /// Head of the list. - const fdbm_t *const_head() const { return fhead; } - fdbm_t *head() { return fhead; } - fdbm_t **atHead() { return &fhead; } - - /// Update the federation size. - void incSize(size_t n = 1) { fedSize += n; } - void decSize(size_t n = 1) - { - assert(fedSize >= n); - fedSize -= n; - } - - /// Brutal re-set of the list. - void reset(fdbm_t *dbms = NULL, size_t size = 0) - { - fedSize = size; - fhead = dbms; - } - void reset(dbmlist_t &l) { reset(l.fhead, l.fedSize); } - - /// @return 'this' intersected with arg. @pre same dimension. - dbmlist_t &intersection(const raw_t *arg, cindex_t dim); - dbmlist_t &intersection(const dbm_t &arg, cindex_t dim); - - /// @return a simple copy of this list of DBMs. - dbmlist_t copyList() const { return dbmlist_t(fedSize, fdbm_t::copy(fhead)); } - - /// Steal one DBM of a dbmlist_t. - void steal(fdbm_t **dbm, dbmlist_t &owner) { steal(&fhead, dbm, owner); } - /// @pre head is somewhere in this list of DBMs - fdbm_t **steal(fdbm_t **head, fdbm_t **dbm, dbmlist_t &owner) - { - assert(owner.fedSize && dbm && *dbm && head); - fdbm_t **atNext = (*dbm)->getNextMutable(); - fdbm_t *next = *atNext; - *atNext = *head; - *head = *dbm; - *dbm = next; - incSize(); - owner.decSize(); - return atNext; - } - - /// Steal a list and append it at the end. - void stealFromToEnd(fdbm_t **next, dbmlist_t &dbmList) - { - while (*next) - next = (*next)->getNextMutable(); - *next = dbmList.fhead; - incSize(dbmList.fedSize); - dbmList.reset(); - } - - /// Swap DBM lists. - void swap(dbmlist_t &arg) - { - size_t s = fedSize; - fedSize = arg.fedSize; - arg.fedSize = s; - fdbm_t *h = fhead; - fhead = arg.fhead; - arg.fhead = h; - } - - /// Copy ref. - void copyRef(dbmlist_t &arg) - { - fedSize = arg.fedSize; - fhead = arg.fhead; - } - - /// Remove head of list. @pre size() > 0. - void removeHead() - { - assert(fedSize && fhead); - fhead = fhead->removeAndNext(); - decSize(); - } - -#ifndef NDEBUG - /// Print for debugging only, use operator << on fed_t instead. - void print(std::ostream &os = std::cerr) const; - void err() const; - void out() const; -#endif - - protected: - size_t fedSize; //< size of the federation - fdbm_t *fhead; //< federation head of the list (1st DBM) - }; - - class ifed_t : public dbmlist_t - { - public: - /// Creation and initialization of ifed_t. @pre the dbm is not empty. - static ifed_t *create(const raw_t *adbm, cindex_t dim, size_t nxtSize = 0, - fdbm_t *nxt = NULL) - { - return create(dim, 1 + nxtSize, fdbm_t::create(adbm, dim, nxt)); - } - static ifed_t *create(const dbm_t &adbm, size_t nxtSize = 0, fdbm_t *nxt = NULL) - { - return create(adbm.const_idbmt()->getDimension(), 1 + nxtSize, - fdbm_t::create(adbm, nxt)); - } - static ifed_t *create(cindex_t dim) - { // initial empty - return create(dim, 0, NULL); - } - static ifed_t *create(cindex_t dim, dbmlist_t dbmlist) - { - return create(dim, dbmlist.size(), dbmlist.head()); - } - - /// Update the 1st DBM, @pre size() > 0 and same dimension. - void update(const raw_t *adbm, cindex_t adim) - { - assert(size() > 0 && adim == dim); - fhead->dbmt().updateCopy(adbm, adim); - } - void update(const dbm_t &adbm) - { - assert(size() > 0 && adbm.getDimension() == dim); - fhead->dbmt().updateCopy(adbm); - } - - /// Check invariants. - bool isOK() const - { - size_t n = 0; - for (const fdbm_t *f = fhead; f != NULL; f = f->getNext(), n++) - { - if (f->isEmpty() || f->getDimension() != dim) - { - return false; - } - } - return fedSize == n; - } - - /// @return dimension of this federation. - cindex_t getDimension() const { return dim; } - - /// Change the dimension @pre isEmpty() - void setDimension(cindex_t d) - { - assert(isEmpty()); - dim = d; - } - - /// Set this federation to one DBM. - void setToDBM(const dbm_t &arg) - { - assert(refCounter == 1); - // Add arg before deallocating DBMs. - dim = arg.pdim(); - insert(arg); - // Now fix the rest of the list. - fdbm_t::removeAll(fhead->getNext()); - fhead->setNext(NULL); - fedSize = 1; - } - - /// @return true if this federation is empty. - bool isEmpty() const - { - assert((size() == 0) == (fhead == NULL)); - return fhead == NULL; - } - - /// Compute a hash value that does not depend on the order of the DBMs. - uint32_t hash(uint32_t seed = 0) const; - - /// Decrement reference count, maybe deallocate. - void decRef() - { - assert(refCounter > 0); - if (!--refCounter) - remove(); - } - - /// Decrement reference count with @pre !isMutable() - void decRefImmutable() - { - assert(refCounter > 1); - --refCounter; - } - - /// Increment reference count. - void incRef() { ++refCounter; } - - /// @return if this ifed_t can be modified. - bool isMutable() const - { - assert(refCounter > 0); - return refCounter == 1; - } - - /// Remove this ifed_t with @pre isMutable() - void removeMutable() - { - assert(--refCounter == 0); // For debugging purposes. - remove(); - } - - /// @return copy of this ifed_t with appended list. - /// @pre other is mutable. - ifed_t *copy(ifed_t *other) const - { - assert(other && other->isMutable() && other->dim == dim && other->isOK()); - other->fhead = fdbm_t::copy(fhead, other->fhead); - other->fedSize += fedSize; - return other; - } - ifed_t *copy(fdbm_t *end = NULL, size_t endSize = 0) const - { - assert(endSize == (end ? end->size() : 0)); - return create(getDimension(), size() + endSize, fdbm_t::copy(fhead, end)); - } - - /// Insert a dbm, @pre same dimension & not empty. - void insert(const dbm_t &adbm) - { - assert(adbm.getDimension() == getDimension() && !adbm.isEmpty()); - fhead = fdbm_t::create(adbm, fhead); - incSize(); - } - void insert(const raw_t *adbm, cindex_t adim) - { - assert(adim == getDimension()); - fhead = fdbm_t::create(adbm, adim, fhead); - incSize(); - } - - /// Deallocate the list + update state. - void setEmpty() - { - assert(refCounter <= 1); - fdbm_t::removeAll(fhead); - reset(); - } - - /// Deallocate the list and set the new list to 1 DBM. - void setDBM(fdbm_t *fdbm) - { - fdbm_t::removeAll(fhead); - fhead = fdbm; - fedSize = 1; - fdbm->setNext(NULL); - } - // Similar but for a ready list. - void setFed(fdbm_t *fdbm, size_t nb) - { - fdbm_t::removeAll(fhead); - fhead = fdbm; - fedSize = nb; - } - - private: - friend class fed_t; - - /// Update the dimension - called when DBMs - /// have been resized. - void updateDimension(cindex_t d) - { - dim = d; - assert(isOK()); - } - - /// Allocation of an ifed_t (and a fdbm_t) with an allocator. - static ifed_t *create(cindex_t dim, size_t size, fdbm_t *head); - - /// Deallocate this ifed and its list of DBMs. - void remove(); - - uint32_t refCounter; //< reference counter - cindex_t dim; //< dimension - }; - - /*********************************************************** - * Inlined implementation of template ClockOperation * - ***********************************************************/ - -#define TEMPLATE \ - template \ - inline -#define CLOCKOP ClockOperation - - TEMPLATE CLOCKOP::ClockOperation(TYPE *d, cindex_t c) : ptr(d), clock(c), incVal(0) - { - assert(ptr && c < d->getDimension()); - } - - TEMPLATE CLOCKOP &CLOCKOP::operator+(int32_t val) - { - incVal += val; // intended to be used that way - return *this; - } - - TEMPLATE CLOCKOP &CLOCKOP::operator-(int32_t val) - { - incVal -= val; // intended to be used that way - return *this; - } - - TEMPLATE CLOCKOP &CLOCKOP::operator+=(int32_t val) { return (*this = *this + val); } - - TEMPLATE CLOCKOP &CLOCKOP::operator-=(int32_t val) { return (*this = *this - val); } - - TEMPLATE CLOCKOP &CLOCKOP::operator=(const CLOCKOP &op) - { - assert(ptr == op.ptr); // don't mix-up operations - ptr->update(clock, op.clock, op.incVal); - incVal = 0; - return *this; - } - - TEMPLATE CLOCKOP &CLOCKOP::operator=(int32_t val) - { - ptr->updateValue(clock, val); - incVal = 0; - return *this; - } - - TEMPLATE bool CLOCKOP::operator<(const CLOCKOP &x) const - { - assert(ptr == x.ptr); // clock - x.clock < x.incVal - incVal - return ptr->satisfies(clock, x.clock, dbm_bound2raw(x.incVal - incVal, dbm_STRICT)); - } - - TEMPLATE bool CLOCKOP::operator<=(const CLOCKOP &x) const - { - assert(ptr == x.ptr); // clock - x.clock <= x.incVal - incVal - return ptr->satisfies(clock, x.clock, dbm_bound2raw(x.incVal - incVal, dbm_WEAK)); - } - - TEMPLATE bool CLOCKOP::operator>(const CLOCKOP &x) const - { - assert(ptr == x.ptr); // x.clock - clock < incVal - x.incVal - return ptr->satisfies(x.clock, clock, dbm_bound2raw(incVal - x.incVal, dbm_STRICT)); - } - - TEMPLATE bool CLOCKOP::operator>=(const CLOCKOP &x) const - { - assert(ptr == x.ptr); // x.clock - clock <= incVal - x.incVal - return ptr->satisfies(x.clock, clock, dbm_bound2raw(incVal - x.incVal, dbm_WEAK)); - } - - TEMPLATE bool CLOCKOP::operator==(const CLOCKOP &x) const - { - return (*this >= x) && (*this <= x); - } - - TEMPLATE bool CLOCKOP::operator<(int32_t v) const - { - return ptr->satisfies(clock, 0, dbm_bound2raw(v - incVal, dbm_STRICT)); - } - - TEMPLATE bool CLOCKOP::operator<=(int32_t v) const - { - return ptr->satisfies(clock, 0, dbm_bound2raw(v - incVal, dbm_WEAK)); - } - - TEMPLATE bool CLOCKOP::operator>(int32_t v) const - { - return ptr->satisfies(0, clock, dbm_bound2raw(incVal - v, dbm_STRICT)); - } - - TEMPLATE bool CLOCKOP::operator>=(int32_t v) const - { - return ptr->satisfies(0, clock, dbm_bound2raw(incVal - v, dbm_WEAK)); - } - - TEMPLATE bool CLOCKOP::operator==(int32_t v) const { return (*this <= v) && (*this >= v); } - -#undef CLOCKOP -#undef TEMPLATE - - /*********************************** - * Inlined implementation of dbm_t * - ***********************************/ - - inline dbm_t::dbm_t(cindex_t dim) - { - assert(dim); - setEmpty(dim); - } - - inline dbm_t::dbm_t(const raw_t *arg, cindex_t dim) - { - assert(arg && dim); - assertx(dbm_isValid(arg, dim)); - dbm_copy(setNew(dim), arg, dim); - } - - inline dbm_t::dbm_t(const dbm_t &arg) - { - idbmPtr = arg.idbmPtr; - incRef(); - } - - inline dbm_t::~dbm_t() { decRef(); } - - inline cindex_t dbm_t::getDimension() const { return isEmpty() ? edim() : pdim(); } - - inline void dbm_t::setDimension(cindex_t dim) - { - decRef(); - setEmpty(dim); - } - - inline bool dbm_t::isEmpty() const { return uval() & 1; } - - inline void dbm_t::setEmpty() { setDimension(getDimension()); } - - inline void dbm_t::nil() { setDimension(1); } - - inline uint32_t dbm_t::hash(uint32_t seed) const - { - return isEmpty() ? uval() : const_idbmt()->hash(seed); - } - - inline bool dbm_t::sameAs(const dbm_t &arg) const { return idbmPtr == arg.idbmPtr; } - - inline void dbm_t::intern() - { - if (!isEmpty()) - ptr_intern(); - } - - inline const raw_t *dbm_t::operator()() const { return isEmpty() ? NULL : const_dbm(); } - - inline raw_t dbm_t::operator()(cindex_t i, cindex_t j) const - { - assert(i < getDimension() && j < getDimension() && !isEmpty()); - return const_dbm()[i * pdim() + j]; - } - - inline const raw_t *dbm_t::operator[](cindex_t i) const - { - assert(i < getDimension() && !isEmpty()); - return const_dbm() + i * pdim(); - } - - inline raw_t *dbm_t::getDBM() { return isEmpty() ? setNew(edim()) : getCopy(); } - -#ifdef ENABLE_STORE_MINGRAPH - inline const uint32_t *dbm_t::getMinDBM(size_t *size) const - { - assert(!isEmpty()); - return idbmPtr->getMinGraph(size); - } - - inline size_t dbm_t::analyzeForMinDBM(uint32_t *bitMatrix) const - { - size_t result; - size_t dim = pdim(); - auto mdbm = getMinDBM(&result); - std::copy(mdbm, mdbm + bits2intsize(dim * dim), bitMatrix); - return result; - } -#else - inline size_t dbm_t::analyzeForMinDBM(uint32_t *bitMatrix) const - { - assert(!isEmpty()); - return dbm_analyzeForMinDBM(const_dbm(), pdim(), bitMatrix); - } -#endif - - inline int32_t *dbm_t::writeToMinDBMWithOffset(bool minimizeGraph, bool tryConstraints16, - allocator_t c_alloc, size_t offset) const - { - assert(!isEmpty()); - return dbm_writeToMinDBMWithOffset(const_dbm(), pdim(), minimizeGraph, tryConstraints16, - c_alloc, offset); - } - - inline int32_t *dbm_t::writeAnalyzedDBM(uint32_t *bitMatrix, size_t nbConstraints, - bool tryConstraints16, allocator_t c_alloc, - size_t offset) const - { - assert(!isEmpty()); - return dbm_writeAnalyzedDBM(const_dbm(), pdim(), bitMatrix, nbConstraints, tryConstraints16, - c_alloc, offset); - } - - inline dbm_t dbm_t::readFromMinDBM(cindex_t dim, mingraph_t ming) - { - assert(ming); - assert(dim == dbm_getDimOfMinDBM(ming)); - dbm_t result(dim); - dbm_readFromMinDBM(result.getDBM(), ming); - return result; - } - - inline size_t dbm_t::getSizeOfMinDBM(cindex_t dim, mingraph_t ming) - { - assert(dim == dbm_getDimOfMinDBM(ming)); - return dbm_getSizeOfMinDBM(ming); - } - - inline relation_t dbm_t::relation(mingraph_t ming, raw_t *unpackBuffer) const - { - // A mingraph_t never represents empty DBMs. - return isEmpty() ? base_SUBSET - : dbm_relationWithMinDBM(const_dbm(), pdim(), ming, unpackBuffer); - } - - inline dbm_t &dbm_t::operator=(const dbm_t &arg) - { - arg.incRef(); // first in case a = a; - decRef(); - idbmPtr = arg.idbmPtr; - return *this; - } - - inline dbm_t &dbm_t::operator=(const raw_t *arg) - { - copyFrom(arg, getDimension()); - return *this; - } - - inline bool dbm_t::operator==(const fed_t &arg) const - { - return arg == *this; // fed_t has the implementation - } - - inline bool dbm_t::operator!=(const dbm_t &arg) const { return !(*this == arg); } - - inline bool dbm_t::operator!=(const raw_t *arg) const { return !(*this == arg); } - - inline bool dbm_t::operator!=(const fed_t &arg) const { return !(*this == arg); } - - inline bool dbm_t::operator<(const dbm_t &arg) const { return relation(arg) == base_SUBSET; } - - inline bool dbm_t::operator<(const fed_t &arg) const - { - return arg > *this; // fed_t has the implementation - } - - inline bool dbm_t::operator>(const dbm_t &arg) const { return relation(arg) == base_SUPERSET; } - - inline bool dbm_t::operator>(const fed_t &arg) const - { - return arg < *this; // fed_t has the implementation - } - - inline bool dbm_t::operator<=(const fed_t &arg) const - { - return arg >= *this; // fed_t has the implementation - } - - inline bool dbm_t::operator<=(const raw_t *arg) const - { - return isEmpty() || dbm_isSubsetEq(const_dbm(), arg, pdim()); - } - - inline bool dbm_t::operator>=(const dbm_t &arg) const { return arg <= *this; } - - inline bool dbm_t::operator>=(const fed_t &arg) const - { - return arg <= *this; // fed_t has the implementation - } - - inline bool dbm_t::operator>=(const raw_t *arg) const - { - return !isEmpty() && dbm_isSubsetEq(arg, const_dbm(), pdim()); - } - - inline relation_t dbm_t::relation(const fed_t &arg) const - { - return base_symRelation(arg.relation(*this)); // symmetric -- fed_t has the implementation - } - - inline bool dbm_t::lt(const fed_t &arg) const - { - return arg.gt(*this); // fed_t has the implementation - } - - inline bool dbm_t::gt(const fed_t &arg) const - { - return arg.lt(*this); // fed_t has the implementation - } - - inline bool dbm_t::le(const fed_t &arg) const - { - return arg.ge(*this); // fed_t has the implementation - } - - inline bool dbm_t::ge(const fed_t &arg) const - { - return arg.le(*this); // fed_t has the implementation - } - - inline bool dbm_t::eq(const fed_t &arg) const - { - return arg.eq(*this); // fed_t has the implementation - } - - inline relation_t dbm_t::exactRelation(const fed_t &arg) const - { - return base_symRelation(arg.exactRelation(*this)); // fed_t has the implementation - } - - inline bool dbm_t::isInit() const - { - return !isEmpty() && dbm_isEqualToInit(const_dbm(), pdim()); - } - - inline bool dbm_t::isZero() const - { - return !isEmpty() && dbm_isEqualToZero(const_dbm(), pdim()); - } - - inline dbm_t &dbm_t::operator&=(const constraint_t &c) - { - constrain(c.i, c.j, c.value); - return *this; - } - - inline dbm_t &dbm_t::operator&=(const base::pointer_t &c) - { - constrain(c.begin(), c.size()); - return *this; - } - - inline dbm_t &dbm_t::operator&=(const std::vector &vec) - { - constrain(&vec[0], vec.size()); - return *this; - } - - inline bool dbm_t::constrain(cindex_t i, int32_t value) - { - return !isEmpty() && ptr_constrain(i, value); - } - - inline bool dbm_t::constrain(cindex_t i, cindex_t j, raw_t c) - { - return !isEmpty() && ptr_constrain(i, j, c); - } - - inline bool dbm_t::constrain(cindex_t i, cindex_t j, int32_t b, strictness_t s) - { - return !isEmpty() && ptr_constrain(i, j, dbm_bound2raw(b, s)); - } - - inline bool dbm_t::constrain(cindex_t i, cindex_t j, int32_t b, bool isStrict) - { - return !isEmpty() && ptr_constrain(i, j, dbm_boundbool2raw(b, isStrict)); - } - - inline bool dbm_t::constrain(const constraint_t &c) - { - return !isEmpty() && ptr_constrain(c.i, c.j, c.value); - } - - inline bool dbm_t::constrain(const constraint_t *cnstr, size_t n) - { - assert(n == 0 || cnstr); - return !isEmpty() && - (n == 1 ? ptr_constrain(cnstr->i, cnstr->j, cnstr->value) : ptr_constrain(cnstr, n)); - } - - inline bool dbm_t::constrain(const cindex_t *table, const constraint_t *cnstr, size_t n) - { - return !isEmpty() && ptr_constrain(table, cnstr, n); - } - - inline bool dbm_t::constrain(const cindex_t *table, const base::pointer_t &vec) - { - return !isEmpty() && ptr_constrain(table, vec.begin(), vec.size()); - } - - inline bool dbm_t::constrain(const cindex_t *table, const std::vector &vec) - { - return !isEmpty() && constrain(table, &vec[0], vec.size()); - } - - inline dbm_t &dbm_t::up() - { - if (!isEmpty()) - ptr_up(); - return *this; - } - - inline dbm_t &dbm_t::upStop(const uint32_t *stopped) - { - if (!isEmpty()) - { - if (stopped) - ptr_upStop(stopped); - else - ptr_up(); - } - return *this; - } - - inline dbm_t &dbm_t::down() - { - if (!isEmpty()) - ptr_down(); - return *this; - } - - inline dbm_t &dbm_t::downStop(const uint32_t *stopped) - { - if (!isEmpty()) - { - if (stopped) - ptr_downStop(stopped); - else - ptr_down(); - } - return *this; - } - - inline dbm_t &dbm_t::freeClock(cindex_t k) - { - if (!isEmpty()) - ptr_freeClock(k); - return *this; - } - - inline dbm_t &dbm_t::freeUp(cindex_t k) - { - if (!isEmpty()) - ptr_freeUp(k); - return *this; - } - - inline dbm_t &dbm_t::freeDown(cindex_t k) - { - if (!isEmpty()) - ptr_freeDown(k); - return *this; - } - - inline dbm_t &dbm_t::freeAllUp() - { - if (!isEmpty()) - ptr_freeAllUp(); - return *this; - } - - inline dbm_t &dbm_t::freeAllDown() - { - if (!isEmpty()) - ptr_freeAllDown(); - return *this; - } - - inline void dbm_t::updateValue(cindex_t k, int32_t v) - { - if (!isEmpty()) - ptr_updateValue(k, v); - } - - inline void dbm_t::updateClock(cindex_t i, cindex_t j) - { - if (i != j && !isEmpty()) - ptr_updateClock(i, j); - } - - inline void dbm_t::updateIncrement(cindex_t i, int32_t v) - { - // There is no point in even trying not to copy because the lower - // bounds are always going to be incremented. - if (v != 0 && !isEmpty()) - dbm_updateIncrement(getCopy(), pdim(), i, v); - } - - inline bool dbm_t::satisfies(cindex_t i, cindex_t j, raw_t c) const - { - assert(i < getDimension() && j < getDimension()); - return !isEmpty() && dbm_satisfies(const_dbm(), pdim(), i, j, c); - } - - inline bool dbm_t::satisfies(const constraint_t &c) const - { - return satisfies(c.i, c.j, c.value); - } - - inline bool dbm_t::operator&&(const constraint_t &c) const { return satisfies(c); } - - inline bool dbm_t::isUnbounded() const - { - return !isEmpty() && dbm_isUnbounded(const_dbm(), pdim()); - } - - inline dbm_t &dbm_t::relaxUp() { return relaxDownClock(0); } - - inline dbm_t &dbm_t::relaxDown() { return relaxUpClock(0); } - - inline dbm_t &dbm_t::tightenDown() - { - if (!isEmpty()) - ptr_tightenDown(); - return *this; - } - - inline dbm_t &dbm_t::tightenUp() - { - if (!isEmpty()) - ptr_tightenUp(); - return *this; - } - - inline dbm_t &dbm_t::relaxUpClock(cindex_t k) - { - if (!isEmpty()) - ptr_relaxUpClock(k); - return *this; - } - - inline dbm_t &dbm_t::relaxDownClock(cindex_t k) - { - if (!isEmpty()) - ptr_relaxDownClock(k); - return *this; - } - - inline dbm_t &dbm_t::relaxAll() - { - if (!isEmpty()) - ptr_relaxAll(); - return *this; - } - - inline void dbm_t::swapClocks(cindex_t x, cindex_t y) - { - if (!isEmpty()) - ptr_swapClocks(x, y); - } - - inline void dbm_t::extrapolateMaxBounds(const int32_t *max) - { - if (!isEmpty()) - dbm_extrapolateMaxBounds(getCopy(), pdim(), max); - } - - inline void dbm_t::diagonalExtrapolateMaxBounds(const int32_t *max) - { - if (!isEmpty()) - dbm_diagonalExtrapolateMaxBounds(getCopy(), pdim(), max); - } - - inline void dbm_t::extrapolateLUBounds(const int32_t *lower, const int32_t *upper) - { - if (!isEmpty()) - dbm_extrapolateLUBounds(getCopy(), pdim(), lower, upper); - } - - inline void dbm_t::diagonalExtrapolateLUBounds(const int32_t *lower, const int32_t *upper) - { - if (!isEmpty()) - dbm_diagonalExtrapolateLUBounds(getCopy(), pdim(), lower, upper); - } - - inline dbm_t::dbm_t(const ClockOperation &op) - { - idbmPtr = op.getPtr()->idbmPtr; - incRef(); - updateIncrement(op.getClock(), op.getVal()); - } - - inline ClockOperation dbm_t::operator()(cindex_t clk) - { - assert(clk < getDimension()); - return ClockOperation(this, clk); - } - - inline bool dbm_t::isSubtractionEmpty(const raw_t *arg, cindex_t dim) const - { - assert(getDimension() == dim); - assertx(dbm_isValid(arg, dim)); - // this - arg == empty if all DBMs of this <= arg because arg is a DBM. - return isEmpty() || (dbm_relation(const_dbm(), arg, dim) & base_SUBSET) != 0; - } - - inline bool dbm_t::isSubtractionEmpty(const dbm_t &arg) const - { - assert(getDimension() == arg.getDimension()); - return *this <= arg; - } - - inline void dbm_t::newCopy(const raw_t *arg, cindex_t dim) - { - assert(arg && dim > 0); - assertx(dbm_isValid(arg, dim)); - dbm_copy(setNew(dim), arg, dim); - } - - inline void dbm_t::newCopy(const dbm_t &arg) - { - arg.idbmPtr->incRef(); - setPtr(arg.idbmPtr); - } - - inline void dbm_t::updateCopy(const raw_t *arg, cindex_t dim) - { - assert(arg && dim > 0); - assertx(dbm_isValid(arg, dim)); - idbmt()->decRef(); - dbm_copy(setNew(dim), arg, dim); - } - - inline void dbm_t::updateCopy(const dbm_t &arg) - { - arg.idbmPtr->incRef(); - idbmt()->decRef(); - setPtr(arg.idbmPtr); - } - - inline const idbm_t *dbm_t::const_idbmt() const - { - assert(isPointer(idbmPtr)); // stronger than !isEmpty() - return idbmPtr; - } - - inline idbm_t *dbm_t::idbmt() - { - assert(isPointer(idbmPtr)); // stronger than !isEmpty() - return idbmPtr; - } - - inline uintptr_t dbm_t::uval() const { return (uintptr_t)idbmPtr; } - - inline void dbm_t::incRef() const - { - if (!isEmpty()) - idbmPtr->incRef(); - } - - inline void dbm_t::decRef() const - { - if (!isEmpty()) - idbmPtr->decRef(); - } - - inline void dbm_t::empty(cindex_t dim) - { - idbmt()->decRef(); - setEmpty(dim); - } - - inline void dbm_t::emptyImmutable(cindex_t dim) - { - idbmt()->decRefImmutable(); - setEmpty(dim); - } - - inline void dbm_t::emptyMutable(cindex_t dim) - { - idbmt()->removeMutable(); - setEmpty(dim); - } - - inline void dbm_t::setEmpty(cindex_t dim) - { - idbmPtr = reinterpret_cast((dim << 1) | 1); - } - - inline void dbm_t::setPtr(idbm_t *ptr) - { - assert(isPointer(ptr)); - idbmPtr = ptr; - } - - inline cindex_t dbm_t::edim() const - { - assert(isEmpty()); - return uval() >> 1; - } - - inline cindex_t dbm_t::pdim() const { return const_idbmt()->getDimension(); } - - inline bool dbm_t::isMutable() const { return const_idbmt()->isMutable(); } - - inline bool dbm_t::tryMutable() { return idbmt()->tryMutable(); } - - inline const raw_t *dbm_t::const_dbm() const { return const_idbmt()->const_dbm(); } - - inline raw_t *dbm_t::dbm() - { - assert(isMutable()); -#ifdef ENABLE_STORE_MINGRAPH - assert(!idbmt()->isValid()); -#endif - return idbmt()->dbm(); - } - - inline raw_t *dbm_t::setNew(cindex_t dim) - { - assert(dim); - setPtr(new (dbm_new(dim)) idbm_t(dim)); - return dbm(); - } - - inline raw_t *dbm_t::inew(cindex_t dim) - { - assert(!tryMutable()); - idbmt()->decRefImmutable(); - return setNew(dim); - } - - inline raw_t *dbm_t::icopy(cindex_t dim) - { - assert(!tryMutable() && pdim() == dim); - idbmt()->decRefImmutable(); - setPtr(new (dbm_new(dim)) idbm_t(*idbmPtr)); - return dbm(); - } - - inline raw_t *dbm_t::getNew() - { - RECORD_STAT(); - RECORD_SUBSTAT(tryMutable() ? "mutable" : "new"); - return tryMutable() ? dbm() : inew(pdim()); - } - - inline raw_t *dbm_t::getCopy() - { - RECORD_STAT(); - RECORD_SUBSTAT(tryMutable() ? "mutable" : "copy"); - return tryMutable() ? dbm() : icopy(pdim()); - } - - // Wrapper functions - - inline dbm_t zero(cindex_t dim) { return dbm_t(dim).setZero(); } - inline dbm_t init(cindex_t dim) { return dbm_t(dim).setInit(); } - inline dbm_t up(const dbm_t &d) { return dbm_t(d).up(); } - inline dbm_t down(const dbm_t &d) { return dbm_t(d).down(); } - inline dbm_t freeClock(const dbm_t &d, cindex_t x) { return dbm_t(d).freeClock(x); } - inline dbm_t freeUp(const dbm_t &d, cindex_t k) { return dbm_t(d).freeUp(k); } - inline dbm_t freeDown(const dbm_t &d, cindex_t k) { return dbm_t(d).freeDown(k); } - inline dbm_t freeAllUp(const dbm_t &d) { return dbm_t(d).freeAllUp(); } - inline dbm_t freeAllDown(const dbm_t &d) { return dbm_t(d).freeAllDown(); } - inline dbm_t relaxUp(const dbm_t &d) { return dbm_t(d).relaxUp(); } - inline dbm_t relaxDown(const dbm_t &d) { return dbm_t(d).relaxDown(); } - inline dbm_t relaxUpClock(const dbm_t &d, cindex_t k) { return dbm_t(d).relaxUpClock(k); } - inline dbm_t relaxDownClock(const dbm_t &d, cindex_t k) { return dbm_t(d).relaxDownClock(k); } - - /*********************************************** - * Inlined implementations of fed_t::iterator * - ***********************************************/ - - inline fed_t::iterator::iterator() : fdbm(const_cast(&ENDF)), ifed(NULL) {} - - inline fed_t::iterator::iterator(ifed_t *ifd) : fdbm(ifd->atHead()), ifed(ifd) {} - - inline dbm_t &fed_t::iterator::operator*() const - { - assert(fdbm && *fdbm); - return (*fdbm)->dbmt(); - } - - inline dbm_t *fed_t::iterator::operator->() const - { - assert(fdbm && *fdbm); - return &(*fdbm)->dbmt(); - } - - inline raw_t *fed_t::iterator::operator()() const - { - assert(fdbm && *fdbm); - return (*fdbm)->dbmt().getDBM(); - } - - inline raw_t fed_t::iterator::operator()(cindex_t i, cindex_t j) const - { - assert(fdbm && *fdbm); - return (*fdbm)->dbmt()(i, j); - } - - inline fed_t::iterator &fed_t::iterator::operator++() - { - assert(fdbm && *fdbm); - fdbm = (*fdbm)->getNextMutable(); - return *this; - } - - inline bool fed_t::iterator::null() const - { - assert(fdbm); - return *fdbm == NULL; - } - - inline bool fed_t::iterator::hasNext() const - { - assert(fdbm); - return (*fdbm)->getNext() != NULL; - } - - inline bool fed_t::iterator::operator==(const iterator &arg) const - { - assert(fdbm && arg.fdbm); - return *fdbm == *arg.fdbm; // don't check ifed - } - - inline bool fed_t::iterator::operator!=(const iterator &arg) const { return !(*this == arg); } - - inline void fed_t::iterator::remove() - { - assert(fdbm && *fdbm); - *fdbm = (*fdbm)->removeAndNext(); - ifed->decSize(); - } - - inline void fed_t::iterator::removeEmpty() - { - assert(fdbm && *fdbm); - *fdbm = (*fdbm)->removeEmptyAndNext(); - ifed->decSize(); - } - - inline fdbm_t *fed_t::iterator::extract() - { - assert(fdbm && *fdbm); - fdbm_t *current = *fdbm; - *fdbm = current->getNext(); - ifed->decSize(); - return current; - } - - inline void fed_t::iterator::insert(fdbm_t *dbm) - { - assert(fdbm); - dbm->setNext(*fdbm); - *fdbm = dbm; - ifed->incSize(); - } - - inline fed_t::iterator fed_t::beginMutable() - { - setMutable(); - return fed_t::iterator(ifed()); - } - - inline const fed_t::iterator fed_t::endMutable() const { return fed_t::iterator(); } - - inline fed_t::iterator fed_t::erase(iterator &iter) - { - assert(hasSame(*iter)); - iter.remove(); - return iter; - } - - /***************************************************** - * Inlined implementations of fed_t::const_iterator * - *****************************************************/ - - inline fed_t::const_iterator::const_iterator(const fdbm_t *fed) : fdbm(fed) {} - inline fed_t::const_iterator::const_iterator(const fed_t &fed) : fdbm(fed.ifed()->const_head()) - { - } - inline fed_t::const_iterator::const_iterator() : fdbm(NULL) {} - - inline const dbm_t &fed_t::const_iterator::operator*() const - { - assert(fdbm); - return fdbm->const_dbmt(); - } - - inline const dbm_t *fed_t::const_iterator::operator->() const - { - assert(fdbm); - return &fdbm->const_dbmt(); - } - - inline const raw_t *fed_t::const_iterator::operator()() const - { - assert(fdbm); - return fdbm->const_dbmt()(); - } - - inline raw_t fed_t::const_iterator::operator()(cindex_t i, cindex_t j) const - { - assert(fdbm); - return fdbm->const_dbmt()(i, j); - } - - inline fed_t::const_iterator &fed_t::const_iterator::operator++() - { - assert(fdbm); - fdbm = fdbm->getNext(); - return *this; - } - - inline bool fed_t::const_iterator::null() const { return fdbm == NULL; } - - inline bool fed_t::const_iterator::hasNext() const - { - assert(fdbm); - return fdbm->getNext() != NULL; - } - - inline bool fed_t::const_iterator::operator==(const const_iterator &arg) const - { - return fdbm == arg.fdbm; - } - - inline bool fed_t::const_iterator::operator!=(const const_iterator &arg) const - { - return fdbm != arg.fdbm; - } - - inline fed_t::const_iterator fed_t::begin() const - { - return fed_t::const_iterator(ifed()->const_head()); - } - - inline const fed_t::const_iterator fed_t::end() const { return fed_t::const_iterator::ENDI; } - - /*********************************** - * Inlined implementation of fed_t * - ***********************************/ - - fed_t::fed_t(cindex_t dim) : ifedPtr(ifed_t::create(dim)) { assert(dim >= 1); } - - fed_t::fed_t(const fed_t &arg) : ifedPtr(arg.ifedPtr) { incRef(); } - - inline fed_t::fed_t(ifed_t *ifed) : ifedPtr(ifed) {} - - inline fed_t::fed_t(const dbm_t &arg) : ifedPtr(arg.isEmpty() ? ifed_t::create(arg.edim()) : ifed_t::create(arg)) - { - } - - inline fed_t::fed_t(const raw_t *arg, cindex_t dim) : ifedPtr(ifed_t::create(arg, dim)) {} - - inline fed_t::~fed_t() { decRef(); } - - inline size_t fed_t::size() const { return ifed()->size(); } - - inline cindex_t fed_t::getDimension() const { return ifed()->getDimension(); } - - inline bool fed_t::isEmpty() const { return ifed()->isEmpty(); } - - inline void fed_t::nil() { setDimension(1); } - - inline fed_t &fed_t::reduce() - { - assert(isOK()); - ifed()->reduce(getDimension()); - return *this; - } - - inline fed_t &fed_t::mergeReduce(size_t skip, int expensiveTry) - { - assert(isOK()); - ifed()->mergeReduce(getDimension(), skip, expensiveTry); - return *this; - } - - inline fed_t &fed_t::unionWithC(fed_t arg) { return unionWith(arg); } - - inline fed_t &fed_t::appendC(fed_t arg) { return append(arg); } - - inline fed_t &fed_t::steal(fed_t &arg) - { - size_t s = size(); - return appendEnd(arg).mergeReduce(s); - } - - inline fed_t &fed_t::stealC(fed_t arg) { return steal(arg); } - - inline void fed_t::swap(fed_t &arg) - { - ifed_t *tmp = ifedPtr; - ifedPtr = arg.ifedPtr; - arg.ifedPtr = tmp; - } - - inline uint32_t fed_t::hash(uint32_t seed) const { return ifed()->hash(seed); } - - inline bool fed_t::sameAs(const fed_t &arg) const { return ifedPtr == arg.ifedPtr; } - - inline fed_t &fed_t::operator=(const fed_t &arg) - { - arg.incRef(); - decRef(); - ifedPtr = arg.ifedPtr; - return *this; - } - - inline bool fed_t::operator==(const fed_t &arg) const { return relation(arg) == base_EQUAL; } - - inline bool fed_t::operator==(const dbm_t &arg) const { return relation(arg) == base_EQUAL; } - - inline bool fed_t::operator==(const raw_t *arg) const - { - return relation(arg, getDimension()) == base_EQUAL; - } - - inline bool fed_t::operator!=(const fed_t &arg) const { return !(*this == arg); } - - inline bool fed_t::operator!=(const dbm_t &arg) const { return !(*this == arg); } - - inline bool fed_t::operator!=(const raw_t *arg) const { return !(*this == arg); } - - inline bool fed_t::operator<(const fed_t &arg) const { return relation(arg) == base_SUBSET; } - - inline bool fed_t::operator<(const dbm_t &arg) const { return relation(arg) == base_SUBSET; } - - inline bool fed_t::operator<(const raw_t *arg) const - { - return relation(arg, getDimension()) == base_SUBSET; - } - - inline bool fed_t::operator>(const fed_t &arg) const { return relation(arg) == base_SUPERSET; } - - inline bool fed_t::operator>(const dbm_t &arg) const { return relation(arg) == base_SUPERSET; } - - inline bool fed_t::operator>(const raw_t *arg) const - { - return relation(arg, getDimension()) == base_SUPERSET; - } - - inline bool fed_t::operator<=(const fed_t &arg) const - { - return (relation(arg) & base_SUBSET) != 0; - } - - inline bool fed_t::operator<=(const raw_t *arg) const { return le(arg, getDimension()); } - - inline bool fed_t::operator>=(const fed_t &arg) const - { - return (relation(arg) & base_SUPERSET) != 0; - } - - inline bool fed_t::operator>=(const raw_t *arg) const - { - return isSupersetEq(arg, getDimension()); - } - - inline bool fed_t::eq(const fed_t &arg) const { return exactRelation(arg) == base_EQUAL; } - - inline bool fed_t::eq(const dbm_t &arg) const { return exactRelation(arg) == base_EQUAL; } - - inline bool fed_t::eq(const raw_t *arg, cindex_t dim) const - { - return exactRelation(arg, dim) == base_EQUAL; - } - - inline bool fed_t::lt(const fed_t &arg) const { return exactRelation(arg) == base_SUBSET; } - - inline bool fed_t::lt(const dbm_t &arg) const { return exactRelation(arg) == base_SUBSET; } - - inline bool fed_t::lt(const raw_t *arg, cindex_t dim) const - { - return exactRelation(arg, dim) == base_SUBSET; - } - - inline bool fed_t::gt(const fed_t &arg) const { return exactRelation(arg) == base_SUPERSET; } - - inline bool fed_t::gt(const dbm_t &arg) const { return exactRelation(arg) == base_SUPERSET; } - - inline bool fed_t::gt(const raw_t *arg, cindex_t dim) const - { - return exactRelation(arg, dim) == base_SUPERSET; - } - - inline bool fed_t::ge(const fed_t &arg) const { return arg.le(*this); } - - inline bool fed_t::ge(const dbm_t &arg) const { return arg.isSubtractionEmpty(*this); } - - inline bool fed_t::ge(const raw_t *arg, cindex_t dim) const - { - return isSubtractionEmpty(arg, dim, *this); - } - - inline bool fed_t::le(const fed_t &arg) const { return isSubtractionEmpty(arg); } - - inline bool fed_t::le(const dbm_t &arg) const - { - return *this <= arg; // only case exact - } - - inline fed_t &fed_t::add(const fed_t &arg) - { - fed_t f(arg); - return append(f); - } - - inline fed_t &fed_t::add(const dbm_t &arg) - { - assert(isOK() && arg.getDimension() == getDimension()); - if (!arg.isEmpty()) - { - ifed()->insert(arg); - } - return *this; - } - - inline fed_t &fed_t::add(const raw_t *arg, cindex_t dim) - { - assert(isOK() && dim == getDimension()); - assertx(dbm_isValid(arg, dim)); - ifed()->insert(arg, dim); - return *this; - } - - inline fed_t &fed_t::operator&=(const constraint_t &c) - { - constrain(c.i, c.j, c.value); - return *this; - } - - inline fed_t &fed_t::operator&=(const base::pointer_t &c) - { - constrain(c.begin(), c.size()); - return *this; - } - - inline fed_t &fed_t::operator&=(const std::vector &vec) - { - constrain(&vec[0], vec.size()); - return *this; - } - - inline bool fed_t::constrain(cindex_t i, cindex_t j, int32_t b, strictness_t s) - { - return constrain(i, j, dbm_bound2raw(b, s)); - } - - inline bool fed_t::constrain(cindex_t i, cindex_t j, int32_t b, bool isStrict) - { - return constrain(i, j, dbm_boundbool2raw(b, isStrict)); - } - - inline bool fed_t::constrain(const constraint_t &c) { return constrain(c.i, c.j, c.value); } - - inline bool fed_t::satisfies(const constraint_t &c) const - { - return satisfies(c.i, c.j, c.value); - } - - inline bool fed_t::operator&&(const constraint_t &c) const - { - return satisfies(c.i, c.j, c.value); - } - - inline fed_t &fed_t::relaxUp() - { - return relaxDownClock(0); // see dbm.h - } - - inline fed_t &fed_t::relaxDown() - { - return relaxUpClock(0); // see dbm.h - } - - inline bool fed_t::removeIncludedIn(const dbm_t &arg) - { - assert(isOK()); - assert(getDimension() == arg.getDimension()); - return !arg.isEmpty() && removeIncludedIn(arg.const_dbm(), getDimension()); - } - - inline fed_t::fed_t(const ClockOperation &op) : ifedPtr(op.getPtr()->ifed()->copy()) - { - updateIncrement(op.getClock(), op.getVal()); - } - - inline ClockOperation fed_t::operator()(cindex_t clk) - { - assert(clk < getDimension()); - return ClockOperation(this, clk); - } - - inline bool fed_t::isSubtractionEmpty(const dbm_t &arg) const - { - return *this <= arg; // only exact case with "normal" relation - } - - inline ifed_t *fed_t::ifed() - { - assert(isPointer(ifedPtr)); - return ifedPtr; - } - - inline const ifed_t *fed_t::ifed() const - { - assert(isPointer(ifedPtr)); - return ifedPtr; - } - - inline void fed_t::incRef() const - { - assert(isPointer(ifedPtr)); - ifedPtr->incRef(); - } - - inline void fed_t::decRef() const - { - assert(isPointer(ifedPtr)); - ifedPtr->decRef(); - } - - inline void fed_t::decRefImmutable() const - { - assert(isPointer(ifedPtr)); - ifedPtr->decRefImmutable(); - } - - inline bool fed_t::isMutable() const { return ifed()->isMutable(); } - - inline bool fed_t::isOK() const { return ifed()->isOK(); } - - inline void fed_t::setMutable() - { - if (!isMutable()) - { - decRefImmutable(); - ifedPtr = ifed()->copy(); - } - assert(isMutable()); - } - - inline const dbm_t &fed_t::const_dbmt() const - { - assert(size()); - return ifed()->const_head()->const_dbmt(); - } - - inline dbm_t &fed_t::dbmt() - { - assert(size() == 1 && isMutable()); - return ifed()->head()->dbmt(); - } - - // Trivial wrappers - - inline fed_t up(const fed_t &arg) { return fed_t(arg).up(); } - inline fed_t down(const fed_t &arg) { return fed_t(arg).down(); } - inline fed_t freeClock(const fed_t &arg, cindex_t x) { return fed_t(arg).freeClock(x); } - inline fed_t freeUp(const fed_t &arg, cindex_t x) { return fed_t(arg).freeUp(x); } - inline fed_t freeDown(const fed_t &arg, cindex_t x) { return fed_t(arg).freeDown(x); } - inline fed_t freeAllUp(const fed_t &arg) { return fed_t(arg).freeAllUp(); } - inline fed_t freeAllDown(const fed_t &arg) { return fed_t(arg).freeAllDown(); } - inline fed_t relaxUp(const fed_t &arg) { return fed_t(arg).relaxUp(); } - inline fed_t relaxDown(const fed_t &arg) { return fed_t(arg).relaxDown(); } - inline fed_t relaxUpClock(const fed_t &arg, cindex_t k) { return fed_t(arg).relaxUpClock(k); } - inline fed_t relaxDownClock(const fed_t &arg, cindex_t k) - { - return fed_t(arg).relaxDownClock(k); - } - inline fed_t reduce(const fed_t &arg) { return fed_t(arg).reduce(); } - inline fed_t expensiveReduce(const fed_t &arg) { return fed_t(arg).expensiveReduce(); } - inline fed_t predt(const fed_t &g, const fed_t &b) { return fed_t(g).predt(b); } - inline fed_t predt(const fed_t &g, const dbm_t &b) { return fed_t(g).predt(b); } - inline fed_t predt(const fed_t &g, const raw_t *b, cindex_t dim) - { - return fed_t(g).predt(b, dim); - } - inline fed_t predt(const dbm_t &g, const fed_t &b) { return fed_t(g).predt(b); } - inline fed_t predt(const dbm_t &g, const dbm_t &b) { return fed_t(g).predt(b); } - inline fed_t predt(const dbm_t &g, const raw_t *b, cindex_t dim) - { - return fed_t(g).predt(b, dim); - } - inline fed_t predt(const raw_t *g, cindex_t dim, const fed_t &b) - { - return fed_t(g, dim).predt(b); - } - inline fed_t predt(const raw_t *g, cindex_t dim, const dbm_t &b) - { - return fed_t(g, dim).predt(b); - } - inline fed_t predt(const raw_t *g, const raw_t *b, cindex_t dim) - { - return fed_t(g, dim).predt(b, dim); - } - - /************ Operator overload -- trivial implementations ************/ - - inline dbm_t operator+(const dbm_t &a, const raw_t *b) { return dbm_t(a) += b; } - inline dbm_t operator+(const fed_t &a, const raw_t *b) - { - return dbm_t(b, a.getDimension()) += a; - } - inline dbm_t operator+(const dbm_t &a, const dbm_t &b) { return dbm_t(a) += b; } - inline dbm_t operator+(const dbm_t &a, const fed_t &b) { return dbm_t(a) += b; } - inline dbm_t operator+(const fed_t &a, const dbm_t &b) { return dbm_t(b) += a; } - inline dbm_t operator+(const fed_t &a, const fed_t &b) - { - return (dbm_t(a.getDimension()) += a) += b; - } - - inline dbm_t operator&(const dbm_t &a, const raw_t *b) { return dbm_t(a) &= b; } - inline fed_t operator&(const fed_t &a, const raw_t *b) { return fed_t(a) &= b; } - inline dbm_t operator&(const dbm_t &a, const dbm_t &b) { return dbm_t(a) &= b; } - inline fed_t operator&(const dbm_t &a, const fed_t &b) { return fed_t(b) &= a; } - inline fed_t operator&(const fed_t &a, const dbm_t &b) { return fed_t(a) &= b; } - inline fed_t operator&(const fed_t &a, const fed_t &b) { return fed_t(a) &= b; } - - inline dbm_t operator&(const dbm_t &a, const constraint_t &c) { return dbm_t(a) &= c; } - inline dbm_t operator&(const constraint_t &c, const dbm_t &a) { return dbm_t(a) &= c; } - inline fed_t operator&(const fed_t &a, const constraint_t &c) { return fed_t(a) &= c; } - inline fed_t operator&(const constraint_t &c, const fed_t &a) { return fed_t(a) &= c; } - - inline dbm_t operator&(const dbm_t &a, const base::pointer_t &c) - { - return dbm_t(a) &= c; - } - inline dbm_t operator&(const base::pointer_t &c, const dbm_t &a) - { - return dbm_t(a) &= c; - } - inline fed_t operator&(const fed_t &a, const base::pointer_t &c) - { - return fed_t(a) &= c; - } - inline fed_t operator&(const base::pointer_t &c, const fed_t &a) - { - return fed_t(a) &= c; - } - - inline dbm_t operator&(const dbm_t &a, const std::vector &vec) - { - return dbm_t(a) &= vec; - } - inline dbm_t operator&(const std::vector &vec, const dbm_t &a) - { - return dbm_t(a) &= vec; - } - inline fed_t operator&(const fed_t &a, const std::vector &vec) - { - return fed_t(a) &= vec; - } - inline fed_t operator&(const std::vector &vec, const fed_t &a) - { - return fed_t(a) &= vec; - } - - inline fed_t operator|(const dbm_t &a, const raw_t *b) { return fed_t(a) |= b; } - inline fed_t operator|(const fed_t &a, const raw_t *b) { return fed_t(a) |= b; } - inline fed_t operator|(const dbm_t &a, const dbm_t &b) { return fed_t(a) |= b; } - inline fed_t operator|(const fed_t &a, const dbm_t &b) { return fed_t(a) |= b; } - inline fed_t operator|(const dbm_t &a, const fed_t &b) { return fed_t(b) |= a; } - inline fed_t operator|(const fed_t &a, const fed_t &b) { return fed_t(a) |= b; } - - inline fed_t operator-(const fed_t &a, const raw_t *b) { return fed_t(a) -= b; } - inline fed_t operator-(const fed_t &a, const dbm_t &b) { return fed_t(a) -= b; } - inline fed_t operator-(const dbm_t &a, const fed_t &b) { return fed_t(a) -= b; } - inline fed_t operator-(const fed_t &a, const fed_t &b) { return fed_t(a) -= b; } - - inline fed_t operator-(const dbm_t &arg1, const raw_t *arg2) - { - return fed_t::subtract(arg1, arg2); - } - inline fed_t operator-(const dbm_t &arg1, const dbm_t &arg2) - { - return fed_t::subtract(arg1, arg2); - } - - inline fed_t operator!(const dbm_t &arg) { return fed_t(arg.getDimension()).setInit() -= arg; } - inline fed_t operator!(const fed_t &arg) { return fed_t(arg.getDimension()).setInit() -= arg; } -} // namespace dbm diff --git a/dbm/include/dbm/mingraph.h b/dbm/include/dbm/mingraph.h deleted file mode 100644 index c63dc58f..00000000 --- a/dbm/include/dbm/mingraph.h +++ /dev/null @@ -1,438 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : mingraph.h (dbm) - * - * Minimal graph representation, encoded with the cheapest format - * possible. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * $Id: mingraph.h,v 1.22 2005/09/29 16:10:43 adavid Exp $ - * - **********************************************************************/ - -#ifndef INCLUDE_DBM_MINGRAPH_H -#define INCLUDE_DBM_MINGRAPH_H - -#include "base/c_allocator.h" -#include "base/intutils.h" -#include "dbm/dbm.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/************************************************************************* - * For practical reasons we assume that DBM dimensions are - * <= 2^16-1. This is large enough since the size needed is - * dim*dim integers per DBM and for dim=2^16 we need 2^32 integers - * for only 1 DBM, which go well beyond the addressable memory in 32 bits. - *************************************************************************/ - -/** - * @file - * - * Support for minimum graph representation. - * - * The minimal graph is represented internally by the cheapest format - * possible, and in some cases it may even not be reduced. In addition - * to this, the size of the minimal graph depends on the actual input - * DBM, which makes the size of the allocated memory unpredictable - * from the caller point of view. - * - * - * - * @section allocation How allocation works - * - * The idea is to have generic implementation that can be used with - * standard allocation schemes (malloc, new) and with custom - * allocators. This interface is in C to make it easy to wrap to other - * languages so we use a generic function to allocate memory. The - * type of this function is - * \code - * int32_t* function(uint32_t size, void *data) - * \endcode - * where: - * - \a size is the size in \c int to allocate, and it returns a - * pointer to a \c int32_t[size] - * - \a data is other custom data. - * - * Possible wrappers are: - * - for a custom allocator Alloc: - * \code - * int32_t *alloc(uint32_t size, void *data) { - * return ((Alloc*)data)->alloc(size); - * } - * \endcode - * defined as base_allocate in base/DataAllocator.h - * - for malloc: - * \code - * int32_t *alloc(uint32_t size, void *) { - * return (int32_t*) malloc(size*sizeof(int32_t)); - * } - * \endcode - * defined as base_malloc in base/c_allocator.h - * - for new: - * \code - * int32_t *alloc(uint32_t size, void *) { - * return new int32_t[size]; - * } - * \endcode - * defined as base_new in base/DataAllocator.h - * - * The allocator function and the custom data are packed - * together inside the allocator_t type. - * - * @see base/c_allocator.h - * @see dbm_writeToMinDBMWithOffset() - */ - -/** Style typedef: to make the difference clear - * between just allocated memory and the minimal - * graph representation. - */ -typedef const int32_t* mingraph_t; - -/** Save a DBM in minimal representation. - * - * The API supports allocation of larger data structures than needed - * for the actual zone representation. When the \a offset argument is - * bigger than zero, \a offset extra integers are allocated and the - * zone is written with the given offset. Thus when \c - * int32_t[data_size] is needed to represent the reduced zone, an \c - * int32_t array of size \c offset+data_size\c is allocated. The - * first \a offset elements can be used by the caller. It is important - * to notice that the other functions typically expect a pointer to - * the actual zone data and not to the beginning of the allocated - * block. Thus in the following piece of code, most functions expect - * \c mg and not \c memory: - * - * \code - * int32_t *memory = dbm_writeToMinDBMWithOffset(...); - * mingraph_t mg = &memory[offset]; - * \endcode - * - * \b NOTES: - * - if \a offset is 0 and \a dim is 1, NULL may be returned. - * NULL is valid as an input to the other functions. - * - it could be possible to send as argument the maximal - * value of the constraints that can be deduced from - * the maximal constants but this would tie the algorithm - * to the extrapolation. - * - * - * @param dbm: the DBM to save. - * @param dim: its dimension. - * @param minimizeGraph: activate minimized graph - * reduction. If it is false, then the DBM is copied - * without its diagonal. - * @param tryConstraints16: flag to try to save - * constraints on 16 bits, will cost dim*dim time. - * @param c_alloc: C allocator wrapper - * @param offset: offset for allocation. - * @return allocated memory. - * @pre - * - dbm is a raw_t[dim*dim] - * - allocFunction allocates memory in integer units - * - dbm is closed. - * - dim > 0 (at least ref clock) - * @post the returned memory is of size offset+something - * unknown from the caller point of view. - */ -int32_t* dbm_writeToMinDBMWithOffset(const raw_t* dbm, cindex_t dim, bool minimizeGraph, - bool tryConstraints16, allocator_t c_alloc, size_t offset); - -/** Save a pre-analyzed DBM in minimal representation. - * @param dbm: the DBM to save. - * @param dim: its dimension. - * @param bitMatrix: bit matrix resulting from the - * analysis (ie dbm_analyzeForMinDBM). - * @param nbConstraints: number of constraints in the - * bit matrix. - * @param tryConstraints16: flag to try to save - * constraints on 16 bits, will cost dim*dim time. - * @param allocFunction: the allocation function. - * @param offset: offset for allocation. - * @return allocated memory. - * @pre - * - dbm is a raw_t[dim*dim] - * - allocFunction allocates memory in integer units - * - dbm is closed. - * - dim > 0 (at least ref clock) - * - bitMatrix != NULL, obtained from dbm_analyzeForMinDBM - * - nbConstraints = number of bits set in bitMatrix - * - bitMatrix is a uint32_t[bits2intsize(dim*dim)] - * @post - * - the returned memory is of size offset+something - * unknown from the caller point of view. - * - bitMatrix is cleaned from the constraints xi >= 0 - */ -int32_t* dbm_writeAnalyzedDBM(const raw_t* dbm, cindex_t dim, uint32_t* bitMatrix, - size_t nbConstraints, bool tryConstraints16, allocator_t c_alloc, - size_t offset); - -/** - * Analyze a DBM for its minimal graph representation. Computes the - * smallest number of constraints needed to represent the same zone as - * the full DBM in \a dbm. The result in returned in \a bitMatrix: If - * the bit \f$ i \cdot dim + j\f$ is set, then the constraint - * \f$(i,j)\f$ of \a dbm is needed. - * @param dbm: DBM. - * @param dim: dimension. - * @param bitMatrix: bit matrix. - * @return - * - number of needed constraints to save - * - bit matrix that marks which constraints belong to the minimal graph - * @pre bitMatrix is a uint32_t[bits2intsize(dim*dim)] - */ -size_t dbm_analyzeForMinDBM(const raw_t* dbm, cindex_t dim, uint32_t* bitMatrix); - -/** @return true if the mingraph contains zero, false otherwise. - */ -bool dbm_mingraphHasZero(mingraph_t ming); - -/** - * This is a post-processing function for dbm_analyzeForMinDBM - * to remove constraints of the form x>=0 that are part of the - * minimal graph but that do not give information - if CLOCKS_POSITIVE. - * @param dbm,dim: DBM of dimension dim - * @param bitMatrix: bit matrix (already computed minimal graph) - * @param nbConstraints: the number of constraints of the minimal graph. - * @return the updated number of constraints of the modified minimal - * graph where constraints x>=0 may have been removed. - * @pre dbm_analyzeForMinDBM has been called before and nbConstraints - * corresponds to the number of constraints of the minimal graph. - */ -size_t dbm_cleanBitMatrix(const raw_t* dbm, cindex_t dim, uint32_t* bitMatrix, - size_t nbConstraints); - -/** - * Get back the minimal graph from the internal representation. - * It might be the case that the minimal graph is recomputed if - * the DBM was copied. - * @param ming: internal representation of the minimal graph. - * @param bitMatrix: bit matrix of the minimal graph to write. - * @param isUnpacked: says if buffer contains the unpacked DBM already. - * @param buffer: where to uncompress the full DBM if needed. - * @return the number of constraints part of the minimal graph. - * @pre let dim be the dimension of ming, bitMatrix is a uint32_t[bit2intsize(dim*dim)], - * buffer is a raw_t[dim*dim], and if isUnpacked is true then buffer contains - * the full DBM of ming. - * @post if ming is the result of saving a given dbm A, then the resulting - * bitMatrix is the same as the one given by dbm_analyzeForMinDBM(A,dim,bitMatrix) - * + buffer always contains the unpacked mingraph. - */ -size_t dbm_getBitMatrixFromMinDBM(uint32_t* bitMatrix, mingraph_t ming, bool isUnpacked, - raw_t* buffer); - -/** - * Convert a bit matrix marking constraints to an array of indices. - * Encoding: i[k] = (index[k] & 0xffff) and j[k] = (index[k] >> 16) - * @param bitMatrix: the bit matrix to convert. - * @param nbConstraints: number of set bit in the matrix. - * @param index: the index array to write. - * @param dim: dimension of the bit matrix. - * @pre index is a indexij_t[dim*(dim-1)] and bits on the - * diagonal are not marked, nbConstraints <= dim*(dim-1). - */ -void dbm_bitMatrix2indices(const uint32_t* bitMatrix, size_t nbConstraints, uint32_t* index, - cindex_t dim); - -/** Read a DBM from its minimal DBM representation. - * @param dbm: where to write. - * @param minDBM: the minimal representation to read from. - * @pre - * - dbm is a raw_t[dim*dim] where dim = dbm_getDimOfMinDBM(minDBM) - * - minDBM points to the data of the minDBM directly. There is no - * offset. - * @return dimension of DBM and unpacked DBM in dbm. - */ -cindex_t dbm_readFromMinDBM(raw_t* dbm, mingraph_t minDBM); - -/** Dimension of a DBM from its packed minimal representation. - * @param minDBM: the minimal DBM data directly, without offset. - * @return dimension of DBM. - */ -cindex_t dbm_getDimOfMinDBM(mingraph_t minDBM); - -/** Size of the representation of the MinDBM. - * This is the size of the allocated memory (without offset) for the - * minimal representation. It is at most dim*(dim-1)+1 because in the - * worst case the DBM is copied without its diagonal and we need one - * integer to store the size. - * @param minDBM: minimal DBM representation (without offset). - * @return size in int32_t allocated for the representation. - * NOTE: the write function allocates exactly - * int32_t[offset+dbm_getSizeOfMinDBM(minDBM)] - */ -size_t dbm_getSizeOfMinDBM(mingraph_t minDBM); - -/** Equality test with a full DBM. - * Unfortunately, this may be expensive (dim^3) if the - * minimal graph format is used. - * @param dbm: full DBM. - * @param dim: dimension of dbm. - * @param minDBM: minimal DBM representation (without offset). - * @pre dbm is a raw_t[dim*dim] and dim > 0 (at least ref clock) - * @return true if the DBMs are the same, false otherwise. - */ -bool dbm_isEqualToMinDBM(const raw_t* dbm, cindex_t dim, mingraph_t minDBM); - -/** Equality test between 2 minimal graphs (saved - * with the same function and flags). - * @param mg1,mg2: minimal graph arguments. - * @return true if the graphs are the same, provided - * they were saved with the same flags, false otherwise. - */ -static inline bool dbm_areMinDBMVerbatimEqual(mingraph_t mg1, mingraph_t mg2) -{ - assert(mg1 && mg2); /* mingraph_t == const int* */ - return (*mg1 == *mg2 && base_areEqual(mg1 + 1, mg2 + 1, dbm_getSizeOfMinDBM(mg1) - 1)); -} - -/** Equality test with a full DBM. - * This variant of the equality test may be used if the - * DBM has already been analyzed or if you need to reuse - * the result of the analysis. - * @param dbm: full DBM. - * @param dim: dimension of dbm. - * @param bitMatrix: bit matrix resulting from the analysis - * of dbm (dbm_analyzeforMinDBM). - * @param nbConstraints: number of constraints marked in - * the bit matrix = number of bits set. - * @param minDBM: minimal DBM representation (without offset). - * @pre - * - dbm is a raw_t[dim*dim] and dim > 0 (at least ref clock) - * - bitMatrix is a uint32_t[bits2intsize(dim*dim)] - * @return true if the DBMs are the same, false otherwise. - * @post the bitMatrix may have the bits for the constraints on - * the 1st row cleaned and nbConstraints will be updated accordingly. - */ -bool dbm_isAnalyzedDBMEqualToMinDBM(const raw_t* dbm, cindex_t dim, uint32_t* bitMatrix, - size_t* nbConstraints, mingraph_t minDBM); - -/** Another variant for equality checking: - * this one may unpack the minimal graph if needed. - * It needs a buffer as an input to do so. - * @param dbm, dim: full DBM of dimension dim. - * @param minDBM: minimal DBM representation (without offset). - * @param buffer: buffer to unpack the DBM if needed - * @pre - * - dbm is a raw_t[dim*dim] and dim > 0 (at leat ref clock) - * - buffer != NULL is a raw_t[dim*dim] - * @post - * - buffer may be written or not. If you want to know - * it, you can set buffer[0] = 0, and test afterwards - * if buffer[0] == 0. If mingraph is unpacked then it - * is guaranteed that buffer[0] == dbm_LE_ZERO, otherwise - * buffer is untouched. - * @return true if the DBMs are the same, false otherwise. - */ -bool dbm_isUnpackedEqualToMinDBM(const raw_t* dbm, cindex_t dim, mingraph_t minDBM, raw_t* buffer); - -/** Relation between a full DBM and a minimal representation - * DBM. The relation may be exact or not: - * if the relation is exact then - * dbm_EQUAL is returned if dbm == minDBM - * dbm_SUBSET is returned if dbm < minDBM - * dbm_SUPERSET is returned if dbm > minDBM - * dbm_DIFFERENT is returned if dbm not comparable with minDBM - * else - * dbm_SUBSET is returned if dbm <= minDBM - * dbm_DIFFERENT otherwise - * - * @param dbm: full DBM to test. - * @param dim: its dimension. - * @param minDBM: minimal DBM representation. - * @param unpackBuffer: memory space to unpack. - * if unpackBuffer == NULL then the relation is not exact - * if unpackBuffer != NULL then assume that buffer = raw_t[dim*dim] - * to be able to unpack the DBM and compute an exact relation. - * - * NOTE: unpackBuffer is sent as an argument to avoid stackoverflow - * if using stack allocation. The needed size is in dim*dim*sizeof(int). - * It is NOT guaranteed that unpackBuffer will be written. The dbm - * MAY be unpacked only if relation != subset and unpackBuffer != NULL. - * - * @pre - * - dbm is closed and not empty - * - dbm is a raw_t[dim*dim] (full DBM) - * - dim > 0 (at least ref clock) - * @return relation as described above. - */ -relation_t dbm_relationWithMinDBM(const raw_t* dbm, cindex_t dim, mingraph_t minDBM, - raw_t* unpackBuffer); - -/** Variant of the previous relation function. - * This may be cheaper if what count is to know - * (subset or equal) or different or superset. - * if unpackBuffer != NULL then - * dbm_EQUAL or dbm_SUBSET is returned if dbm == minDBM - * dbm_SUBSET is returned if dbm < minDBM - * dbm_SUPERSET is returned if dbm > minDBM - * dbm_DIFFERENT is returned if dbm not comparable with minDBM - * else - * dbm_SUBSET is returned if dbm <= minDBM - * dbm_DIFFERENT is returned otherwise - * - * @param dbm: full DBM to test. - * @param dim: its dimension. - * @param minDBM: minimal DBM representation. - * @param unpackBuffer: memory space to unpack. - * if unpackBuffer == NULL then the relation is not exact - * if unpackBuffer != NULL then assume that buffer = raw_t[dim*dim] - * to be able to unpack the DBM and compute an exact relation. - * @pre - * - dbm is closed and not empty - * - dbm is a raw_t[dim*dim] (full DBM) - * - dim > 0 (at least ref clock) - * @return relation as described above. - */ -relation_t dbm_approxRelationWithMinDBM(const raw_t* dbm, cindex_t dim, mingraph_t minDBM, - raw_t* unpackBuffer); - -/** Convex union. - * This may cost dim^3 in time since the minimal DBM has - * to be unpacked to a full DBM. - * Computes dbm = dbm + minDBM - * @param dbm: dbm to make the union with. - * @param dim: its dimension. - * @param minDBM: minDBM to add to dbm (without offset). - * @param unpackBuffer: memory space to unpack the DBM. - * @pre - * - dbm is a raw_t[dim*dim] and dim > 0 (at least ref clock). - * - DBMs have the same dimensions - * - unpackBuffer != NULL and is a raw_t[dim*dim] - */ -void dbm_convexUnionWithMinDBM(raw_t* dbm, cindex_t dim, mingraph_t minDBM, raw_t* unpackBuffer); - -/** Simple type to allow for statistics on the different internal - * formats used. The format are not user controllable and should - * not be read from outside. For the tuple representation, it is - * not said here if it is (i,j,c_ij) or a bunch of c_ij and (i,j). - */ -typedef enum { - dbm_MINDBM_TRIVIAL = 0, /**< only clock ref, dim == 1 */ - dbm_MINDBM_COPY32, /**< 32 bits, dbm copy without diagonal */ - dbm_MINDBM_BITMATRIX32, /**< 32 bits, c_ij and a bit matrix */ - dbm_MINDBM_TUPLES32, /**< 32 bits, c_ij and tuples (i,j) */ - dbm_MINDBM_COPY16, /**< 16 bits, dbm copy without diagonal */ - dbm_MINDBM_BITMATRIX16, /**< 16 bits, c_ij and a bit matrix */ - dbm_MINDBM_TUPLES16, /**< 16 bits, c_ij and tuples (i,j) */ - dbm_MINDBM_ERROR /**< should never be the case */ -} representationOfMinDBM_t; - -/** @return the type of the internal format used. - * @param minDBM: minimal representation (without offset) - * to read. - */ -representationOfMinDBM_t dbm_getRepresentationType(mingraph_t minDBM); - -#ifdef __cplusplus -} -#endif - -#endif /* INCLUDE_DBM_MINGRAPH_H */ diff --git a/dbm/include/dbm/partition.h b/dbm/include/dbm/partition.h deleted file mode 100644 index 6bb9c5f9..00000000 --- a/dbm/include/dbm/partition.h +++ /dev/null @@ -1,318 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : partition.h -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: partition.h,v 1.9 2005/08/02 09:36:43 adavid Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_DBM_PARTITION_H -#define INCLUDE_DBM_PARTITION_H - -#include "dbm/fed.h" -#include "base/intutils.h" - -/** - * @file The type partition_t defines a partition - * of federations (fed_t) indexed by a given ID. - * The federations added are kept disjoint by - * definition of a partition and the decision of - * where to add the intersecting parts is left to - * the user. - */ - -namespace dbm -{ - /// Type for partitions, designed to be used as a simple scalar with - /// cheap copies as long as there is no need to modify a partition_t. - class partition_t - { - public: - /** Initialise an empty partition for federations - * of dimension dim. - * @param noPartition ignores the partition for IDs != 0 - * (0 interpreted as delay). - */ - partition_t(cindex_t dim, bool noPartition = false): fedTable(dimFlag2ptr(dim, noPartition)) - {} - - /// The copy is a reference copy only. - partition_t(const partition_t& arg): fedTable(arg.fedTable) - { - assert(fedTable); - if (isPtr()) - fedTable->incRef(); - } - - /// Copy operator is a reference copy only. - partition_t& operator=(const partition_t& arg) - { - assert(fedTable); - if (arg.isPtr()) - arg.fedTable->incRef(); - if (isPtr()) - fedTable->decRef(); - fedTable = arg.fedTable; - return *this; - } - - /// Reset the partition. - void reset() - { - if (isPtr()) { - cindex_t dim = fedTable->getDimension(); - bool flag = fedTable->isNotPartition(); - fedTable->decRef(); - fedTable = dimFlag2ptr(dim, flag); - } - } - - ~partition_t() - { - assert(fedTable); - if (isPtr()) - fedTable->decRef(); - } - - bool isPartition() const { return !(isPtr() ? fedTable->isNotPartition() : eflag()); } - - /// Wrappers to the federations of the partition. - /// @see fed_t - void intern(); - - /** Add a federation to the partition subset - * 'id'. The intersecting DBMs of fed with - * the partition will be given to fed or one - * subset of the partition and subtracted from - * fed or the partition depending on the decision - * function (@see constructor and setChooser). - * @param id,fed ID of the federation fed to add - * to the partition. - * @pre fed.getDimension() == getDimension() - * @post fed.isEmpty() and convexReduce() is - * maintained on the internal federations. - */ - void add(uintptr_t id, fed_t& fed); - - /** @return the federation corresponding to the - * subset 'id' of the partition. If there is no - * such subset, an empty federation is returned. - * @param id ID of the subset to find. - */ - fed_t get(uint32_t id) const - { - assert(fedTable); - return isPtr() ? fedTable->get(id) : fed_t(edim()); - } - fed_t getAll() const - { - assert(fedTable); - return isPtr() ? fedTable->getAll() : fed_t(edim()); - } - - /// @return the dimension of the federations. - cindex_t getDimension() const - { - assert(fedTable); - return isPtr() ? fedTable->getDimension() : edim(); - } - - /// @return total number of DBMs of all the federations - /// (compute the number on demand). - size_t getNumberOfDBMs() const - { - assert(fedTable); - return isPtr() ? fedTable->getNumberOfDBMs() : 0; - } - - /// An entry in the table of federations. - class entry_t - { - public: - entry_t(uintptr_t i, const fed_t& f): id(i), fed(f) {} - - uintptr_t id; //< ID of the federation, subset of the partition. - fed_t fed; //< Subset of partition. - }; - - /// Iterator to read the federation of the partitions. Only - /// const is provided since modifying federations may destroy - /// the partition. - class const_iterator - { - public: - /// Constructor should be used only by partition_t. - const_iterator(const entry_t* const* start): current(start) {} - - /// Dereference returns a federation. - const fed_t& operator*() - { - assert(current && *current); - return (*current)->fed; - } - const fed_t* operator->() - { - assert(current && *current); - return &(*current)->fed; - } - - bool isNull() const - { - assert(current); - return *current == NULL; - } - uintptr_t id() const - { - assert(current && *current); - return (*current)->id; - } - - const_iterator& operator++() - { - assert(current); - ++current; - return *this; - } - - /// Standard == and != operators. The implementation uses ||, - /// this is not a typo. The hash table may be sparse internally - /// and the ++ operator stops to increment whenever there is - /// nothing left. - bool operator==(const const_iterator& arg) const { return current == arg.current; } - bool operator!=(const const_iterator& arg) const { return !(*this == arg); } - bool operator<(const const_iterator& arg) const { return current < arg.current; } - - private: - const entry_t* const* current; /// Current position in the table. - }; - - /// Standard begin() and end() for const_iterator. - const_iterator begin() const - { - assert(fedTable); - return isPtr() ? const_iterator(fedTable->getBeginTable()) : const_iterator(NULL); - } - const_iterator end() const - { - assert(fedTable); - return isPtr() ? const_iterator(fedTable->getEndTable()) : const_iterator(NULL); - } - - private: - /// The federation table (a simple hash table with chained collisions - /// on the table entries) to access the subsets (fed_t) of the partition. - class fedtable_t - { - public: - static fedtable_t* create(cindex_t dim, bool noPartition); - - /// @pre !isMutable() or it is stupid to call this - /// @post refCounter is decremented - fedtable_t* copy(); - - void incRef() { refCounter++; } - void decRef() - { - assert(refCounter > 0); - if (!--refCounter) { - remove(); - } - } - bool isMutable() - { - assert(refCounter > 0); - return refCounter == 1; - } - - /// Access methods. - entry_t** getTable() { return table; } - const entry_t* const* getBeginTable() const { return table; } - const entry_t* const* getEndTable() const { return getBeginTable() + getSize(); } - cindex_t getDimension() const { return all.getDimension(); } - size_t getSize() const { return mask + 1; } - bool isNotPartition() const { return noPartition; } - - /// Remove (deallocate) this fedTable. @pre refCounter == 0. - void remove(); - - /// @return the fed_t corresponding to the partition's subset id. - /// The federation is empty if the subset id is not defined. - fed_t get(uint32_t id) const; - fed_t getAll() const { return all; } - - /// Add a federation to the subset 'id' of the partition. - /// @return true if this table must be resized. - bool add(uintptr_t id, fed_t& fed); - - /// @return a resized table. - /// @pre isMutable() - /// @post this table is deallocated. - fedtable_t* larger(); - - /// @return total number of DBMs. - size_t getNumberOfDBMs() const; - - private: - /// Constants for initialization. - enum { INIT_POWER = 1, INIT_SIZE = (1 << INIT_POWER), INIT_MASK = (INIT_SIZE - 1) }; - - /// Private constructors because the allocation is special. - fedtable_t(cindex_t d, size_t nb, uint32_t m, bool noP): - refCounter(1), all(d), nbEntries(nb), mask(m), noPartition(noP) - { - // table not initialized - } - - /// Default initial constructor. - fedtable_t(cindex_t d, bool noP): - refCounter(1), all(d), nbEntries(0), mask(INIT_MASK), noPartition(noP) - { - std::fill(table, table + INIT_SIZE, nullptr); - } - - uint32_t refCounter; //< standard reference counter - fed_t all; //< union of all federations - size_t nbEntries; //< number of non null entries - uint32_t mask; //< bit mask for access, table size = mask+1 - bool noPartition; - entry_t* table[]; //< the table of federations. - }; - - /// Check that the referenced fedTable is mutable (refCounter == 1) - /// and make a copy if necessary. - void checkMutable() - { - assert(fedTable); - if (!fedTable->isMutable()) { - fedTable = fedTable->copy(); - } - } - - // this assumes that the alignment is sound (i.e. lsb is unused). - static_assert((alignof(fedtable_t) % 2) != 1); - static fedtable_t* dimFlag2ptr(cindex_t dim, bool flag) - { - return reinterpret_cast((dim << 2) | (flag << 1) | 1); - } - bool isPtr() const { return (((uintptr_t)fedTable) & 1) == 0; } - cindex_t edim() const - { - assert(!isPtr()); - return ((uintptr_t)fedTable) >> 2; - } - bool eflag() const - { - assert(!isPtr()); - return (((uintptr_t)fedTable) & 2) != 0; - } - - fedtable_t* fedTable; //< table of federations. - }; -} // namespace dbm - -#endif // INCLUDE_DBM_PARTITION_H diff --git a/dbm/include/dbm/pfed.h b/dbm/include/dbm/pfed.h deleted file mode 100644 index 07b7da90..00000000 --- a/dbm/include/dbm/pfed.h +++ /dev/null @@ -1,648 +0,0 @@ -// -*- Mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*- -/////////////////////////////////////////////////////////////////////////////// -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 2006, Uppsala University and Aalborg University. -// All right reserved. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef DBM_PFED_H -#define DBM_PFED_H - -#include "dbm/priced.h" -#include "Valuation.h" - -#include -#include - -namespace dbm -{ - /** - * Small C++ wrapper for the PDBM priced DBM type. - * - * The wrapper handles all reference counting, thus freeing you - * from calling pdbm_incRef and pdbm_decRef yourself. - * - * It provides a type-conversion operator to PDBM, thus the - * preferred way of working with priced DBMs is to use the C - * functions directly on the wrapper type (the compiler will - * handle the conversion for you). - * - * For compatibility with dbm_t (the C++ wrapper for normal DBMs), - * a few selected additional methods have been implemented. This - * also happens to be the only reason why the dimension of the - * priced DBM is stored in the wrapper. However, the bulk of the - * pdbm_X() functions are not made available as methods. - */ - class pdbm_t - { - protected: - PDBM pdbm; - cindex_t dim; - - public: - /** - * The default constructor constructs an empty priced DBM of - * dimension zero. This must not be assigned to another - * pdbm_t. - */ - pdbm_t(); - - /** - * Allocates a new empty priced DBM of the given - * dimension. This must not be assigned to another pdbm_t. - * - * @see pdbm_allocate() - */ - explicit pdbm_t(cindex_t); - - /** - * Makes a reference to the given priced DBM. - */ - pdbm_t(PDBM pdbm, cindex_t dim); - - /** - * Copy constructor. This will increment the reference count - * to the priced DBM given. - */ - pdbm_t(const pdbm_t&); - - /** - * Destructor. Reduces the reference count to the priced - * DBM. This in turn may result in its deallocation. - */ - ~pdbm_t(); - - /** - * Assignment operator. - */ - pdbm_t& operator=(const pdbm_t&); - - /** - * Type conversion to PDBM. Notice that a reference to the - * PDBM is provided, thus the pdbm_t object can even be used - * with pdbm_X() functions modifying the priced DBM. - */ - operator PDBM&() { return pdbm; } - - /** - * Type conversion to constant PDBM. - */ - operator PDBM() const { return pdbm; } - - /** - * Returns a hash value for the priced DBM. - */ - uint32_t hash(uint32_t seed = 0) const; - - /** - * Returns the bound on x(i) - x(j). - */ - raw_t operator()(cindex_t i, cindex_t j) const; - - /** @see dbm_t::setDimension() */ - void setDimension(cindex_t dim); - - /** Returns the dimension of this priced DBM. */ - cindex_t getDimension() const { return dim; } - - /** @see dbm_t::const_dbm() */ - const raw_t* const_dbm() const; - - /** @see dbm_t::getDBM() */ - raw_t* getDBM(); - - /** @see dbm_t::analyseForMinDBM() */ - size_t analyzeForMinDBM(uint32_t* bitMatrix) const; - - /** @see dbm_t::writeToMinDBMWithOffset() */ - int32_t* writeToMinDBMWithOffset(bool minimizeGraph, bool tryConstraints16, - allocator_t c_alloc, uint32_t offset) const; - - /** @see pdbm_relationWithMinDBM() */ - relation_t relation(const int32_t*, raw_t*) const; - - /** @see dbm_t::freeClock() */ - pdbm_t& freeClock(cindex_t clock); - - /** @see dbm_t::getSizeOfMinDBM() */ - static size_t getSizeOfMinDBM(cindex_t dimension, const int32_t*); - - /** @see dbm_t::readFromMinDBM() */ - static pdbm_t readFromMinDBM(cindex_t dimension, const int32_t*); - }; - - inline pdbm_t::pdbm_t(): pdbm(nullptr), dim(0) {} - - inline pdbm_t::pdbm_t(cindex_t dim): pdbm(nullptr), dim(dim) {} - - inline pdbm_t::pdbm_t(PDBM pdbm, cindex_t dim): pdbm(pdbm), dim(dim) { pdbm_incRef(pdbm); } - - inline pdbm_t::pdbm_t(const pdbm_t& other): pdbm(other.pdbm), dim(other.dim) - { - pdbm_incRef(pdbm); - } - - inline pdbm_t::~pdbm_t() { pdbm_decRef(pdbm); } - - inline pdbm_t& pdbm_t::operator=(const pdbm_t& other) - { - pdbm_incRef(other.pdbm); - pdbm_decRef(pdbm); - dim = other.dim; - pdbm = other.pdbm; - return *this; - } - - inline void pdbm_t::setDimension(cindex_t dim) - { - pdbm_decRef(pdbm); - pdbm = nullptr; - this->dim = dim; - } - - inline const raw_t* pdbm_t::const_dbm() const { return pdbm_getMatrix(pdbm, dim); } - - inline raw_t* pdbm_t::getDBM() { return pdbm_getMutableMatrix(pdbm, dim); } - - inline uint32_t pdbm_t::hash(uint32_t seed) const { return pdbm_hash(pdbm, dim, seed); } - - inline raw_t pdbm_t::operator()(cindex_t i, cindex_t j) const - { - return pdbm_getMatrix(pdbm, dim)[i * dim + j]; - } - - inline size_t pdbm_t::analyzeForMinDBM(uint32_t* bitMatrix) const - { - return pdbm_analyzeForMinDBM(pdbm, dim, bitMatrix); - } - - inline int32_t* pdbm_t::writeToMinDBMWithOffset(bool minimizeGraph, bool tryConstraints16, - allocator_t c_alloc, uint32_t offset) const - { - return pdbm_writeToMinDBMWithOffset(pdbm, dim, minimizeGraph, tryConstraints16, c_alloc, - offset); - } - - inline relation_t pdbm_t::relation(const int32_t* graph, raw_t* buffer) const - { - return pdbm_relationWithMinDBM(pdbm, dim, graph, buffer); - } - - inline size_t pdbm_t::getSizeOfMinDBM(cindex_t dim, const int32_t* graph) - { - return dbm_getSizeOfMinDBM(graph + dim + 2) + dim + 2; - } - - inline pdbm_t pdbm_t::readFromMinDBM(cindex_t dim, const int32_t* graph) - { - pdbm_t pdbm(dim); - pdbm_readFromMinDBM(pdbm, dim, graph); - return pdbm; - } - - inline pdbm_t& pdbm_t::freeClock(cindex_t clock) - { - pdbm_freeClock(pdbm, dim, clock); - return *this; - } - - /** - * Implementation of priced federations. - * - * A priced federation is essentially a list of priced DBMs. - * Semantically, the priced federation represents the union of the - * priced DBMs. - * - * Priced federations implement copy-on-write using reference - * counting. - */ - class pfed_t - { - public: - typedef std::list::const_iterator const_iterator; - - typedef std::list::iterator iterator; - - protected: - struct pfed_s - { - std::list zones; - uint32_t count; - cindex_t dim; - }; - - static std::allocator alloc; - - /** Pointer to record holding the federation. */ - struct pfed_s* ptr; - - /** Increment reference count. */ - void incRef(); - - /** Decrement reference count. */ - void decRef(); - - /** Prepare federation for modification. */ - void prepare(); - - /** Copy-on-write: Creates an unshared copy of the federation. */ - void cow(); - - /** - * Adds \a pdbm to the federation. The reference count on pdbm - * is incremented by one. - */ - void add(const PDBM pdbm, cindex_t dim); - - public: - /** Allocate empty priced federation of dimension 0. */ - pfed_t(); - - /** Allocate empty priced federation of dimension \a dim. */ - explicit pfed_t(cindex_t dim); - - /** - * Allocate a priced federation of dimension \a dim initialised to - * \a pdbm. - */ - pfed_t(const PDBM pdbm, cindex_t dim); - - /** The copy constructor implements copy on write. */ - pfed_t(const pfed_t&); - - /** - * The destructor decrements the reference count and deallocates - * the priced DBM when the count reaches zero. - */ - ~pfed_t(); - - /** - * Constrain x(i) to value. - * - * @return Returns true if non-empty after operation. - */ - bool constrain(cindex_t i, uint32_t value); - - /** - * Constrain federation to valuations satisfying x(i) - x(j) ~ - * constraint. - * - * @return Returns true if non-empty after operation. - */ - bool constrain(cindex_t i, cindex_t j, raw_t constraint); - - /** - * Constrain federation to valuations satisfying x(i) - x(j) ~ - * (b, isStrict). - * - * @return Returns true if non-empty after operation. - */ - bool constrain(cindex_t i, cindex_t j, int32_t b, bool isStrict); - - /** - * Constrain federation to valuations satisfying the - * constraints. - * - * @param constraints Array of length \a n of constraints. - * @param n length of \a constraints. - * @pre n > 0 - * @return Returns true if non-empty after operation. - */ - bool constrain(const constraint_t* constraints, size_t n); - - /** - * Constrain federation to valuations satisfying \a c. - * - * @return Returns true if non-empty after operation. - */ - bool constrain(const constraint_t& c); - - /** Returns the infimum of the federation. */ - int32_t getInfimum() const; - - /** - * Check if the federation satisfies a given constraint. - * - * @return Returns true if the federation satisfies \a c. - */ - bool satisfies(const constraint_t& c) const; - - /** - * Check if the federation satisfies a given constraint. - * - * @return Returns true if the federation satisfies x(i) - - * x(j) ~ constraint. - */ - bool satisfies(cindex_t i, cindex_t j, raw_t constraint) const; - - /** Returns true iff the federation is empty. */ - bool isEmpty() const; - - bool isUnbounded() const; - - /** Contains a hash of the federation. */ - uint32_t hash(uint32_t seed) const; - - /** Returns true iff the federation contains \v. */ - bool contains(const DoubleValuation& v) const; - - /** Returns true iff the federation contains \v. */ - bool contains(const IntValuation& v) const; - - /** - * Returns true iff the federation contains \v, ignoring - * strictness of constraints. - */ - bool containsWeakly(const IntValuation& v) const; - - /** Delay with the current delay rate. */ - void up(); - - /** Delay with rate \a rate. */ - void up(int32_t rate); - - /** Set x(clock) to \a value. */ - void updateValue(cindex_t clock, uint32_t value); - - /** - * Set x(clock) to \a value. x(zero) must be on a zero-cycle with - * x(clock). - */ - void updateValueZero(cindex_t clock, int32_t value, cindex_t zero); - - void extrapolateMaxBounds(int32_t* max); - void diagonalExtrapolateMaxBounds(int32_t* max); - void diagonalExtrapolateLUBounds(int32_t* lower, int32_t* upper); - - void incrementCost(int32_t value); - - int32_t getCostOfValuation(const IntValuation& valuation) const; - void relax(); - - void freeClock(cindex_t clock); - - /** - * Resets the federation to the federation containing only the - * origin, with a cost of 0. - */ - void setZero(); - - /** - * Resets the federation to the federation containing all - * valuations, with a cost of 0. - */ - void setInit(); - - /** - * Resets the federation to the empty federation. - */ - void setEmpty(); - - /** - * Returns an iterator to the first zone of the federation. - */ - const_iterator begin() const; - - /** - * Returns an iterator to the position after the last zone of - * the federation. - */ - const_iterator end() const; - - /** - * Returns a mutable iterator to the beginning of the federation. - */ - iterator beginMutable(); - - /** - * Returns a mutable iterator to the end of the federation. - */ - iterator endMutable(); - - /** - * Erases a DBM from the federation and returns an iterator to - * the successor element. - */ - iterator erase(iterator); - - /** Assignment operator. */ - pfed_t& operator=(const pfed_t&); - - /** Assignment operator. */ - pfed_t& operator=(const PDBM); - - /** Union operator. */ - pfed_t& operator|=(const pfed_t&); - - /** Union operator. */ - pfed_t& operator|=(const PDBM); - - /** Not implemented. */ - pfed_t& operator-=(const pfed_t&); - - /** Not implemented. */ - pfed_t& operator+=(const pfed_t&); - - /** Not implemented. */ - pfed_t& operator&=(const pfed_t&); - - /** Not implemented. */ - bool intersects(const pfed_t&) const; - - /** Not implemented. */ - pfed_t operator&(const pfed_t& b) const; - - /** Not implemented. */ - pfed_t operator-(const pfed_t& b) const; - - /** Not implemented. */ - void down(); - - /** Not implemented. */ - int32_t getUpperMinimumCost(cindex_t) const; - - /** Not implemented. */ - void relaxUp(); - - /** Not implemented. */ - void getValuation(double* cval, size_t dim, bool* freeC = nullptr) const; - - /** Not implemented. */ - void swapClocks(cindex_t, cindex_t); - - /** Not implemented. */ - void splitExtrapolate(const constraint_t*, const constraint_t*, const int32_t*); - - /** Not implemented (REVISIT). */ - void setDimension(cindex_t); - - /** Not implemented. */ - raw_t* getDBM(); - - /** Not implemented. */ - const raw_t* const_dbm() const; - - /** Not implemented. */ - pfed_t& convexHull(); - - /** - * Relation between two priced federations: SUBSET is returned - * if all zones of this federation are contained in some zone - * of fed. SUPERSET is returned if all zones of \a fed are - * contained in some zone of this federation. EQUAL is - * returned if both conditions are true. DIFFERENT is returned - * if none of them are true. - * - * Notice that this implementation of set inclusion is not - * complete in the sense that DIFFERENT could be returned even - * though the two federations are comparable. - */ - relation_t relation(const pfed_t& fed) const; - - /** - * Exact version of relation(). Only correct if both - * federations have size one. - */ - relation_t exactRelation(const pfed_t& fed) const; - - /** - * Returns the infimum of the federation given a partial - * valuation. - */ - int32_t getInfimumValuation(IntValuation& valuation, const bool* free = nullptr) const; - - /** Returns the number of zones in the federation. */ - size_t size() const; - - /** Returns the dimension of the federation. */ - cindex_t getDimension() const; - - /** - * Implementation of the free up operation for priced - * federations. - * - * @see pdbm_freeUp - */ - void freeUp(cindex_t); - - /** - * Implementation of the free down operation for priced - * federations. - * - * @see pdbm_freeDown - */ - void freeDown(cindex_t); - - template - void erase_if(Predicate p); - - template - void erase_if_not(Predicate p); - - const pdbm_t& const_dbmt() const; - pdbm_t& dbmt(); - }; - - template - inline void pfed_t::erase_if(Predicate p) - { - iterator first = beginMutable(); - iterator last = endMutable(); - while (first != last) { - if (p(*first)) { - first = erase(first); - } else { - ++first; - } - } - } - - template - void pfed_t::erase_if_not(Predicate p) - { - iterator first = beginMutable(); - iterator last = endMutable(); - while (first != last) { - if (p(*first)) { - ++first; - } else { - first = erase(first); - } - } - } - - inline pfed_t::pfed_t(const pfed_t& pfed): ptr(pfed.ptr) { incRef(); } - - inline pfed_t::~pfed_t() - { - assert(ptr->count > 0); - decRef(); - } - - inline void pfed_t::prepare() - { - if (ptr->count > 1) { - cow(); - } - } - - inline pfed_t::iterator pfed_t::beginMutable() - { - prepare(); - return ptr->zones.begin(); - } - - inline pfed_t::iterator pfed_t::endMutable() - { - prepare(); - return ptr->zones.end(); - } - - inline pfed_t::const_iterator pfed_t::begin() const { return ptr->zones.begin(); } - - inline pfed_t::const_iterator pfed_t::end() const { return ptr->zones.end(); } - - inline cindex_t pfed_t::getDimension() const { return ptr->dim; } - - inline size_t pfed_t::size() const { return ptr->zones.size(); } - - inline void pfed_t::incRef() { ptr->count++; } - - inline bool pfed_t::isEmpty() const { return ptr->zones.empty(); } - - inline const pdbm_t& pfed_t::const_dbmt() const - { - assert(size() == 1); - return ptr->zones.front(); - } - - inline pdbm_t& pfed_t::dbmt() - { - assert(size() == 1); - return ptr->zones.front(); - } - - inline pfed_t& pfed_t::operator=(const PDBM pdbm) - { - *this = pfed_t(pdbm, ptr->dim); - return *this; - } - - inline bool pfed_t::constrain(cindex_t i, cindex_t j, int32_t b, bool isStrict) - { - return constrain(i, j, dbm_boundbool2raw(b, isStrict)); - } - - inline bool pfed_t::constrain(const constraint_t& c) { return constrain(c.i, c.j, c.value); } - - inline bool pfed_t::satisfies(const constraint_t& c) const - { - return satisfies(c.i, c.j, c.value); - } - - std::ostream& operator<<(std::ostream&, const pfed_t&); -} // namespace dbm - -#endif /* DBM_PFED_H */ diff --git a/dbm/include/dbm/priced.h b/dbm/include/dbm/priced.h deleted file mode 100644 index af7a4d51..00000000 --- a/dbm/include/dbm/priced.h +++ /dev/null @@ -1,795 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2005, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: priced.h,v 1.15 2005/05/31 20:54:59 behrmann Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_DBM_PRICED_H -#define INCLUDE_DBM_PRICED_H - -#include "base/inttypes.h" -#include "dbm/dbm.h" -#include "dbm/mingraph.h" - -#include -#include -#include - -/** - * @file - * - * Functions for handling priced DBMs. - * - * A priced DBM is a data structure representing a zone with an affine - * hyperplane over the zone assigning a cost to each point in the - * zone. - * - * A few facts about priced DBMs: - * - * - Priced DBMs have a positive dimension. - * - * - Priced DBMs are stored continously in memory. - * - * - The clock with index zero is the reference clock. - * - * - The affine hyperplane is given by the cost in the offset point - * and the coefficients of the hyperplane. - * - * - A closed DBM is never empty. - * - * Allocation can be handled by the library by using \c - * pdbm_allocate() and \c pdbm_deallocate(). This can optionally be - * combined with reference counting using \c pdbm_incRef() and \c - * pdbm_decRef(), in which case \c pdbm_deallocate() is called - * automatically as soon as the reference count reaches zero. - * Reference counting is used to implement copy on write - * semantics. Thus whenever you modify a priced DBM with a reference - * count larger than 1, then that DBM is automatically copied. For - * this reason, all functions modifying priced DBMs take a reference - * parameter to the priced DBM to modify. - * - * A NULL pointer is equivalent to an empty DBM with a reference count - * of 1. Functions that can cause the priced DBM to become empty can - * choose to deallocate the DBM rather than to copy it. All functions - * that do not require the input DBM to be closed will allocate a new - * DBM when given a NULL pointer as input. - * - * Alternatively, memory can be allocated outside the library. In that - * case \c pdbm_size() bytes need to be allocated and preinitialized - * for the use by the library by calling \c pdbm_reserve(). Priced - * DBMs allocated in this manner must not be reference counted. - */ - -/** - * Data type for priced dbm. - */ -typedef struct PDBM_s* PDBM; - -/** - * Computes the size in number of bytes of a priced dbm of the given - * dimension. - * - * @param dim is a dimension. - * @pre dim > 0 - * @return Amount of memory in bytes. - */ -size_t pdbm_size(cindex_t dim); - -/** - * Reserves a memory area for use as a priced DBM. The priced DBM will - * be unitialised, hence further initialised with e.g. \c pdbm_init() - * or \c pdbm_zero() is required. - * - * @param dim is the dimension of the priced DBM to reserve. - * @param p is a memory area of size \c pdbm_size(dim). - * - * @return An unitialised priced DBM of dimension \a dim. - */ -PDBM pdbm_reserve(cindex_t dim, void* p); - -/** - * Allocates a new priced DBM. The reference count is initialised to - * 0. No other initialisation is performed. - * - * @param dim is the dimension. - * @return A newly allocated priced DBM of dimension \a dim. - * @pre dim is larger than 0. - */ -PDBM pdbm_allocate(cindex_t dim); - -/** - * Deallocates a priced DBM. - * - * @pre - * - \a pdbm was allocated with \c pdbm_allocate(). - * - The reference count of \a pdbm is zero. - */ -void pdbm_deallocate(PDBM& pdbm); - -/** - * Increases reference count on priced DBM. - * - * @param pdbm is a priced DBM. - * @pre - * \a pdbm has been allocated with \c pdbm_allocate() and is not NULL. - */ -inline static void pdbm_incRef(PDBM pdbm) -{ - assert(pdbm); - - (*(int32_t*)pdbm)++; -} - -/** - * Decreases reference count on priced DBM. The DBM is deallocated - * when the reference count reaches zero. - * - * @param pdbm is a priced DBM. - * @pre \a pdbm has been allocated with \c pdbm_allocate(). - */ -inline static void pdbm_decRef(PDBM pdbm) -{ - assert(pdbm == nullptr || *(int32_t*)pdbm); - - /* The following relies on the reference counter being the first - * field of the structure. - */ - if (pdbm && !--*(int32_t*)pdbm) { - pdbm_deallocate(pdbm); - } -} - -/** - * Copy a priced DBM. - * - * Priced DBMs normally use a copy-on-write scheme, thus is no need to - * call this function. The only use of it (besides internally in the - * library as part of the copy-on-write implementation) is for priced - * DBMs, for which you choose not to use reference counting. Hence, a - * call to this function is only permissible if the reference count of - * \a dst is zero. If \a dst is NULL, a new DBM is allocate with \c - * pdbm_allocate(). - * - * @param dst The destination. - * @param src The source. - * @param dim The dimension of \a dst and \a src. - * @pre The reference count of \a dst is zero or dst is NULL. - * @post The reference count of the return value is zero. - * @return The destination. - */ -PDBM pdbm_copy(PDBM dst, const PDBM src, cindex_t dim); - -/** - * Initialises a priced DBM to the DBM containing all valuations. The - * cost of all valuations will be zero. If \a pdbm is NULL, a new DBM - * is allocated with \c pdbm_allocate(). - * - * @param pdbm is the priced DBM to initialize. - * @param dim is the dimension of \a pdbm. - */ -void pdbm_init(PDBM& pdbm, cindex_t dim); - -/** - * Initialize a priced DBM to only contain the origin with a cost of - * 0. If \a pdbm is NULL, a new DBM is allocated with \c - * pdbm_allocate(). - * - * @param pdbm is the priced DBM to initialise. - * @param dim is the dimension of \a pdbm. - */ -void pdbm_zero(PDBM& pdbm, cindex_t dim); - -/** - * Constrain a priced DBM. - * - * After the call, the DBM will be constrained such that the - * difference between clock \a i and clock \a j is smaller than \a - * constraint. - * - * @see dbm_constrain1 - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param i is a clock index. - * @param j is a clock index. - * @param constraint is a raw_t bound. - * @pre i != j - * @post The DBM is empty or closed. - * @return True if and only if the result is not empty. - */ -bool pdbm_constrain1(PDBM& pdbm, cindex_t dim, cindex_t i, cindex_t j, raw_t constraint); - -/** - * Constrain a priced DBM with multiple constraints. - * - * @see dbm_constraint1 - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param constraints is an array of \a n constraints. - * @param n is the length of \a constraints. - * @pre the constraints are valid - * @post The DBM is empty or closed. - * @return - * - true if the DBM is non empty + - * closed non empty DBM + updated consistent rates - * - or false if the DBM is empty + - * empty DBM + inconsistent rates - */ -bool pdbm_constrainN(PDBM& pdbm, cindex_t dim, const constraint_t* constraints, size_t n); - -/** - * Constrain a priced DBM to a facet (\a i, \a j). - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param i is a clock index - * @param j is a clock index - * @post The DBM is empty or closed. - * @return - * true if and only if the result is non empty. - */ -bool pdbm_constrainToFacet(PDBM& pdbm, cindex_t dim, cindex_t i, cindex_t j); - -/** - * Relation between two priced DBMs. - * - * @see relation_t - * @param pdbm1 is a closed priced DBMs of dimension \a dim. - * @param pdbm2 is a closed priced DBMs of dimension \a dim. - * @param dim is the dimension of \a pdbm1 and \a pdbm2. - * @return The relation between pdbm1 and pdbm2 - */ -relation_t pdbm_relation(const PDBM pdbm1, const PDBM pdbm2, cindex_t dim); - -/** - * Relation between 2 priced dbms where one is in compressed. Notice - * that in constract to dbm_relationWithMinDBM, \a buffer may not be - * NULL. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param minDBM is the compressed priced dbm. - * @param buffer is a buffer of size dim*dim. - * @return The relation between pdbm1 and pdbm2 - * @see dbm_relationWithMinDBM - * @see relation_t - */ -relation_t pdbm_relationWithMinDBM(const PDBM pdbm, cindex_t dim, const mingraph_t minDBM, - raw_t* buffer); - -/** - * Computes the infimum cost of the priced DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim - * @param dim is the dimension of \a pdbm. - * @return The infimum cost of \a pdbm. - */ -int32_t pdbm_getInfimum(const PDBM pdbm, cindex_t dim); - -/** - * Generates a valuation which has the infimum cost of the priced DBM. - * - * There is no guarantee that the valuation will be contained in the - * priced DBM, but if it is not it is arbitrarily close to a valuation - * that is contained in the priced DBM. - * - * A \a false entry in \a free indicates that the value of this clock - * has already been set in \a valuation and that this clock must not - * be modified. The function will only modify free clocks. - * - * @param pdbm is a closed priced DBM of dimension \a dim - * @param dim is the dimension of \a pdbm. - * @param valuation is an array of at least \a dim elements to which the - * the valuation will be written. - * @param free is an array of at least \a dim elements. - * - * @return The cost of \a valuation. - * - * @throw out_of_range if no valuation with the given constraints can - * be found. - */ -int32_t pdbm_getInfimumValuation(const PDBM pdbm, cindex_t dim, int32_t* valuation, - const bool* free); - -/** - * Check if a priced DBM satisfies a given constraint. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param i,j are theindices of clocks for the clock constraint. - * @param constraint is the raw_t bound. - * @return true if the DBM satisfies the constraint. - */ -bool pdbm_satisfies(const PDBM pdbm, cindex_t dim, cindex_t i, cindex_t j, raw_t constraint); - -/** - * Returns true if the priced DBM is empty. - * - * @param pdbm is a closed or empty priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @return true if and only if the priced dbm is empty. - */ -bool pdbm_isEmpty(const PDBM pdbm, cindex_t dim); - -/** - * Check if at least one point can delay infinitely. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @return true if unbounded, false otherwise. - */ -bool pdbm_isUnbounded(const PDBM pdbm, cindex_t dim); - -/** - * Compute a hash value for a priced DBM. - * - * ISSUE: canonical form needed. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param seed is a seed for the hash function. - * @return hash value. - */ -uint32_t pdbm_hash(const PDBM pdbm, cindex_t dim, uint32_t seed); - -/** - * Test if a point is included in the priced DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param pt is a clock valuation. - * @return true if \a pt satisfies the constraints of dbm. - */ -bool pdbm_containsInt(const PDBM pdbm, cindex_t dim, const int32_t* pt); - -/** - * Test if a point is included in the priced DBM when strictness of - * constraints are ignored. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param pt is a clock valuation. - * @return true if \a pt satisfies the constraints of dbm - * (ignoring strictness) - */ -bool pdbm_containsIntWeakly(const PDBM pdbm, cindex_t dim, const int32_t* pt); - -/** - * Test if a point is included in the priced DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param pt is a clock valuation. - * @return true if \a pt satisfies the constraints of dbm. - */ -bool pdbm_containsDouble(const PDBM pdbm, cindex_t dim, const double* pt); - -/** - * Delay with the current delay rate. - * - * @param pdbm is a closed priced dbm of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @see pdbm_delayRate() - * @post The priced DBM is closed. - */ -void pdbm_up(PDBM& pdbm, cindex_t dim); - -/** - * Delay with delay rate \a rate. There must be at least one clock - * forming a zero cycle with the reference clock. - * - * @param pdbm is a closed priced dbm of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param rate is the cost of delaying. - * @param zero is the index of a clock forming a zero cycle with the - * reference clock. - * @post The priced DBM is closed. - */ -void pdbm_upZero(PDBM& pdbm, cindex_t dim, int32_t rate, cindex_t zero); - -/** - * Updates \a clock to \a value. This is only legitimate if the - * current rate of \a clock is zero. - * - * @param pdbm is a closed priced dbm of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param clock is the index of the clock to reset. - * @param value is the value to which to set \a clock. - * @pre pdbm_getRate(pdbm, dim, clock) == 0 - * @post The priced DBM is closed. - */ -void pdbm_updateValue(PDBM& pdbm, cindex_t dim, cindex_t clock, uint32_t value); - -/** - * Updates \a clock to \a value. This is only legitimate if the clock - * forms a zero cycle with another clock (possibly the reference - * clock). - * - * @param pdbm is a closed priced dbm of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param clock is the index of the clock to reset. - * @param value is the value to which to set \a clock. - * @param zero is a clock (possibly zero) forming a zero cycle - * with \a clock. - * @post The priced DBM is closed. - * @post pdbm_getRate(pdbm, dim, clock) == 0 - */ -void pdbm_updateValueZero(PDBM& pdbm, cindex_t dim, cindex_t clock, uint32_t value, cindex_t zero); - -/** - * Unfinished extrapolation function. - * - * @see dbm_extrapolateMaxBounds - */ -void pdbm_extrapolateMaxBounds(PDBM& pdbm, cindex_t dim, int32_t* max); - -/** - * Unfinished extrapolation function. - * - * @see dbm_diagonalExtrapolateMaxBounds - */ -void pdbm_diagonalExtrapolateMaxBounds(PDBM& pdbm, cindex_t dim, int32_t* max); - -/** - * Extrapolate a priced zone. The extrapolation is based on a lower - * and an upper bound for each clock. The output zone simulates the - * input zone. - * - * The implementation is not finished. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param lower is an array of lower bounds for each clock. - * @param upper is an array of upper bounds for each clock. - * @pre lower[0] = upper[0] = 0 - * @post The priced DBM is closed. - * @see dbm_diagonalExtrapolateLUBounds - */ -void pdbm_diagonalExtrapolateLUBounds(PDBM& pdbm, cindex_t dim, int32_t* lower, int32_t* upper); - -/** - * Increments the cost of each point in a priced DBM by \a value. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param value is the amount with which to increase the cost. - * @post The priced DBM is closed. - * @pre value >= 0 - */ -void pdbm_incrementCost(PDBM& pdbm, cindex_t dim, int32_t value); - -/** - * Compute the closure of a priced DBM. This function is only relevant - * if the DBM has been modified with \c pdbm_setBound(). - * - * @param pdbm is a priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @post The priced DBM is closed or empty. - * @see pdbm_setBound - */ -void pdbm_close(PDBM& pdbm, cindex_t dim); - -/** - * Analyze a priced DBM for its minimal graph representation. Computes - * the smallest number of constraints needed to represent the same - * zone. - * - * The result is returned as a bit matrix, where each bit indicates - * whether that entry of the DBM is relevant. I.e. if the bit \f$ i - * \cdot dim + j\f$ is set, then the constraint \f$(i,j)\f$ of \a dbm - * is needed. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param bitMatrix is bit matrix of size dim*dim - * @return The number of bits marked one in \a bitMatrix. - */ -size_t pdbm_analyzeForMinDBM(const PDBM pdbm, cindex_t dim, uint32_t* bitMatrix); - -/** - * Convert the DBM to a more compact representation. - * - * The API supports allocation of larger data structures than needed - * for the actual zone representation. When the \a offset argument is - * bigger than zero, \a offset extra integers are allocated and the - * zone is written with the given offset. Thus when \c - * int32_t[data_size] is needed to represent the reduced zone, an \c - * int32_t array of size \c offset+data_size is allocated. The first - * \a offset elements can be used by the caller. It is important to - * notice that the other functions typically expect a pointer to the - * actual zone data and not to the beginning of the allocated - * block. Thus in the following piece of code, most functions expect - * \c mg and not \c memory: - * - * \code - * int32_t *memory = dbm_writeToMinDBMWithOffset(...); - * mingraph_t mg = &memory[offset]; - * \endcode - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param minimizeGraph when true, try to use minimal constraint form. - * @param tryConstraints16 when true, try to save constraints on 16 bits. - * @param c_alloc is a C allocator wrapper. - * @param offset is the offset for allocation. - * @return The converted priced DBM. The first \a offset integers are unused. - * @pre allocFunction allocates memory in integer units - */ -int32_t* pdbm_writeToMinDBMWithOffset(const PDBM pdbm, cindex_t dim, bool minimizeGraph, - bool tryConstraints16, allocator_t c_alloc, uint32_t offset); - -/** - * Uncompresses a compressed priced DBM. The compressed priced DBM \a - * src is written to \a dst. The destination does not need to - * initialised beforehand. The dimension \a dim must match the - * dimension of the compressed priced DBM. - * - * @param dst is a memory area of size pdbm_size(dim). - * @param dim is the dimension of the priced DBM. - * @param src is the compressed priced DBM. - * @post dst is a closed priced DBM. - */ -void pdbm_readFromMinDBM(PDBM& dst, cindex_t dim, mingraph_t src); - -/** - * Finds a clock that is on a zero cycle with \a clock. Returns true - * if and only if such a clock is found. If multiple clocks are on a - * zero cycle with \a clock, then the clock with the smallest index is - * returned. - * - * This function is equivalent to calling \c pdbm_findNextZeroCyle - * with \a output initialised to zero. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param clock is the index of a clock. - * @param out is where the clock found is written. - * @return true if and only if a clock is found. - */ -bool pdbm_findZeroCycle(const PDBM pdbm, cindex_t dim, cindex_t clock, cindex_t* out); - -/** - * Finds a clock that is on a zero cycle with \a clock. Returns true - * if and only if such a clock is found. Only clocks with a value - * equal to or greater than the existing value of \a output are - * considered. If multiple clocks are on a zero cycle with \a clock, - * then the clock with the smallest index is returned. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param clock is the index of a clock. - * @param out is where the clock found is written. - * @return true if and only if a clock is found. - */ -bool pdbm_findNextZeroCycle(const PDBM pdbm, cindex_t dim, cindex_t x, cindex_t* out); - -/** - * Returns the slope of the cost plane along the delay trajectory. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - */ -int32_t pdbm_getSlopeOfDelayTrajectory(const PDBM pdbm, cindex_t dim); - -/** - * Returns the rate (coefficient of the hyperplane) of \a clock. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param clock is the clock for which to return the coefficient. - * @return the rate of \a clock. - */ -int32_t pdbm_getRate(const PDBM pdbm, cindex_t dim, cindex_t clock); - -const int32_t* pdbm_getRates(const PDBM pdbm, cindex_t dim); - -/** - * Returns the cost of the offset point. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - */ -uint32_t pdbm_getCostAtOffset(const PDBM pdbm, cindex_t dim); - -/** - * Sets the cost at the offset point. - * - * Notice that the value must be large enough such that the infimum - * cost of the priced DBM is not negative. Temporary inconsistencies - * are allowed as long as no operations are performed on the priced - * DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param value is the new cost of the offset point. - */ -void pdbm_setCostAtOffset(PDBM& pdbm, cindex_t dim, uint32_t value); - -/** - * Returns true if the DBM is valid. Useful for debugging. - * - * @param pdbm is a priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - */ -bool pdbm_isValid(const PDBM pdbm, cindex_t dim); - -/** - * Computes the lower facets of a priced DBM relative to \a clock. As - * a side-effect, all lower facets relative to \a clock are converted - * to weak facets. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param clock is the clock for which to return the lower facets - * @param facets is an array of at least \a dim elements to which - * the lower facets will be written. - * @return The number of facets written to \a facets. - */ -uint32_t pdbm_getLowerRelativeFacets(PDBM& pdbm, cindex_t dim, cindex_t clock, cindex_t* facets); - -/** - * Computes the upper facets of a priced DBM relative to \a clock. As - * a side-effect, all upper facets relative to \a clock are converted - * to weak facets. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param clock is the clock for which to return the upper facets - * @param facets is an array of at least \a dim elements to which - * the upper facets will be written. - * @return The number of facets written to \a facets. - */ -uint32_t pdbm_getUpperRelativeFacets(PDBM& pdbm, cindex_t dim, cindex_t clock, cindex_t* facets); - -/** - * Computes the lower facets of a priced DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param facets is an array of at least \a dim elements to which the - * lower facets will be written. - * @return The number of facets written to \a facets. - */ -uint32_t pdbm_getLowerFacets(PDBM& pdbm, cindex_t dim, cindex_t* facets); - -/** - * Computes the upper facets of a priced DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param facets is an array of at least \a dim elements to which the - * upper facets will be written. - * @return The number of facets written to \a facets. - */ -uint32_t pdbm_getUpperFacets(PDBM& pdbm, cindex_t dim, cindex_t* facets); - -/** - * Computes the cost of a valuation in a priced DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param valuation is a valuation in \a pdbm. - * @pre pdbm_containsInt(pdbm, dim, valuation) - * @return The cost of \a valuation in \a pdbm. - */ -int32_t pdbm_getCostOfValuation(const PDBM pdbm, cindex_t dim, const int32_t* valuation); - -/** - * Makes all strong constraints of a priced DBM weak. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @post The priced DBM is closed. - */ -void pdbm_relax(PDBM& pdbm, cindex_t dim); - -/** - * Computes the offset point of a priced DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param valuation is an array of at least \a dim elements to which the - * offset point is written. - */ -void pdbm_getOffset(const PDBM pdbm, cindex_t dim, int32_t* valuation); - -/** - * Sets a coefficient of the hyperplane of a priced DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param clock is the index of a clock for which to set the coefficient. - * @param rate is the coefficient. - */ -void pdbm_setRate(PDBM& pdbm, cindex_t dim, cindex_t clock, int32_t rate); - -/** - * Returns the inner matrix of a priced DBM. The matrix can be - * modified as long as \c pdbm_close() is called before any other - * operations are performed on the priced DBM. - * - * @param pdbm is a priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - */ -raw_t* pdbm_getMutableMatrix(PDBM& pdbm, cindex_t dim); - -/** - * Returns the inner matrix of a priced DBM. The matrix is read-only. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - */ -const raw_t* pdbm_getMatrix(const PDBM pdbm, cindex_t dim); - -/** - * Frees a clock of a priced DBM. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param clock is the index of the clock to free. - */ -void pdbm_freeClock(PDBM& pdbm, cindex_t dim, cindex_t clock); - -/** - * Prints a priced DBM to a stream. - * - * @param f is the stream to print to. - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @see dbm_print - */ -void pdbm_print(FILE* f, const PDBM pdbm, cindex_t dim); - -/** - * Prints a priced DBM to a stream. - * - * @param o is the stream to print to. - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @see dbm_print - */ -void pdbm_print(std::ostream& o, const PDBM pdbm, cindex_t dim); - -/** - * Implementation of the free up operation for priced DBMs. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param index is an index of a clock. - * @see dbm_freeUp - */ -void pdbm_freeUp(PDBM& pdbm, cindex_t dim, cindex_t index); - -/** - * Implementation of the free down operation for priced DBMs. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - * @param index is an index of a clock. * - * @see dbm_freeDown - */ -void pdbm_freeDown(PDBM& pdbm, cindex_t dim, cindex_t index); - -/** - * Checks whether a priced DBM is in normal form. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - */ -bool pdbm_hasNormalForm(PDBM pdbm, cindex_t dim); - -/** - * Brings a priced DBM into normal form. - * - * @param pdbm is a closed priced DBM of dimension \a dim. - * @param dim is the dimension of \a pdbm. - */ -void pdbm_normalise(PDBM pdbm, cindex_t dim); - -/////////////////////////////////////////////////////////////////////////// - -#endif /* INCLUDE_DBM_PRICED_H */ diff --git a/dbm/include/dbm/print.h b/dbm/include/dbm/print.h deleted file mode 100644 index d845e6eb..00000000 --- a/dbm/include/dbm/print.h +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : print.h (dbm) - * C/C++ header. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * $Id: print.h,v 1.4 2005/05/24 19:13:24 adavid Exp $ - * - **********************************************************************/ - -#ifndef INCLUDE_DBM_PRINT_H -#define INCLUDE_DBM_PRINT_H - -#include "dbm/constraints.h" -#include - -#ifdef __cplusplus - -#include - -/** Pretty print of a DBM. - * @param dbm: DBM. - * @param dim: dimension. - * @param out: output stream. - */ -std::ostream& dbm_cppPrint(std::ostream& out, const raw_t* dbm, cindex_t dim); - -/** Pretty print of the difference between 2 DBMs: - * prints 2 DBMS with the difference in color. - * If color printing is desactivated then the - * differences are marked with *. - * @param dbm1,dbm2: DBMs. - * @param dim: dimension. - * @param out: output stream. - * @pre same dimension for both DBMs. - */ -std::ostream& dbm_cppPrintDiff(std::ostream& out, const raw_t* dbm1, const raw_t* dbm2, - cindex_t dim); - -/** Pretty print of the difference between a DBM - * and its closure: shows the updates that will be - * done by the closure. - * @param out: output stream. - * @param dbm: the DBM. - * @param dim: dimension. - */ -std::ostream& dbm_cppPrintCloseDiff(std::ostream& out, const raw_t* dbm, cindex_t dim); - -/** Pretty print of one clock constraint. - * @param out: output stream. - * @param c: the encoded constraint. - */ -std::ostream& dbm_cppPrintRaw(std::ostream& out, raw_t c); - -/** Pretty print of one clock bound. - * @param out: output stream. - * @param b: the decoded bound. - */ -std::ostream& dbm_cppPrintBound(std::ostream& out, int32_t b); - -/** Print a vector of constraints. - * @param data: the vector of constraints - * @param size: size of the vector. - * @param out: where to print. - * @pre data is a int32_t[size] - */ -std::ostream& dbm_cppPrintRaws(std::ostream& out, const raw_t* data, size_t size); - -/** Print a vector of bounds. - * @param data: the vector of bounds. - * @param size: size of the vector. - * @param out: where to print. - * @pre data is a int32_t[size] - */ -std::ostream& dbm_cppPrintBounds(std::ostream& out, const int32_t* data, size_t size); - -/** Print constraints. - * @param c: constraints to print. - * @param n: number of constraints - */ -std::ostream& dbm_cppPrintConstraints(std::ostream& out, const constraint_t* c, size_t n); - -#ifndef INCLUDE_DBM_FED_H -namespace dbm -{ - class dbm_t; - class fed_t; -} // namespace dbm -#endif - -/** Operator overload. - * @param c: constraint to print. - */ -std::ostream& operator<<(std::ostream& os, const constraint_t& c); - -namespace dbm // Needed for unidentifed reason. -{ - /** Operator overload. - * @param dbm: DBM to print. - */ - std::ostream& operator<<(std::ostream& os, const dbm::dbm_t& dbm); - - /** Operator overload. - * @param fed: federation to print. - */ - std::ostream& operator<<(std::ostream& os, const dbm::fed_t& fed); -} // namespace dbm - -extern "C" { - -#endif - -/** Print prefix for every line of DBM. - * Do not deallocate the string in argument - * since only a reference is kept. If you - * want to deallocate, then reset the library - * with NULL. - */ -void dbm_setPrintPrefix(const char* prefix); - -/** Change printing format to match the - * input format of the Ruby binding. - * By default it is off. - */ -void dbm_setRubyFormat(bool mode); - -/** Pretty print of a DBM. - * @param dbm: DBM. - * @param dim: dimension. - * @param out: output stream. - */ -void dbm_print(FILE* out, const raw_t* dbm, cindex_t dim); - -/** Pretty print of the difference between 2 DBMs: - * prints 2 DBMS with the difference in color. - * If color printing is desactivated then the - * differences are marked with *. - * @param dbm1,dbm2: DBMs. - * @param dim: dimension. - * @param out: output stream. - * @pre same dimension for both DBMs. - */ -void dbm_printDiff(FILE* out, const raw_t* dbm1, const raw_t* dbm2, cindex_t dim); - -/** Pretty print of the difference between a DBM - * and its closure: shows the updates that will be - * done by the closure. - * @param out: output stream. - * @param dbm: the DBM. - * @param dim: dimension. - */ -void dbm_printCloseDiff(FILE* out, const raw_t* dbm, cindex_t dim); - -/** Pretty print of one clock constraint. - * @param out: output stream. - * @param c: the encoded constraint. - */ -void dbm_printRaw(FILE* out, raw_t c); - -/** Pretty print of one clock bound. - * @param out: output stream. - * @param b: the decoded bound. - */ -void dbm_printBound(FILE* out, int32_t b); - -/** Print a vector of constraints. - * @param data: the vector of constraints - * @param size: size of the vector. - * @param out: where to print. - * @pre data is a int32_t[size] - */ -void dbm_printRaws(FILE* out, const raw_t* data, size_t size); - -/** Print a vector of bounds. - * @param data: the vector of bounds. - * @param size: size of the vector. - * @param out: where to print. - * @pre data is a int32_t[size] - */ -void dbm_printBounds(FILE* out, const int32_t* data, size_t size); - -/** Print constraints. - * @param n: number of constraints to print. - * @param c: constraint. - * @param out: where to print. - */ -void dbm_printConstraints(FILE* out, const constraint_t* c, size_t n); - -#ifdef __cplusplus -} -#endif - -#endif /* INCLUDE_DBM_PRINT_H */ diff --git a/dbm/include/debug/macros.h b/dbm/include/debug/macros.h deleted file mode 100644 index 8d1d9a34..00000000 --- a/dbm/include/debug/macros.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : macros.h (debug) - * C header. - * - * Debugging macros: - * - debugging statement with DODEBUG(something) - * - pretty colors - * - print position (in a function/method) - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * v 1.2 reviewed. - * $Id: macros.h,v 1.13 2005/06/22 13:30:32 adavid Exp $ - * - **********************************************************************/ - -#ifndef INCLUDE_DEBUG_MACROS_H -#define INCLUDE_DEBUG_MACROS_H - -#include "debug/utils.h" - -/********************************************************************** - * Macros for debugging - * NPRETTY_COLORS -> deactivate colorized printouts - * NSHORTFILENAME -> deactivate short filename printouts - * NDEBUG: controls debugging, standard - **********************************************************************/ - -/* Incompatibility: deactive pretty features */ -#ifdef _WIN32 -#define __PRETTY_FUNCTION__ __FUNCTION__ -#ifndef NPRETTY_COLORS -#define NPRETTY_COLORS -#endif -#endif - -/* C++ example: std::cout << RED(BOLD) "Warning!" NORMAL << std::endl - * C example: printf(RED(BOLD)"Warning!"NORMAL"\n") - */ -#ifndef NPRETTY_COLORS -#define THIN "0" -#define BOLD "1" -#define RED(S) "\033[" S ";31m" -#define GREEN(S) "\033[" S ";32m" -#define YELLOW(S) "\033[" S ";33m" -#define BLUE(S) "\033[" S ";34m" -#define MAGENTA(S) "\033[" S ";35m" -#define CYAN(S) "\033[" S ";36m" -#define WHITE(S) "\033[" S ";37m" -#define NORMAL "\033[0;0m" -#else -#define THIN "" -#define BOLD "" -#define RED(S) "" -#define GREEN(S) "" -#define YELLOW(S) "" -#define BLUE(S) "" -#define MAGENTA(S) "" -#define CYAN(S) "" -#define WHITE(S) "" -#define NORMAL "" -#endif - -/* C/C++ default output streams. - * No need to be in conditional def. - */ -#ifdef __cplusplus -#define DEFAULT_OUT std::cout -#define DEFAULT_ERR std::cerr -#else -#define DEFAULT_OUT stdout -#define DEFAULT_ERR stderr -#endif - -#ifndef NDEBUG - -#include // abort(void) - -/* C/C++ print style - */ -#ifdef __cplusplus -#define PRINT(OUT, S) (OUT) << (S) -#define PRINT_INT(OUT, N) (OUT) << (N) -#else -#define PRINT(OUT, S) fprintf(OUT, "%s", (S)) -#define PRINT_INT(OUT, N) fprintf(OUT, "%d", (N)) -#endif - -/* Long or short printouts? - */ -#ifndef NSHORTFILENAME -#define PRINT_FILE(OUT) PRINT(OUT, debug_shortSource(__FILE__)) -#else -#define PRINT_FILE(OUT) PRINT(OUT, __FILE__) -#endif - -/* Statement to execute only for debugging - * WARNING: there should not be side effect - * on the normal code. - */ -#define DODEBUG(STATEMENT) STATEMENT - -/* Print some info from a function. - */ -#define PRINT_INFO(INFO) \ - do { \ - PRINT(DEFAULT_OUT, __PRETTY_FUNCTION__); \ - PRINT(DEFAULT_OUT, ": " INFO "\n"); \ - } while (0) - -/* Pretty print info in debugging mode: - * with and without color. - * Do not concatenate __PRETTY_FUNCTION__ - * because it is deprecated. - */ -#ifndef NPRETTY_COLORS -#define PRINT_CINFO(COLOR, INFO) \ - do { \ - PRINT(DEFAULT_OUT, COLOR); \ - PRINT(DEFAULT_OUT, __PRETTY_FUNCTION__); \ - PRINT(DEFAULT_OUT, ": " INFO NORMAL "\n"); \ - } while (0) -#else -#define PRINT_CINFO(COLOR, INFO) PRINT_INFO(INFO) -#endif - -/* This is essentially to avoid warning - * on printf("") - */ -#ifndef NPRETTY_COLORS -#define PRINT_COLOR(OUT, COLOR) PRINT(OUT, COLOR) -#else -#define PRINT_COLOR(OUT, COLOR) -#endif - -/* Like an ordinary assert but allow - * to print debug information if the - * assertion is violated. - */ -#define ASSERT(COND, PRINTME) \ - do { \ - if (!(COND)) { \ - PRINT_COLOR(DEFAULT_ERR, RED(BOLD)); \ - PRINT_FILE(DEFAULT_ERR); \ - PRINT(DEFAULT_ERR, "("); \ - PRINT_INT(DEFAULT_ERR, __LINE__); \ - PRINT(DEFAULT_ERR, ") "); \ - PRINT(DEFAULT_ERR, __PRETTY_FUNCTION__); \ - PRINT(DEFAULT_ERR, \ - ": Assertion `" MAGENTA(BOLD) #COND RED(BOLD) "' failed." NORMAL "\n"); \ - PRINTME; \ - abort(); \ - } \ - } while (0) /* standard trick to make it a statement */ - -/* Like assert but controlled by another flag - * to tune testing with or without expensive asserts. - */ -#ifndef DISABLE_ASSERTX -#define assertx(STATEMENT) assert(STATEMENT) -#define DODEBUGX(STATEMENT) STATEMENT -#else -#define assertx(STATEMENT) -#define DODEBUGX(STATEMENT) -#endif - -#else /* NDEBUG */ - -#define PRINT(OUT, S) -#define PRINT_INT(OUT, N) -#define PRINT_FILE(OUT) -#define DODEBUG(STATEMENT) -#define PRINT_INFO(INFO) -#define PRINT_CINFO(COLOR, INFO) -#define ASSERT(COND, PRINTME) -#define PRINT_COLOR(OUT, COLOR) -#define assertx(STATEMENT) -#define DODEBUGX(STATEMENT) - -#endif /* NDEBUG */ - -/* On Sun/Solaris, rand() is bugged, - * thank you Sun! rand() returns a - * random number only on 16 bits, - * which is quite laughable. - * It is fine to use rand() if you - * are satisfied with a 16 bits number - * though. This #define may be wrong - * on Intel running Solaris, but it - * isn't sane to do so anyway. - */ -#if INTEL_ARCH - -#define RAND() rand() - -/* include inttypes.h for this */ -#define RAND64() ((((uint64_t)rand()) << 32) | (((uint64_t)rand()))) - -#else - -#define RAND() ((rand() ^ (rand() << 16)) & 0x7fffffff) - -/* include inttypes.h for this */ -#define RAND64() \ - ((((uint64_t)rand()) << 48) | (((uint64_t)rand()) << 32) | (((uint64_t)rand()) << 16) | \ - (((uint64_t)rand()))) - -#endif /* INTEL_ARCH */ - -#if UINTPTR_MAX == 0xFFFFFFFF -#define RAND_SIZE() RAND() -#elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFu -#define RAND_SIZE() RAND64() -#else -#error unknown pointer size -#endif - -#endif /* INCLUDE_DEBUG_MACROS_H */ diff --git a/dbm/include/debug/malloc.h b/dbm/include/debug/malloc.h deleted file mode 100644 index 41254205..00000000 --- a/dbm/include/debug/malloc.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : malloc.h (debug) - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * $Id: malloc.h,v 1.3 2005/07/22 12:55:54 adavid Exp $ - * - *********************************************************************/ - -#ifndef INCLUDE_DEBUG_MALLOC_H -#define INCLUDE_DEBUG_MALLOC_H - -#include "debug/monitor.h" - -#ifdef ENABLE_MONITOR - -#ifdef __cplusplus -extern "C" { -#endif - -/** @file - * Replace malloc and free by calls to monitored malloc and free - * to check for leaks. The check is automatic because we use g++ - * linker with some internal C++ objects that are automatically - * initialized and destroyed. - * To monitor malloc and free, just add #include "debug/malloc.h" - * to the files where malloc and free are used. - */ - -#define malloc(SIZE) debug_monitoredMalloc(SIZE, __FILE__, __LINE__, __FUNCTION__) -#define free(PTR) debug_monitoredFree(PTR, __FILE__, __LINE__, __FUNCTION__) - -/** Monitored malloc. - * @return allocated memory, as malloc would do - * @param size: size to allocate, like malloc - * @param filename: filename where malloc is called - * @param line: line where malloc is called - * @param function: function in which malloc is called - */ -void* debug_monitoredMalloc(size_t size, const char* filename, int line, const char* function); - -/** Monitored free. - * @param ptr: memory to free - * @param filename: filename where free is called - * @param line: line where free is called - * @param function: function in which free is called - */ -void debug_monitoredFree(void* ptr, const char* filename, int line, const char* function); - -#ifdef __cplusplus -} -#endif - -#endif /* ENABLE_MONITOR */ - -#endif /* INCLUDE_DEBUG_MALLOC_H */ diff --git a/dbm/include/debug/monitor.h b/dbm/include/debug/monitor.h deleted file mode 100644 index 3357db83..00000000 --- a/dbm/include/debug/monitor.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : monitor.h (debug) - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * $Id: monitor.h,v 1.2 2005/07/22 12:55:54 adavid Exp $ - * - *********************************************************************/ - -#ifndef INCLUDE_DEBUG_MONITOR_H -#define INCLUDE_DEBUG_MONITOR_H - -#include - -#ifdef ENABLE_MONITOR - -#ifdef __cplusplus -extern "C" { -#endif - -/** Remember a pointer and returns it. - * @param ptr: pointer to remember - * @param filename: in which file the call was made - * @param line: at which line the call was made - * @param function: in which function the call was made - * @return ptr - */ -void* debug_rememberPointer(void* ptr, const char* filename, int line, const char* function); - -/** Forget a previously remembered pointer. - * @param ptr: pointer to forget - * @param filename: in which file the call was made - * @param line: at which line he call was made - * @param function: in which function the call was made - * @pre ptr was remembered before or an error will be printed - */ -void debug_forgetPointer(void* ptr, const char* filename, int line, const char* function); - -/** Forget a previously remembered pointer - * @param ptr: pointer to forget - * @pre ptr was remembered before or an error will be printed - */ -void debug_forgetPtr(void* ptr); - -/** Remember a position just before a call to forgetPtr. - * The position will be gone after one call to forgetPtr. - * @param filename: in which file the call was made - * @param line: at which line he call was made - * @param function: in which function the call was made - */ -void debug_prepareDelete(const char* filename, int line, const char* function); - -/** Push a position for later retrieval by pop. - * @param filename: in which file the call was made - * @param line: at which line he call was made - * @param function: in which function the call was made - */ -void debug_pushPosition(const char* filename, int line, const char* function); - -/** Equivalent to calling prepareDelete on a previously pushed position. - */ -void debug_pop(); - -/* Macros to simplify calls */ - -#define debug_remember(TYPE, PTR) \ - ((TYPE)debug_rememberPointer(PTR, __FILE__, __LINE__, __FUNCTION__)) -#define debug_forget(PTR) debug_forgetPointer(PTR, __FILE__, __LINE__, __FUNCTION__) -#define debug_mark() debug_prepareDelete(__FILE__, __LINE__, __FUNCTION__) -#define debug_push() debug_pushPosition(__FILE__, __LINE__, __FUNCTION__) - -#ifdef __cplusplus -} -#endif - -#endif /* ENABLE_MONITOR */ - -#endif /* INCLUDE_DEBUG_MONITOR_H */ diff --git a/dbm/include/debug/new.h b/dbm/include/debug/new.h deleted file mode 100644 index 26dc08b7..00000000 --- a/dbm/include/debug/new.h +++ /dev/null @@ -1,67 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : new.h -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: new.h,v 1.5 2005/07/22 12:55:54 adavid Exp $ -// -/////////////////////////////////////////////////////////////////// - -/** - * @file - * Monitor all new/delete operator calls. ALL or NONE of them must be - * monitored. - * Limitations for more information in new: - * 1) no placement constructor - * 2) the new with no exception will fail too. - * - * Limitation for the verbose delete: - * - delete MUST be enclosed within brackets, statements like - * if (test) delete me; WILL FAIL - * => if (test) { delete me; } is correct - * Check this with a grep command. - * - * Define: - * - ENABLE_MONITOR to enable the monitor - * - NNEW_INFO to skip incompatible new replacements -- local to .h or .cpp - * - NDELETE_INFO to skip incompatible delete replacements -- local to .h or .cpp - * - * NOTE: defining NDEBUG will *not* skip this, which allows for - * optimized compilation with new monitor. - */ - -#ifndef INCLUDE_DEBUG_NEW_H -#define INCLUDE_DEBUG_NEW_H - -#include "debug/monitor.h" - -#if !defined(_WIN32) && defined(ENABLE_MONITOR) - -#include - -#ifndef NNEW_INFO - -void* operator new(size_t size, const char*, int, const char*); -void* operator new[](size_t size, const char*, int, const char*); - -#define new new (__FILE__, __LINE__, __FUNCTION__) - -// Don't need to overload these: they fail anyway! -// void *operator new(size_t size, const std::nothrow_t&) noexcept; -// void *operator new[](size_t size, const std::nothrow_t&) noexcept; - -#endif // NNEW_INFO - -#ifndef NDELETE_INFO -#define delete \ - debug_prepareDelete(__FILE__, __LINE__, __FUNCTION__); \ - delete -#endif - -#endif // ndef(_WIN32) && def(ENABLE_MONITOR) - -#endif // INCLUDE_DEBUG_NEW_H diff --git a/dbm/include/debug/utils.h b/dbm/include/debug/utils.h deleted file mode 100644 index be1d0a2b..00000000 --- a/dbm/include/debug/utils.h +++ /dev/null @@ -1,291 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : utils.h (debug) - * C header. - * - * Utility functions for debugging. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * v 1.3 reviewed. - * $Id: utils.h,v 1.17 2005/05/11 19:08:14 adavid Exp $ - * - **********************************************************************/ - -#ifndef INCLUDE_DEBUG_UTILS_H -#define INCLUDE_DEBUG_UTILS_H - -#include "base/inttypes.h" -#include // FILE - -#ifdef __cplusplus -#include - -/** Tabulation: print n spaces. - * @param n: size of the tabulation. - * @param out: output stream where to print (cerr, cout) - */ -static inline std::ostream& debug_cpptab(std::ostream& os, size_t n) -{ - while (n) { - os << ' '; - --n; - } - return os; -} - -/** Print bitstring, lower bits first. - * @param s: start of the string. - * @param n: size in int of the string to - * @param out: output stream where to print (cerr,cout) - * print. int[n] will be printed as bits. - */ -std::ostream& debug_cppPrintBitstring(std::ostream& out, const uint32_t* s, size_t n); - -/** Print a matrix of bit. - * @param out: output stream. - * @param s,dim: bit matrix dimxdim. - * @pre s is a uint32_t[bits2intsize(dim*dim)] - */ -std::ostream& debug_cppPrintBitMatrix(std::ostream& out, const uint32_t* s, cindex_t dim); - -/** Print diff between bitstrings, lower bits first. - * @param s1,s2: start of the strings. - * @param n: size in int of the string to - * @param out: output stream where to print (cerr,cout) - * print. int[n] will be printed as bits. - */ -std::ostream& debug_cppPrintDiffBitstrings(std::ostream& out, const uint32_t* s1, - const uint32_t* s2, size_t n); - -/** Print bits, lower bits first. - * @param i: the int to print. - * @param out: output stream where to print (cerr,cout) - */ -std::ostream& debug_cppPrintBits(std::ostream& out, uint32_t i); - -/** Print diff bits of i with j, lower bits first. - * @param i,j: the ints to print. - * @param out: output stream where to print (cerr,cout) - */ -std::ostream& debug_cppPrintDiffBits(std::ostream& out, uint32_t i, uint32_t j); - -/** Print a vector of ints. - * @param data: the vector of ints. - * @param size: size of the vector. - * @param out: where to print. - * @pre data is a int32_t[size] - */ -std::ostream& debug_cppPrintVector(std::ostream& out, const int32_t* data, size_t size); - -/** Print a vector of ints. - * @param data: the vector of ints. - * @param size: size of the vector. - * @param out: where to print. - * @pre data is a int32_t[size] - */ -std::ostream& debug_cppPrintRealVector(std::ostream& out, const double* data, size_t size); - -/** Print 2 vectors and highlight - * the difference between them. - * @param vec1,vec2: the vectors to print. - * @param size: size of the vectors. - * @param out: where t print. - * @pre vec1 and vec2 are int32_t[size] - */ -std::ostream& debug_cppPrintDiffVectors(std::ostream& out, const int32_t* vec1, const int32_t* vec2, - size_t size); - -/** Print memory quantity in human - * readable format with B,MB,GB units. - * @param mem: memory to print - * @param out: where to print. - */ -std::ostream& debug_cppPrintMemory(std::ostream& out, size_t mem); - -/** Print the set of active "things" according - * to a bit vector that marks which ones are active. - * @param out: where to print. - * @param bits: bit array. - * @param intSize: size in ints of the array. - */ -std::ostream& debug_cppPrintActiveSet(std::ostream& out, const uint32_t* bits, size_t intSize); - -extern "C" { - -#endif /* __cplusplus */ - -/** Randomize memory. - * Write random numbers (rand()) in memory. - * NOTE: one should call seed(something) to initialize - * the random generator beforehand. - * @param data: where to write. - * @param intSize: size to write in int. Will - * write int[intSize]. - * @post ((int*)data)[intSize] is randomized. - */ -void debug_randomize(void* data, size_t intSize); - -/** Tabulation: print n spaces. - * @param n: size of the tabulation. - * @param out: output stream where to print (stderr,stdout) - */ -static inline void debug_tab(FILE* out, size_t n) -{ - while (n) { - fputc(' ', out); - --n; - } -} - -/** Print bitstring, lower bits first. - * @param s: start of the string. - * @param n: size in int of the string to - * @param out: output stream where to print (stderr,stdout) - * print. int[n] will be printed as bits. - */ -void debug_printBitstring(FILE* out, const uint32_t* s, size_t n); - -/** Print a bit matrix. - * @param s,dim: bit matrix dimxdim. - * @param out: output stream. - * @pre s is a uint32_t[bits2intsize(dim*dim)] - */ -void debug_printBitMatrix(FILE* out, const uint32_t* s, cindex_t dim); - -/** Print diff between bitstrings, lower bits first. - * @param s1,s2: start of the strings. - * @param n: size in int of the string to - * @param out: output stream where to print (stderr,stdout) - * print. int[n] will be printed as bits. - */ -void debug_printDiffBitstrings(FILE* out, const uint32_t* s1, const uint32_t* s2, size_t n); - -/** Print bits, lower bits first. - * @param i: the int to print. - * @param out: output stream where to print (stderr,stdout) - */ -void debug_printBits(FILE* out, uint32_t i); - -/** Print diff bits of i with j, lower bits first. - * @param i,j: the ints to print. - * @param out: output stream where to print (stderr,stdout) - */ -void debug_printDiffBits(FILE* out, uint32_t i, uint32_t j); - -/** Print a vector of ints. - * @param data: the vector of ints. - * @param size: size of the vector. - * @param out: where to print. - * @pre data is a int32_t[size] - */ -void debug_printVector(FILE* out, const int32_t* data, size_t size); - -/** Print a vector of ints. - * @param data: the vector of ints. - * @param size: size of the vector. - * @param out: where to print. - * @pre data is a int32_t[size] - */ -void debug_printRealVector(FILE* out, const double* data, size_t size); - -/** Print 2 vectors and highlight - * the difference between them. - * @param vec1,vec2: the vectors to print. - * @param size: size of the vectors. - * @param out: where t print. - * @pre vec1 and vec2 are int32_t[size] - */ -void debug_printDiffVectors(FILE* out, const int32_t* vec1, const int32_t* vec2, size_t size); - -/** Print the set of active "things" according - * to a bit vector that marks which ones are active. - * @param out: where to print. - * @param bits: bit array. - * @param intSize: size in ints of the array. - */ -void debug_printActiveSet(FILE* out, const uint32_t* bits, size_t intSize); - -/** Return sub-string of filename. - * No allocation, it is just a pointer offset. - * @param filename: filename to truncate. - * @param test: test directory name (typically "tests/") - * NOTE: the test is done as a strncmp(xx, test, strlen(test)) - * so if '/' is ommitted, then we test for the beginning of - * the name only. - * @pre filename != NULL && test != NULL - * @return pointer in filename to truncate from - * absolute path to module path. - * e.g.: - * "somewhere/hop/foo.c" -> "hop/foo.c" - * "somewhere/tests/foo.c" -> "somewhere/tests/foo.c" - * "long/path/here/foo.cpp" -> "here/foo.cpp" - */ -const char* debug_shortName(const char* filename, const char* test); - -static inline const char* debug_shortSource(const char* filename) -{ - return debug_shortName(filename, "tests/"); -} - -/** Generate random bits. To the diffence of - * randomize, this function allows specifying - * the number of bits we want to be set. - * @param bits: bit string to write. - * @param bitSize: size in int of the bit string. - * @param nbits: nb of bits to set. - * @param bit1: to force the 1st bit to be set, - * if == 0, does not force anything, if == 1 - * force 1st bit to 1. - * @pre: - * - nbits <= 32*bitSize otherwise it is not - * possible to meet the specification - * - bits is a uint32_t[bitSize] - */ -void debug_generateBits(uint32_t* bits, size_t bitSize, size_t nbits, bool bit1); - -/** Fix generated bits (typically by debug_generateBits) - * so that the index of the highest bit < bitStringSize - * @param bits,bitSize: bitstring of size bitSize (ints) - * @param bitStringSize: size in bits of the bitstring - * @pre bitStringSize <= number of bits to keep == 1, otherwise - * bits will be lost. - */ -void debug_fixGeneratedBits(uint32_t* bits, size_t bitSize, size_t bitStringSize); - -/** Test if a the unpacking of a bit table - * gives the given index table as a result. - * @param table: index redirection table - * @param nbSet: number of used indices - * (check that = number of bits in 'bits') - * @param bits: bit array - * @param n: size in int of the bit array - * @return true if table matches bits. - * @pre - * - table is large enough: at least - * uint32_t[number of bits read == n*32] - * - bits is at least a uint32_t[n] - */ -bool debug_bits2indexTableOK(const uint32_t* bits, size_t n, const uint32_t* table, size_t nbSet); - -/** Print memory quantity in human - * readable format with B,MB,GB units. - * @param mem: memory to print - * @param out: where to print. - */ -void debug_printMemory(FILE* out, size_t mem); - -/** Print a spinning bar on a given output. - * Successive calls will make the bar spin. - * @param out: stream for output. - */ -void debug_spin(FILE* out); - -#ifdef __cplusplus -} -#endif - -#endif /* INCLUDE_DEBUG_UTILS_H */ diff --git a/dbm/include/doctest.h b/dbm/include/doctest.h deleted file mode 100644 index 42eb0399..00000000 --- a/dbm/include/doctest.h +++ /dev/null @@ -1,6580 +0,0 @@ -// ====================================================================== lgtm [cpp/missing-header-guard] -// == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == -// ====================================================================== -// -// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD -// -// Copyright (c) 2016-2021 Viktor Kirilov -// -// Distributed under the MIT Software License -// See accompanying file LICENSE.txt or copy at -// https://opensource.org/licenses/MIT -// -// The documentation can be found at the library's page: -// https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md -// -// ================================================================================================= -// ================================================================================================= -// ================================================================================================= -// -// The library is heavily influenced by Catch - https://github.com/catchorg/Catch2 -// which uses the Boost Software License - Version 1.0 -// see here - https://github.com/catchorg/Catch2/blob/master/LICENSE.txt -// -// The concept of subcases (sections in Catch) and expression decomposition are from there. -// Some parts of the code are taken directly: -// - stringification - the detection of "ostream& operator<<(ostream&, const T&)" and StringMaker<> -// - the Approx() helper class for floating point comparison -// - colors in the console -// - breaking into a debugger -// - signal / SEH handling -// - timer -// - XmlWriter class - thanks to Phil Nash for allowing the direct reuse (AKA copy/paste) -// -// The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest -// which uses the Boost Software License - Version 1.0 -// see here - https://github.com/martinmoene/lest/blob/master/LICENSE.txt -// -// ================================================================================================= -// ================================================================================================= -// ================================================================================================= - -#ifndef DOCTEST_LIBRARY_INCLUDED -#define DOCTEST_LIBRARY_INCLUDED - -// ================================================================================================= -// == VERSION ====================================================================================== -// ================================================================================================= - -#define DOCTEST_VERSION_MAJOR 2 -#define DOCTEST_VERSION_MINOR 4 -#define DOCTEST_VERSION_PATCH 6 -#define DOCTEST_VERSION_STR "2.4.6" - -#define DOCTEST_VERSION \ - (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) - -// ================================================================================================= -// == COMPILER VERSION ============================================================================= -// ================================================================================================= - -// ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect - -#define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH)) - -// GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl... -#if defined(_MSC_VER) && defined(_MSC_FULL_VER) -#if _MSC_VER == _MSC_FULL_VER / 10000 -#define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) -#else // MSVC -#define DOCTEST_MSVC \ - DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) -#endif // MSVC -#endif // MSVC -#if defined(__clang__) && defined(__clang_minor__) -#define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) -#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && \ - !defined(__INTEL_COMPILER) -#define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#endif // GCC - -#ifndef DOCTEST_MSVC -#define DOCTEST_MSVC 0 -#endif // DOCTEST_MSVC -#ifndef DOCTEST_CLANG -#define DOCTEST_CLANG 0 -#endif // DOCTEST_CLANG -#ifndef DOCTEST_GCC -#define DOCTEST_GCC 0 -#endif // DOCTEST_GCC - -// ================================================================================================= -// == COMPILER WARNINGS HELPERS ==================================================================== -// ================================================================================================= - -#if DOCTEST_CLANG -#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) -#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push") -#define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w) -#define DOCTEST_CLANG_SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop") -#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) \ - DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING(w) -#else // DOCTEST_CLANG -#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -#define DOCTEST_CLANG_SUPPRESS_WARNING(w) -#define DOCTEST_CLANG_SUPPRESS_WARNING_POP -#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) -#endif // DOCTEST_CLANG - -#if DOCTEST_GCC -#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) -#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push") -#define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w) -#define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") -#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) \ - DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING(w) -#else // DOCTEST_GCC -#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH -#define DOCTEST_GCC_SUPPRESS_WARNING(w) -#define DOCTEST_GCC_SUPPRESS_WARNING_POP -#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) -#endif // DOCTEST_GCC - -#if DOCTEST_MSVC -#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push)) -#define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w)) -#define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop)) -#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) \ - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w) -#else // DOCTEST_MSVC -#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -#define DOCTEST_MSVC_SUPPRESS_WARNING(w) -#define DOCTEST_MSVC_SUPPRESS_WARNING_POP -#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) -#endif // DOCTEST_MSVC - -// ================================================================================================= -// == COMPILER WARNINGS ============================================================================ -// ================================================================================================= - -DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") - -DOCTEST_GCC_SUPPRESS_WARNING_PUSH -DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") -DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") -DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") -DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") -DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") -DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo") - -DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration -DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression -DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated -DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant -DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding -DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe -// static analysis -DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept' -DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable -DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ... -DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtr... -DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum' - -// 4548 - expression before comma has no effect; expected expression with side - effect -// 4265 - class has virtual functions, but destructor is not virtual -// 4986 - exception specification does not match previous declaration -// 4350 - behavior change: 'member1' called instead of 'member2' -// 4668 - 'x' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' -// 4365 - conversion from 'int' to 'unsigned long', signed/unsigned mismatch -// 4774 - format string expected in argument 'x' is not a string literal -// 4820 - padding in structs - -// only 4 should be disabled globally: -// - 4514 # unreferenced inline function has been removed -// - 4571 # SEH related -// - 4710 # function not inlined -// - 4711 # function 'x' selected for automatic inline expansion - -#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN \ - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ - DOCTEST_MSVC_SUPPRESS_WARNING(4548) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4265) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4986) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4350) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4668) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4365) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4774) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4820) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4625) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4626) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5027) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5026) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4623) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5039) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5045) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5105) - -#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP - -// ================================================================================================= -// == FEATURE DETECTION ============================================================================ -// ================================================================================================= - -// general compiler feature support table: https://en.cppreference.com/w/cpp/compiler_support -// MSVC C++11 feature support table: https://msdn.microsoft.com/en-us/library/hh567368.aspx -// GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html -// MSVC version table: -// https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering -// MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019) -// MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017) -// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) -// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) -// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) -// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) -// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) -// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) - -#if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH) -#define DOCTEST_CONFIG_WINDOWS_SEH -#endif // MSVC -#if defined(DOCTEST_CONFIG_NO_WINDOWS_SEH) && defined(DOCTEST_CONFIG_WINDOWS_SEH) -#undef DOCTEST_CONFIG_WINDOWS_SEH -#endif // DOCTEST_CONFIG_NO_WINDOWS_SEH - -#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && \ - !defined(__EMSCRIPTEN__) -#define DOCTEST_CONFIG_POSIX_SIGNALS -#endif // _WIN32 -#if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS) -#undef DOCTEST_CONFIG_POSIX_SIGNALS -#endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS - -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) -#define DOCTEST_CONFIG_NO_EXCEPTIONS -#endif // no exceptions -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - -#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -#define DOCTEST_CONFIG_NO_EXCEPTIONS -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - -#if defined(DOCTEST_CONFIG_NO_EXCEPTIONS) && !defined(DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS) -#define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS - -#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT) -#define DOCTEST_CONFIG_IMPLEMENT -#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN - -#if defined(_WIN32) || defined(__CYGWIN__) -#if DOCTEST_MSVC -#define DOCTEST_SYMBOL_EXPORT __declspec(dllexport) -#define DOCTEST_SYMBOL_IMPORT __declspec(dllimport) -#else // MSVC -#define DOCTEST_SYMBOL_EXPORT __attribute__((dllexport)) -#define DOCTEST_SYMBOL_IMPORT __attribute__((dllimport)) -#endif // MSVC -#else // _WIN32 -#define DOCTEST_SYMBOL_EXPORT __attribute__((visibility("default"))) -#define DOCTEST_SYMBOL_IMPORT -#endif // _WIN32 - -#ifdef DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL -#ifdef DOCTEST_CONFIG_IMPLEMENT -#define DOCTEST_INTERFACE DOCTEST_SYMBOL_EXPORT -#else // DOCTEST_CONFIG_IMPLEMENT -#define DOCTEST_INTERFACE DOCTEST_SYMBOL_IMPORT -#endif // DOCTEST_CONFIG_IMPLEMENT -#else // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL -#define DOCTEST_INTERFACE -#endif // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL - -#define DOCTEST_EMPTY - -#if DOCTEST_MSVC -#define DOCTEST_NOINLINE __declspec(noinline) -#define DOCTEST_UNUSED -#define DOCTEST_ALIGNMENT(x) -#elif DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 5, 0) -#define DOCTEST_NOINLINE -#define DOCTEST_UNUSED -#define DOCTEST_ALIGNMENT(x) -#else -#define DOCTEST_NOINLINE __attribute__((noinline)) -#define DOCTEST_UNUSED __attribute__((unused)) -#define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x))) -#endif - -#ifndef DOCTEST_NORETURN -#define DOCTEST_NORETURN [[noreturn]] -#endif // DOCTEST_NORETURN - -#ifndef DOCTEST_NOEXCEPT -#define DOCTEST_NOEXCEPT noexcept -#endif // DOCTEST_NOEXCEPT - -// ================================================================================================= -// == FEATURE DETECTION END ======================================================================== -// ================================================================================================= - -// internal macros for string concatenation and anonymous variable name generation -#define DOCTEST_CAT_IMPL(s1, s2) s1##s2 -#define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2) -#ifdef __COUNTER__ // not standard and may be missing for some compilers -#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__) -#else // __COUNTER__ -#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) -#endif // __COUNTER__ - -#define DOCTEST_TOSTR(x) #x - -#ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE -#define DOCTEST_REF_WRAP(x) x& -#else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE -#define DOCTEST_REF_WRAP(x) x -#endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE - -// not using __APPLE__ because... this is how Catch does it -#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED -#define DOCTEST_PLATFORM_MAC -#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) -#define DOCTEST_PLATFORM_IPHONE -#elif defined(_WIN32) -#define DOCTEST_PLATFORM_WINDOWS -#else // DOCTEST_PLATFORM -#define DOCTEST_PLATFORM_LINUX -#endif // DOCTEST_PLATFORM - -#define DOCTEST_GLOBAL_NO_WARNINGS(var) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \ - DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable") \ - static const int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp) -#define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP - -#ifndef DOCTEST_BREAK_INTO_DEBUGGER -// should probably take a look at https://github.com/scottt/debugbreak -#ifdef DOCTEST_PLATFORM_LINUX -#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) -// Break at the location of the failing check if possible -#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler) -#else -#include -#define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP) -#endif -#elif defined(DOCTEST_PLATFORM_MAC) -#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) -#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler) -#else -#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); // NOLINT (hicpp-no-assembler) -#endif -#elif DOCTEST_MSVC -#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() -#elif defined(__MINGW32__) -DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wredundant-decls") -extern "C" __declspec(dllimport) void __stdcall DebugBreak(); -DOCTEST_GCC_SUPPRESS_WARNING_POP -#define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() -#else // linux -#define DOCTEST_BREAK_INTO_DEBUGGER() (static_cast(0)) -#endif // linux -#endif // DOCTEST_BREAK_INTO_DEBUGGER - -// this is kept here for backwards compatibility since the config option was changed -#ifdef DOCTEST_CONFIG_USE_IOSFWD -#define DOCTEST_CONFIG_USE_STD_HEADERS -#endif // DOCTEST_CONFIG_USE_IOSFWD - -#ifdef DOCTEST_CONFIG_USE_STD_HEADERS -#ifndef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -#define DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -#include -#include -#include -#else // DOCTEST_CONFIG_USE_STD_HEADERS - -#if DOCTEST_CLANG -// to detect if libc++ is being used with clang (the _LIBCPP_VERSION identifier) -#include -#endif // clang - -#ifdef _LIBCPP_VERSION -#define DOCTEST_STD_NAMESPACE_BEGIN _LIBCPP_BEGIN_NAMESPACE_STD -#define DOCTEST_STD_NAMESPACE_END _LIBCPP_END_NAMESPACE_STD -#else // _LIBCPP_VERSION -#define DOCTEST_STD_NAMESPACE_BEGIN namespace std { -#define DOCTEST_STD_NAMESPACE_END } -#endif // _LIBCPP_VERSION - -// Forward declaring 'X' in namespace std is not permitted by the C++ Standard. -DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643) - -DOCTEST_STD_NAMESPACE_BEGIN // NOLINT (cert-dcl58-cpp) -typedef decltype(nullptr) nullptr_t; -template -struct char_traits; -template <> -struct char_traits; -template -class basic_ostream; -typedef basic_ostream> ostream; -template -class tuple; -#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) -// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 -template -class allocator; -template -class basic_string; -using string = basic_string, allocator>; -#endif // VS 2019 -DOCTEST_STD_NAMESPACE_END - -DOCTEST_MSVC_SUPPRESS_WARNING_POP - -#endif // DOCTEST_CONFIG_USE_STD_HEADERS - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -#include -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - -namespace doctest { - -DOCTEST_INTERFACE extern bool is_running_in_test; - -// A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length -// of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for: -// - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128) -// - if small - capacity left before going on the heap - using the lowest 5 bits -// - if small - 2 bits are left unused - the second and third highest ones -// - if small - acts as a null terminator if strlen() is 23 (24 including the null terminator) -// and the "is small" bit remains "0" ("as well as the capacity left") so its OK -// Idea taken from this lecture about the string implementation of facebook/folly - fbstring -// https://www.youtube.com/watch?v=kPR8h4-qZdk -// TODO: -// - optimizations - like not deleting memory unnecessarily in operator= and etc. -// - resize/reserve/clear -// - substr -// - replace -// - back/front -// - iterator stuff -// - find & friends -// - push_back/pop_back -// - assign/insert/erase -// - relational operators as free functions - taking const char* as one of the params -class DOCTEST_INTERFACE String -{ - static const unsigned len = 24; //!OCLINT avoid private static members - static const unsigned last = len - 1; //!OCLINT avoid private static members - - struct view // len should be more than sizeof(view) - because of the final byte for flags - { - char* ptr; - unsigned size; - unsigned capacity; - }; - - union - { - char buf[len]; - view data; - }; - - bool isOnStack() const { return (buf[last] & 128) == 0; } - void setOnHeap(); - void setLast(unsigned in = last); - - void copy(const String& other); - -public: - String(); - ~String(); - - // cppcheck-suppress noExplicitConstructor - String(const char* in); - String(const char* in, unsigned in_size); - - String(const String& other); - String& operator=(const String& other); - - String& operator+=(const String& other); - String operator+(const String& other) const; - - String(String&& other); - String& operator=(String&& other); - - char operator[](unsigned i) const; - char& operator[](unsigned i); - - // the only functions I'm willing to leave in the interface - available for inlining - const char* c_str() const { return const_cast(this)->c_str(); } // NOLINT - char* c_str() { - if(isOnStack()) - return reinterpret_cast(buf); - return data.ptr; - } - - unsigned size() const; - unsigned capacity() const; - - int compare(const char* other, bool no_case = false) const; - int compare(const String& other, bool no_case = false) const; -}; - -DOCTEST_INTERFACE bool operator==(const String& lhs, const String& rhs); -DOCTEST_INTERFACE bool operator!=(const String& lhs, const String& rhs); -DOCTEST_INTERFACE bool operator<(const String& lhs, const String& rhs); -DOCTEST_INTERFACE bool operator>(const String& lhs, const String& rhs); -DOCTEST_INTERFACE bool operator<=(const String& lhs, const String& rhs); -DOCTEST_INTERFACE bool operator>=(const String& lhs, const String& rhs); - -DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in); - -namespace Color { - enum Enum - { - None = 0, - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, - - Bright = 0x10, - - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White - }; - - DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, Color::Enum code); -} // namespace Color - -namespace assertType { - enum Enum - { - // macro traits - - is_warn = 1, - is_check = 2 * is_warn, - is_require = 2 * is_check, - - is_normal = 2 * is_require, - is_throws = 2 * is_normal, - is_throws_as = 2 * is_throws, - is_throws_with = 2 * is_throws_as, - is_nothrow = 2 * is_throws_with, - - is_false = 2 * is_nothrow, - is_unary = 2 * is_false, // not checked anywhere - used just to distinguish the types - - is_eq = 2 * is_unary, - is_ne = 2 * is_eq, - - is_lt = 2 * is_ne, - is_gt = 2 * is_lt, - - is_ge = 2 * is_gt, - is_le = 2 * is_ge, - - // macro types - - DT_WARN = is_normal | is_warn, - DT_CHECK = is_normal | is_check, - DT_REQUIRE = is_normal | is_require, - - DT_WARN_FALSE = is_normal | is_false | is_warn, - DT_CHECK_FALSE = is_normal | is_false | is_check, - DT_REQUIRE_FALSE = is_normal | is_false | is_require, - - DT_WARN_THROWS = is_throws | is_warn, - DT_CHECK_THROWS = is_throws | is_check, - DT_REQUIRE_THROWS = is_throws | is_require, - - DT_WARN_THROWS_AS = is_throws_as | is_warn, - DT_CHECK_THROWS_AS = is_throws_as | is_check, - DT_REQUIRE_THROWS_AS = is_throws_as | is_require, - - DT_WARN_THROWS_WITH = is_throws_with | is_warn, - DT_CHECK_THROWS_WITH = is_throws_with | is_check, - DT_REQUIRE_THROWS_WITH = is_throws_with | is_require, - - DT_WARN_THROWS_WITH_AS = is_throws_with | is_throws_as | is_warn, - DT_CHECK_THROWS_WITH_AS = is_throws_with | is_throws_as | is_check, - DT_REQUIRE_THROWS_WITH_AS = is_throws_with | is_throws_as | is_require, - - DT_WARN_NOTHROW = is_nothrow | is_warn, - DT_CHECK_NOTHROW = is_nothrow | is_check, - DT_REQUIRE_NOTHROW = is_nothrow | is_require, - - DT_WARN_EQ = is_normal | is_eq | is_warn, - DT_CHECK_EQ = is_normal | is_eq | is_check, - DT_REQUIRE_EQ = is_normal | is_eq | is_require, - - DT_WARN_NE = is_normal | is_ne | is_warn, - DT_CHECK_NE = is_normal | is_ne | is_check, - DT_REQUIRE_NE = is_normal | is_ne | is_require, - - DT_WARN_GT = is_normal | is_gt | is_warn, - DT_CHECK_GT = is_normal | is_gt | is_check, - DT_REQUIRE_GT = is_normal | is_gt | is_require, - - DT_WARN_LT = is_normal | is_lt | is_warn, - DT_CHECK_LT = is_normal | is_lt | is_check, - DT_REQUIRE_LT = is_normal | is_lt | is_require, - - DT_WARN_GE = is_normal | is_ge | is_warn, - DT_CHECK_GE = is_normal | is_ge | is_check, - DT_REQUIRE_GE = is_normal | is_ge | is_require, - - DT_WARN_LE = is_normal | is_le | is_warn, - DT_CHECK_LE = is_normal | is_le | is_check, - DT_REQUIRE_LE = is_normal | is_le | is_require, - - DT_WARN_UNARY = is_normal | is_unary | is_warn, - DT_CHECK_UNARY = is_normal | is_unary | is_check, - DT_REQUIRE_UNARY = is_normal | is_unary | is_require, - - DT_WARN_UNARY_FALSE = is_normal | is_false | is_unary | is_warn, - DT_CHECK_UNARY_FALSE = is_normal | is_false | is_unary | is_check, - DT_REQUIRE_UNARY_FALSE = is_normal | is_false | is_unary | is_require, - }; -} // namespace assertType - -DOCTEST_INTERFACE const char* assertString(assertType::Enum at); -DOCTEST_INTERFACE const char* failureString(assertType::Enum at); -DOCTEST_INTERFACE const char* skipPathFromFilename(const char* file); - -struct DOCTEST_INTERFACE TestCaseData -{ - String m_file; // the file in which the test was registered (using String - see #350) - unsigned m_line; // the line where the test was registered - const char* m_name; // name of the test case - const char* m_test_suite; // the test suite in which the test was added - const char* m_description; - bool m_skip; - bool m_no_breaks; - bool m_no_output; - bool m_may_fail; - bool m_should_fail; - int m_expected_failures; - double m_timeout; -}; - -struct DOCTEST_INTERFACE AssertData -{ - // common - for all asserts - const TestCaseData* m_test_case; - assertType::Enum m_at; - const char* m_file; - int m_line; - const char* m_expr; - bool m_failed; - - // exception-related - for all asserts - bool m_threw; - String m_exception; - - // for normal asserts - String m_decomp; - - // for specific exception-related asserts - bool m_threw_as; - const char* m_exception_type; - const char* m_exception_string; -}; - -struct DOCTEST_INTERFACE MessageData -{ - String m_string; - const char* m_file; - int m_line; - assertType::Enum m_severity; -}; - -struct DOCTEST_INTERFACE SubcaseSignature -{ - String m_name; - const char* m_file; - int m_line; - - bool operator<(const SubcaseSignature& other) const; -}; - -struct DOCTEST_INTERFACE IContextScope -{ - IContextScope(); - virtual ~IContextScope(); - virtual void stringify(std::ostream*) const = 0; -}; - -namespace detail { - struct DOCTEST_INTERFACE TestCase; -} // namespace detail - -struct ContextOptions //!OCLINT too many fields -{ - std::ostream* cout; // stdout stream - std::cout by default - std::ostream* cerr; // stderr stream - std::cerr by default - String binary_name; // the test binary name - - const detail::TestCase* currentTest = nullptr; - - // == parameters from the command line - String out; // output filename - String order_by; // how tests should be ordered - unsigned rand_seed; // the seed for rand ordering - - unsigned first; // the first (matching) test to be executed - unsigned last; // the last (matching) test to be executed - - int abort_after; // stop tests after this many failed assertions - int subcase_filter_levels; // apply the subcase filters for the first N levels - - bool success; // include successful assertions in output - bool case_sensitive; // if filtering should be case sensitive - bool exit; // if the program should be exited after the tests are ran/whatever - bool duration; // print the time duration of each test case - bool no_throw; // to skip exceptions-related assertion macros - bool no_exitcode; // if the framework should return 0 as the exitcode - bool no_run; // to not run the tests at all (can be done with an "*" exclude) - bool no_version; // to not print the version of the framework - bool no_colors; // if output to the console should be colorized - bool force_colors; // forces the use of colors even when a tty cannot be detected - bool no_breaks; // to not break into the debugger - bool no_skip; // don't skip test cases which are marked to be skipped - bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x): - bool no_path_in_filenames; // if the path to files should be removed from the output - bool no_line_numbers; // if source code line numbers should be omitted from the output - bool no_debug_output; // no output in the debug console when a debugger is attached - bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!! - bool no_time_in_output; // omit any time/timestamps from output !!! UNDOCUMENTED !!! - - bool help; // to print the help - bool version; // to print the version - bool count; // if only the count of matching tests is to be retrieved - bool list_test_cases; // to list all tests matching the filters - bool list_test_suites; // to list all suites matching the filters - bool list_reporters; // lists all registered reporters -}; - -namespace detail { - template - struct enable_if - {}; - - template - struct enable_if - { typedef TYPE type; }; - - // clang-format off - template struct remove_reference { typedef T type; }; - template struct remove_reference { typedef T type; }; - template struct remove_reference { typedef T type; }; - - template U declval(int); - - template T declval(long); - - template auto declval() DOCTEST_NOEXCEPT -> decltype(declval(0)) ; - - template struct is_lvalue_reference { const static bool value=false; }; - template struct is_lvalue_reference { const static bool value=true; }; - - template - inline T&& forward(typename remove_reference::type& t) DOCTEST_NOEXCEPT - { - return static_cast(t); - } - - template - inline T&& forward(typename remove_reference::type&& t) DOCTEST_NOEXCEPT - { - static_assert(!is_lvalue_reference::value, - "Can not forward an rvalue as an lvalue."); - return static_cast(t); - } - - template struct remove_const { typedef T type; }; - template struct remove_const { typedef T type; }; -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - template struct is_enum : public std::is_enum {}; - template struct underlying_type : public std::underlying_type {}; -#else - // Use compiler intrinsics - template struct is_enum { constexpr static bool value = __is_enum(T); }; - template struct underlying_type { typedef __underlying_type(T) type; }; -#endif - // clang-format on - - template - struct deferred_false - // cppcheck-suppress unusedStructMember - { static const bool value = false; }; - - namespace has_insertion_operator_impl { - std::ostream &os(); - template - DOCTEST_REF_WRAP(T) val(); - - template - struct check { - static constexpr bool value = false; - }; - - template - struct check(), void())> { - static constexpr bool value = true; - }; - } // namespace has_insertion_operator_impl - - template - using has_insertion_operator = has_insertion_operator_impl::check; - - DOCTEST_INTERFACE void my_memcpy(void* dest, const void* src, unsigned num); - - DOCTEST_INTERFACE std::ostream* getTlsOss(); // returns a thread-local ostringstream - DOCTEST_INTERFACE String getTlsOssResult(); - - template - struct StringMakerBase - { - template - static String convert(const DOCTEST_REF_WRAP(T)) { - return "{?}"; - } - }; - - template <> - struct StringMakerBase - { - template - static String convert(const DOCTEST_REF_WRAP(T) in) { - *getTlsOss() << in; - return getTlsOssResult(); - } - }; - - DOCTEST_INTERFACE String rawMemoryToString(const void* object, unsigned size); - - template - String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) { - return rawMemoryToString(&object, sizeof(object)); - } - - template - const char* type_to_string() { - return "<>"; - } -} // namespace detail - -template -struct StringMaker : public detail::StringMakerBase::value> -{}; - -template -struct StringMaker -{ - template - static String convert(U* p) { - if(p) - return detail::rawMemoryToString(p); - return "NULL"; - } -}; - -template -struct StringMaker -{ - static String convert(R C::*p) { - if(p) - return detail::rawMemoryToString(p); - return "NULL"; - } -}; - -template ::value, bool>::type = true> -String toString(const DOCTEST_REF_WRAP(T) value) { - return StringMaker::convert(value); -} - -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -DOCTEST_INTERFACE String toString(char* in); -DOCTEST_INTERFACE String toString(const char* in); -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -DOCTEST_INTERFACE String toString(bool in); -DOCTEST_INTERFACE String toString(float in); -DOCTEST_INTERFACE String toString(double in); -DOCTEST_INTERFACE String toString(double long in); - -DOCTEST_INTERFACE String toString(char in); -DOCTEST_INTERFACE String toString(char signed in); -DOCTEST_INTERFACE String toString(char unsigned in); -DOCTEST_INTERFACE String toString(int short in); -DOCTEST_INTERFACE String toString(int short unsigned in); -DOCTEST_INTERFACE String toString(int in); -DOCTEST_INTERFACE String toString(int unsigned in); -DOCTEST_INTERFACE String toString(int long in); -DOCTEST_INTERFACE String toString(int long unsigned in); -DOCTEST_INTERFACE String toString(int long long in); -DOCTEST_INTERFACE String toString(int long long unsigned in); -DOCTEST_INTERFACE String toString(std::nullptr_t in); - -template ::value, bool>::type = true> -String toString(const DOCTEST_REF_WRAP(T) value) { - typedef typename detail::underlying_type::type UT; - return toString(static_cast(value)); -} - -#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) -// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 -DOCTEST_INTERFACE String toString(const std::string& in); -#endif // VS 2019 - -class DOCTEST_INTERFACE Approx -{ -public: - explicit Approx(double value); - - Approx operator()(double value) const; - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - template - explicit Approx(const T& value, - typename detail::enable_if::value>::type* = - static_cast(nullptr)) { - *this = Approx(static_cast(value)); - } -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - Approx& epsilon(double newEpsilon); - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - template - typename detail::enable_if::value, Approx&>::type epsilon( - const T& newEpsilon) { - m_epsilon = static_cast(newEpsilon); - return *this; - } -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - Approx& scale(double newScale); - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - template - typename detail::enable_if::value, Approx&>::type scale( - const T& newScale) { - m_scale = static_cast(newScale); - return *this; - } -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - // clang-format off - DOCTEST_INTERFACE friend bool operator==(double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator==(const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator!=(double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator!=(const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator<=(double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator<=(const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator>=(double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator>=(const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator< (double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator< (const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator> (const Approx & lhs, double rhs); - - DOCTEST_INTERFACE friend String toString(const Approx& in); - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -#define DOCTEST_APPROX_PREFIX \ - template friend typename detail::enable_if::value, bool>::type - - DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(double(lhs), rhs); } - DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); } - DOCTEST_APPROX_PREFIX operator!=(const T& lhs, const Approx& rhs) { return !operator==(lhs, rhs); } - DOCTEST_APPROX_PREFIX operator!=(const Approx& lhs, const T& rhs) { return !operator==(rhs, lhs); } - DOCTEST_APPROX_PREFIX operator<=(const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator<=(const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator>=(const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator>=(const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator< (const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value && lhs != rhs; } - DOCTEST_APPROX_PREFIX operator< (const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) && lhs != rhs; } - DOCTEST_APPROX_PREFIX operator> (const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value && lhs != rhs; } - DOCTEST_APPROX_PREFIX operator> (const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) && lhs != rhs; } -#undef DOCTEST_APPROX_PREFIX -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - // clang-format on - -private: - double m_epsilon; - double m_scale; - double m_value; -}; - -DOCTEST_INTERFACE String toString(const Approx& in); - -DOCTEST_INTERFACE const ContextOptions* getContextOptions(); - -#if !defined(DOCTEST_CONFIG_DISABLE) - -namespace detail { - // clang-format off -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - template struct decay_array { typedef T type; }; - template struct decay_array { typedef T* type; }; - template struct decay_array { typedef T* type; }; - - template struct not_char_pointer { enum { value = 1 }; }; - template<> struct not_char_pointer { enum { value = 0 }; }; - template<> struct not_char_pointer { enum { value = 0 }; }; - - template struct can_use_op : public not_char_pointer::type> {}; -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - // clang-format on - - struct DOCTEST_INTERFACE TestFailureException - { - }; - - DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); - -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - DOCTEST_NORETURN -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - DOCTEST_INTERFACE void throwException(); - - struct DOCTEST_INTERFACE Subcase - { - SubcaseSignature m_signature; - bool m_entered = false; - - Subcase(const String& name, const char* file, int line); - ~Subcase(); - - operator bool() const; - }; - - template - String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op, - const DOCTEST_REF_WRAP(R) rhs) { - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - return toString(lhs) + op + toString(rhs); - } - -#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) -DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison") -#endif - -// This will check if there is any way it could find a operator like member or friend and uses it. -// If not it doesn't find the operator or if the operator at global scope is defined after -// this template, the template won't be instantiated due to SFINAE. Once the template is not -// instantiated it can look for global operator using normal conversions. -#define SFINAE_OP(ret,op) decltype(doctest::detail::declval() op doctest::detail::declval(),static_cast(0)) - -#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ - template \ - DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& rhs) { \ - bool res = op_macro(doctest::detail::forward(lhs), doctest::detail::forward(rhs)); \ - if(m_at & assertType::is_false) \ - res = !res; \ - if(!res || doctest::getContextOptions()->success) \ - return Result(res, stringifyBinaryExpr(lhs, op_str, rhs)); \ - return Result(res); \ - } - - // more checks could be added - like in Catch: - // https://github.com/catchorg/Catch2/pull/1480/files - // https://github.com/catchorg/Catch2/pull/1481/files -#define DOCTEST_FORBIT_EXPRESSION(rt, op) \ - template \ - rt& operator op(const R&) { \ - static_assert(deferred_false::value, \ - "Expression Too Complex Please Rewrite As Binary Comparison!"); \ - return *this; \ - } - - struct DOCTEST_INTERFACE Result - { - bool m_passed; - String m_decomp; - - Result(bool passed, const String& decomposition = String()); - - // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence - DOCTEST_FORBIT_EXPRESSION(Result, &) - DOCTEST_FORBIT_EXPRESSION(Result, ^) - DOCTEST_FORBIT_EXPRESSION(Result, |) - DOCTEST_FORBIT_EXPRESSION(Result, &&) - DOCTEST_FORBIT_EXPRESSION(Result, ||) - DOCTEST_FORBIT_EXPRESSION(Result, ==) - DOCTEST_FORBIT_EXPRESSION(Result, !=) - DOCTEST_FORBIT_EXPRESSION(Result, <) - DOCTEST_FORBIT_EXPRESSION(Result, >) - DOCTEST_FORBIT_EXPRESSION(Result, <=) - DOCTEST_FORBIT_EXPRESSION(Result, >=) - DOCTEST_FORBIT_EXPRESSION(Result, =) - DOCTEST_FORBIT_EXPRESSION(Result, +=) - DOCTEST_FORBIT_EXPRESSION(Result, -=) - DOCTEST_FORBIT_EXPRESSION(Result, *=) - DOCTEST_FORBIT_EXPRESSION(Result, /=) - DOCTEST_FORBIT_EXPRESSION(Result, %=) - DOCTEST_FORBIT_EXPRESSION(Result, <<=) - DOCTEST_FORBIT_EXPRESSION(Result, >>=) - DOCTEST_FORBIT_EXPRESSION(Result, &=) - DOCTEST_FORBIT_EXPRESSION(Result, ^=) - DOCTEST_FORBIT_EXPRESSION(Result, |=) - }; - -#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - - DOCTEST_CLANG_SUPPRESS_WARNING_PUSH - DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-compare") - //DOCTEST_CLANG_SUPPRESS_WARNING("-Wdouble-promotion") - //DOCTEST_CLANG_SUPPRESS_WARNING("-Wconversion") - //DOCTEST_CLANG_SUPPRESS_WARNING("-Wfloat-equal") - - DOCTEST_GCC_SUPPRESS_WARNING_PUSH - DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") - DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-compare") - //DOCTEST_GCC_SUPPRESS_WARNING("-Wdouble-promotion") - //DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") - //DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal") - - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH - // https://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389 - DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch - DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch - DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch - //DOCTEST_MSVC_SUPPRESS_WARNING(4805) // 'operation' : unsafe mix of type 'type' and type 'type' in operation - -#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - - // clang-format off -#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -#define DOCTEST_COMPARISON_RETURN_TYPE bool -#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -#define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if::value || can_use_op::value, bool>::type - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); } - inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); } - inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); } - inline bool gt(const char* lhs, const char* rhs) { return String(lhs) > String(rhs); } - inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); } - inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); } -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - // clang-format on - -#define DOCTEST_RELATIONAL_OP(name, op) \ - template \ - DOCTEST_COMPARISON_RETURN_TYPE name(const DOCTEST_REF_WRAP(L) lhs, \ - const DOCTEST_REF_WRAP(R) rhs) { \ - return lhs op rhs; \ - } - - DOCTEST_RELATIONAL_OP(eq, ==) - DOCTEST_RELATIONAL_OP(ne, !=) - DOCTEST_RELATIONAL_OP(lt, <) - DOCTEST_RELATIONAL_OP(gt, >) - DOCTEST_RELATIONAL_OP(le, <=) - DOCTEST_RELATIONAL_OP(ge, >=) - -#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -#define DOCTEST_CMP_EQ(l, r) l == r -#define DOCTEST_CMP_NE(l, r) l != r -#define DOCTEST_CMP_GT(l, r) l > r -#define DOCTEST_CMP_LT(l, r) l < r -#define DOCTEST_CMP_GE(l, r) l >= r -#define DOCTEST_CMP_LE(l, r) l <= r -#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -#define DOCTEST_CMP_EQ(l, r) eq(l, r) -#define DOCTEST_CMP_NE(l, r) ne(l, r) -#define DOCTEST_CMP_GT(l, r) gt(l, r) -#define DOCTEST_CMP_LT(l, r) lt(l, r) -#define DOCTEST_CMP_GE(l, r) ge(l, r) -#define DOCTEST_CMP_LE(l, r) le(l, r) -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - - template - // cppcheck-suppress copyCtorAndEqOperator - struct Expression_lhs - { - L lhs; - assertType::Enum m_at; - - explicit Expression_lhs(L&& in, assertType::Enum at) - : lhs(doctest::detail::forward(in)) - , m_at(at) {} - - DOCTEST_NOINLINE operator Result() { -// this is needed only foc MSVC 2015: -// https://ci.appveyor.com/project/onqtam/doctest/builds/38181202 -DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool - bool res = static_cast(lhs); -DOCTEST_MSVC_SUPPRESS_WARNING_POP - if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional - res = !res; - - if(!res || getContextOptions()->success) - return Result(res, toString(lhs)); - return Result(res); - } - - /* This is required for user-defined conversions from Expression_lhs to L */ - //operator L() const { return lhs; } - operator L() const { return lhs; } - - // clang-format off - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>, " > ", DOCTEST_CMP_GT) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<, " < ", DOCTEST_CMP_LT) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>=, " >= ", DOCTEST_CMP_GE) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional - // clang-format on - - // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &&) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ||) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, =) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, +=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, -=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, *=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, /=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, %=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |=) - // these 2 are unfortunate because they should be allowed - they have higher precedence over the comparisons, but the - // ExpressionDecomposer class uses the left shift operator to capture the left operand of the binary expression... - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>) - }; - -#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - - DOCTEST_CLANG_SUPPRESS_WARNING_POP - DOCTEST_MSVC_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - -#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - -#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) -DOCTEST_CLANG_SUPPRESS_WARNING_POP -#endif - - struct DOCTEST_INTERFACE ExpressionDecomposer - { - assertType::Enum m_at; - - ExpressionDecomposer(assertType::Enum at); - - // The right operator for capturing expressions is "<=" instead of "<<" (based on the operator precedence table) - // but then there will be warnings from GCC about "-Wparentheses" and since "_Pragma()" is problematic this will stay for now... - // https://github.com/catchorg/Catch2/issues/870 - // https://github.com/catchorg/Catch2/issues/565 - template - Expression_lhs operator<<(L &&operand) { - return Expression_lhs(doctest::detail::forward(operand), m_at); - } - }; - - struct DOCTEST_INTERFACE TestSuite - { - const char* m_test_suite; - const char* m_description; - bool m_skip; - bool m_no_breaks; - bool m_no_output; - bool m_may_fail; - bool m_should_fail; - int m_expected_failures; - double m_timeout; - - TestSuite& operator*(const char* in); - - template - TestSuite& operator*(const T& in) { - in.fill(*this); - return *this; - } - }; - - typedef void (*funcType)(); - - struct DOCTEST_INTERFACE TestCase : public TestCaseData - { - funcType m_test; // a function pointer to the test case - - const char* m_type; // for templated test cases - gets appended to the real name - int m_template_id; // an ID used to distinguish between the different versions of a templated test case - String m_full_name; // contains the name (only for templated test cases!) + the template type - - TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, - const char* type = "", int template_id = -1); - - TestCase(const TestCase& other); - - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function - TestCase& operator=(const TestCase& other); - DOCTEST_MSVC_SUPPRESS_WARNING_POP - - TestCase& operator*(const char* in); - - template - TestCase& operator*(const T& in) { - in.fill(*this); - return *this; - } - - bool operator<(const TestCase& other) const; - }; - - // forward declarations of functions used by the macros - DOCTEST_INTERFACE int regTest(const TestCase& tc); - DOCTEST_INTERFACE int setTestSuite(const TestSuite& ts); - DOCTEST_INTERFACE bool isDebuggerActive(); - - template - int instantiationHelper(const T&) { return 0; } - - namespace binaryAssertComparison { - enum Enum - { - eq = 0, - ne, - gt, - lt, - ge, - le - }; - } // namespace binaryAssertComparison - - // clang-format off - template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; - -#define DOCTEST_BINARY_RELATIONAL_OP(n, op) \ - template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } }; - // clang-format on - - DOCTEST_BINARY_RELATIONAL_OP(0, doctest::detail::eq) - DOCTEST_BINARY_RELATIONAL_OP(1, doctest::detail::ne) - DOCTEST_BINARY_RELATIONAL_OP(2, doctest::detail::gt) - DOCTEST_BINARY_RELATIONAL_OP(3, doctest::detail::lt) - DOCTEST_BINARY_RELATIONAL_OP(4, doctest::detail::ge) - DOCTEST_BINARY_RELATIONAL_OP(5, doctest::detail::le) - - struct DOCTEST_INTERFACE ResultBuilder : public AssertData - { - ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, - const char* exception_type = "", const char* exception_string = ""); - - void setResult(const Result& res); - - template - DOCTEST_NOINLINE void binary_assert(const DOCTEST_REF_WRAP(L) lhs, - const DOCTEST_REF_WRAP(R) rhs) { - m_failed = !RelationalComparator()(lhs, rhs); - if(m_failed || getContextOptions()->success) - m_decomp = stringifyBinaryExpr(lhs, ", ", rhs); - } - - template - DOCTEST_NOINLINE void unary_assert(const DOCTEST_REF_WRAP(L) val) { - m_failed = !val; - - if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional - m_failed = !m_failed; - - if(m_failed || getContextOptions()->success) - m_decomp = toString(val); - } - - void translateException(); - - bool log(); - void react() const; - }; - - namespace assertAction { - enum Enum - { - nothing = 0, - dbgbreak = 1, - shouldthrow = 2 - }; - } // namespace assertAction - - DOCTEST_INTERFACE void failed_out_of_a_testing_context(const AssertData& ad); - - DOCTEST_INTERFACE void decomp_assert(assertType::Enum at, const char* file, int line, - const char* expr, Result result); - -#define DOCTEST_ASSERT_OUT_OF_TESTS(decomp) \ - do { \ - if(!is_running_in_test) { \ - if(failed) { \ - ResultBuilder rb(at, file, line, expr); \ - rb.m_failed = failed; \ - rb.m_decomp = decomp; \ - failed_out_of_a_testing_context(rb); \ - if(isDebuggerActive() && !getContextOptions()->no_breaks) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - if(checkIfShouldThrow(at)) \ - throwException(); \ - } \ - return; \ - } \ - } while(false) - -#define DOCTEST_ASSERT_IN_TESTS(decomp) \ - ResultBuilder rb(at, file, line, expr); \ - rb.m_failed = failed; \ - if(rb.m_failed || getContextOptions()->success) \ - rb.m_decomp = decomp; \ - if(rb.log()) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - if(rb.m_failed && checkIfShouldThrow(at)) \ - throwException() - - template - DOCTEST_NOINLINE void binary_assert(assertType::Enum at, const char* file, int line, - const char* expr, const DOCTEST_REF_WRAP(L) lhs, - const DOCTEST_REF_WRAP(R) rhs) { - bool failed = !RelationalComparator()(lhs, rhs); - - // ################################################################################### - // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT - // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED - // ################################################################################### - DOCTEST_ASSERT_OUT_OF_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); - DOCTEST_ASSERT_IN_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); - } - - template - DOCTEST_NOINLINE void unary_assert(assertType::Enum at, const char* file, int line, - const char* expr, const DOCTEST_REF_WRAP(L) val) { - bool failed = !val; - - if(at & assertType::is_false) //!OCLINT bitwise operator in conditional - failed = !failed; - - // ################################################################################### - // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT - // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED - // ################################################################################### - DOCTEST_ASSERT_OUT_OF_TESTS(toString(val)); - DOCTEST_ASSERT_IN_TESTS(toString(val)); - } - - struct DOCTEST_INTERFACE IExceptionTranslator - { - IExceptionTranslator(); - virtual ~IExceptionTranslator(); - virtual bool translate(String&) const = 0; - }; - - template - class ExceptionTranslator : public IExceptionTranslator //!OCLINT destructor of virtual class - { - public: - explicit ExceptionTranslator(String (*translateFunction)(T)) - : m_translateFunction(translateFunction) {} - - bool translate(String& res) const override { -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - try { - throw; // lgtm [cpp/rethrow-no-exception] - // cppcheck-suppress catchExceptionByValue - } catch(T ex) { // NOLINT - res = m_translateFunction(ex); //!OCLINT parameter reassignment - return true; - } catch(...) {} //!OCLINT - empty catch statement -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - static_cast(res); // to silence -Wunused-parameter - return false; - } - - private: - String (*m_translateFunction)(T); - }; - - DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator* et); - - template - struct StringStreamBase - { - template - static void convert(std::ostream* s, const T& in) { - *s << toString(in); - } - - // always treat char* as a string in this context - no matter - // if DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING is defined - static void convert(std::ostream* s, const char* in) { *s << String(in); } - }; - - template <> - struct StringStreamBase - { - template - static void convert(std::ostream* s, const T& in) { - *s << in; - } - }; - - template - struct StringStream : public StringStreamBase::value> - {}; - - template - void toStream(std::ostream* s, const T& value) { - StringStream::convert(s, value); - } - -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - DOCTEST_INTERFACE void toStream(std::ostream* s, char* in); - DOCTEST_INTERFACE void toStream(std::ostream* s, const char* in); -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - DOCTEST_INTERFACE void toStream(std::ostream* s, bool in); - DOCTEST_INTERFACE void toStream(std::ostream* s, float in); - DOCTEST_INTERFACE void toStream(std::ostream* s, double in); - DOCTEST_INTERFACE void toStream(std::ostream* s, double long in); - - DOCTEST_INTERFACE void toStream(std::ostream* s, char in); - DOCTEST_INTERFACE void toStream(std::ostream* s, char signed in); - DOCTEST_INTERFACE void toStream(std::ostream* s, char unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int short in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int short unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in); - - // ContextScope base class used to allow implementing methods of ContextScope - // that don't depend on the template parameter in doctest.cpp. - class DOCTEST_INTERFACE ContextScopeBase : public IContextScope { - protected: - ContextScopeBase(); - - void destroy(); - }; - - template class ContextScope : public ContextScopeBase - { - const L lambda_; - - public: - explicit ContextScope(const L &lambda) : lambda_(lambda) {} - - ContextScope(ContextScope &&other) : lambda_(other.lambda_) {} - - void stringify(std::ostream* s) const override { lambda_(s); } - - ~ContextScope() override { destroy(); } - }; - - struct DOCTEST_INTERFACE MessageBuilder : public MessageData - { - std::ostream* m_stream; - - MessageBuilder(const char* file, int line, assertType::Enum severity); - MessageBuilder() = delete; - ~MessageBuilder(); - - // the preferred way of chaining parameters for stringification - template - MessageBuilder& operator,(const T& in) { - toStream(m_stream, in); - return *this; - } - - // kept here just for backwards-compatibility - the comma operator should be preferred now - template - MessageBuilder& operator<<(const T& in) { return this->operator,(in); } - - // the `,` operator has the lowest operator precedence - if `<<` is used by the user then - // the `,` operator will be called last which is not what we want and thus the `*` operator - // is used first (has higher operator precedence compared to `<<`) so that we guarantee that - // an operator of the MessageBuilder class is called first before the rest of the parameters - template - MessageBuilder& operator*(const T& in) { return this->operator,(in); } - - bool log(); - void react(); - }; - - template - ContextScope MakeContextScope(const L &lambda) { - return ContextScope(lambda); - } -} // namespace detail - -#define DOCTEST_DEFINE_DECORATOR(name, type, def) \ - struct name \ - { \ - type data; \ - name(type in = def) \ - : data(in) {} \ - void fill(detail::TestCase& state) const { state.DOCTEST_CAT(m_, name) = data; } \ - void fill(detail::TestSuite& state) const { state.DOCTEST_CAT(m_, name) = data; } \ - } - -DOCTEST_DEFINE_DECORATOR(test_suite, const char*, ""); -DOCTEST_DEFINE_DECORATOR(description, const char*, ""); -DOCTEST_DEFINE_DECORATOR(skip, bool, true); -DOCTEST_DEFINE_DECORATOR(no_breaks, bool, true); -DOCTEST_DEFINE_DECORATOR(no_output, bool, true); -DOCTEST_DEFINE_DECORATOR(timeout, double, 0); -DOCTEST_DEFINE_DECORATOR(may_fail, bool, true); -DOCTEST_DEFINE_DECORATOR(should_fail, bool, true); -DOCTEST_DEFINE_DECORATOR(expected_failures, int, 0); - -template -int registerExceptionTranslator(String (*translateFunction)(T)) { - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") - static detail::ExceptionTranslator exceptionTranslator(translateFunction); - DOCTEST_CLANG_SUPPRESS_WARNING_POP - detail::registerExceptionTranslatorImpl(&exceptionTranslator); - return 0; -} - -} // namespace doctest - -// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro -// introduces an anonymous namespace in which getCurrentTestSuite gets overridden -namespace doctest_detail_test_suite_ns { -DOCTEST_INTERFACE doctest::detail::TestSuite& getCurrentTestSuite(); -} // namespace doctest_detail_test_suite_ns - -namespace doctest { -#else // DOCTEST_CONFIG_DISABLE -template -int registerExceptionTranslator(String (*)(T)) { - return 0; -} -#endif // DOCTEST_CONFIG_DISABLE - -namespace detail { - typedef void (*assert_handler)(const AssertData&); - struct ContextState; -} // namespace detail - -class DOCTEST_INTERFACE Context -{ - detail::ContextState* p; - - void parseArgs(int argc, const char* const* argv, bool withDefaults = false); - -public: - explicit Context(int argc = 0, const char* const* argv = nullptr); - - ~Context(); - - void applyCommandLine(int argc, const char* const* argv); - - void addFilter(const char* filter, const char* value); - void clearFilters(); - void setOption(const char* option, int value); - void setOption(const char* option, const char* value); - - bool shouldExit(); - - void setAsDefaultForAssertsOutOfTestCases(); - - void setAssertHandler(detail::assert_handler ah); - - int run(); -}; - -namespace TestCaseFailureReason { - enum Enum - { - None = 0, - AssertFailure = 1, // an assertion has failed in the test case - Exception = 2, // test case threw an exception - Crash = 4, // a crash... - TooManyFailedAsserts = 8, // the abort-after option - Timeout = 16, // see the timeout decorator - ShouldHaveFailedButDidnt = 32, // see the should_fail decorator - ShouldHaveFailedAndDid = 64, // see the should_fail decorator - DidntFailExactlyNumTimes = 128, // see the expected_failures decorator - FailedExactlyNumTimes = 256, // see the expected_failures decorator - CouldHaveFailedAndDid = 512 // see the may_fail decorator - }; -} // namespace TestCaseFailureReason - -struct DOCTEST_INTERFACE CurrentTestCaseStats -{ - int numAssertsCurrentTest; - int numAssertsFailedCurrentTest; - double seconds; - int failure_flags; // use TestCaseFailureReason::Enum -}; - -struct DOCTEST_INTERFACE TestCaseException -{ - String error_string; - bool is_crash; -}; - -struct DOCTEST_INTERFACE TestRunStats -{ - unsigned numTestCases; - unsigned numTestCasesPassingFilters; - unsigned numTestSuitesPassingFilters; - unsigned numTestCasesFailed; - int numAsserts; - int numAssertsFailed; -}; - -struct QueryData -{ - const TestRunStats* run_stats = nullptr; - const TestCaseData** data = nullptr; - unsigned num_data = 0; -}; - -struct DOCTEST_INTERFACE IReporter -{ - // The constructor has to accept "const ContextOptions&" as a single argument - // which has most of the options for the run + a pointer to the stdout stream - // Reporter(const ContextOptions& in) - - // called when a query should be reported (listing test cases, printing the version, etc.) - virtual void report_query(const QueryData&) = 0; - - // called when the whole test run starts - virtual void test_run_start() = 0; - // called when the whole test run ends (caching a pointer to the input doesn't make sense here) - virtual void test_run_end(const TestRunStats&) = 0; - - // called when a test case is started (safe to cache a pointer to the input) - virtual void test_case_start(const TestCaseData&) = 0; - // called when a test case is reentered because of unfinished subcases (safe to cache a pointer to the input) - virtual void test_case_reenter(const TestCaseData&) = 0; - // called when a test case has ended - virtual void test_case_end(const CurrentTestCaseStats&) = 0; - - // called when an exception is thrown from the test case (or it crashes) - virtual void test_case_exception(const TestCaseException&) = 0; - - // called whenever a subcase is entered (don't cache pointers to the input) - virtual void subcase_start(const SubcaseSignature&) = 0; - // called whenever a subcase is exited (don't cache pointers to the input) - virtual void subcase_end() = 0; - - // called for each assert (don't cache pointers to the input) - virtual void log_assert(const AssertData&) = 0; - // called for each message (don't cache pointers to the input) - virtual void log_message(const MessageData&) = 0; - - // called when a test case is skipped either because it doesn't pass the filters, has a skip decorator - // or isn't in the execution range (between first and last) (safe to cache a pointer to the input) - virtual void test_case_skipped(const TestCaseData&) = 0; - - // doctest will not be managing the lifetimes of reporters given to it but this would still be nice to have - virtual ~IReporter(); - - // can obtain all currently active contexts and stringify them if one wishes to do so - static int get_num_active_contexts(); - static const IContextScope* const* get_active_contexts(); - - // can iterate through contexts which have been stringified automatically in their destructors when an exception has been thrown - static int get_num_stringified_contexts(); - static const String* get_stringified_contexts(); -}; - -namespace detail { - typedef IReporter* (*reporterCreatorFunc)(const ContextOptions&); - - DOCTEST_INTERFACE void registerReporterImpl(const char* name, int prio, reporterCreatorFunc c, bool isReporter); - - template - IReporter* reporterCreator(const ContextOptions& o) { - return new Reporter(o); - } -} // namespace detail - -template -int registerReporter(const char* name, int priority, bool isReporter) { - detail::registerReporterImpl(name, priority, detail::reporterCreator, isReporter); - return 0; -} -} // namespace doctest - -// if registering is not disabled -#if !defined(DOCTEST_CONFIG_DISABLE) - -// common code in asserts - for convenience -#define DOCTEST_ASSERT_LOG_AND_REACT(b) \ - if(b.log()) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - b.react() - -#ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS -#define DOCTEST_WRAP_IN_TRY(x) x; -#else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS -#define DOCTEST_WRAP_IN_TRY(x) \ - try { \ - x; \ - } catch(...) { _DOCTEST_RB.translateException(); } -#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS - -#ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS -#define DOCTEST_CAST_TO_VOID(...) \ - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast") \ - static_cast(__VA_ARGS__); \ - DOCTEST_GCC_SUPPRESS_WARNING_POP -#else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS -#define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__; -#endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS - -// registers the test by initializing a dummy var with a function -#define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators) \ - global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ - doctest::detail::regTest( \ - doctest::detail::TestCase( \ - f, __FILE__, __LINE__, \ - doctest_detail_test_suite_ns::getCurrentTestSuite()) * \ - decorators); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() - -#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators) \ - namespace { \ - struct der : public base \ - { \ - void f(); \ - }; \ - static void func() { \ - der v; \ - v.f(); \ - } \ - DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, func, decorators) \ - } \ - inline DOCTEST_NOINLINE void der::f() - -#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators) \ - static void f(); \ - DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, f, decorators) \ - static void f() - -#define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators) \ - static doctest::detail::funcType proxy() { return f; } \ - DOCTEST_REGISTER_FUNCTION(inline const, proxy(), decorators) \ - static void f() - -// for registering tests -#define DOCTEST_TEST_CASE(decorators) \ - DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) - -// for registering tests in classes - requires C++17 for inline variables! -#if __cplusplus >= 201703L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 12, 0) && _MSVC_LANG >= 201703L) -#define DOCTEST_TEST_CASE_CLASS(decorators) \ - DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), \ - DOCTEST_ANONYMOUS(_DOCTEST_ANON_PROXY_), \ - decorators) -#else // DOCTEST_TEST_CASE_CLASS -#define DOCTEST_TEST_CASE_CLASS(...) \ - TEST_CASES_CAN_BE_REGISTERED_IN_CLASSES_ONLY_IN_CPP17_MODE_OR_WITH_VS_2017_OR_NEWER -#endif // DOCTEST_TEST_CASE_CLASS - -// for registering tests with a fixture -#define DOCTEST_TEST_CASE_FIXTURE(c, decorators) \ - DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c, \ - DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) - -// for converting types to strings without the header and demangling -#define DOCTEST_TYPE_TO_STRING_IMPL(...) \ - template <> \ - inline const char* type_to_string<__VA_ARGS__>() { \ - return "<" #__VA_ARGS__ ">"; \ - } -#define DOCTEST_TYPE_TO_STRING(...) \ - namespace doctest { namespace detail { \ - DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__) \ - } \ - } \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \ - template \ - static void func(); \ - namespace { \ - template \ - struct iter; \ - template \ - struct iter> \ - { \ - iter(const char* file, unsigned line, int index) { \ - doctest::detail::regTest(doctest::detail::TestCase(func, file, line, \ - doctest_detail_test_suite_ns::getCurrentTestSuite(), \ - doctest::detail::type_to_string(), \ - int(line) * 1000 + index) \ - * dec); \ - iter>(file, line, index + 1); \ - } \ - }; \ - template <> \ - struct iter> \ - { \ - iter(const char*, unsigned, int) {} \ - }; \ - } \ - template \ - static void func() - -#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id) \ - DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR), \ - DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) - -#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = \ - doctest::detail::instantiationHelper(DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__>(__FILE__, __LINE__, 0));\ - DOCTEST_GLOBAL_NO_WARNINGS_END() - -#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon); \ - DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(anon, anon, std::tuple<__VA_ARGS__>) \ - template \ - static void anon() - -#define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) - -// for subcases -#define DOCTEST_SUBCASE(name) \ - if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ - doctest::detail::Subcase(name, __FILE__, __LINE__)) - -// for grouping tests in test suites by using code blocks -#define DOCTEST_TEST_SUITE_IMPL(decorators, ns_name) \ - namespace ns_name { namespace doctest_detail_test_suite_ns { \ - static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \ - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \ - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmissing-field-initializers") \ - static doctest::detail::TestSuite data{}; \ - static bool inited = false; \ - DOCTEST_MSVC_SUPPRESS_WARNING_POP \ - DOCTEST_CLANG_SUPPRESS_WARNING_POP \ - DOCTEST_GCC_SUPPRESS_WARNING_POP \ - if(!inited) { \ - data* decorators; \ - inited = true; \ - } \ - return data; \ - } \ - } \ - } \ - namespace ns_name - -#define DOCTEST_TEST_SUITE(decorators) \ - DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_)) - -// for starting a testsuite block -#define DOCTEST_TEST_SUITE_BEGIN(decorators) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ - doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for ending a testsuite block -#define DOCTEST_TEST_SUITE_END \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ - doctest::detail::setTestSuite(doctest::detail::TestSuite() * ""); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for registering exception translators -#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature) \ - inline doctest::String translatorName(signature); \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)) = \ - doctest::registerExceptionTranslator(translatorName); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ - doctest::String translatorName(signature) - -#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ - DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_), \ - signature) - -// for registering reporters -#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ - doctest::registerReporter(name, priority, true); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for registering listeners -#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ - doctest::registerReporter(name, priority, false); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for logging -#define DOCTEST_INFO(...) \ - DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), \ - __VA_ARGS__) - -#define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \ - auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope( \ - [&](std::ostream* s_name) { \ - doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ - mb_name.m_stream = s_name; \ - mb_name * __VA_ARGS__; \ - }) - -#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x) - -#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, ...) \ - do { \ - doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type); \ - mb * __VA_ARGS__; \ - DOCTEST_ASSERT_LOG_AND_REACT(mb); \ - } while(false) - -// clang-format off -#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__) -#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__) -#define DOCTEST_ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), __VA_ARGS__) -// clang-format on - -#define DOCTEST_MESSAGE(...) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, __VA_ARGS__) -#define DOCTEST_FAIL_CHECK(...) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, __VA_ARGS__) -#define DOCTEST_FAIL(...) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, __VA_ARGS__) - -#define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility. - -#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ - __LINE__, #__VA_ARGS__); \ - DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.setResult( \ - doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ - << __VA_ARGS__)) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB) \ - DOCTEST_CLANG_SUPPRESS_WARNING_POP - -#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ - do { \ - DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__); \ - } while(false) - -#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -// necessary for _MESSAGE -#define DOCTEST_ASSERT_IMPLEMENT_2 DOCTEST_ASSERT_IMPLEMENT_1 - -#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ - doctest::detail::decomp_assert( \ - doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, \ - doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ - << __VA_ARGS__) DOCTEST_CLANG_SUPPRESS_WARNING_POP - -#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN, __VA_ARGS__) -#define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK, __VA_ARGS__) -#define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE, __VA_ARGS__) -#define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN_FALSE, __VA_ARGS__) -#define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK_FALSE, __VA_ARGS__) -#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__) - -// clang-format off -#define DOCTEST_WARN_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } while(false) -#define DOCTEST_CHECK_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } while(false) -#define DOCTEST_REQUIRE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } while(false) -#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } while(false) -#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } while(false) -#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } while(false) -// clang-format on - -#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...) \ - do { \ - if(!doctest::getContextOptions()->no_throw) { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ - __LINE__, #expr, #__VA_ARGS__, message); \ - try { \ - DOCTEST_CAST_TO_VOID(expr) \ - } catch(const typename doctest::detail::remove_const< \ - typename doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) { \ - _DOCTEST_RB.translateException(); \ - _DOCTEST_RB.m_threw_as = true; \ - } catch(...) { _DOCTEST_RB.translateException(); } \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } \ - } while(false) - -#define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...) \ - do { \ - if(!doctest::getContextOptions()->no_throw) { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ - __LINE__, expr_str, "", __VA_ARGS__); \ - try { \ - DOCTEST_CAST_TO_VOID(expr) \ - } catch(...) { _DOCTEST_RB.translateException(); } \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } \ - } while(false) - -#define DOCTEST_ASSERT_NOTHROW(assert_type, ...) \ - do { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ - __LINE__, #__VA_ARGS__); \ - try { \ - DOCTEST_CAST_TO_VOID(__VA_ARGS__) \ - } catch(...) { _DOCTEST_RB.translateException(); } \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } while(false) - -// clang-format off -#define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, "") -#define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, "") -#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, "") - -#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, "", __VA_ARGS__) -#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, "", __VA_ARGS__) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, "", __VA_ARGS__) - -#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__) -#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__) -#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__) - -#define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__) -#define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__) -#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__) - -#define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__) -#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__) -#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__) - -#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS(expr); } while(false) -#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS(expr); } while(false) -#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS(expr); } while(false) -#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_AS(expr, ex); } while(false) -#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_AS(expr, ex); } while(false) -#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } while(false) -#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH(expr, with); } while(false) -#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH(expr, with); } while(false) -#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH(expr, with); } while(false) -#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); } while(false) -#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); } while(false) -#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); } while(false) -#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_NOTHROW(expr); } while(false) -#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_NOTHROW(expr); } while(false) -#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) do { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_NOTHROW(expr); } while(false) -// clang-format on - -#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_BINARY_ASSERT(assert_type, comp, ...) \ - do { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ - __LINE__, #__VA_ARGS__); \ - DOCTEST_WRAP_IN_TRY( \ - _DOCTEST_RB.binary_assert( \ - __VA_ARGS__)) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } while(false) - -#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ - do { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ - __LINE__, #__VA_ARGS__); \ - DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(__VA_ARGS__)) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } while(false) - -#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_BINARY_ASSERT(assert_type, comparison, ...) \ - doctest::detail::binary_assert( \ - doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__) - -#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ - doctest::detail::unary_assert(doctest::assertType::assert_type, __FILE__, __LINE__, \ - #__VA_ARGS__, __VA_ARGS__) - -#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, eq, __VA_ARGS__) -#define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, eq, __VA_ARGS__) -#define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, eq, __VA_ARGS__) -#define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, ne, __VA_ARGS__) -#define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, ne, __VA_ARGS__) -#define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, ne, __VA_ARGS__) -#define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, gt, __VA_ARGS__) -#define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, gt, __VA_ARGS__) -#define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, gt, __VA_ARGS__) -#define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lt, __VA_ARGS__) -#define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lt, __VA_ARGS__) -#define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lt, __VA_ARGS__) -#define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, ge, __VA_ARGS__) -#define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, ge, __VA_ARGS__) -#define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, ge, __VA_ARGS__) -#define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, le, __VA_ARGS__) -#define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, le, __VA_ARGS__) -#define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, le, __VA_ARGS__) - -#define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, __VA_ARGS__) -#define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, __VA_ARGS__) -#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, __VA_ARGS__) -#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, __VA_ARGS__) -#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, __VA_ARGS__) -#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, __VA_ARGS__) - -#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS - -#undef DOCTEST_WARN_THROWS -#undef DOCTEST_CHECK_THROWS -#undef DOCTEST_REQUIRE_THROWS -#undef DOCTEST_WARN_THROWS_AS -#undef DOCTEST_CHECK_THROWS_AS -#undef DOCTEST_REQUIRE_THROWS_AS -#undef DOCTEST_WARN_THROWS_WITH -#undef DOCTEST_CHECK_THROWS_WITH -#undef DOCTEST_REQUIRE_THROWS_WITH -#undef DOCTEST_WARN_THROWS_WITH_AS -#undef DOCTEST_CHECK_THROWS_WITH_AS -#undef DOCTEST_REQUIRE_THROWS_WITH_AS -#undef DOCTEST_WARN_NOTHROW -#undef DOCTEST_CHECK_NOTHROW -#undef DOCTEST_REQUIRE_NOTHROW - -#undef DOCTEST_WARN_THROWS_MESSAGE -#undef DOCTEST_CHECK_THROWS_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_MESSAGE -#undef DOCTEST_WARN_THROWS_AS_MESSAGE -#undef DOCTEST_CHECK_THROWS_AS_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_AS_MESSAGE -#undef DOCTEST_WARN_THROWS_WITH_MESSAGE -#undef DOCTEST_CHECK_THROWS_WITH_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_WITH_MESSAGE -#undef DOCTEST_WARN_THROWS_WITH_AS_MESSAGE -#undef DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE -#undef DOCTEST_WARN_NOTHROW_MESSAGE -#undef DOCTEST_CHECK_NOTHROW_MESSAGE -#undef DOCTEST_REQUIRE_NOTHROW_MESSAGE - -#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - -#define DOCTEST_WARN_THROWS(...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS(...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS(...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_AS(expr, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_AS(expr, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_WITH(expr, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_WITH(expr, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) (static_cast(0)) -#define DOCTEST_WARN_NOTHROW(...) (static_cast(0)) -#define DOCTEST_CHECK_NOTHROW(...) (static_cast(0)) -#define DOCTEST_REQUIRE_NOTHROW(...) (static_cast(0)) - -#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast(0)) -#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) (static_cast(0)) - -#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - -#undef DOCTEST_REQUIRE -#undef DOCTEST_REQUIRE_FALSE -#undef DOCTEST_REQUIRE_MESSAGE -#undef DOCTEST_REQUIRE_FALSE_MESSAGE -#undef DOCTEST_REQUIRE_EQ -#undef DOCTEST_REQUIRE_NE -#undef DOCTEST_REQUIRE_GT -#undef DOCTEST_REQUIRE_LT -#undef DOCTEST_REQUIRE_GE -#undef DOCTEST_REQUIRE_LE -#undef DOCTEST_REQUIRE_UNARY -#undef DOCTEST_REQUIRE_UNARY_FALSE - -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - -// ================================================================================================= -// == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING! == -// == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY! == -// ================================================================================================= -#else // DOCTEST_CONFIG_DISABLE - -#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ - namespace { \ - template \ - struct der : public base \ - { void f(); }; \ - } \ - template \ - inline void der::f() - -#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ - template \ - static inline void f() - -// for registering tests -#define DOCTEST_TEST_CASE(name) \ - DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) - -// for registering tests in classes -#define DOCTEST_TEST_CASE_CLASS(name) \ - DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) - -// for registering tests with a fixture -#define DOCTEST_TEST_CASE_FIXTURE(x, name) \ - DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x, \ - DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) - -// for converting types to strings without the header and demangling -#define DOCTEST_TYPE_TO_STRING(...) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -#define DOCTEST_TYPE_TO_STRING_IMPL(...) - -// for typed tests -#define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...) \ - template \ - inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() - -#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id) \ - template \ - inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() - -#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for subcases -#define DOCTEST_SUBCASE(name) - -// for a testsuite block -#define DOCTEST_TEST_SUITE(name) namespace - -// for starting a testsuite block -#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for ending a testsuite block -#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ - template \ - static inline doctest::String DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)(signature) - -#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) -#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) - -#define DOCTEST_INFO(...) (static_cast(0)) -#define DOCTEST_CAPTURE(x) (static_cast(0)) -#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) (static_cast(0)) -#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) (static_cast(0)) -#define DOCTEST_ADD_FAIL_AT(file, line, ...) (static_cast(0)) -#define DOCTEST_MESSAGE(...) (static_cast(0)) -#define DOCTEST_FAIL_CHECK(...) (static_cast(0)) -#define DOCTEST_FAIL(...) (static_cast(0)) - -#define DOCTEST_WARN(...) (static_cast(0)) -#define DOCTEST_CHECK(...) (static_cast(0)) -#define DOCTEST_REQUIRE(...) (static_cast(0)) -#define DOCTEST_WARN_FALSE(...) (static_cast(0)) -#define DOCTEST_CHECK_FALSE(...) (static_cast(0)) -#define DOCTEST_REQUIRE_FALSE(...) (static_cast(0)) - -#define DOCTEST_WARN_MESSAGE(cond, ...) (static_cast(0)) -#define DOCTEST_CHECK_MESSAGE(cond, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_MESSAGE(cond, ...) (static_cast(0)) -#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) (static_cast(0)) -#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) (static_cast(0)) - -#define DOCTEST_WARN_THROWS(...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS(...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS(...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_AS(expr, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_AS(expr, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_WITH(expr, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_WITH(expr, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) (static_cast(0)) -#define DOCTEST_WARN_NOTHROW(...) (static_cast(0)) -#define DOCTEST_CHECK_NOTHROW(...) (static_cast(0)) -#define DOCTEST_REQUIRE_NOTHROW(...) (static_cast(0)) - -#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) (static_cast(0)) -#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast(0)) -#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) (static_cast(0)) -#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) (static_cast(0)) -#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) (static_cast(0)) - -#define DOCTEST_WARN_EQ(...) (static_cast(0)) -#define DOCTEST_CHECK_EQ(...) (static_cast(0)) -#define DOCTEST_REQUIRE_EQ(...) (static_cast(0)) -#define DOCTEST_WARN_NE(...) (static_cast(0)) -#define DOCTEST_CHECK_NE(...) (static_cast(0)) -#define DOCTEST_REQUIRE_NE(...) (static_cast(0)) -#define DOCTEST_WARN_GT(...) (static_cast(0)) -#define DOCTEST_CHECK_GT(...) (static_cast(0)) -#define DOCTEST_REQUIRE_GT(...) (static_cast(0)) -#define DOCTEST_WARN_LT(...) (static_cast(0)) -#define DOCTEST_CHECK_LT(...) (static_cast(0)) -#define DOCTEST_REQUIRE_LT(...) (static_cast(0)) -#define DOCTEST_WARN_GE(...) (static_cast(0)) -#define DOCTEST_CHECK_GE(...) (static_cast(0)) -#define DOCTEST_REQUIRE_GE(...) (static_cast(0)) -#define DOCTEST_WARN_LE(...) (static_cast(0)) -#define DOCTEST_CHECK_LE(...) (static_cast(0)) -#define DOCTEST_REQUIRE_LE(...) (static_cast(0)) - -#define DOCTEST_WARN_UNARY(...) (static_cast(0)) -#define DOCTEST_CHECK_UNARY(...) (static_cast(0)) -#define DOCTEST_REQUIRE_UNARY(...) (static_cast(0)) -#define DOCTEST_WARN_UNARY_FALSE(...) (static_cast(0)) -#define DOCTEST_CHECK_UNARY_FALSE(...) (static_cast(0)) -#define DOCTEST_REQUIRE_UNARY_FALSE(...) (static_cast(0)) - -#endif // DOCTEST_CONFIG_DISABLE - -// clang-format off -// KEPT FOR BACKWARDS COMPATIBILITY - FORWARDING TO THE RIGHT MACROS -#define DOCTEST_FAST_WARN_EQ DOCTEST_WARN_EQ -#define DOCTEST_FAST_CHECK_EQ DOCTEST_CHECK_EQ -#define DOCTEST_FAST_REQUIRE_EQ DOCTEST_REQUIRE_EQ -#define DOCTEST_FAST_WARN_NE DOCTEST_WARN_NE -#define DOCTEST_FAST_CHECK_NE DOCTEST_CHECK_NE -#define DOCTEST_FAST_REQUIRE_NE DOCTEST_REQUIRE_NE -#define DOCTEST_FAST_WARN_GT DOCTEST_WARN_GT -#define DOCTEST_FAST_CHECK_GT DOCTEST_CHECK_GT -#define DOCTEST_FAST_REQUIRE_GT DOCTEST_REQUIRE_GT -#define DOCTEST_FAST_WARN_LT DOCTEST_WARN_LT -#define DOCTEST_FAST_CHECK_LT DOCTEST_CHECK_LT -#define DOCTEST_FAST_REQUIRE_LT DOCTEST_REQUIRE_LT -#define DOCTEST_FAST_WARN_GE DOCTEST_WARN_GE -#define DOCTEST_FAST_CHECK_GE DOCTEST_CHECK_GE -#define DOCTEST_FAST_REQUIRE_GE DOCTEST_REQUIRE_GE -#define DOCTEST_FAST_WARN_LE DOCTEST_WARN_LE -#define DOCTEST_FAST_CHECK_LE DOCTEST_CHECK_LE -#define DOCTEST_FAST_REQUIRE_LE DOCTEST_REQUIRE_LE - -#define DOCTEST_FAST_WARN_UNARY DOCTEST_WARN_UNARY -#define DOCTEST_FAST_CHECK_UNARY DOCTEST_CHECK_UNARY -#define DOCTEST_FAST_REQUIRE_UNARY DOCTEST_REQUIRE_UNARY -#define DOCTEST_FAST_WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE -#define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE -#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE - -#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id,__VA_ARGS__) -// clang-format on - -// BDD style macros -// clang-format off -#define DOCTEST_SCENARIO(name) DOCTEST_TEST_CASE(" Scenario: " name) -#define DOCTEST_SCENARIO_CLASS(name) DOCTEST_TEST_CASE_CLASS(" Scenario: " name) -#define DOCTEST_SCENARIO_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(" Scenario: " name, T, __VA_ARGS__) -#define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(" Scenario: " name, T, id) - -#define DOCTEST_GIVEN(name) DOCTEST_SUBCASE(" Given: " name) -#define DOCTEST_WHEN(name) DOCTEST_SUBCASE(" When: " name) -#define DOCTEST_AND_WHEN(name) DOCTEST_SUBCASE("And when: " name) -#define DOCTEST_THEN(name) DOCTEST_SUBCASE(" Then: " name) -#define DOCTEST_AND_THEN(name) DOCTEST_SUBCASE(" And: " name) -// clang-format on - -// == SHORT VERSIONS OF THE MACROS -#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES) - -#define TEST_CASE(name) DOCTEST_TEST_CASE(name) -#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name) -#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name) -#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__) -#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__) -#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id) -#define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__) -#define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__) -#define SUBCASE(name) DOCTEST_SUBCASE(name) -#define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators) -#define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name) -#define TEST_SUITE_END DOCTEST_TEST_SUITE_END -#define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) -#define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter) -#define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter) -#define INFO(...) DOCTEST_INFO(__VA_ARGS__) -#define CAPTURE(x) DOCTEST_CAPTURE(x) -#define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__) -#define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__) -#define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__) -#define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__) -#define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__) -#define FAIL(...) DOCTEST_FAIL(__VA_ARGS__) -#define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__) - -#define WARN(...) DOCTEST_WARN(__VA_ARGS__) -#define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__) -#define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__) -#define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__) -#define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__) -#define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__) -#define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__) -#define CHECK(...) DOCTEST_CHECK(__VA_ARGS__) -#define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__) -#define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__) -#define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__) -#define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__) -#define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__) -#define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__) -#define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__) -#define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__) -#define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__) -#define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__) -#define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__) -#define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__) -#define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__) - -#define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__) -#define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__) -#define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__) -#define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) -#define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) -#define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) -#define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__) -#define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__) -#define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__) -#define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__) -#define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) -#define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) -#define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) -#define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__) -#define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__) -#define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__) -#define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__) -#define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) -#define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) -#define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) -#define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__) - -#define SCENARIO(name) DOCTEST_SCENARIO(name) -#define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name) -#define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__) -#define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) -#define GIVEN(name) DOCTEST_GIVEN(name) -#define WHEN(name) DOCTEST_WHEN(name) -#define AND_WHEN(name) DOCTEST_AND_WHEN(name) -#define THEN(name) DOCTEST_THEN(name) -#define AND_THEN(name) DOCTEST_AND_THEN(name) - -#define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__) -#define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__) -#define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__) -#define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__) -#define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__) -#define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__) -#define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__) -#define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__) -#define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__) -#define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__) -#define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__) -#define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__) -#define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__) -#define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__) -#define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__) -#define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__) -#define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__) -#define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__) -#define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__) -#define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__) -#define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__) -#define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__) -#define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__) -#define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__) - -// KEPT FOR BACKWARDS COMPATIBILITY -#define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__) -#define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__) -#define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__) -#define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__) -#define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__) -#define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__) -#define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__) -#define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__) -#define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__) -#define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__) -#define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__) -#define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__) -#define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__) -#define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__) -#define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__) -#define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__) -#define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__) -#define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__) - -#define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__) -#define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__) -#define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__) -#define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__) -#define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__) -#define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__) - -#define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__) - -#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES - -#if !defined(DOCTEST_CONFIG_DISABLE) - -// this is here to clear the 'current test suite' for the current translation unit - at the top -DOCTEST_TEST_SUITE_END(); - -// add stringification for primitive/fundamental types -namespace doctest { namespace detail { - DOCTEST_TYPE_TO_STRING_IMPL(bool) - DOCTEST_TYPE_TO_STRING_IMPL(float) - DOCTEST_TYPE_TO_STRING_IMPL(double) - DOCTEST_TYPE_TO_STRING_IMPL(long double) - DOCTEST_TYPE_TO_STRING_IMPL(char) - DOCTEST_TYPE_TO_STRING_IMPL(signed char) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned char) -#if !DOCTEST_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - DOCTEST_TYPE_TO_STRING_IMPL(wchar_t) -#endif // not MSVC or wchar_t support enabled - DOCTEST_TYPE_TO_STRING_IMPL(short int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned short int) - DOCTEST_TYPE_TO_STRING_IMPL(int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned int) - DOCTEST_TYPE_TO_STRING_IMPL(long int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned long int) - DOCTEST_TYPE_TO_STRING_IMPL(long long int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned long long int) -}} // namespace doctest::detail - -#endif // DOCTEST_CONFIG_DISABLE - -DOCTEST_CLANG_SUPPRESS_WARNING_POP -DOCTEST_MSVC_SUPPRESS_WARNING_POP -DOCTEST_GCC_SUPPRESS_WARNING_POP - -#endif // DOCTEST_LIBRARY_INCLUDED - -#ifndef DOCTEST_SINGLE_HEADER -#define DOCTEST_SINGLE_HEADER -#endif // DOCTEST_SINGLE_HEADER - -#if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER) - -#ifndef DOCTEST_SINGLE_HEADER -#include "doctest_fwd.h" -#endif // DOCTEST_SINGLE_HEADER - -DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros") - -#ifndef DOCTEST_LIBRARY_IMPLEMENTATION -#define DOCTEST_LIBRARY_IMPLEMENTATION - -DOCTEST_CLANG_SUPPRESS_WARNING_POP - -DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path") - -DOCTEST_GCC_SUPPRESS_WARNING_PUSH -DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") -DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") -DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") -DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch") -DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum") -DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations") -DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") -DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance") -DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") -DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute") - -DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration -DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data -DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression -DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated -DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant -DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled -DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified -DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal -DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch -DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding in structs -DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe -DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C -DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation stuff -DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning) -// static analysis -DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept' -DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable -DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ... -DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtor... -DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum' - -DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN - -// required includes - will go only in one translation unit! -#include -#include -#include -// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37 -#ifdef __BORLANDC__ -#include -#endif // __BORLANDC__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef DOCTEST_PLATFORM_MAC -#include -#include -#include -#endif // DOCTEST_PLATFORM_MAC - -#ifdef DOCTEST_PLATFORM_WINDOWS - -// defines for a leaner windows.h -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -// not sure what AfxWin.h is for - here I do what Catch does -#ifdef __AFXDLL -#include -#else -#include -#endif -#include - -#else // DOCTEST_PLATFORM_WINDOWS - -#include -#include - -#endif // DOCTEST_PLATFORM_WINDOWS - -// this is a fix for https://github.com/onqtam/doctest/issues/348 -// https://mail.gnome.org/archives/xml/2012-January/msg00000.html -#if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO) -#define STDOUT_FILENO fileno(stdout) -#endif // HAVE_UNISTD_H - -DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END - -// counts the number of elements in a C array -#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) - -#ifdef DOCTEST_CONFIG_DISABLE -#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_disabled -#else // DOCTEST_CONFIG_DISABLE -#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_not_disabled -#endif // DOCTEST_CONFIG_DISABLE - -#ifndef DOCTEST_CONFIG_OPTIONS_PREFIX -#define DOCTEST_CONFIG_OPTIONS_PREFIX "dt-" -#endif - -#ifndef DOCTEST_THREAD_LOCAL -#define DOCTEST_THREAD_LOCAL thread_local -#endif - -#ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES -#define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32 -#endif - -#ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE -#define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64 -#endif - -#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS -#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX -#else -#define DOCTEST_OPTIONS_PREFIX_DISPLAY "" -#endif - -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -#define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS -#endif - -namespace doctest { - -bool is_running_in_test = false; - -namespace { - using namespace detail; - // case insensitive strcmp - int stricmp(const char* a, const char* b) { - for(;; a++, b++) { - const int d = tolower(*a) - tolower(*b); - if(d != 0 || !*a) - return d; - } - } - - template - String fpToString(T value, int precision) { - std::ostringstream oss; - oss << std::setprecision(precision) << std::fixed << value; - std::string d = oss.str(); - size_t i = d.find_last_not_of('0'); - if(i != std::string::npos && i != d.size() - 1) { - if(d[i] == '.') - i++; - d = d.substr(0, i + 1); - } - return d.c_str(); - } - - struct Endianness - { - enum Arch - { - Big, - Little - }; - - static Arch which() { - int x = 1; - // casting any data pointer to char* is allowed - auto ptr = reinterpret_cast(&x); - if(*ptr) - return Little; - return Big; - } - }; -} // namespace - -namespace detail { - void my_memcpy(void* dest, const void* src, unsigned num) { memcpy(dest, src, num); } - - String rawMemoryToString(const void* object, unsigned size) { - // Reverse order for little endian architectures - int i = 0, end = static_cast(size), inc = 1; - if(Endianness::which() == Endianness::Little) { - i = end - 1; - end = inc = -1; - } - - unsigned const char* bytes = static_cast(object); - std::ostringstream oss; - oss << "0x" << std::setfill('0') << std::hex; - for(; i != end; i += inc) - oss << std::setw(2) << static_cast(bytes[i]); - return oss.str().c_str(); - } - - DOCTEST_THREAD_LOCAL std::ostringstream g_oss; // NOLINT(cert-err58-cpp) - - std::ostream* getTlsOss() { - g_oss.clear(); // there shouldn't be anything worth clearing in the flags - g_oss.str(""); // the slow way of resetting a string stream - //g_oss.seekp(0); // optimal reset - as seen here: https://stackoverflow.com/a/624291/3162383 - return &g_oss; - } - - String getTlsOssResult() { - //g_oss << std::ends; // needed - as shown here: https://stackoverflow.com/a/624291/3162383 - return g_oss.str().c_str(); - } - -#ifndef DOCTEST_CONFIG_DISABLE - -namespace timer_large_integer -{ - -#if defined(DOCTEST_PLATFORM_WINDOWS) - typedef ULONGLONG type; -#else // DOCTEST_PLATFORM_WINDOWS - using namespace std; - typedef uint64_t type; -#endif // DOCTEST_PLATFORM_WINDOWS -} - -typedef timer_large_integer::type ticks_t; - -#ifdef DOCTEST_CONFIG_GETCURRENTTICKS - ticks_t getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); } -#elif defined(DOCTEST_PLATFORM_WINDOWS) - ticks_t getCurrentTicks() { - static LARGE_INTEGER hz = {0}, hzo = {0}; - if(!hz.QuadPart) { - QueryPerformanceFrequency(&hz); - QueryPerformanceCounter(&hzo); - } - LARGE_INTEGER t; - QueryPerformanceCounter(&t); - return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart; - } -#else // DOCTEST_PLATFORM_WINDOWS - ticks_t getCurrentTicks() { - timeval t; - gettimeofday(&t, nullptr); - return static_cast(t.tv_sec) * 1000000 + static_cast(t.tv_usec); - } -#endif // DOCTEST_PLATFORM_WINDOWS - - struct Timer - { - void start() { m_ticks = getCurrentTicks(); } - unsigned int getElapsedMicroseconds() const { - return static_cast(getCurrentTicks() - m_ticks); - } - //unsigned int getElapsedMilliseconds() const { - // return static_cast(getElapsedMicroseconds() / 1000); - //} - double getElapsedSeconds() const { return static_cast(getCurrentTicks() - m_ticks) / 1000000.0; } - - private: - ticks_t m_ticks = 0; - }; - -#ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS - template - using AtomicOrMultiLaneAtomic = std::atomic; -#else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS - // Provides a multilane implementation of an atomic variable that supports add, sub, load, - // store. Instead of using a single atomic variable, this splits up into multiple ones, - // each sitting on a separate cache line. The goal is to provide a speedup when most - // operations are modifying. It achieves this with two properties: - // - // * Multiple atomics are used, so chance of congestion from the same atomic is reduced. - // * Each atomic sits on a separate cache line, so false sharing is reduced. - // - // The disadvantage is that there is a small overhead due to the use of TLS, and load/store - // is slower because all atomics have to be accessed. - template - class MultiLaneAtomic - { - struct CacheLineAlignedAtomic - { - std::atomic atomic{}; - char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic)]; - }; - CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES]; - - static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE, - "guarantee one atomic takes exactly one cache line"); - - public: - T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; } - - T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); } - - T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { - return myAtomic().fetch_add(arg, order); - } - - T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { - return myAtomic().fetch_sub(arg, order); - } - - operator T() const DOCTEST_NOEXCEPT { return load(); } - - T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT { - auto result = T(); - for(auto const& c : m_atomics) { - result += c.atomic.load(order); - } - return result; - } - - T operator=(T desired) DOCTEST_NOEXCEPT { - store(desired); - return desired; - } - - void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { - // first value becomes desired", all others become 0. - for(auto& c : m_atomics) { - c.atomic.store(desired, order); - desired = {}; - } - } - - private: - // Each thread has a different atomic that it operates on. If more than NumLanes threads - // use this, some will use the same atomic. So performance will degrate a bit, but still - // everything will work. - // - // The logic here is a bit tricky. The call should be as fast as possible, so that there - // is minimal to no overhead in determining the correct atomic for the current thread. - // - // 1. A global static counter laneCounter counts continuously up. - // 2. Each successive thread will use modulo operation of that counter so it gets an atomic - // assigned in a round-robin fashion. - // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with - // little overhead. - std::atomic& myAtomic() DOCTEST_NOEXCEPT { - static std::atomic laneCounter; - DOCTEST_THREAD_LOCAL size_t tlsLaneIdx = - laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES; - - return m_atomics[tlsLaneIdx].atomic; - } - }; - - template - using AtomicOrMultiLaneAtomic = MultiLaneAtomic; -#endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS - - // this holds both parameters from the command line and runtime data for tests - struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats - { - AtomicOrMultiLaneAtomic numAssertsCurrentTest_atomic; - AtomicOrMultiLaneAtomic numAssertsFailedCurrentTest_atomic; - - std::vector> filters = decltype(filters)(9); // 9 different filters - - std::vector reporters_currently_used; - - assert_handler ah = nullptr; - - Timer timer; - - std::vector stringifiedContexts; // logging from INFO() due to an exception - - // stuff for subcases - std::vector subcasesStack; - std::set subcasesPassed; - int subcasesCurrentMaxLevel; - bool should_reenter; - std::atomic shouldLogCurrentException; - - void resetRunData() { - numTestCases = 0; - numTestCasesPassingFilters = 0; - numTestSuitesPassingFilters = 0; - numTestCasesFailed = 0; - numAsserts = 0; - numAssertsFailed = 0; - numAssertsCurrentTest = 0; - numAssertsFailedCurrentTest = 0; - } - - void finalizeTestCaseData() { - seconds = timer.getElapsedSeconds(); - - // update the non-atomic counters - numAsserts += numAssertsCurrentTest_atomic; - numAssertsFailed += numAssertsFailedCurrentTest_atomic; - numAssertsCurrentTest = numAssertsCurrentTest_atomic; - numAssertsFailedCurrentTest = numAssertsFailedCurrentTest_atomic; - - if(numAssertsFailedCurrentTest) - failure_flags |= TestCaseFailureReason::AssertFailure; - - if(Approx(currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 && - Approx(seconds).epsilon(DBL_EPSILON) > currentTest->m_timeout) - failure_flags |= TestCaseFailureReason::Timeout; - - if(currentTest->m_should_fail) { - if(failure_flags) { - failure_flags |= TestCaseFailureReason::ShouldHaveFailedAndDid; - } else { - failure_flags |= TestCaseFailureReason::ShouldHaveFailedButDidnt; - } - } else if(failure_flags && currentTest->m_may_fail) { - failure_flags |= TestCaseFailureReason::CouldHaveFailedAndDid; - } else if(currentTest->m_expected_failures > 0) { - if(numAssertsFailedCurrentTest == currentTest->m_expected_failures) { - failure_flags |= TestCaseFailureReason::FailedExactlyNumTimes; - } else { - failure_flags |= TestCaseFailureReason::DidntFailExactlyNumTimes; - } - } - - bool ok_to_fail = (TestCaseFailureReason::ShouldHaveFailedAndDid & failure_flags) || - (TestCaseFailureReason::CouldHaveFailedAndDid & failure_flags) || - (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags); - - // if any subcase has failed - the whole test case has failed - if(failure_flags && !ok_to_fail) - numTestCasesFailed++; - } - }; - - ContextState* g_cs = nullptr; - - // used to avoid locks for the debug output - // TODO: figure out if this is indeed necessary/correct - seems like either there still - // could be a race or that there wouldn't be a race even if using the context directly - DOCTEST_THREAD_LOCAL bool g_no_colors; - -#endif // DOCTEST_CONFIG_DISABLE -} // namespace detail - -void String::setOnHeap() { *reinterpret_cast(&buf[last]) = 128; } -void String::setLast(unsigned in) { buf[last] = char(in); } - -void String::copy(const String& other) { - using namespace std; - if(other.isOnStack()) { - memcpy(buf, other.buf, len); - } else { - setOnHeap(); - data.size = other.data.size; - data.capacity = data.size + 1; - data.ptr = new char[data.capacity]; - memcpy(data.ptr, other.data.ptr, data.size + 1); - } -} - -String::String() { - buf[0] = '\0'; - setLast(); -} - -String::~String() { - if(!isOnStack()) - delete[] data.ptr; - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) -} - -String::String(const char* in) - : String(in, strlen(in)) {} - -String::String(const char* in, unsigned in_size) { - using namespace std; - if(in_size <= last) { - memcpy(buf, in, in_size); - buf[in_size] = '\0'; - setLast(last - in_size); - } else { - setOnHeap(); - data.size = in_size; - data.capacity = data.size + 1; - data.ptr = new char[data.capacity]; - memcpy(data.ptr, in, in_size); - data.ptr[in_size] = '\0'; - } -} - -String::String(const String& other) { copy(other); } - -String& String::operator=(const String& other) { - if(this != &other) { - if(!isOnStack()) - delete[] data.ptr; - - copy(other); - } - - return *this; -} - -String& String::operator+=(const String& other) { - const unsigned my_old_size = size(); - const unsigned other_size = other.size(); - const unsigned total_size = my_old_size + other_size; - using namespace std; - if(isOnStack()) { - if(total_size < len) { - // append to the current stack space - memcpy(buf + my_old_size, other.c_str(), other_size + 1); - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - setLast(last - total_size); - } else { - // alloc new chunk - char* temp = new char[total_size + 1]; - // copy current data to new location before writing in the union - memcpy(temp, buf, my_old_size); // skip the +1 ('\0') for speed - // update data in union - setOnHeap(); - data.size = total_size; - data.capacity = data.size + 1; - data.ptr = temp; - // transfer the rest of the data - memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); - } - } else { - if(data.capacity > total_size) { - // append to the current heap block - data.size = total_size; - memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); - } else { - // resize - data.capacity *= 2; - if(data.capacity <= total_size) - data.capacity = total_size + 1; - // alloc new chunk - char* temp = new char[data.capacity]; - // copy current data to new location before releasing it - memcpy(temp, data.ptr, my_old_size); // skip the +1 ('\0') for speed - // release old chunk - delete[] data.ptr; - // update the rest of the union members - data.size = total_size; - data.ptr = temp; - // transfer the rest of the data - memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); - } - } - - return *this; -} - -// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) -String String::operator+(const String& other) const { return String(*this) += other; } - -String::String(String&& other) { - using namespace std; - memcpy(buf, other.buf, len); - other.buf[0] = '\0'; - other.setLast(); -} - -String& String::operator=(String&& other) { - using namespace std; - if(this != &other) { - if(!isOnStack()) - delete[] data.ptr; - memcpy(buf, other.buf, len); - other.buf[0] = '\0'; - other.setLast(); - } - return *this; -} - -char String::operator[](unsigned i) const { - return const_cast(this)->operator[](i); // NOLINT -} - -char& String::operator[](unsigned i) { - if(isOnStack()) - return reinterpret_cast(buf)[i]; - return data.ptr[i]; -} - -DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized") -unsigned String::size() const { - if(isOnStack()) - return last - (unsigned(buf[last]) & 31); // using "last" would work only if "len" is 32 - return data.size; -} -DOCTEST_GCC_SUPPRESS_WARNING_POP - -unsigned String::capacity() const { - if(isOnStack()) - return len; - return data.capacity; -} - -int String::compare(const char* other, bool no_case) const { - if(no_case) - return doctest::stricmp(c_str(), other); - return std::strcmp(c_str(), other); -} - -int String::compare(const String& other, bool no_case) const { - return compare(other.c_str(), no_case); -} - -// clang-format off -bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } -bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } -bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; } -bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; } -bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; } -bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; } -// clang-format on - -std::ostream& operator<<(std::ostream& s, const String& in) { return s << in.c_str(); } - -namespace { - void color_to_stream(std::ostream&, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;) -} // namespace - -namespace Color { - std::ostream& operator<<(std::ostream& s, Color::Enum code) { - color_to_stream(s, code); - return s; - } -} // namespace Color - -// clang-format off -const char* assertString(assertType::Enum at) { - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4062) // enum 'x' in switch of enum 'y' is not handled - switch(at) { //!OCLINT missing default in switch statements - case assertType::DT_WARN : return "WARN"; - case assertType::DT_CHECK : return "CHECK"; - case assertType::DT_REQUIRE : return "REQUIRE"; - - case assertType::DT_WARN_FALSE : return "WARN_FALSE"; - case assertType::DT_CHECK_FALSE : return "CHECK_FALSE"; - case assertType::DT_REQUIRE_FALSE : return "REQUIRE_FALSE"; - - case assertType::DT_WARN_THROWS : return "WARN_THROWS"; - case assertType::DT_CHECK_THROWS : return "CHECK_THROWS"; - case assertType::DT_REQUIRE_THROWS : return "REQUIRE_THROWS"; - - case assertType::DT_WARN_THROWS_AS : return "WARN_THROWS_AS"; - case assertType::DT_CHECK_THROWS_AS : return "CHECK_THROWS_AS"; - case assertType::DT_REQUIRE_THROWS_AS : return "REQUIRE_THROWS_AS"; - - case assertType::DT_WARN_THROWS_WITH : return "WARN_THROWS_WITH"; - case assertType::DT_CHECK_THROWS_WITH : return "CHECK_THROWS_WITH"; - case assertType::DT_REQUIRE_THROWS_WITH : return "REQUIRE_THROWS_WITH"; - - case assertType::DT_WARN_THROWS_WITH_AS : return "WARN_THROWS_WITH_AS"; - case assertType::DT_CHECK_THROWS_WITH_AS : return "CHECK_THROWS_WITH_AS"; - case assertType::DT_REQUIRE_THROWS_WITH_AS : return "REQUIRE_THROWS_WITH_AS"; - - case assertType::DT_WARN_NOTHROW : return "WARN_NOTHROW"; - case assertType::DT_CHECK_NOTHROW : return "CHECK_NOTHROW"; - case assertType::DT_REQUIRE_NOTHROW : return "REQUIRE_NOTHROW"; - - case assertType::DT_WARN_EQ : return "WARN_EQ"; - case assertType::DT_CHECK_EQ : return "CHECK_EQ"; - case assertType::DT_REQUIRE_EQ : return "REQUIRE_EQ"; - case assertType::DT_WARN_NE : return "WARN_NE"; - case assertType::DT_CHECK_NE : return "CHECK_NE"; - case assertType::DT_REQUIRE_NE : return "REQUIRE_NE"; - case assertType::DT_WARN_GT : return "WARN_GT"; - case assertType::DT_CHECK_GT : return "CHECK_GT"; - case assertType::DT_REQUIRE_GT : return "REQUIRE_GT"; - case assertType::DT_WARN_LT : return "WARN_LT"; - case assertType::DT_CHECK_LT : return "CHECK_LT"; - case assertType::DT_REQUIRE_LT : return "REQUIRE_LT"; - case assertType::DT_WARN_GE : return "WARN_GE"; - case assertType::DT_CHECK_GE : return "CHECK_GE"; - case assertType::DT_REQUIRE_GE : return "REQUIRE_GE"; - case assertType::DT_WARN_LE : return "WARN_LE"; - case assertType::DT_CHECK_LE : return "CHECK_LE"; - case assertType::DT_REQUIRE_LE : return "REQUIRE_LE"; - - case assertType::DT_WARN_UNARY : return "WARN_UNARY"; - case assertType::DT_CHECK_UNARY : return "CHECK_UNARY"; - case assertType::DT_REQUIRE_UNARY : return "REQUIRE_UNARY"; - case assertType::DT_WARN_UNARY_FALSE : return "WARN_UNARY_FALSE"; - case assertType::DT_CHECK_UNARY_FALSE : return "CHECK_UNARY_FALSE"; - case assertType::DT_REQUIRE_UNARY_FALSE : return "REQUIRE_UNARY_FALSE"; - } - DOCTEST_MSVC_SUPPRESS_WARNING_POP - return ""; -} -// clang-format on - -const char* failureString(assertType::Enum at) { - if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional - return "WARNING"; - if(at & assertType::is_check) //!OCLINT bitwise operator in conditional - return "ERROR"; - if(at & assertType::is_require) //!OCLINT bitwise operator in conditional - return "FATAL ERROR"; - return ""; -} - -DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") -DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") -// depending on the current options this will remove the path of filenames -const char* skipPathFromFilename(const char* file) { -#ifndef DOCTEST_CONFIG_DISABLE - if(getContextOptions()->no_path_in_filenames) { - auto back = std::strrchr(file, '\\'); - auto forward = std::strrchr(file, '/'); - if(back || forward) { - if(back > forward) - forward = back; - return forward + 1; - } - } -#endif // DOCTEST_CONFIG_DISABLE - return file; -} -DOCTEST_CLANG_SUPPRESS_WARNING_POP -DOCTEST_GCC_SUPPRESS_WARNING_POP - -bool SubcaseSignature::operator<(const SubcaseSignature& other) const { - if(m_line != other.m_line) - return m_line < other.m_line; - if(std::strcmp(m_file, other.m_file) != 0) - return std::strcmp(m_file, other.m_file) < 0; - return m_name.compare(other.m_name) < 0; -} - -IContextScope::IContextScope() = default; -IContextScope::~IContextScope() = default; - -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -String toString(char* in) { return toString(static_cast(in)); } -// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) -String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -String toString(bool in) { return in ? "true" : "false"; } -String toString(float in) { return fpToString(in, 5) + "f"; } -String toString(double in) { return fpToString(in, 10); } -String toString(double long in) { return fpToString(in, 15); } - -#define DOCTEST_TO_STRING_OVERLOAD(type, fmt) \ - String toString(type in) { \ - char buf[64]; \ - std::sprintf(buf, fmt, in); \ - return buf; \ - } - -DOCTEST_TO_STRING_OVERLOAD(char, "%d") -DOCTEST_TO_STRING_OVERLOAD(char signed, "%d") -DOCTEST_TO_STRING_OVERLOAD(char unsigned, "%u") -DOCTEST_TO_STRING_OVERLOAD(int short, "%d") -DOCTEST_TO_STRING_OVERLOAD(int short unsigned, "%u") -DOCTEST_TO_STRING_OVERLOAD(int, "%d") -DOCTEST_TO_STRING_OVERLOAD(unsigned, "%u") -DOCTEST_TO_STRING_OVERLOAD(int long, "%ld") -DOCTEST_TO_STRING_OVERLOAD(int long unsigned, "%lu") -DOCTEST_TO_STRING_OVERLOAD(int long long, "%lld") -DOCTEST_TO_STRING_OVERLOAD(int long long unsigned, "%llu") - -String toString(std::nullptr_t) { return "NULL"; } - -#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) -// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 -String toString(const std::string& in) { return in.c_str(); } -#endif // VS 2019 - -Approx::Approx(double value) - : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100) - , m_scale(1.0) - , m_value(value) {} - -Approx Approx::operator()(double value) const { - Approx approx(value); - approx.epsilon(m_epsilon); - approx.scale(m_scale); - return approx; -} - -Approx& Approx::epsilon(double newEpsilon) { - m_epsilon = newEpsilon; - return *this; -} -Approx& Approx::scale(double newScale) { - m_scale = newScale; - return *this; -} - -bool operator==(double lhs, const Approx& rhs) { - // Thanks to Richard Harris for his help refining this formula - return std::fabs(lhs - rhs.m_value) < - rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); -} -bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); } -bool operator!=(double lhs, const Approx& rhs) { return !operator==(lhs, rhs); } -bool operator!=(const Approx& lhs, double rhs) { return !operator==(rhs, lhs); } -bool operator<=(double lhs, const Approx& rhs) { return lhs < rhs.m_value || lhs == rhs; } -bool operator<=(const Approx& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; } -bool operator>=(double lhs, const Approx& rhs) { return lhs > rhs.m_value || lhs == rhs; } -bool operator>=(const Approx& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; } -bool operator<(double lhs, const Approx& rhs) { return lhs < rhs.m_value && lhs != rhs; } -bool operator<(const Approx& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; } -bool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs != rhs; } -bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; } - -String toString(const Approx& in) { - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - return String("Approx( ") + doctest::toString(in.m_value) + " )"; -} -const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); } - -} // namespace doctest - -#ifdef DOCTEST_CONFIG_DISABLE -namespace doctest { -Context::Context(int, const char* const*) {} -Context::~Context() = default; -void Context::applyCommandLine(int, const char* const*) {} -void Context::addFilter(const char*, const char*) {} -void Context::clearFilters() {} -void Context::setOption(const char*, int) {} -void Context::setOption(const char*, const char*) {} -bool Context::shouldExit() { return false; } -void Context::setAsDefaultForAssertsOutOfTestCases() {} -void Context::setAssertHandler(detail::assert_handler) {} -int Context::run() { return 0; } - -IReporter::~IReporter() = default; - -int IReporter::get_num_active_contexts() { return 0; } -const IContextScope* const* IReporter::get_active_contexts() { return nullptr; } -int IReporter::get_num_stringified_contexts() { return 0; } -const String* IReporter::get_stringified_contexts() { return nullptr; } - -int registerReporter(const char*, int, IReporter*) { return 0; } - -} // namespace doctest -#else // DOCTEST_CONFIG_DISABLE - -#if !defined(DOCTEST_CONFIG_COLORS_NONE) -#if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI) -#ifdef DOCTEST_PLATFORM_WINDOWS -#define DOCTEST_CONFIG_COLORS_WINDOWS -#else // linux -#define DOCTEST_CONFIG_COLORS_ANSI -#endif // platform -#endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI -#endif // DOCTEST_CONFIG_COLORS_NONE - -namespace doctest_detail_test_suite_ns { -// holds the current test suite -doctest::detail::TestSuite& getCurrentTestSuite() { - static doctest::detail::TestSuite data{}; - return data; -} -} // namespace doctest_detail_test_suite_ns - -namespace doctest { -namespace { - // the int (priority) is part of the key for automatic sorting - sadly one can register a - // reporter with a duplicate name and a different priority but hopefully that won't happen often :| - typedef std::map, reporterCreatorFunc> reporterMap; - - reporterMap& getReporters() { - static reporterMap data; - return data; - } - reporterMap& getListeners() { - static reporterMap data; - return data; - } -} // namespace -namespace detail { -#define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...) \ - for(auto& curr_rep : g_cs->reporters_currently_used) \ - curr_rep->function(__VA_ARGS__) - - bool checkIfShouldThrow(assertType::Enum at) { - if(at & assertType::is_require) //!OCLINT bitwise operator in conditional - return true; - - if((at & assertType::is_check) //!OCLINT bitwise operator in conditional - && getContextOptions()->abort_after > 0 && - (g_cs->numAssertsFailed + g_cs->numAssertsFailedCurrentTest_atomic) >= - getContextOptions()->abort_after) - return true; - - return false; - } - -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - DOCTEST_NORETURN void throwException() { - g_cs->shouldLogCurrentException = false; - throw TestFailureException(); - } // NOLINT(cert-err60-cpp) -#else // DOCTEST_CONFIG_NO_EXCEPTIONS - void throwException() {} -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS -} // namespace detail - -namespace { - using namespace detail; - // matching of a string against a wildcard mask (case sensitivity configurable) taken from - // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing - int wildcmp(const char* str, const char* wild, bool caseSensitive) { - const char* cp = str; - const char* mp = wild; - - while((*str) && (*wild != '*')) { - if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && - (*wild != '?')) { - return 0; - } - wild++; - str++; - } - - while(*str) { - if(*wild == '*') { - if(!*++wild) { - return 1; - } - mp = wild; - cp = str + 1; - } else if((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) || - (*wild == '?')) { - wild++; - str++; - } else { - wild = mp; //!OCLINT parameter reassignment - str = cp++; //!OCLINT parameter reassignment - } - } - - while(*wild == '*') { - wild++; - } - return !*wild; - } - - //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html - //unsigned hashStr(unsigned const char* str) { - // unsigned long hash = 5381; - // char c; - // while((c = *str++)) - // hash = ((hash << 5) + hash) + c; // hash * 33 + c - // return hash; - //} - - // checks if the name matches any of the filters (and can be configured what to do when empty) - bool matchesAny(const char* name, const std::vector& filters, bool matchEmpty, - bool caseSensitive) { - if(filters.empty() && matchEmpty) - return true; - for(auto& curr : filters) - if(wildcmp(name, curr.c_str(), caseSensitive)) - return true; - return false; - } -} // namespace -namespace detail { - - Subcase::Subcase(const String& name, const char* file, int line) - : m_signature({name, file, line}) { - auto* s = g_cs; - - // check subcase filters - if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) { - if(!matchesAny(m_signature.m_name.c_str(), s->filters[6], true, s->case_sensitive)) - return; - if(matchesAny(m_signature.m_name.c_str(), s->filters[7], false, s->case_sensitive)) - return; - } - - // if a Subcase on the same level has already been entered - if(s->subcasesStack.size() < size_t(s->subcasesCurrentMaxLevel)) { - s->should_reenter = true; - return; - } - - // push the current signature to the stack so we can check if the - // current stack + the current new subcase have been traversed - s->subcasesStack.push_back(m_signature); - if(s->subcasesPassed.count(s->subcasesStack) != 0) { - // pop - revert to previous stack since we've already passed this - s->subcasesStack.pop_back(); - return; - } - - s->subcasesCurrentMaxLevel = s->subcasesStack.size(); - m_entered = true; - - DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); - } - - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - - Subcase::~Subcase() { - if(m_entered) { - // only mark the subcase stack as passed if no subcases have been skipped - if(g_cs->should_reenter == false) - g_cs->subcasesPassed.insert(g_cs->subcasesStack); - g_cs->subcasesStack.pop_back(); - -#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) - if(std::uncaught_exceptions() > 0 -#else - if(std::uncaught_exception() -#endif - && g_cs->shouldLogCurrentException) { - DOCTEST_ITERATE_THROUGH_REPORTERS( - test_case_exception, {"exception thrown in subcase - will translate later " - "when the whole test case has been exited (cannot " - "translate while there is an active exception)", - false}); - g_cs->shouldLogCurrentException = false; - } - DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); - } - } - - DOCTEST_CLANG_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - DOCTEST_MSVC_SUPPRESS_WARNING_POP - - Subcase::operator bool() const { return m_entered; } - - Result::Result(bool passed, const String& decomposition) - : m_passed(passed) - , m_decomp(decomposition) {} - - ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at) - : m_at(at) {} - - TestSuite& TestSuite::operator*(const char* in) { - m_test_suite = in; - // clear state - m_description = nullptr; - m_skip = false; - m_no_breaks = false; - m_no_output = false; - m_may_fail = false; - m_should_fail = false; - m_expected_failures = 0; - m_timeout = 0; - return *this; - } - - TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, - const char* type, int template_id) { - m_file = file; - m_line = line; - m_name = nullptr; // will be later overridden in operator* - m_test_suite = test_suite.m_test_suite; - m_description = test_suite.m_description; - m_skip = test_suite.m_skip; - m_no_breaks = test_suite.m_no_breaks; - m_no_output = test_suite.m_no_output; - m_may_fail = test_suite.m_may_fail; - m_should_fail = test_suite.m_should_fail; - m_expected_failures = test_suite.m_expected_failures; - m_timeout = test_suite.m_timeout; - - m_test = test; - m_type = type; - m_template_id = template_id; - } - - TestCase::TestCase(const TestCase& other) - : TestCaseData() { - *this = other; - } - - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function - DOCTEST_MSVC_SUPPRESS_WARNING(26437) // Do not slice - TestCase& TestCase::operator=(const TestCase& other) { - static_cast(*this) = static_cast(other); - - m_test = other.m_test; - m_type = other.m_type; - m_template_id = other.m_template_id; - m_full_name = other.m_full_name; - - if(m_template_id != -1) - m_name = m_full_name.c_str(); - return *this; - } - DOCTEST_MSVC_SUPPRESS_WARNING_POP - - TestCase& TestCase::operator*(const char* in) { - m_name = in; - // make a new name with an appended type for templated test case - if(m_template_id != -1) { - m_full_name = String(m_name) + m_type; - // redirect the name to point to the newly constructed full name - m_name = m_full_name.c_str(); - } - return *this; - } - - bool TestCase::operator<(const TestCase& other) const { - // this will be used only to differentiate between test cases - not relevant for sorting - if(m_line != other.m_line) - return m_line < other.m_line; - const int name_cmp = strcmp(m_name, other.m_name); - if(name_cmp != 0) - return name_cmp < 0; - const int file_cmp = m_file.compare(other.m_file); - if(file_cmp != 0) - return file_cmp < 0; - return m_template_id < other.m_template_id; - } - - // all the registered tests - std::set& getRegisteredTests() { - static std::set data; - return data; - } -} // namespace detail -namespace { - using namespace detail; - // for sorting tests by file/line - bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) { - // this is needed because MSVC gives different case for drive letters - // for __FILE__ when evaluated in a header and a source file - const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC)); - if(res != 0) - return res < 0; - if(lhs->m_line != rhs->m_line) - return lhs->m_line < rhs->m_line; - return lhs->m_template_id < rhs->m_template_id; - } - - // for sorting tests by suite/file/line - bool suiteOrderComparator(const TestCase* lhs, const TestCase* rhs) { - const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite); - if(res != 0) - return res < 0; - return fileOrderComparator(lhs, rhs); - } - - // for sorting tests by name/suite/file/line - bool nameOrderComparator(const TestCase* lhs, const TestCase* rhs) { - const int res = std::strcmp(lhs->m_name, rhs->m_name); - if(res != 0) - return res < 0; - return suiteOrderComparator(lhs, rhs); - } - -#ifdef DOCTEST_CONFIG_COLORS_WINDOWS - HANDLE g_stdoutHandle; - WORD g_origFgAttrs; - WORD g_origBgAttrs; - bool g_attrsInitted = false; - - int colors_init() { - if(!g_attrsInitted) { - g_stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); - g_attrsInitted = true; - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo(g_stdoutHandle, &csbiInfo); - g_origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | - BACKGROUND_BLUE | BACKGROUND_INTENSITY); - g_origBgAttrs = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | - FOREGROUND_BLUE | FOREGROUND_INTENSITY); - } - return 0; - } - - int dumy_init_console_colors = colors_init(); -#endif // DOCTEST_CONFIG_COLORS_WINDOWS - - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - void color_to_stream(std::ostream& s, Color::Enum code) { - static_cast(s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS - static_cast(code); // for DOCTEST_CONFIG_COLORS_NONE -#ifdef DOCTEST_CONFIG_COLORS_ANSI - if(g_no_colors || - (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false)) - return; - - auto col = ""; - // clang-format off - switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement - case Color::Red: col = "[0;31m"; break; - case Color::Green: col = "[0;32m"; break; - case Color::Blue: col = "[0;34m"; break; - case Color::Cyan: col = "[0;36m"; break; - case Color::Yellow: col = "[0;33m"; break; - case Color::Grey: col = "[1;30m"; break; - case Color::LightGrey: col = "[0;37m"; break; - case Color::BrightRed: col = "[1;31m"; break; - case Color::BrightGreen: col = "[1;32m"; break; - case Color::BrightWhite: col = "[1;37m"; break; - case Color::Bright: // invalid - case Color::None: - case Color::White: - default: col = "[0m"; - } - // clang-format on - s << "\033" << col; -#endif // DOCTEST_CONFIG_COLORS_ANSI - -#ifdef DOCTEST_CONFIG_COLORS_WINDOWS - if(g_no_colors || - (isatty(fileno(stdout)) == false && getContextOptions()->force_colors == false)) - return; - -#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(g_stdoutHandle, x | g_origBgAttrs) - - // clang-format off - switch (code) { - case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; - case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; - case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; - case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; - case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; - case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; - case Color::Grey: DOCTEST_SET_ATTR(0); break; - case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; - case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; - case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; - case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; - case Color::None: - case Color::Bright: // invalid - default: DOCTEST_SET_ATTR(g_origFgAttrs); - } - // clang-format on -#endif // DOCTEST_CONFIG_COLORS_WINDOWS - } - DOCTEST_CLANG_SUPPRESS_WARNING_POP - - std::vector& getExceptionTranslators() { - static std::vector data; - return data; - } - - String translateActiveException() { -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - String res; - auto& translators = getExceptionTranslators(); - for(auto& curr : translators) - if(curr->translate(res)) - return res; - // clang-format off - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcatch-value") - try { - throw; - } catch(std::exception& ex) { - return ex.what(); - } catch(std::string& msg) { - return msg.c_str(); - } catch(const char* msg) { - return msg; - } catch(...) { - return "unknown exception"; - } - DOCTEST_GCC_SUPPRESS_WARNING_POP -// clang-format on -#else // DOCTEST_CONFIG_NO_EXCEPTIONS - return ""; -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - } -} // namespace - -namespace detail { - // used by the macros for registering tests - int regTest(const TestCase& tc) { - getRegisteredTests().insert(tc); - return 0; - } - - // sets the current test suite - int setTestSuite(const TestSuite& ts) { - doctest_detail_test_suite_ns::getCurrentTestSuite() = ts; - return 0; - } - -#ifdef DOCTEST_IS_DEBUGGER_ACTIVE - bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); } -#else // DOCTEST_IS_DEBUGGER_ACTIVE -#ifdef DOCTEST_PLATFORM_LINUX - class ErrnoGuard { - public: - ErrnoGuard() : m_oldErrno(errno) {} - ~ErrnoGuard() { errno = m_oldErrno; } - private: - int m_oldErrno; - }; - // See the comments in Catch2 for the reasoning behind this implementation: - // https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102 - bool isDebuggerActive() { - ErrnoGuard guard; - std::ifstream in("/proc/self/status"); - for(std::string line; std::getline(in, line);) { - static const int PREFIX_LEN = 11; - if(line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) { - return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; - } - } - return false; - } -#elif defined(DOCTEST_PLATFORM_MAC) - // The following function is taken directly from the following technical note: - // https://developer.apple.com/library/archive/qa/qa1361/_index.html - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive() { - int mib[4]; - kinfo_proc info; - size_t size; - // Initialize the flags so that, if sysctl fails for some bizarre - // reason, we get a predictable result. - info.kp_proc.p_flag = 0; - // Initialize mib, which tells sysctl the info we want, in this case - // we're looking for information about a specific process ID. - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - // Call sysctl. - size = sizeof(info); - if(sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) { - std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n"; - return false; - } - // We're being debugged if the P_TRACED flag is set. - return ((info.kp_proc.p_flag & P_TRACED) != 0); - } -#elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__) - bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } -#else - bool isDebuggerActive() { return false; } -#endif // Platform -#endif // DOCTEST_IS_DEBUGGER_ACTIVE - - void registerExceptionTranslatorImpl(const IExceptionTranslator* et) { - if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) == - getExceptionTranslators().end()) - getExceptionTranslators().push_back(et); - } - -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - void toStream(std::ostream* s, char* in) { *s << in; } - void toStream(std::ostream* s, const char* in) { *s << in; } -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; } - void toStream(std::ostream* s, float in) { *s << in; } - void toStream(std::ostream* s, double in) { *s << in; } - void toStream(std::ostream* s, double long in) { *s << in; } - - void toStream(std::ostream* s, char in) { *s << in; } - void toStream(std::ostream* s, char signed in) { *s << in; } - void toStream(std::ostream* s, char unsigned in) { *s << in; } - void toStream(std::ostream* s, int short in) { *s << in; } - void toStream(std::ostream* s, int short unsigned in) { *s << in; } - void toStream(std::ostream* s, int in) { *s << in; } - void toStream(std::ostream* s, int unsigned in) { *s << in; } - void toStream(std::ostream* s, int long in) { *s << in; } - void toStream(std::ostream* s, int long unsigned in) { *s << in; } - void toStream(std::ostream* s, int long long in) { *s << in; } - void toStream(std::ostream* s, int long long unsigned in) { *s << in; } - - DOCTEST_THREAD_LOCAL std::vector g_infoContexts; // for logging with INFO() - - ContextScopeBase::ContextScopeBase() { - g_infoContexts.push_back(this); - } - - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - - // destroy cannot be inlined into the destructor because that would mean calling stringify after - // ContextScope has been destroyed (base class destructors run after derived class destructors). - // Instead, ContextScope calls this method directly from its destructor. - void ContextScopeBase::destroy() { -#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) - if(std::uncaught_exceptions() > 0) { -#else - if(std::uncaught_exception()) { -#endif - std::ostringstream s; - this->stringify(&s); - g_cs->stringifiedContexts.push_back(s.str().c_str()); - } - g_infoContexts.pop_back(); - } - - DOCTEST_CLANG_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - DOCTEST_MSVC_SUPPRESS_WARNING_POP -} // namespace detail -namespace { - using namespace detail; - -#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) - struct FatalConditionHandler - { - static void reset() {} - static void allocateAltStackMem() {} - static void freeAltStackMem() {} - }; -#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH - - void reportFatal(const std::string&); - -#ifdef DOCTEST_PLATFORM_WINDOWS - - struct SignalDefs - { - DWORD id; - const char* name; - }; - // There is no 1-1 mapping between signals and windows exceptions. - // Windows can easily distinguish between SO and SigSegV, - // but SigInt, SigTerm, etc are handled differently. - SignalDefs signalDefs[] = { - {static_cast(EXCEPTION_ILLEGAL_INSTRUCTION), - "SIGILL - Illegal instruction signal"}, - {static_cast(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow"}, - {static_cast(EXCEPTION_ACCESS_VIOLATION), - "SIGSEGV - Segmentation violation signal"}, - {static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error"}, - }; - - struct FatalConditionHandler - { - static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) { - // Multiple threads may enter this filter/handler at once. We want the error message to be printed on the - // console just once no matter how many threads have crashed. - static std::mutex mutex; - static bool execute = true; - { - std::lock_guard lock(mutex); - if(execute) { - bool reported = false; - for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { - reportFatal(signalDefs[i].name); - reported = true; - break; - } - } - if(reported == false) - reportFatal("Unhandled SEH exception caught"); - if(isDebuggerActive() && !g_cs->no_breaks) - DOCTEST_BREAK_INTO_DEBUGGER(); - } - execute = false; - } - std::exit(EXIT_FAILURE); - } - - static void allocateAltStackMem() {} - static void freeAltStackMem() {} - - FatalConditionHandler() { - isSet = true; - // 32k seems enough for doctest to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - // Register an unhandled exception filter - previousTop = SetUnhandledExceptionFilter(handleException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); - - // On Windows uncaught exceptions from another thread, exceptions from - // destructors, or calls to std::terminate are not a SEH exception - - // The terminal handler gets called when: - // - std::terminate is called FROM THE TEST RUNNER THREAD - // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD - original_terminate_handler = std::get_terminate(); - std::set_terminate([]() DOCTEST_NOEXCEPT { - reportFatal("Terminate handler called"); - if(isDebuggerActive() && !g_cs->no_breaks) - DOCTEST_BREAK_INTO_DEBUGGER(); - std::exit(EXIT_FAILURE); // explicitly exit - otherwise the SIGABRT handler may be called as well - }); - - // SIGABRT is raised when: - // - std::terminate is called FROM A DIFFERENT THREAD - // - an exception is thrown from a destructor FROM A DIFFERENT THREAD - // - an uncaught exception is thrown FROM A DIFFERENT THREAD - prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT { - if(signal == SIGABRT) { - reportFatal("SIGABRT - Abort (abnormal termination) signal"); - if(isDebuggerActive() && !g_cs->no_breaks) - DOCTEST_BREAK_INTO_DEBUGGER(); - std::exit(EXIT_FAILURE); - } - }); - - // The following settings are taken from google test, and more - // specifically from UnitTest::Run() inside of gtest.cc - - // the user does not want to see pop-up dialogs about crashes - prev_error_mode_1 = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | - SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); - // This forces the abort message to go to stderr in all circumstances. - prev_error_mode_2 = _set_error_mode(_OUT_TO_STDERR); - // In the debug version, Visual Studio pops up a separate dialog - // offering a choice to debug the aborted program - we want to disable that. - prev_abort_behavior = _set_abort_behavior(0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); - // In debug mode, the Windows CRT can crash with an assertion over invalid - // input (e.g. passing an invalid file descriptor). The default handling - // for these assertions is to pop up a dialog and wait for user input. - // Instead ask the CRT to dump such assertions to stderr non-interactively. - prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - prev_report_file = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); - } - - static void reset() { - if(isSet) { - // Unregister handler and restore the old guarantee - SetUnhandledExceptionFilter(previousTop); - SetThreadStackGuarantee(&guaranteeSize); - std::set_terminate(original_terminate_handler); - std::signal(SIGABRT, prev_sigabrt_handler); - SetErrorMode(prev_error_mode_1); - _set_error_mode(prev_error_mode_2); - _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); - static_cast(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode)); - static_cast(_CrtSetReportFile(_CRT_ASSERT, prev_report_file)); - isSet = false; - } - } - - ~FatalConditionHandler() { reset(); } - - private: - static UINT prev_error_mode_1; - static int prev_error_mode_2; - static unsigned int prev_abort_behavior; - static int prev_report_mode; - static _HFILE prev_report_file; - static void (*prev_sigabrt_handler)(int); - static std::terminate_handler original_terminate_handler; - static bool isSet; - static ULONG guaranteeSize; - static LPTOP_LEVEL_EXCEPTION_FILTER previousTop; - }; - - UINT FatalConditionHandler::prev_error_mode_1; - int FatalConditionHandler::prev_error_mode_2; - unsigned int FatalConditionHandler::prev_abort_behavior; - int FatalConditionHandler::prev_report_mode; - _HFILE FatalConditionHandler::prev_report_file; - void (*FatalConditionHandler::prev_sigabrt_handler)(int); - std::terminate_handler FatalConditionHandler::original_terminate_handler; - bool FatalConditionHandler::isSet = false; - ULONG FatalConditionHandler::guaranteeSize = 0; - LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr; - -#else // DOCTEST_PLATFORM_WINDOWS - - struct SignalDefs - { - int id; - const char* name; - }; - SignalDefs signalDefs[] = {{SIGINT, "SIGINT - Terminal interrupt signal"}, - {SIGILL, "SIGILL - Illegal instruction signal"}, - {SIGFPE, "SIGFPE - Floating point error signal"}, - {SIGSEGV, "SIGSEGV - Segmentation violation signal"}, - {SIGTERM, "SIGTERM - Termination request signal"}, - {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}}; - - struct FatalConditionHandler - { - static bool isSet; - static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)]; - static stack_t oldSigStack; - static size_t altStackSize; - static char* altStackMem; - - static void handleSignal(int sig) { - const char* name = ""; - for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - SignalDefs& def = signalDefs[i]; - if(sig == def.id) { - name = def.name; - break; - } - } - reset(); - reportFatal(name); - raise(sig); - } - - static void allocateAltStackMem() { - altStackMem = new char[altStackSize]; - } - - static void freeAltStackMem() { - delete[] altStackMem; - } - - FatalConditionHandler() { - isSet = true; - stack_t sigStack; - sigStack.ss_sp = altStackMem; - sigStack.ss_size = altStackSize; - sigStack.ss_flags = 0; - sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = {}; - sa.sa_handler = handleSignal; // NOLINT - sa.sa_flags = SA_ONSTACK; - for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); - } - } - - ~FatalConditionHandler() { reset(); } - static void reset() { - if(isSet) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); - } - // Return the old stack - sigaltstack(&oldSigStack, nullptr); - isSet = false; - } - } - }; - - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - size_t FatalConditionHandler::altStackSize = 4 * SIGSTKSZ; - char* FatalConditionHandler::altStackMem = nullptr; - -#endif // DOCTEST_PLATFORM_WINDOWS -#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH - -} // namespace - -namespace { - using namespace detail; - -#ifdef DOCTEST_PLATFORM_WINDOWS -#define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text) -#else - // TODO: integration with XCode and other IDEs -#define DOCTEST_OUTPUT_DEBUG_STRING(text) // NOLINT(clang-diagnostic-unused-macros) -#endif // Platform - - void addAssert(assertType::Enum at) { - if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional - g_cs->numAssertsCurrentTest_atomic++; - } - - void addFailedAssert(assertType::Enum at) { - if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional - g_cs->numAssertsFailedCurrentTest_atomic++; - } - -#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) - void reportFatal(const std::string& message) { - g_cs->failure_flags |= TestCaseFailureReason::Crash; - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true}); - - while(g_cs->subcasesStack.size()) { - g_cs->subcasesStack.pop_back(); - DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); - } - - g_cs->finalizeTestCaseData(); - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); - } -#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH -} // namespace -namespace detail { - - ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, - const char* exception_type, const char* exception_string) { - m_test_case = g_cs->currentTest; - m_at = at; - m_file = file; - m_line = line; - m_expr = expr; - m_failed = true; - m_threw = false; - m_threw_as = false; - m_exception_type = exception_type; - m_exception_string = exception_string; -#if DOCTEST_MSVC - if(m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC - ++m_expr; -#endif // MSVC - } - - void ResultBuilder::setResult(const Result& res) { - m_decomp = res.m_decomp; - m_failed = !res.m_passed; - } - - void ResultBuilder::translateException() { - m_threw = true; - m_exception = translateActiveException(); - } - - bool ResultBuilder::log() { - if(m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional - m_failed = !m_threw; - } else if((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //!OCLINT - m_failed = !m_threw_as || (m_exception != m_exception_string); - } else if(m_at & assertType::is_throws_as) { //!OCLINT bitwise operator in conditional - m_failed = !m_threw_as; - } else if(m_at & assertType::is_throws_with) { //!OCLINT bitwise operator in conditional - m_failed = m_exception != m_exception_string; - } else if(m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional - m_failed = m_threw; - } - - if(m_exception.size()) - m_exception = String("\"") + m_exception + "\""; - - if(is_running_in_test) { - addAssert(m_at); - DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this); - - if(m_failed) - addFailedAssert(m_at); - } else if(m_failed) { - failed_out_of_a_testing_context(*this); - } - - return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks && - (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger - } - - void ResultBuilder::react() const { - if(m_failed && checkIfShouldThrow(m_at)) - throwException(); - } - - void failed_out_of_a_testing_context(const AssertData& ad) { - if(g_cs->ah) - g_cs->ah(ad); - else - std::abort(); - } - - void decomp_assert(assertType::Enum at, const char* file, int line, const char* expr, - Result result) { - bool failed = !result.m_passed; - - // ################################################################################### - // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT - // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED - // ################################################################################### - DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp); - DOCTEST_ASSERT_IN_TESTS(result.m_decomp); - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) - } - - MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) { - m_stream = getTlsOss(); - m_file = file; - m_line = line; - m_severity = severity; - } - - IExceptionTranslator::IExceptionTranslator() = default; - IExceptionTranslator::~IExceptionTranslator() = default; - - bool MessageBuilder::log() { - m_string = getTlsOssResult(); - DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this); - - const bool isWarn = m_severity & assertType::is_warn; - - // warn is just a message in this context so we don't treat it as an assert - if(!isWarn) { - addAssert(m_severity); - addFailedAssert(m_severity); - } - - return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn && - (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger - } - - void MessageBuilder::react() { - if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional - throwException(); - } - - MessageBuilder::~MessageBuilder() = default; -} // namespace detail -namespace { - using namespace detail; - - template - DOCTEST_NORETURN void throw_exception(Ex const& e) { -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - throw e; -#else // DOCTEST_CONFIG_NO_EXCEPTIONS - std::cerr << "doctest will terminate because it needed to throw an exception.\n" - << "The message was: " << e.what() << '\n'; - std::terminate(); -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - } - -#ifndef DOCTEST_INTERNAL_ERROR -#define DOCTEST_INTERNAL_ERROR(msg) \ - throw_exception(std::logic_error( \ - __FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg)) -#endif // DOCTEST_INTERNAL_ERROR - - // clang-format off - -// ================================================================================================= -// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp -// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. -// ================================================================================================= - - class XmlEncode { - public: - enum ForWhat { ForTextNodes, ForAttributes }; - - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - - void encodeTo( std::ostream& os ) const; - - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); - - private: - std::string m_str; - ForWhat m_forWhat; - }; - - class XmlWriter { - public: - - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ); - - ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT; - ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT; - - ~ScopedElement(); - - ScopedElement& writeText( std::string const& text, bool indent = true ); - - template - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - private: - mutable XmlWriter* m_writer = nullptr; - }; - - XmlWriter( std::ostream& os = std::cout ); - ~XmlWriter(); - - XmlWriter( XmlWriter const& ) = delete; - XmlWriter& operator=( XmlWriter const& ) = delete; - - XmlWriter& startElement( std::string const& name ); - - ScopedElement scopedElement( std::string const& name ); - - XmlWriter& endElement(); - - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); - - XmlWriter& writeAttribute( std::string const& name, const char* attribute ); - - XmlWriter& writeAttribute( std::string const& name, bool attribute ); - - template - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - std::stringstream rss; - rss << attribute; - return writeAttribute( name, rss.str() ); - } - - XmlWriter& writeText( std::string const& text, bool indent = true ); - - //XmlWriter& writeComment( std::string const& text ); - - //void writeStylesheetRef( std::string const& url ); - - //XmlWriter& writeBlankLine(); - - void ensureTagClosed(); - - private: - - void writeDeclaration(); - - void newlineIfNecessary(); - - bool m_tagIsOpen = false; - bool m_needsNewline = false; - std::vector m_tags; - std::string m_indent; - std::ostream& m_os; - }; - -// ================================================================================================= -// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp -// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. -// ================================================================================================= - -using uchar = unsigned char; - -namespace { - - size_t trailingBytes(unsigned char c) { - if ((c & 0xE0) == 0xC0) { - return 2; - } - if ((c & 0xF0) == 0xE0) { - return 3; - } - if ((c & 0xF8) == 0xF0) { - return 4; - } - DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); - } - - uint32_t headerValue(unsigned char c) { - if ((c & 0xE0) == 0xC0) { - return c & 0x1F; - } - if ((c & 0xF0) == 0xE0) { - return c & 0x0F; - } - if ((c & 0xF8) == 0xF0) { - return c & 0x07; - } - DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); - } - - void hexEscapeChar(std::ostream& os, unsigned char c) { - std::ios_base::fmtflags f(os.flags()); - os << "\\x" - << std::uppercase << std::hex << std::setfill('0') << std::setw(2) - << static_cast(c); - os.flags(f); - } - -} // anonymous namespace - - XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) - : m_str( str ), - m_forWhat( forWhat ) - {} - - void XmlEncode::encodeTo( std::ostream& os ) const { - // Apostrophe escaping not necessary if we always use " to write attributes - // (see: https://www.w3.org/TR/xml/#syntax) - - for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { - uchar c = m_str[idx]; - switch (c) { - case '<': os << "<"; break; - case '&': os << "&"; break; - - case '>': - // See: https://www.w3.org/TR/xml/#syntax - if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') - os << ">"; - else - os << c; - break; - - case '\"': - if (m_forWhat == ForAttributes) - os << """; - else - os << c; - break; - - default: - // Check for control characters and invalid utf-8 - - // Escape control characters in standard ascii - // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { - hexEscapeChar(os, c); - break; - } - - // Plain ASCII: Write it to stream - if (c < 0x7F) { - os << c; - break; - } - - // UTF-8 territory - // Check if the encoding is valid and if it is not, hex escape bytes. - // Important: We do not check the exact decoded values for validity, only the encoding format - // First check that this bytes is a valid lead byte: - // This means that it is not encoded as 1111 1XXX - // Or as 10XX XXXX - if (c < 0xC0 || - c >= 0xF8) { - hexEscapeChar(os, c); - break; - } - - auto encBytes = trailingBytes(c); - // Are there enough bytes left to avoid accessing out-of-bounds memory? - if (idx + encBytes - 1 >= m_str.size()) { - hexEscapeChar(os, c); - break; - } - // The header is valid, check data - // The next encBytes bytes must together be a valid utf-8 - // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) - bool valid = true; - uint32_t value = headerValue(c); - for (std::size_t n = 1; n < encBytes; ++n) { - uchar nc = m_str[idx + n]; - valid &= ((nc & 0xC0) == 0x80); - value = (value << 6) | (nc & 0x3F); - } - - if ( - // Wrong bit pattern of following bytes - (!valid) || - // Overlong encodings - (value < 0x80) || - ( value < 0x800 && encBytes > 2) || // removed "0x80 <= value &&" because redundant - (0x800 < value && value < 0x10000 && encBytes > 3) || - // Encoded value out of range - (value >= 0x110000) - ) { - hexEscapeChar(os, c); - break; - } - - // If we got here, this is in fact a valid(ish) utf-8 sequence - for (std::size_t n = 0; n < encBytes; ++n) { - os << m_str[idx + n]; - } - idx += encBytes - 1; - break; - } - } - } - - std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { - xmlEncode.encodeTo( os ); - return os; - } - - XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} - - XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT - : m_writer( other.m_writer ){ - other.m_writer = nullptr; - } - XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT { - if ( m_writer ) { - m_writer->endElement(); - } - m_writer = other.m_writer; - other.m_writer = nullptr; - return *this; - } - - - XmlWriter::ScopedElement::~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } - - XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { - m_writer->writeText( text, indent ); - return *this; - } - - XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) - { - writeDeclaration(); - } - - XmlWriter::~XmlWriter() { - while( !m_tags.empty() ) - endElement(); - } - - XmlWriter& XmlWriter::startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - m_os << m_indent << '<' << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; - } - - XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; - } - - XmlWriter& XmlWriter::endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - m_os << "/>"; - m_tagIsOpen = false; - } - else { - m_os << m_indent << ""; - } - m_os << std::endl; - m_tags.pop_back(); - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, const char* attribute ) { - if( !name.empty() && attribute && attribute[0] != '\0' ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { - m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - m_os << m_indent; - m_os << XmlEncode( text ); - m_needsNewline = true; - } - return *this; - } - - //XmlWriter& XmlWriter::writeComment( std::string const& text ) { - // ensureTagClosed(); - // m_os << m_indent << ""; - // m_needsNewline = true; - // return *this; - //} - - //void XmlWriter::writeStylesheetRef( std::string const& url ) { - // m_os << "\n"; - //} - - //XmlWriter& XmlWriter::writeBlankLine() { - // ensureTagClosed(); - // m_os << '\n'; - // return *this; - //} - - void XmlWriter::ensureTagClosed() { - if( m_tagIsOpen ) { - m_os << ">" << std::endl; - m_tagIsOpen = false; - } - } - - void XmlWriter::writeDeclaration() { - m_os << "\n"; - } - - void XmlWriter::newlineIfNecessary() { - if( m_needsNewline ) { - m_os << std::endl; - m_needsNewline = false; - } - } - -// ================================================================================================= -// End of copy-pasted code from Catch -// ================================================================================================= - - // clang-format on - - struct XmlReporter : public IReporter - { - XmlWriter xml; - std::mutex mutex; - - // caching pointers/references to objects of these types - safe to do - const ContextOptions& opt; - const TestCaseData* tc = nullptr; - - XmlReporter(const ContextOptions& co) - : xml(*co.cout) - , opt(co) {} - - void log_contexts() { - int num_contexts = get_num_active_contexts(); - if(num_contexts) { - auto contexts = get_active_contexts(); - std::stringstream ss; - for(int i = 0; i < num_contexts; ++i) { - contexts[i]->stringify(&ss); - xml.scopedElement("Info").writeText(ss.str()); - ss.str(""); - } - } - } - - unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } - - void test_case_start_impl(const TestCaseData& in) { - bool open_ts_tag = false; - if(tc != nullptr) { // we have already opened a test suite - if(std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) { - xml.endElement(); - open_ts_tag = true; - } - } - else { - open_ts_tag = true; // first test case ==> first test suite - } - - if(open_ts_tag) { - xml.startElement("TestSuite"); - xml.writeAttribute("name", in.m_test_suite); - } - - tc = ∈ - xml.startElement("TestCase") - .writeAttribute("name", in.m_name) - .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str())) - .writeAttribute("line", line(in.m_line)) - .writeAttribute("description", in.m_description); - - if(Approx(in.m_timeout) != 0) - xml.writeAttribute("timeout", in.m_timeout); - if(in.m_may_fail) - xml.writeAttribute("may_fail", true); - if(in.m_should_fail) - xml.writeAttribute("should_fail", true); - } - - // ========================================================================================= - // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE - // ========================================================================================= - - void report_query(const QueryData& in) override { - test_run_start(); - if(opt.list_reporters) { - for(auto& curr : getListeners()) - xml.scopedElement("Listener") - .writeAttribute("priority", curr.first.first) - .writeAttribute("name", curr.first.second); - for(auto& curr : getReporters()) - xml.scopedElement("Reporter") - .writeAttribute("priority", curr.first.first) - .writeAttribute("name", curr.first.second); - } else if(opt.count || opt.list_test_cases) { - for(unsigned i = 0; i < in.num_data; ++i) { - xml.scopedElement("TestCase").writeAttribute("name", in.data[i]->m_name) - .writeAttribute("testsuite", in.data[i]->m_test_suite) - .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str())) - .writeAttribute("line", line(in.data[i]->m_line)); - } - xml.scopedElement("OverallResultsTestCases") - .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); - } else if(opt.list_test_suites) { - for(unsigned i = 0; i < in.num_data; ++i) - xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]->m_test_suite); - xml.scopedElement("OverallResultsTestCases") - .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); - xml.scopedElement("OverallResultsTestSuites") - .writeAttribute("unskipped", in.run_stats->numTestSuitesPassingFilters); - } - xml.endElement(); - } - - void test_run_start() override { - // remove .exe extension - mainly to have the same output on UNIX and Windows - std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); -#ifdef DOCTEST_PLATFORM_WINDOWS - if(binary_name.rfind(".exe") != std::string::npos) - binary_name = binary_name.substr(0, binary_name.length() - 4); -#endif // DOCTEST_PLATFORM_WINDOWS - - xml.startElement("doctest").writeAttribute("binary", binary_name); - if(opt.no_version == false) - xml.writeAttribute("version", DOCTEST_VERSION_STR); - - // only the consequential ones (TODO: filters) - xml.scopedElement("Options") - .writeAttribute("order_by", opt.order_by.c_str()) - .writeAttribute("rand_seed", opt.rand_seed) - .writeAttribute("first", opt.first) - .writeAttribute("last", opt.last) - .writeAttribute("abort_after", opt.abort_after) - .writeAttribute("subcase_filter_levels", opt.subcase_filter_levels) - .writeAttribute("case_sensitive", opt.case_sensitive) - .writeAttribute("no_throw", opt.no_throw) - .writeAttribute("no_skip", opt.no_skip); - } - - void test_run_end(const TestRunStats& p) override { - if(tc) // the TestSuite tag - only if there has been at least 1 test case - xml.endElement(); - - xml.scopedElement("OverallResultsAsserts") - .writeAttribute("successes", p.numAsserts - p.numAssertsFailed) - .writeAttribute("failures", p.numAssertsFailed); - - xml.startElement("OverallResultsTestCases") - .writeAttribute("successes", - p.numTestCasesPassingFilters - p.numTestCasesFailed) - .writeAttribute("failures", p.numTestCasesFailed); - if(opt.no_skipped_summary == false) - xml.writeAttribute("skipped", p.numTestCases - p.numTestCasesPassingFilters); - xml.endElement(); - - xml.endElement(); - } - - void test_case_start(const TestCaseData& in) override { - test_case_start_impl(in); - xml.ensureTagClosed(); - } - - void test_case_reenter(const TestCaseData&) override {} - - void test_case_end(const CurrentTestCaseStats& st) override { - xml.startElement("OverallResultsAsserts") - .writeAttribute("successes", - st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest) - .writeAttribute("failures", st.numAssertsFailedCurrentTest); - if(opt.duration) - xml.writeAttribute("duration", st.seconds); - if(tc->m_expected_failures) - xml.writeAttribute("expected_failures", tc->m_expected_failures); - xml.endElement(); - - xml.endElement(); - } - - void test_case_exception(const TestCaseException& e) override { - std::lock_guard lock(mutex); - - xml.scopedElement("Exception") - .writeAttribute("crash", e.is_crash) - .writeText(e.error_string.c_str()); - } - - void subcase_start(const SubcaseSignature& in) override { - std::lock_guard lock(mutex); - - xml.startElement("SubCase") - .writeAttribute("name", in.m_name) - .writeAttribute("filename", skipPathFromFilename(in.m_file)) - .writeAttribute("line", line(in.m_line)); - xml.ensureTagClosed(); - } - - void subcase_end() override { xml.endElement(); } - - void log_assert(const AssertData& rb) override { - if(!rb.m_failed && !opt.success) - return; - - std::lock_guard lock(mutex); - - xml.startElement("Expression") - .writeAttribute("success", !rb.m_failed) - .writeAttribute("type", assertString(rb.m_at)) - .writeAttribute("filename", skipPathFromFilename(rb.m_file)) - .writeAttribute("line", line(rb.m_line)); - - xml.scopedElement("Original").writeText(rb.m_expr); - - if(rb.m_threw) - xml.scopedElement("Exception").writeText(rb.m_exception.c_str()); - - if(rb.m_at & assertType::is_throws_as) - xml.scopedElement("ExpectedException").writeText(rb.m_exception_type); - if(rb.m_at & assertType::is_throws_with) - xml.scopedElement("ExpectedExceptionString").writeText(rb.m_exception_string); - if((rb.m_at & assertType::is_normal) && !rb.m_threw) - xml.scopedElement("Expanded").writeText(rb.m_decomp.c_str()); - - log_contexts(); - - xml.endElement(); - } - - void log_message(const MessageData& mb) override { - std::lock_guard lock(mutex); - - xml.startElement("Message") - .writeAttribute("type", failureString(mb.m_severity)) - .writeAttribute("filename", skipPathFromFilename(mb.m_file)) - .writeAttribute("line", line(mb.m_line)); - - xml.scopedElement("Text").writeText(mb.m_string.c_str()); - - log_contexts(); - - xml.endElement(); - } - - void test_case_skipped(const TestCaseData& in) override { - if(opt.no_skipped_summary == false) { - test_case_start_impl(in); - xml.writeAttribute("skipped", "true"); - xml.endElement(); - } - } - }; - - DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter); - - void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) { - if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) == - 0) //!OCLINT bitwise operator in conditional - s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) " - << Color::None; - - if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional - s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; - } else if((rb.m_at & assertType::is_throws_as) && - (rb.m_at & assertType::is_throws_with)) { //!OCLINT - s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" - << rb.m_exception_string << "\", " << rb.m_exception_type << " ) " << Color::None; - if(rb.m_threw) { - if(!rb.m_failed) { - s << "threw as expected!\n"; - } else { - s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n"; - } - } else { - s << "did NOT throw at all!\n"; - } - } else if(rb.m_at & - assertType::is_throws_as) { //!OCLINT bitwise operator in conditional - s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", " - << rb.m_exception_type << " ) " << Color::None - << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" : - "threw a DIFFERENT exception: ") : - "did NOT throw at all!") - << Color::Cyan << rb.m_exception << "\n"; - } else if(rb.m_at & - assertType::is_throws_with) { //!OCLINT bitwise operator in conditional - s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" - << rb.m_exception_string << "\" ) " << Color::None - << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" : - "threw a DIFFERENT exception: ") : - "did NOT throw at all!") - << Color::Cyan << rb.m_exception << "\n"; - } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional - s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan - << rb.m_exception << "\n"; - } else { - s << (rb.m_threw ? "THREW exception: " : - (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n")); - if(rb.m_threw) - s << rb.m_exception << "\n"; - else - s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n"; - } - } - - // TODO: - // - log_message() - // - respond to queries - // - honor remaining options - // - more attributes in tags - struct JUnitReporter : public IReporter - { - XmlWriter xml; - std::mutex mutex; - Timer timer; - std::vector deepestSubcaseStackNames; - - struct JUnitTestCaseData - { - static std::string getCurrentTimestamp() { - // Beware, this is not reentrant because of backward compatibility issues - // Also, UTC only, again because of backward compatibility (%z is C++11) - time_t rawtime; - std::time(&rawtime); - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - - std::tm timeInfo; -#ifdef DOCTEST_PLATFORM_WINDOWS - gmtime_s(&timeInfo, &rawtime); -#else // DOCTEST_PLATFORM_WINDOWS - gmtime_r(&rawtime, &timeInfo); -#endif // DOCTEST_PLATFORM_WINDOWS - - char timeStamp[timeStampSize]; - const char* const fmt = "%Y-%m-%dT%H:%M:%SZ"; - - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); - return std::string(timeStamp); - } - - struct JUnitTestMessage - { - JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details) - : message(_message), type(_type), details(_details) {} - - JUnitTestMessage(const std::string& _message, const std::string& _details) - : message(_message), type(), details(_details) {} - - std::string message, type, details; - }; - - struct JUnitTestCase - { - JUnitTestCase(const std::string& _classname, const std::string& _name) - : classname(_classname), name(_name), time(0), failures() {} - - std::string classname, name; - double time; - std::vector failures, errors; - }; - - void add(const std::string& classname, const std::string& name) { - testcases.emplace_back(classname, name); - } - - void appendSubcaseNamesToLastTestcase(std::vector nameStack) { - for(auto& curr: nameStack) - if(curr.size()) - testcases.back().name += std::string("/") + curr.c_str(); - } - - void addTime(double time) { - if(time < 1e-4) - time = 0; - testcases.back().time = time; - totalSeconds += time; - } - - void addFailure(const std::string& message, const std::string& type, const std::string& details) { - testcases.back().failures.emplace_back(message, type, details); - ++totalFailures; - } - - void addError(const std::string& message, const std::string& details) { - testcases.back().errors.emplace_back(message, details); - ++totalErrors; - } - - std::vector testcases; - double totalSeconds = 0; - int totalErrors = 0, totalFailures = 0; - }; - - JUnitTestCaseData testCaseData; - - // caching pointers/references to objects of these types - safe to do - const ContextOptions& opt; - const TestCaseData* tc = nullptr; - - JUnitReporter(const ContextOptions& co) - : xml(*co.cout) - , opt(co) {} - - unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } - - // ========================================================================================= - // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE - // ========================================================================================= - - void report_query(const QueryData&) override {} - - void test_run_start() override {} - - void test_run_end(const TestRunStats& p) override { - // remove .exe extension - mainly to have the same output on UNIX and Windows - std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); -#ifdef DOCTEST_PLATFORM_WINDOWS - if(binary_name.rfind(".exe") != std::string::npos) - binary_name = binary_name.substr(0, binary_name.length() - 4); -#endif // DOCTEST_PLATFORM_WINDOWS - xml.startElement("testsuites"); - xml.startElement("testsuite").writeAttribute("name", binary_name) - .writeAttribute("errors", testCaseData.totalErrors) - .writeAttribute("failures", testCaseData.totalFailures) - .writeAttribute("tests", p.numAsserts); - if(opt.no_time_in_output == false) { - xml.writeAttribute("time", testCaseData.totalSeconds); - xml.writeAttribute("timestamp", JUnitTestCaseData::getCurrentTimestamp()); - } - if(opt.no_version == false) - xml.writeAttribute("doctest_version", DOCTEST_VERSION_STR); - - for(const auto& testCase : testCaseData.testcases) { - xml.startElement("testcase") - .writeAttribute("classname", testCase.classname) - .writeAttribute("name", testCase.name); - if(opt.no_time_in_output == false) - xml.writeAttribute("time", testCase.time); - // This is not ideal, but it should be enough to mimic gtest's junit output. - xml.writeAttribute("status", "run"); - - for(const auto& failure : testCase.failures) { - xml.scopedElement("failure") - .writeAttribute("message", failure.message) - .writeAttribute("type", failure.type) - .writeText(failure.details, false); - } - - for(const auto& error : testCase.errors) { - xml.scopedElement("error") - .writeAttribute("message", error.message) - .writeText(error.details); - } - - xml.endElement(); - } - xml.endElement(); - xml.endElement(); - } - - void test_case_start(const TestCaseData& in) override { - testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); - timer.start(); - } - - void test_case_reenter(const TestCaseData& in) override { - testCaseData.addTime(timer.getElapsedSeconds()); - testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); - deepestSubcaseStackNames.clear(); - - timer.start(); - testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); - } - - void test_case_end(const CurrentTestCaseStats&) override { - testCaseData.addTime(timer.getElapsedSeconds()); - testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); - deepestSubcaseStackNames.clear(); - } - - void test_case_exception(const TestCaseException& e) override { - std::lock_guard lock(mutex); - testCaseData.addError("exception", e.error_string.c_str()); - } - - void subcase_start(const SubcaseSignature& in) override { - std::lock_guard lock(mutex); - deepestSubcaseStackNames.push_back(in.m_name); - } - - void subcase_end() override {} - - void log_assert(const AssertData& rb) override { - if(!rb.m_failed) // report only failures & ignore the `success` option - return; - - std::lock_guard lock(mutex); - - std::ostringstream os; - os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(") - << line(rb.m_line) << (opt.gnu_file_line ? ":" : "):") << std::endl; - - fulltext_log_assert_to_stream(os, rb); - log_contexts(os); - testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str()); - } - - void log_message(const MessageData&) override {} - - void test_case_skipped(const TestCaseData&) override {} - - void log_contexts(std::ostringstream& s) { - int num_contexts = get_num_active_contexts(); - if(num_contexts) { - auto contexts = get_active_contexts(); - - s << " logged: "; - for(int i = 0; i < num_contexts; ++i) { - s << (i == 0 ? "" : " "); - contexts[i]->stringify(&s); - s << std::endl; - } - } - } - }; - - DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter); - - struct Whitespace - { - int nrSpaces; - explicit Whitespace(int nr) - : nrSpaces(nr) {} - }; - - std::ostream& operator<<(std::ostream& out, const Whitespace& ws) { - if(ws.nrSpaces != 0) - out << std::setw(ws.nrSpaces) << ' '; - return out; - } - - struct ConsoleReporter : public IReporter - { - std::ostream& s; - bool hasLoggedCurrentTestStart; - std::vector subcasesStack; - size_t currentSubcaseLevel; - std::mutex mutex; - - // caching pointers/references to objects of these types - safe to do - const ContextOptions& opt; - const TestCaseData* tc; - - ConsoleReporter(const ContextOptions& co) - : s(*co.cout) - , opt(co) {} - - ConsoleReporter(const ContextOptions& co, std::ostream& ostr) - : s(ostr) - , opt(co) {} - - // ========================================================================================= - // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE - // ========================================================================================= - - void separator_to_stream() { - s << Color::Yellow - << "===============================================================================" - "\n"; - } - - const char* getSuccessOrFailString(bool success, assertType::Enum at, - const char* success_str) { - if(success) - return success_str; - return failureString(at); - } - - Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at) { - return success ? Color::BrightGreen : - (at & assertType::is_warn) ? Color::Yellow : Color::Red; - } - - void successOrFailColoredStringToStream(bool success, assertType::Enum at, - const char* success_str = "SUCCESS") { - s << getSuccessOrFailColor(success, at) - << getSuccessOrFailString(success, at, success_str) << ": "; - } - - void log_contexts() { - int num_contexts = get_num_active_contexts(); - if(num_contexts) { - auto contexts = get_active_contexts(); - - s << Color::None << " logged: "; - for(int i = 0; i < num_contexts; ++i) { - s << (i == 0 ? "" : " "); - contexts[i]->stringify(&s); - s << "\n"; - } - } - - s << "\n"; - } - - // this was requested to be made virtual so users could override it - virtual void file_line_to_stream(const char* file, int line, - const char* tail = "") { - s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(") - << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option - << (opt.gnu_file_line ? ":" : "):") << tail; - } - - void logTestStart() { - if(hasLoggedCurrentTestStart) - return; - - separator_to_stream(); - file_line_to_stream(tc->m_file.c_str(), tc->m_line, "\n"); - if(tc->m_description) - s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n"; - if(tc->m_test_suite && tc->m_test_suite[0] != '\0') - s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n"; - if(strncmp(tc->m_name, " Scenario:", 11) != 0) - s << Color::Yellow << "TEST CASE: "; - s << Color::None << tc->m_name << "\n"; - - for(size_t i = 0; i < currentSubcaseLevel; ++i) { - if(subcasesStack[i].m_name[0] != '\0') - s << " " << subcasesStack[i].m_name << "\n"; - } - - if(currentSubcaseLevel != subcasesStack.size()) { - s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" << Color::None; - for(size_t i = 0; i < subcasesStack.size(); ++i) { - if(subcasesStack[i].m_name[0] != '\0') - s << " " << subcasesStack[i].m_name << "\n"; - } - } - - s << "\n"; - - hasLoggedCurrentTestStart = true; - } - - void printVersion() { - if(opt.no_version == false) - s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \"" - << DOCTEST_VERSION_STR << "\"\n"; - } - - void printIntro() { - printVersion(); - s << Color::Cyan << "[doctest] " << Color::None - << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n"; - } - - void printHelp() { - int sizePrefixDisplay = static_cast(strlen(DOCTEST_OPTIONS_PREFIX_DISPLAY)); - printVersion(); - // clang-format off - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"; - s << Color::Cyan << "[doctest] " << Color::None; - s << "filter values: \"str1,str2,str3\" (comma separated strings)\n"; - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "filters use wildcards for matching strings\n"; - s << Color::Cyan << "[doctest] " << Color::None; - s << "something passes a filter if any of the strings in a filter matches\n"; -#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"" DOCTEST_CONFIG_OPTIONS_PREFIX "\" PREFIX!!!\n"; -#endif - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "Query flags - the program quits after them. Available:\n\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "?, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "help, -" DOCTEST_OPTIONS_PREFIX_DISPLAY "h " - << Whitespace(sizePrefixDisplay*0) << "prints this message\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "v, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "version " - << Whitespace(sizePrefixDisplay*1) << "prints the version\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "c, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "count " - << Whitespace(sizePrefixDisplay*1) << "prints the number of matching tests\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ltc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-cases " - << Whitespace(sizePrefixDisplay*1) << "lists all matching tests by name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-suites " - << Whitespace(sizePrefixDisplay*1) << "lists all matching test suites\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-reporters " - << Whitespace(sizePrefixDisplay*1) << "lists all registered reporters\n\n"; - // ================================================================================== << 79 - s << Color::Cyan << "[doctest] " << Color::None; - s << "The available / options/filters are:\n\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case= " - << Whitespace(sizePrefixDisplay*1) << "filters tests by their name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case-exclude= " - << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file= " - << Whitespace(sizePrefixDisplay*1) << "filters tests by their file\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sfe, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file-exclude= " - << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their file\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite= " - << Whitespace(sizePrefixDisplay*1) << "filters tests by their test suite\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tse, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite-exclude= " - << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their test suite\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase= " - << Whitespace(sizePrefixDisplay*1) << "filters subcases by their name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-exclude= " - << Whitespace(sizePrefixDisplay*1) << "filters OUT subcases by their name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "r, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "reporters= " - << Whitespace(sizePrefixDisplay*1) << "reporters to use (console is default)\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "o, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "out= " - << Whitespace(sizePrefixDisplay*1) << "output filename\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by= " - << Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n"; - s << Whitespace(sizePrefixDisplay*3) << " - [file/suite/name/rand/none]\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed= " - << Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first= " - << Whitespace(sizePrefixDisplay*1) << "the first test passing the filters to\n"; - s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "l, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "last= " - << Whitespace(sizePrefixDisplay*1) << "the last test passing the filters to\n"; - s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "aa, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "abort-after= " - << Whitespace(sizePrefixDisplay*1) << "stop after failed assertions\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "scfl,--" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-filter-levels= " - << Whitespace(sizePrefixDisplay*1) << "apply filters for the first levels\n"; - s << Color::Cyan << "\n[doctest] " << Color::None; - s << "Bool options - can be used like flags and true is assumed. Available:\n\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "s, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "success= " - << Whitespace(sizePrefixDisplay*1) << "include successful assertions in output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "cs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "case-sensitive= " - << Whitespace(sizePrefixDisplay*1) << "filters being treated as case sensitive\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "e, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "exit= " - << Whitespace(sizePrefixDisplay*1) << "exits after the tests finish\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "duration= " - << Whitespace(sizePrefixDisplay*1) << "prints the time duration of each test\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw= " - << Whitespace(sizePrefixDisplay*1) << "skips exceptions-related assert checks\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode= " - << Whitespace(sizePrefixDisplay*1) << "returns (or exits) always with success\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run= " - << Whitespace(sizePrefixDisplay*1) << "skips all runtime doctest operations\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version= " - << Whitespace(sizePrefixDisplay*1) << "omit the framework version in the output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors= " - << Whitespace(sizePrefixDisplay*1) << "disables colors in output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "fc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "force-colors= " - << Whitespace(sizePrefixDisplay*1) << "use colors even when not in a tty\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nb, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-breaks= " - << Whitespace(sizePrefixDisplay*1) << "disables breakpoints in debuggers\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ns, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-skip= " - << Whitespace(sizePrefixDisplay*1) << "don't skip test cases marked as skip\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "gfl, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "gnu-file-line= " - << Whitespace(sizePrefixDisplay*1) << ":n: vs (n): for line numbers in output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "npf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-path-filenames= " - << Whitespace(sizePrefixDisplay*1) << "only filenames and no paths in output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nln, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-line-numbers= " - << Whitespace(sizePrefixDisplay*1) << "0 instead of real line numbers in output\n"; - // ================================================================================== << 79 - // clang-format on - - s << Color::Cyan << "\n[doctest] " << Color::None; - s << "for more information visit the project documentation\n\n"; - } - - void printRegisteredReporters() { - printVersion(); - auto printReporters = [this] (const reporterMap& reporters, const char* type) { - if(reporters.size()) { - s << Color::Cyan << "[doctest] " << Color::None << "listing all registered " << type << "\n"; - for(auto& curr : reporters) - s << "priority: " << std::setw(5) << curr.first.first - << " name: " << curr.first.second << "\n"; - } - }; - printReporters(getListeners(), "listeners"); - printReporters(getReporters(), "reporters"); - } - - void list_query_results() { - separator_to_stream(); - if(opt.count || opt.list_test_cases) { - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " - << g_cs->numTestCasesPassingFilters << "\n"; - } else if(opt.list_test_suites) { - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " - << g_cs->numTestCasesPassingFilters << "\n"; - s << Color::Cyan << "[doctest] " << Color::None - << "test suites with unskipped test cases passing the current filters: " - << g_cs->numTestSuitesPassingFilters << "\n"; - } - } - - // ========================================================================================= - // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE - // ========================================================================================= - - void report_query(const QueryData& in) override { - if(opt.version) { - printVersion(); - } else if(opt.help) { - printHelp(); - } else if(opt.list_reporters) { - printRegisteredReporters(); - } else if(opt.count || opt.list_test_cases) { - if(opt.list_test_cases) { - s << Color::Cyan << "[doctest] " << Color::None - << "listing all test case names\n"; - separator_to_stream(); - } - - for(unsigned i = 0; i < in.num_data; ++i) - s << Color::None << in.data[i]->m_name << "\n"; - - separator_to_stream(); - - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " - << g_cs->numTestCasesPassingFilters << "\n"; - - } else if(opt.list_test_suites) { - s << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n"; - separator_to_stream(); - - for(unsigned i = 0; i < in.num_data; ++i) - s << Color::None << in.data[i]->m_test_suite << "\n"; - - separator_to_stream(); - - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " - << g_cs->numTestCasesPassingFilters << "\n"; - s << Color::Cyan << "[doctest] " << Color::None - << "test suites with unskipped test cases passing the current filters: " - << g_cs->numTestSuitesPassingFilters << "\n"; - } - } - - void test_run_start() override { printIntro(); } - - void test_run_end(const TestRunStats& p) override { - separator_to_stream(); - s << std::dec; - - auto totwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters, static_cast(p.numAsserts))) + 1))); - auto passwidth = int(std::ceil(log10((std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast(p.numAsserts - p.numAssertsFailed))) + 1))); - auto failwidth = int(std::ceil(log10((std::max(p.numTestCasesFailed, static_cast(p.numAssertsFailed))) + 1))); - const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0; - s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(totwidth) - << p.numTestCasesPassingFilters << " | " - << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None : - Color::Green) - << std::setw(passwidth) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed" - << Color::None << " | " << (p.numTestCasesFailed > 0 ? Color::Red : Color::None) - << std::setw(failwidth) << p.numTestCasesFailed << " failed" << Color::None << " |"; - if(opt.no_skipped_summary == false) { - const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters; - s << " " << (numSkipped == 0 ? Color::None : Color::Yellow) << numSkipped - << " skipped" << Color::None; - } - s << "\n"; - s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(totwidth) - << p.numAsserts << " | " - << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green) - << std::setw(passwidth) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None - << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth) - << p.numAssertsFailed << " failed" << Color::None << " |\n"; - s << Color::Cyan << "[doctest] " << Color::None - << "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green) - << ((p.numTestCasesFailed > 0) ? "FAILURE!" : "SUCCESS!") << Color::None << std::endl; - } - - void test_case_start(const TestCaseData& in) override { - hasLoggedCurrentTestStart = false; - tc = ∈ - subcasesStack.clear(); - currentSubcaseLevel = 0; - } - - void test_case_reenter(const TestCaseData&) override { - subcasesStack.clear(); - } - - void test_case_end(const CurrentTestCaseStats& st) override { - if(tc->m_no_output) - return; - - // log the preamble of the test case only if there is something - // else to print - something other than that an assert has failed - if(opt.duration || - (st.failure_flags && st.failure_flags != TestCaseFailureReason::AssertFailure)) - logTestStart(); - - if(opt.duration) - s << Color::None << std::setprecision(6) << std::fixed << st.seconds - << " s: " << tc->m_name << "\n"; - - if(st.failure_flags & TestCaseFailureReason::Timeout) - s << Color::Red << "Test case exceeded time limit of " << std::setprecision(6) - << std::fixed << tc->m_timeout << "!\n"; - - if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) { - s << Color::Red << "Should have failed but didn't! Marking it as failed!\n"; - } else if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedAndDid) { - s << Color::Yellow << "Failed as expected so marking it as not failed\n"; - } else if(st.failure_flags & TestCaseFailureReason::CouldHaveFailedAndDid) { - s << Color::Yellow << "Allowed to fail so marking it as not failed\n"; - } else if(st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) { - s << Color::Red << "Didn't fail exactly " << tc->m_expected_failures - << " times so marking it as failed!\n"; - } else if(st.failure_flags & TestCaseFailureReason::FailedExactlyNumTimes) { - s << Color::Yellow << "Failed exactly " << tc->m_expected_failures - << " times as expected so marking it as not failed!\n"; - } - if(st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) { - s << Color::Red << "Aborting - too many failed asserts!\n"; - } - s << Color::None; // lgtm [cpp/useless-expression] - } - - void test_case_exception(const TestCaseException& e) override { - if(tc->m_no_output) - return; - - logTestStart(); - - file_line_to_stream(tc->m_file.c_str(), tc->m_line, " "); - successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require : - assertType::is_check); - s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: ") - << Color::Cyan << e.error_string << "\n"; - - int num_stringified_contexts = get_num_stringified_contexts(); - if(num_stringified_contexts) { - auto stringified_contexts = get_stringified_contexts(); - s << Color::None << " logged: "; - for(int i = num_stringified_contexts; i > 0; --i) { - s << (i == num_stringified_contexts ? "" : " ") - << stringified_contexts[i - 1] << "\n"; - } - } - s << "\n" << Color::None; - } - - void subcase_start(const SubcaseSignature& subc) override { - std::lock_guard lock(mutex); - subcasesStack.push_back(subc); - ++currentSubcaseLevel; - hasLoggedCurrentTestStart = false; - } - - void subcase_end() override { - std::lock_guard lock(mutex); - --currentSubcaseLevel; - hasLoggedCurrentTestStart = false; - } - - void log_assert(const AssertData& rb) override { - if((!rb.m_failed && !opt.success) || tc->m_no_output) - return; - - std::lock_guard lock(mutex); - - logTestStart(); - - file_line_to_stream(rb.m_file, rb.m_line, " "); - successOrFailColoredStringToStream(!rb.m_failed, rb.m_at); - - fulltext_log_assert_to_stream(s, rb); - - log_contexts(); - } - - void log_message(const MessageData& mb) override { - if(tc->m_no_output) - return; - - std::lock_guard lock(mutex); - - logTestStart(); - - file_line_to_stream(mb.m_file, mb.m_line, " "); - s << getSuccessOrFailColor(false, mb.m_severity) - << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity, - "MESSAGE") << ": "; - s << Color::None << mb.m_string << "\n"; - log_contexts(); - } - - void test_case_skipped(const TestCaseData&) override {} - }; - - DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter); - -#ifdef DOCTEST_PLATFORM_WINDOWS - struct DebugOutputWindowReporter : public ConsoleReporter - { - DOCTEST_THREAD_LOCAL static std::ostringstream oss; - - DebugOutputWindowReporter(const ContextOptions& co) - : ConsoleReporter(co, oss) {} - -#define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg) \ - void func(type arg) override { \ - bool with_col = g_no_colors; \ - g_no_colors = false; \ - ConsoleReporter::func(arg); \ - if(oss.tellp() != std::streampos{}) { \ - DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \ - oss.str(""); \ - } \ - g_no_colors = with_col; \ - } - - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_assert, const AssertData&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_message, const MessageData&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_skipped, const TestCaseData&, in) - }; - - DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss; -#endif // DOCTEST_PLATFORM_WINDOWS - - // the implementation of parseOption() - bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) { - // going from the end to the beginning and stopping on the first occurrence from the end - for(int i = argc; i > 0; --i) { - auto index = i - 1; - auto temp = std::strstr(argv[index], pattern); - if(temp && (value || strlen(temp) == strlen(pattern))) { //!OCLINT prefer early exits and continue - // eliminate matches in which the chars before the option are not '-' - bool noBadCharsFound = true; - auto curr = argv[index]; - while(curr != temp) { - if(*curr++ != '-') { - noBadCharsFound = false; - break; - } - } - if(noBadCharsFound && argv[index][0] == '-') { - if(value) { - // parsing the value of an option - temp += strlen(pattern); - const unsigned len = strlen(temp); - if(len) { - *value = temp; - return true; - } - } else { - // just a flag - no value - return true; - } - } - } - } - return false; - } - - // parses an option and returns the string after the '=' character - bool parseOption(int argc, const char* const* argv, const char* pattern, String* value = nullptr, - const String& defaultVal = String()) { - if(value) - *value = defaultVal; -#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - // offset (normally 3 for "dt-") to skip prefix - if(parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value)) - return true; -#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - return parseOptionImpl(argc, argv, pattern, value); - } - - // locates a flag on the command line - bool parseFlag(int argc, const char* const* argv, const char* pattern) { - return parseOption(argc, argv, pattern); - } - - // parses a comma separated list of words after a pattern in one of the arguments in argv - bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern, - std::vector& res) { - String filtersString; - if(parseOption(argc, argv, pattern, &filtersString)) { - // tokenize with "," as a separator - // cppcheck-suppress strtokCalled - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - auto pch = std::strtok(filtersString.c_str(), ","); // modifies the string - while(pch != nullptr) { - if(strlen(pch)) - res.push_back(pch); - // uses the strtok() internal state to go to the next token - // cppcheck-suppress strtokCalled - pch = std::strtok(nullptr, ","); - } - DOCTEST_CLANG_SUPPRESS_WARNING_POP - return true; - } - return false; - } - - enum optionType - { - option_bool, - option_int - }; - - // parses an int/bool option from the command line - bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type, - int& res) { - String parsedValue; - if(!parseOption(argc, argv, pattern, &parsedValue)) - return false; - - if(type == 0) { - // boolean - const char positive[][5] = {"1", "true", "on", "yes"}; // 5 - strlen("true") + 1 - const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1 - - // if the value matches any of the positive/negative possibilities - for(unsigned i = 0; i < 4; i++) { - if(parsedValue.compare(positive[i], true) == 0) { - res = 1; //!OCLINT parameter reassignment - return true; - } - if(parsedValue.compare(negative[i], true) == 0) { - res = 0; //!OCLINT parameter reassignment - return true; - } - } - } else { - // integer - // TODO: change this to use std::stoi or something else! currently it uses undefined behavior - assumes '0' on failed parse... - int theInt = std::atoi(parsedValue.c_str()); // NOLINT - if(theInt != 0) { - res = theInt; //!OCLINT parameter reassignment - return true; - } - } - return false; - } -} // namespace - -Context::Context(int argc, const char* const* argv) - : p(new detail::ContextState) { - parseArgs(argc, argv, true); - if(argc) - p->binary_name = argv[0]; -} - -Context::~Context() { - if(g_cs == p) - g_cs = nullptr; - delete p; -} - -void Context::applyCommandLine(int argc, const char* const* argv) { - parseArgs(argc, argv); - if(argc) - p->binary_name = argv[0]; -} - -// parses args -void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) { - using namespace detail; - - // clang-format off - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file=", p->filters[0]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sf=", p->filters[0]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file-exclude=",p->filters[1]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sfe=", p->filters[1]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite=", p->filters[2]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ts=", p->filters[2]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite-exclude=", p->filters[3]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tse=", p->filters[3]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case=", p->filters[4]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tc=", p->filters[4]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case-exclude=", p->filters[5]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tce=", p->filters[5]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase=", p->filters[6]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sc=", p->filters[6]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase-exclude=", p->filters[7]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sce=", p->filters[7]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "reporters=", p->filters[8]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "r=", p->filters[8]); - // clang-format on - - int intRes = 0; - String strRes; - -#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ - if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \ - parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \ - p->var = static_cast(intRes); \ - else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \ - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \ - p->var = true; \ - else if(withDefaults) \ - p->var = default - -#define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \ - if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_int, intRes) || \ - parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_int, intRes)) \ - p->var = intRes; \ - else if(withDefaults) \ - p->var = default - -#define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ - if(parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", &strRes, default) || \ - parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", &strRes, default) || \ - withDefaults) \ - p->var = strRes - - // clang-format off - DOCTEST_PARSE_STR_OPTION("out", "o", out, ""); - DOCTEST_PARSE_STR_OPTION("order-by", "ob", order_by, "file"); - DOCTEST_PARSE_INT_OPTION("rand-seed", "rs", rand_seed, 0); - - DOCTEST_PARSE_INT_OPTION("first", "f", first, 0); - DOCTEST_PARSE_INT_OPTION("last", "l", last, UINT_MAX); - - DOCTEST_PARSE_INT_OPTION("abort-after", "aa", abort_after, 0); - DOCTEST_PARSE_INT_OPTION("subcase-filter-levels", "scfl", subcase_filter_levels, INT_MAX); - - DOCTEST_PARSE_AS_BOOL_OR_FLAG("success", "s", success, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-breaks", "nb", no_breaks, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skip", "ns", no_skip, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC)); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-debug-output", "ndo", no_debug_output, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-time-in-output", "ntio", no_time_in_output, false); - // clang-format on - - if(withDefaults) { - p->help = false; - p->version = false; - p->count = false; - p->list_test_cases = false; - p->list_test_suites = false; - p->list_reporters = false; - } - if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "help") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "h") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "?")) { - p->help = true; - p->exit = true; - } - if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "version") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "v")) { - p->version = true; - p->exit = true; - } - if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "count") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "c")) { - p->count = true; - p->exit = true; - } - if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-cases") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ltc")) { - p->list_test_cases = true; - p->exit = true; - } - if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-suites") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lts")) { - p->list_test_suites = true; - p->exit = true; - } - if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-reporters") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lr")) { - p->list_reporters = true; - p->exit = true; - } -} - -// allows the user to add procedurally to the filters from the command line -void Context::addFilter(const char* filter, const char* value) { setOption(filter, value); } - -// allows the user to clear all filters from the command line -void Context::clearFilters() { - for(auto& curr : p->filters) - curr.clear(); -} - -// allows the user to override procedurally the int/bool options from the command line -void Context::setOption(const char* option, int value) { - setOption(option, toString(value).c_str()); - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) -} - -// allows the user to override procedurally the string options from the command line -void Context::setOption(const char* option, const char* value) { - auto argv = String("-") + option + "=" + value; - auto lvalue = argv.c_str(); - parseArgs(1, &lvalue); -} - -// users should query this in their main() and exit the program if true -bool Context::shouldExit() { return p->exit; } - -void Context::setAsDefaultForAssertsOutOfTestCases() { g_cs = p; } - -void Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; } - -// the main function that does all the filtering and test running -int Context::run() { - using namespace detail; - - // save the old context state in case such was setup - for using asserts out of a testing context - auto old_cs = g_cs; - // this is the current contest - g_cs = p; - is_running_in_test = true; - - g_no_colors = p->no_colors; - p->resetRunData(); - - // stdout by default - p->cout = &std::cout; - p->cerr = &std::cerr; - - // or to a file if specified - std::fstream fstr; - if(p->out.size()) { - fstr.open(p->out.c_str(), std::fstream::out); - p->cout = &fstr; - } - - FatalConditionHandler::allocateAltStackMem(); - - auto cleanup_and_return = [&]() { - FatalConditionHandler::freeAltStackMem(); - - if(fstr.is_open()) - fstr.close(); - - // restore context - g_cs = old_cs; - is_running_in_test = false; - - // we have to free the reporters which were allocated when the run started - for(auto& curr : p->reporters_currently_used) - delete curr; - p->reporters_currently_used.clear(); - - if(p->numTestCasesFailed && !p->no_exitcode) - return EXIT_FAILURE; - return EXIT_SUCCESS; - }; - - // setup default reporter if none is given through the command line - if(p->filters[8].empty()) - p->filters[8].push_back("console"); - - // check to see if any of the registered reporters has been selected - for(auto& curr : getReporters()) { - if(matchesAny(curr.first.second.c_str(), p->filters[8], false, p->case_sensitive)) - p->reporters_currently_used.push_back(curr.second(*g_cs)); - } - - // TODO: check if there is nothing in reporters_currently_used - - // prepend all listeners - for(auto& curr : getListeners()) - p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs)); - -#ifdef DOCTEST_PLATFORM_WINDOWS - if(isDebuggerActive() && p->no_debug_output == false) - p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs)); -#endif // DOCTEST_PLATFORM_WINDOWS - - // handle version, help and no_run - if(p->no_run || p->version || p->help || p->list_reporters) { - DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, QueryData()); - - return cleanup_and_return(); - } - - std::vector testArray; - for(auto& curr : getRegisteredTests()) - testArray.push_back(&curr); - p->numTestCases = testArray.size(); - - // sort the collected records - if(!testArray.empty()) { - if(p->order_by.compare("file", true) == 0) { - std::sort(testArray.begin(), testArray.end(), fileOrderComparator); - } else if(p->order_by.compare("suite", true) == 0) { - std::sort(testArray.begin(), testArray.end(), suiteOrderComparator); - } else if(p->order_by.compare("name", true) == 0) { - std::sort(testArray.begin(), testArray.end(), nameOrderComparator); - } else if(p->order_by.compare("rand", true) == 0) { - std::srand(p->rand_seed); - - // random_shuffle implementation - const auto first = &testArray[0]; - for(size_t i = testArray.size() - 1; i > 0; --i) { - int idxToSwap = std::rand() % (i + 1); // NOLINT - - const auto temp = first[i]; - - first[i] = first[idxToSwap]; - first[idxToSwap] = temp; - } - } else if(p->order_by.compare("none", true) == 0) { - // means no sorting - beneficial for death tests which call into the executable - // with a specific test case in mind - we don't want to slow down the startup times - } - } - - std::set testSuitesPassingFilt; - - bool query_mode = p->count || p->list_test_cases || p->list_test_suites; - std::vector queryResults; - - if(!query_mode) - DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY); - - // invoke the registered functions if they match the filter criteria (or just count them) - for(auto& curr : testArray) { - const auto& tc = *curr; - - bool skip_me = false; - if(tc.m_skip && !p->no_skip) - skip_me = true; - - if(!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive)) - skip_me = true; - if(matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive)) - skip_me = true; - if(!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive)) - skip_me = true; - if(matchesAny(tc.m_test_suite, p->filters[3], false, p->case_sensitive)) - skip_me = true; - if(!matchesAny(tc.m_name, p->filters[4], true, p->case_sensitive)) - skip_me = true; - if(matchesAny(tc.m_name, p->filters[5], false, p->case_sensitive)) - skip_me = true; - - if(!skip_me) - p->numTestCasesPassingFilters++; - - // skip the test if it is not in the execution range - if((p->last < p->numTestCasesPassingFilters && p->first <= p->last) || - (p->first > p->numTestCasesPassingFilters)) - skip_me = true; - - if(skip_me) { - if(!query_mode) - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_skipped, tc); - continue; - } - - // do not execute the test if we are to only count the number of filter passing tests - if(p->count) - continue; - - // print the name of the test and don't execute it - if(p->list_test_cases) { - queryResults.push_back(&tc); - continue; - } - - // print the name of the test suite if not done already and don't execute it - if(p->list_test_suites) { - if((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\0') { - queryResults.push_back(&tc); - testSuitesPassingFilt.insert(tc.m_test_suite); - p->numTestSuitesPassingFilters++; - } - continue; - } - - // execute the test if it passes all the filtering - { - p->currentTest = &tc; - - p->failure_flags = TestCaseFailureReason::None; - p->seconds = 0; - - // reset atomic counters - p->numAssertsFailedCurrentTest_atomic = 0; - p->numAssertsCurrentTest_atomic = 0; - - p->subcasesPassed.clear(); - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc); - - p->timer.start(); - - bool run_test = true; - - do { - // reset some of the fields for subcases (except for the set of fully passed ones) - p->should_reenter = false; - p->subcasesCurrentMaxLevel = 0; - p->subcasesStack.clear(); - - p->shouldLogCurrentException = true; - - // reset stuff for logging with INFO() - p->stringifiedContexts.clear(); - -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - try { -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS -// MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a static method) -DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable - FatalConditionHandler fatalConditionHandler; // Handle signals - // execute the test - tc.m_test(); - fatalConditionHandler.reset(); -DOCTEST_MSVC_SUPPRESS_WARNING_POP -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - } catch(const TestFailureException&) { - p->failure_flags |= TestCaseFailureReason::AssertFailure; - } catch(...) { - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, - {translateActiveException(), false}); - p->failure_flags |= TestCaseFailureReason::Exception; - } -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - - // exit this loop if enough assertions have failed - even if there are more subcases - if(p->abort_after > 0 && - p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) { - run_test = false; - p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts; - } - - if(p->should_reenter && run_test) - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc); - if(!p->should_reenter) - run_test = false; - } while(run_test); - - p->finalizeTestCaseData(); - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); - - p->currentTest = nullptr; - - // stop executing tests if enough assertions have failed - if(p->abort_after > 0 && p->numAssertsFailed >= p->abort_after) - break; - } - } - - if(!query_mode) { - DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); - } else { - QueryData qdata; - qdata.run_stats = g_cs; - qdata.data = queryResults.data(); - qdata.num_data = unsigned(queryResults.size()); - DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata); - } - - // see these issues on the reasoning for this: - // - https://github.com/onqtam/doctest/issues/143#issuecomment-414418903 - // - https://github.com/onqtam/doctest/issues/126 - auto DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS = []() DOCTEST_NOINLINE - { std::cout << std::string(); }; - DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS(); - - return cleanup_and_return(); -} - -IReporter::~IReporter() = default; - -int IReporter::get_num_active_contexts() { return detail::g_infoContexts.size(); } -const IContextScope* const* IReporter::get_active_contexts() { - return get_num_active_contexts() ? &detail::g_infoContexts[0] : nullptr; -} - -int IReporter::get_num_stringified_contexts() { return detail::g_cs->stringifiedContexts.size(); } -const String* IReporter::get_stringified_contexts() { - return get_num_stringified_contexts() ? &detail::g_cs->stringifiedContexts[0] : nullptr; -} - -namespace detail { - void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) { - if(isReporter) - getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); - else - getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); - } -} // namespace detail - -} // namespace doctest - -#endif // DOCTEST_CONFIG_DISABLE - -#ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182 -int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } -DOCTEST_MSVC_SUPPRESS_WARNING_POP -#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN - -DOCTEST_CLANG_SUPPRESS_WARNING_POP -DOCTEST_MSVC_SUPPRESS_WARNING_POP -DOCTEST_GCC_SUPPRESS_WARNING_POP - -#endif // DOCTEST_LIBRARY_IMPLEMENTATION -#endif // DOCTEST_CONFIG_IMPLEMENT diff --git a/dbm/include/hash/compute.h b/dbm/include/hash/compute.h deleted file mode 100644 index adcc1ded..00000000 --- a/dbm/include/hash/compute.h +++ /dev/null @@ -1,156 +0,0 @@ -/* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -/********************************************************************* - * - * Filename : compute.h (hash) - * C header. - * - * Functions to compute hash values. - * - * This file is a part of the UPPAAL toolkit. - * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. - * All right reserved. - * - * Not reviewed yet. - * $Id: compute.h,v 1.6 2005/04/22 15:20:10 adavid Exp $ - * - **********************************************************************/ - -#ifndef INCLUDE_HASH_COMPUTE_H -#define INCLUDE_HASH_COMPUTE_H - -#define MURMUR2_HASH1 -#define MURMUR2_HASH2 - -#include "base/inttypes.h" - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Hash mix found at http://burtleburtle.net/bob/hash/ - * Original comments from the author: - * -------------------------------------------------------------------- - * mix -- mix 3 32-bit values reversibly. - * For every delta with one or two bit set, and the deltas of all three - * high bits or all three low bits, whether the original value of a,b,c - * is almost all zero or is uniformly distributed, - * * If mix() is run forward or backward, at least 32 bits in a,b,c - * have at least 1/4 probability of changing. - * * If mix() is run forward, every bit of c will change between 1/3 and - * 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) - * mix() takes 36 machine instructions, but only 18 cycles on a superscalar - * machine (like a Pentium or a Sparc). No faster mixer seems to work, - * that's the result of my brute-force search. There were about 2^^68 - * hashes to choose from. I only tested about a billion of those. - * -------------------------------------------------------------------- - * NOTE: the hash function based on this hash mix is much faster than - * MD5 hashing and gives exactly the same results. - */ -#define HASH_MIX(a, b, c) \ - { \ - a -= b; \ - a -= c; \ - a ^= (c >> 13); \ - b -= c; \ - b -= a; \ - b ^= (a << 8); \ - c -= a; \ - c -= b; \ - c ^= (b >> 13); \ - a -= b; \ - a -= c; \ - a ^= (c >> 12); \ - b -= c; \ - b -= a; \ - b ^= (a << 16); \ - c -= a; \ - c -= b; \ - c ^= (b >> 5); \ - a -= b; \ - a -= c; \ - a ^= (c >> 3); \ - b -= c; \ - b -= a; \ - b ^= (a << 10); \ - c -= a; \ - c -= b; \ - c ^= (b >> 15); \ - } - -/** Compute hash value for different data types. - * @param data: data to read. - * @param length: number of types to read - * @param initval: used to initialize the hash computation. - * initval is useful when computing a composite hash - * involving different data types. It is then possible - * to chain the hash computation. - * @pre pointers are 32 bits aligned. - * @return: hash value. - * @note the following calls may not necessarily return - * the same result: - * hash_computeU32((uint32_t*)data, 32, initval) - * hash_computeU16((uint16_t*)data, 64, initval) - * hash_computeU8((uint8_t*)data, 128, initval) - */ -uint32_t hash_computeU8(const uint8_t* data, size_t length, uint32_t initval); -#ifdef MURMUR2_HASH1 -static inline uint32_t hash_computeU32(const uint32_t* data, size_t length, uint32_t initval) -{ - return hash_computeU8((uint8_t*)data, 4 * length, initval); -} -static inline uint32_t hash_computeU16(const uint16_t* data, size_t length, uint32_t initval) -{ - return hash_computeU8((uint8_t*)data, 2 * length, initval); -} -#else -uint32_t hash_computeU32(const uint32_t* data, size_t length, uint32_t initval); -uint32_t hash_computeU16(const uint16_t* data, size_t length, uint32_t initval); -#endif - -/** Wrapper functions for convenience. - * Wrap types of input data: support for - * int32_t => uint32_t - * int16_t => uint16_t - * int8_t => uint8_t - * char[] => uint8_t - */ -static inline uint32_t hash_computeI32(const int32_t* data, size_t length, uint32_t initval) -{ - return hash_computeU32((uint32_t*)data, length, initval); -} - -static inline uint32_t hash_computeI16(const int16_t* data, size_t length, uint32_t initval) -{ - return hash_computeU16((uint16_t*)data, length, initval); -} - -static inline uint32_t hash_computeI8(const int8_t* data, size_t length, uint32_t initval) -{ - return hash_computeU8((uint8_t*)data, length, initval); -} - -static inline uint32_t hash_computeStr(const char* str, uint32_t initval) -{ - assert(sizeof(char) == sizeof(uint8_t)); - return hash_computeU8((uint8_t*)str, strlen(str), initval); -} - -/** Compute a new hash from 3 previous hash values. - * @param a,b,c: values to combine. - * @return a mixed hashed value. - */ -static inline uint32_t hash_compute(uint32_t a, uint32_t b, uint32_t c) -{ - HASH_MIX(a, b, c); - return c; -} - -#ifdef __cplusplus -} -#endif - -#endif // INCLUDE_HASH_COMPUTE_H diff --git a/dbm/include/hash/tables.h b/dbm/include/hash/tables.h deleted file mode 100644 index cd2cb0bd..00000000 --- a/dbm/include/hash/tables.h +++ /dev/null @@ -1,387 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : tables.h -// -// AbstractTable : abstract template -// | -// +-TableSingle : template for single linked bucket hash table -// | -// +-TableDouble : template for double linked bucket hash table -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: tables.h,v 1.11 2005/04/25 16:38:27 behrmann Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_BASE_TABLES_H -#define INCLUDE_BASE_TABLES_H - -#include "base/intutils.h" -#include "base/Enumerator.h" - -#include // std::fill - -/** - * @file - * Basis for hash tables. To get a working hash table one has - * to implement the insert/delete that is dependant on the data - * type, in particular to test for equality. - */ - -namespace uhash -{ - /** Single linked buckets - * info contains the hash value and possible other data: - * (info & mask) free for data, (info & ~mask) reserved. - * We need a concrete type for the generic rehash functions - * that do not depend on any customized data, and a template - * type to avoid tons of casts. - */ - struct SingleBucket_t : /* concrete type */ - public base::SingleLinkable - { - uint32_t info; - }; - - template - struct SingleBucket : /* template */ - public base::SingleLinkable - { - uint32_t info; - }; - - /** Double linked buckets, as for single buckets. - */ - struct DoubleBucket_t : /* concrete type */ - public base::DoubleLinkable - { - uint32_t info; - }; - - template - struct DoubleBucket : /* template */ - public base::DoubleLinkable - { - uint32_t info; - /**< Default use of info lower bits: - * reference counter. - */ - - /** Increment reference counter - * with a given mask being the maximal - * possible value. - * @param mask: mask (also max) - * @pre mask = ((1 << n) - 1) for some n - * such that size of hash table <= 2^n. - */ - void incRef(uint32_t mask) - { - if ((info & mask) != mask) - info++; - } - - /** Decrement reference counter. - * May skip decrement if counter == mask. - * @return true if counter is == 0 - * @param mask: mask (also max) - */ - bool decRef(uint32_t mask) - { - if ((info & mask) == mask) - return false; - assert(info & mask); // must be referenced - return (--info & mask) == 0; - } - }; - - /** Rehashing for single/double linked - * buckets. In practice, the hash value is - * not recomputed since it is stored in the - * 'info' field of the buckets. - * @param tablePtr: where the table of bucket* to - * rehash is. The table will be reallocated. - * @param maskPtr: the mask used to access the indices - * it will be read and written. - * @pre the size of the table is a power of - * 2 and size = mask + 1 - * @post *tablePtr is deallocated (delete) and - * the new table is newly allocated (new). - */ - void rehash(SingleBucket_t*** tablePtr, uint32_t* maskPtr); - void rehash(DoubleBucket_t*** tablePtr, uint32_t* maskPtr); - - /** Abstract general hash table. DO NOT USE DIRECTLY. - * @param BucketType: customized buckets (with customized - * data) to use. - * @param BucketParentType: SingleBucket_t or DoubleBucket_t - * @param BucketParentTemplate: SingleBucket or DoubleBucket - */ - template - class AbstractTable - { - public: - /** Control rehashing: by default - * hash tables rehash themselves - * automatically. You can disable this - * feature. - */ - void disableRehash() { mayRehash = false; } - void enableRehash() { mayRehash = mask < MAX_TABLE_SIZE - 1; } - - /** Return the hash mask to get access - * to the table: index = hashValue & mask. - * @return a binary mask. - */ - uint32_t getHashMask() const { return mask; } - - /** @return the number of used buckets - * so far. - */ - size_t getNbBuckets() const { return nbBuckets; } - - /** @return the size of the table. As the size - * is a power of 2, mask = size - 1. We keep - * mask because it is more useful. - */ - size_t getTableSize() const { return mask + 1; } - - /** Reset the table without deleting the buckets - */ - void reset() - { - nbBuckets = 0; - std::fill(buckets, buckets + getTableSize(), nullptr); - } - - /** Reset the table and delete the buckets. - * Note: as the bucket type is custom, the delete call - * may call destructors of the sub-types. - */ - void resetDelete() - { - size_t n = getTableSize(); // mask + 1 > 0 - BucketType** table = getBuckets(); - do { - if (*table) { - BucketType* bucket = *table; - do { - BucketType* next = bucket->getNext(); - delete bucket; - bucket = next; - } while (bucket); - *table = nullptr; - } - ++table; - } while (--n); - nbBuckets = 0; - } - - /** Simple adapter to tie together the hash table and - * bucket types. - */ - struct Bucket_t : public BucketParentTemplate - {}; - - /** Enumerator - */ - base::Enumerator getEnumerator() const - { - return base::Enumerator(getTableSize(), getBuckets()); - } - - /** Increase the counter of the buckets. This - * automatically calls rehash if needed. Call - * this whenever you add a new bucket in the - * hash table, BUT ALWAYS AFTER adding a bucket - * (bucket->link(somewhere) because of the rehashing. - */ - void incBuckets() - { - ++nbBuckets; - if (needsRehash() && mayRehash) { - rehash(reinterpret_cast(&buckets), &mask); - mayRehash = mask < MAX_TABLE_SIZE - 1; - } - } - - /** Decrease the counter of the buckets. - * Call this whenever you remove a bucket from - * the hash table. - */ - void decBuckets() - { - assert(nbBuckets); - --nbBuckets; - } - - /** Access to a particular table - * entry with a hash value. - * @param hashValue: the hash to compute the index. - */ - BucketType** getAtBucket(uint32_t hashValue) const { return &buckets[hashValue & mask]; } - - /** Access to the first bucket in the - * table with a given hash value. - * @param hashValue: the hash to compute the index. - */ - BucketType* getBucket(uint32_t hashValue) const { return buckets[hashValue & mask]; } - - /** Swap this table with another. - */ - void swap(AbstractTable& arg) - { - size_t n = arg.nbBuckets; - arg.nbBuckets = nbBuckets; - nbBuckets = n; - uint32_t m = arg.mask; - arg.mask = mask; - mask = m; - uint32_t s = arg.shiftThreshold; - arg.shiftThreshold = shiftThreshold; - shiftThreshold = s; - bool r = arg.mayRehash; - arg.mayRehash = mayRehash; - mayRehash = r; - BucketType** b = arg.buckets; - arg.buckets = buckets; - buckets = b; - } - - protected: - /** Access to the bucket table. - */ - BucketType** getBuckets() const { return buckets; } - - /** Protected constructor: this is an abstract - * class only. - * @param sizePower2: size in power of 2, ie, real - * size will be 2**sizePower2. - * @param aggressive: aggressive rehashing or not, - * which decides the threshold for rehashing. - */ - AbstractTable(uint32_t sizePower2, bool aggressive): - nbBuckets(0), mask((1u << sizePower2) - 1), shiftThreshold(aggressive ? 1 : 0), - mayRehash(true) - { - buckets = new BucketType*[getTableSize()]; - std::fill(buckets, buckets + getTableSize(), nullptr); - -#ifndef NDEBUG - for (size_t i = 0; i < getTableSize(); ++i) { - assert(buckets[i] == 0); - } -#endif /* not NDEBUG */ - } - - /** Destructor: not virtual. There is no polymorphism - * involved here. - */ - ~AbstractTable() { delete[] buckets; } - - /** We give a limit to the size of the tables - * to stop rehashing after a certain point. - */ - enum { MAX_TABLE_SIZE = (1u << 26u) }; - - size_t nbBuckets; /**< number of buckets */ - - private: - /** @return true if the threshold for rehashing is reached - */ - bool needsRehash() const { return nbBuckets > (mask >> shiftThreshold); } - - uint32_t mask; /**< mask to apply to hash value - to get indices = size - 1 since - the size of the table is a power of 2 */ - uint32_t shiftThreshold; /**< mask >> shiftThreshold is the threshold */ - bool mayRehash; /**< used to disable rehashing */ - BucketType** buckets; /**< the table of buckets */ - }; - - /************************************************************** - * Adapters to implement easily hash tables using single or - * double linked buckets. - * - * - How to use: - * - * struct MyBucket_t - * : public TableSingle::Bucket_t { ... }; - * class MyHashTable - * : public TableSingle { ... }; - * - * - Better way to make it more readable: - * - * struct MyBucket_t; - * typedef TableSingle ParentTable; - * - * struct MyBucket_t : public ParentTable::Bucket_t { ... }; - * class MyHashtable : public ParentTable { ... }; - * - ***************************************************************/ - - template >> - class TableSingle : public Parent - { - public: - explicit TableSingle(uint32_t sizePower2 = 8, bool aggressive = false): - Parent(sizePower2, aggressive) - {} - - /** Remove a bucket from the hash table. This - * is useful for singly linked buckets only - * where the info field stores the hash value - * ON ALL ITS BITS. - * @param bucket: bucket to remove from the hash table. - * @pre - * - bucket->info = hash value - * - bucket is stored in this hash table (otherwise segfault) - * @post bucket is removed but not deallocated - */ - void remove(BucketType* bucket) { remove(bucket, bucket->info); } - - /** Real implementation of remove, using explicitely the - * hash value that was used to entering this bucket in the - * table. THIS IS VITAL. - * @param bucket: bucket belonging to this table to remove - * @param hashValue: hash that was used to enter this table - */ - void remove(BucketType* bucket, uint32_t hashValue) - { - BucketType** entry = Parent::getAtBucket(hashValue); - while (*entry != bucket) { - assert(*entry); // MUST find it - entry = (*entry)->getAtNext(); - } - *entry = bucket->getNext(); // unlink - Parent::decBuckets(); - } - }; - - template >> - class TableDouble : public Parent - { - public: - TableDouble(uint32_t sizePower2 = 8, bool aggressive = false): - Parent(sizePower2, aggressive) - {} - - /** Remove a bucket from this hash table. - * @param bucket: bucket in this hash table to remove - */ - void remove(BucketType* bucket) - { - assert(bucket); - bucket->unlink(); - Parent::decBuckets(); - } - }; - -} // namespace uhash - -#endif // INCLUDE_BASE_TABLES_H diff --git a/dbm/include/io/FileStreamBuffer.h b/dbm/include/io/FileStreamBuffer.h deleted file mode 100644 index cd520f56..00000000 --- a/dbm/include/io/FileStreamBuffer.h +++ /dev/null @@ -1,58 +0,0 @@ -// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- -//////////////////////////////////////////////////////////////////// -// -// Filename : FileStreamBuffer.h (base) -// -// Wrap (C) FILE* to std::streambuf (very simple wrap). -// -// This file is a part of the UPPAAL toolkit. -// Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. -// All right reserved. -// -// $Id: FileStreamBuffer.h,v 1.1 2004/06/14 07:36:54 adavid Exp $ -// -/////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_IO_FILESTREAMBUFFER_H -#define INCLUDE_IO_FILESTREAMBUFFER_H - -#include -#include - -namespace io -{ - /** Simple wrapper of FILE* to streambuf to use C-style API. - * This class does not open or close the file, it only uses it. - */ - class FileStreamBuffer : public std::streambuf - { - public: - /** Constructor: - * @param theFile: file stream (in C) to wrapp. - * @pre theFile != NULL - */ - FileStreamBuffer(FILE* theFile): wrappedFile(theFile) {} - - /** Destructor: flush. - */ - virtual ~FileStreamBuffer() { fflush(wrappedFile); } - - /** overrides default overflow. - */ - int overflow(int c) override { return fputc(c, wrappedFile); } - - private: - FILE* wrappedFile; - }; -} // namespace io - -/** A macro to wrap print calls based on FILE* to - * calls using ostream. - * @param F: file* to wrap - * @param OBJ: object to print - */ -#define PRINT_OSTREAM(F, OBJ) \ - FileStreamBuffer local_fsb(F); \ - std::ostream(&local_fsb) << OBJ - -#endif // INCLUDE_IO_FILESTREAMBUFFER_H diff --git a/dbm/recompile.sh b/dbm/recompile.sh deleted file mode 100755 index 05ffd434..00000000 --- a/dbm/recompile.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -set -xe - -#Check for missing files -if [ ! -e lib/libbase.a ]; then - echo "Missing lib/libbase.a" - exit 1 -fi - -if [ ! -e lib/libdbm.a ]; then - echo "Missing lib/libdbm.a" - exit 1 -fi - -if [ ! -e lib/libhash.a ]; then - echo "Missing lib/libhash.a" - exit 1 -fi - -if [ ! -e lib/libudebug.a ]; then - echo "Missing lib/libudebug.a" - exit 1 -fi - -#Clean -mkdir objectFiles || true -rm objectFiles/*.o libudbmwrapper.a || true - -# Extract object files from lib folder -( - cd objectFiles - ar x ../lib/libbase.a - ar x ../lib/libdbm.a - ar x ../lib/libhash.a - ar x ../lib/libudebug.a -) - -# Compile wrapper -g++ -c wrapper.cpp -I include/ -o objectFiles/wrapper.o - -# Join wrapper and libudbm.a into a library archive -ar rvs libudbmwrapper.a objectFiles/*.o \ No newline at end of file diff --git a/dbm/toolchain-x86_64-w64-mingw32.cmake b/dbm/toolchain-x86_64-w64-mingw32.cmake deleted file mode 100644 index 809264e6..00000000 --- a/dbm/toolchain-x86_64-w64-mingw32.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# the name of the target operating system -set(CMAKE_SYSTEM_NAME Windows) -set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) - -#Used to define an output folder. The triple should correspond to the target triple that Reveaal is built to -#For native systems leave empty -set(triple x86_64-pc-windows-gnu) - -# which compilers to use for C and C++ -set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) -set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) -set(CMAKE_AR ${TOOLCHAIN_PREFIX}-gcc-ar) -set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) -set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip) -set(CMAKE_SIZEOF_VOID_P 8) # somehow not set by default - -# here is the target environment located -set(CMAKE_FIND_ROOT_PATH "${CMAKE_PREFIX_PATH}") - -# adjust the default behaviour of the FIND_XXX() commands: -# search headers and libraries in the target environment, -# search programs in both target and host environments -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/dbm/wrapper.cpp b/dbm/wrapper.cpp deleted file mode 100644 index 762a61a6..00000000 --- a/dbm/wrapper.cpp +++ /dev/null @@ -1,220 +0,0 @@ -#include "dbm/fed.h" -#include "wrapper.h" -#include "dbm/constraints.h" -#include "dbm/dbm.h" -#include "hash/compute.h" - -raw_t dbm_boundbool2raw_wrapper(int32_t bound, bool isStrict) -{ - return (bound * 2) | (isStrict ^ 1); -} - -int32_t dbm_raw2bound_wrapper(raw_t raw) { return (raw >> 1); } -bool dbm_rawIsStrict_wrapper(raw_t raw) { return ((raw & 1) ^ dbm_WEAK); } -bool dbm_satisfies_wrapper(const dbm::dbm_t &dbm, cindex_t i, cindex_t j, - raw_t constraint) -{ - cindex_t dim = dbm.getDimension(); - assert(dim > 0 && i < dim && j < dim); - return !(dbm(i, j) > constraint && /* tightening ? */ - dbm_negRaw(constraint) >= dbm(j, i)); /* too tight ? */ -} - -bool dbm_check_validity(const dbm::dbm_t *dbm) -{ - try - { - if (dbm_isValid(dbm->const_dbm(), dbm->getDimension()) == true) - { - return true; - } - else - { - return false; - } - } - catch (...) - { - return false; - } -} - -void fed_get_dbm_vec(const dbm::fed_t *fed, raw_t *vec, size_t vec_len) -{ - cindex_t dim = fed->getDimension(); - assert(vec_len == fed->size() * dim * dim); - - for (auto dbm = fed->begin(); dbm != fed->end(); ++dbm) - { - for (cindex_t i = 0; i < dim; ++i) - { - for (cindex_t j = 0; j < dim; ++j, ++vec) - { - *vec = (*dbm)(i, j); - } - } - } -} - -raw_t dbm_get_value(const dbm::dbm_t &dbm, cindex_t i, cindex_t j) -{ - return dbm(i, j); -} - -void fed_subtraction(dbm::fed_t &fed1, const dbm::fed_t &fed2) -{ - fed1 -= fed2; -} - -void fed_intersection(dbm::fed_t &fed1, const dbm::fed_t &fed2) -{ - fed1 &= fed2; -} - -bool fed_is_valid(const dbm::fed_t &fed) -{ - return !fed.isEmpty(); -} - -bool fed_is_empty(const dbm::fed_t &fed) -{ - return fed.isEmpty(); -} - -void fed_up(dbm::fed_t &fed) -{ - fed.up(); -} - -void fed_down(dbm::fed_t &fed) -{ - fed.down(); -} - -void fed_init(dbm::fed_t &fed) -{ - fed.setInit(); -} - -void fed_zero(dbm::fed_t &fed) -{ - fed.setZero(); -} - -bool fed_intersects(const dbm::fed_t &fed1, const dbm::fed_t &fed2) -{ - return fed1.intersects(fed2); -} - -bool fed_constrain(dbm::fed_t &fed, cindex_t i, cindex_t j, int32_t b, bool isStrict) -{ - return fed.constrain(i, j, b, isStrict); -} - -void fed_update(dbm::fed_t &fed, cindex_t x, cindex_t y, int32_t v) -{ - fed.update(x, y, v); -} - -void fed_free_clock(dbm::fed_t &fed, cindex_t x) -{ - fed.freeClock(x); -} - -bool fed_subset_eq(const dbm::fed_t &fed1, const dbm::fed_t &fed2) -{ - return fed1.le(fed2); -} - -relation_t fed_exact_relation(const dbm::fed_t &fed1, const dbm::fed_t &fed2) -{ - return fed1.exactRelation(fed2); -} - -relation_t fed_relation(const dbm::fed_t &fed1, const dbm::fed_t &fed2) -{ - return fed1.relation(fed2); -} - -bool fed_eq(const dbm::fed_t &fed1, const dbm::fed_t &fed2) -{ - return fed1 == fed2; -} - -bool fed_exact_eq(const dbm::fed_t &fed1, const dbm::fed_t &fed2) -{ - return fed1.eq(fed2); -} - -void fed_reduce(dbm::fed_t &fed) -{ - fed.reduce(); -} - -void fed_expensive_reduce(dbm::fed_t &fed) -{ - fed.expensiveReduce(); -} -bool fed_can_delay_indef(const dbm::fed_t &fed) -{ - return fed.isUnbounded(); -} - -void fed_extrapolate_max_bounds(dbm::fed_t &fed, const int32_t *max) -{ - fed.extrapolateMaxBounds(max); -} - -void fed_diagonal_extrapolate_max_bounds(dbm::fed_t &fed, const int32_t *max) -{ - fed.diagonalExtrapolateMaxBounds(max); -} - -void fed_add_fed(dbm::fed_t &fed, const dbm::fed_t &other) -{ - fed.add(other); -} - -void fed_invert(dbm::fed_t &fed) -{ - fed = !fed; -} - -size_t fed_size(const dbm::fed_t &fed) -{ - return fed.size(); -} - -bool fed_is_mutable(dbm::fed_t &fed) -{ - return fed.ifed()->isMutable(); -} - -void fed_new(dbm::fed_t &fed, cindex_t dim) -{ - fed = dbm::fed_t(dim); -} - -void fed_destruct(dbm::fed_t &fed) -{ - fed.nil(); - fed.~fed_t(); -} - -cindex_t fed_dimension(const dbm::fed_t &fed) -{ - return fed.getDimension(); -} - -void fed_predt(dbm::fed_t &good, const dbm::fed_t &bad) -{ - good = good.predt(bad); -} - -/* -void fed_crash(cindex_t dim) -{ - dbm::fed_t fed(dim); - fed.setZero(); - fed.nil(); -}*/ \ No newline at end of file diff --git a/dbm/wrapper.h b/dbm/wrapper.h deleted file mode 100644 index a848811b..00000000 --- a/dbm/wrapper.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef WRAPPER_H -#define WRAPPER_H -#include "dbm/dbm.h" - -extern "C" -{ - raw_t dbm_boundbool2raw_wrapper(int32_t bound, bool isStrict); - int32_t dbm_raw2bound_wrapper(raw_t raw); - bool dbm_rawIsStrict_wrapper(raw_t raw); - bool dbm_satisfies_wrapper(const dbm::dbm_t *dbm, cindex_t i, cindex_t j, - raw_t constraint); - - bool dbm_check_validity(const dbm::dbm_t *dbm); - - raw_t dbm_get_value(const dbm::dbm_t *dbm, cindex_t i, cindex_t j); - - void fed_get_dbm_vec(const dbm::fed_t *fed, raw_t *vec, size_t vec_len); - - void fed_subtraction(dbm::fed_t &fed1, const dbm::fed_t &fed2); - - void fed_intersection(dbm::fed_t &fed1, const dbm::fed_t &fed2); - - bool fed_intersects(const dbm::fed_t &fed1, const dbm::fed_t &fed2); - - bool fed_is_valid(const dbm::fed_t &fed); - - bool fed_is_empty(const dbm::fed_t &fed); - - void fed_up(dbm::fed_t &fed); - - void fed_down(dbm::fed_t &fed); - - void fed_init(dbm::fed_t &fed); - - void fed_zero(dbm::fed_t &fed); - - void fed_predt(dbm::fed_t &good, const dbm::fed_t &bad); - - // maybe call with - // let mut ptr = ::std::mem::MaybeUninit::uninit(); - // func(ptr.as_mut_ptr()); - // ptr.assume_init() - - bool fed_constrain(dbm::fed_t &fed, cindex_t i, cindex_t j, int32_t b, bool isStrict); - - /// Update method where x & y are clocks, v an integer value. - /// x := y + v -> update - void fed_update(dbm::fed_t &fed, cindex_t x, cindex_t y, int32_t v); - - void fed_free_clock(dbm::fed_t &fed, cindex_t x); - - bool fed_subset_eq(const dbm::fed_t &fed1, const dbm::fed_t &fed2); - - relation_t fed_relation(const dbm::fed_t &fed1, const dbm::fed_t &fed2); - - relation_t fed_exact_relation(const dbm::fed_t &fed1, const dbm::fed_t &fed2); - - bool fed_eq(const dbm::fed_t &fed1, const dbm::fed_t &fed2); - - bool fed_exact_eq(const dbm::fed_t &fed1, const dbm::fed_t &fed2); - - void fed_reduce(dbm::fed_t &fed); - - void fed_expensive_reduce(dbm::fed_t &fed); - - // fed.isUnbounded() - bool fed_can_delay_indef(const dbm::fed_t &fed); - - void fed_extrapolate_max_bounds(dbm::fed_t &fed, const int32_t *max); - - void fed_diagonal_extrapolate_max_bounds(dbm::fed_t &fed, const int32_t *max); - - void fed_add_fed(dbm::fed_t &fed, const dbm::fed_t &other); - - void fed_invert(dbm::fed_t &fed); - - size_t fed_size(const dbm::fed_t &fed); - - void fed_destruct(dbm::fed_t &fed); - - bool fed_is_mutable(dbm::fed_t &fed); - - void fed_new(dbm::fed_t &fed, cindex_t dim); - - cindex_t fed_dimension(const dbm::fed_t &fed); - - // void fed_crash(cindex_t dim); -} -// -#endif // WRAPPER_H diff --git a/src/DBMLib/dbm.rs b/src/DBMLib/dbm.rs deleted file mode 100644 index ebd30b31..00000000 --- a/src/DBMLib/dbm.rs +++ /dev/null @@ -1,596 +0,0 @@ -use crate::DBMLib::lib; -use crate::ModelObjects::max_bounds::MaxBounds; -use crate::ModelObjects::representations::{build_guard_from_zone, BoolExpression}; -use colored::Colorize; -use std::cmp::{Ordering, PartialOrd}; -use std::collections::HashMap; -use std::convert::TryInto; -use std::fmt::{Display, Formatter}; -use std::ops; -#[derive(Clone, Debug, std::cmp::PartialEq)] -pub struct Zone { - pub(crate) dimension: u32, - pub(in crate::DBMLib) matrix: Vec, -} - -pub enum Relation { - Different, - Superset, - Subset, - Equal, -} - -impl Zone { - pub fn get_constraint(&self, var_index_i: u32, var_index_j: u32) -> (bool, i32) { - let index: usize = (var_index_i * self.dimension + var_index_j) - .try_into() - .unwrap(); - let raw = self.matrix[index]; - - (lib::rs_raw_is_strict(raw), lib::rs_raw_to_bound(raw)) - } - - pub fn is_constraint_infinity(&self, var_index_i: u32, var_index_j: u32) -> bool { - let index: usize = (var_index_i * self.dimension + var_index_j) - .try_into() - .unwrap(); - let raw = self.matrix[index]; - raw == lib::DBM_INF - } -} - -impl Display for Zone { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_str("\n")?; - for i in 0..self.dimension { - f.write_str("{")?; - for j in 0..self.dimension { - if self.is_constraint_infinity(i, j) { - f.write_fmt(format_args!("{}", "(<∞)".to_string().bright_blue()))?; - } else { - let (rel, val) = self.get_constraint(i, j); - let op = if rel { "<" } else { "≤" }; - - if !rel && val == 0 { - f.write_fmt(format_args!("{}", "(≤0)".to_string().bright_green()))?; - } else { - f.write_fmt(format_args!("({}{})", op, val))?; - } - } - } - f.write_str("}\n")?; - } - - Ok(()) - } -} - -#[derive(Debug)] -pub struct Federation { - pub(in crate::DBMLib) raw: lib::FedRaw, -} - -impl Federation { - /// Get a new federation of a given dimension with the constraints that all clocks are equal to 0 - pub fn zero(dimension: u32) -> Self { - let mut fed = lib::rs_fed_new(dimension); - lib::rs_fed_zero(&mut fed); - fed - } - - /// Get a new empty federation of a given dimension, representing no possible clock valuations - pub fn empty(dimension: u32) -> Self { - lib::rs_fed_new(dimension) - } - - /// Get a new federation of a given dimension without any constraints, representing all possible clock valuation - pub fn full(dimension: u32) -> Self { - let mut fed = lib::rs_fed_new(dimension); - lib::rs_fed_init(&mut fed); - fed - } - - // Get a new federation of a given dimension with the constraints that all clocks are equal (zero(); up()) - pub fn init(dimension: u32) -> Self { - let mut fed = Federation::zero(dimension); - fed.up(); - fed - } - - /// Get a federation containing the subtraction of the federations - /// - /// `self` is unchanged, for change of `self` see `subtract` - /// Can be called with operator `-` consuming both operands - /// - /// [`subtract`]: Federation::subtract - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let fed1 = Federation::zero(); - /// let fed2 = Federation::init(); - /// - /// let fed3 = fed1.subtraction(&fed2); - /// // fed1 and fed2 remain unchanged - /// - /// assert_eq!(Federation::empty(), fed3); - /// ``` - #[must_use] - pub fn subtraction(&self, other: &Self) -> Federation { - let mut result = self.clone(); - lib::rs_fed_subtract(&mut result, &other); - result - } - - /// Update the federation to contain the subtraction of the federations - /// - /// `self` is changed, for unchanged `self` see [`subtraction`]. - /// Can be called with operator `-=` consuming the other federation - /// - /// [`subtraction`]: Federation::subtraction - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut fed1 = Federation::zero(); - /// let fed2 = Federation::init(); - /// - /// fed1.subtract(&fed2); - /// // fed1 is changed and fed2 remains unchanged - /// - /// assert_eq!(Federation::empty(), fed1); - /// ``` - pub fn subtract(&mut self, other: &Self) { - lib::rs_fed_subtract(self, &other); - } - - pub fn is_subset_eq(&self, other: &Self) -> bool { - lib::rs_fed_subset_eq(self, other) - } - - /// Get a federation containing the intersection of the federations - /// - /// `self` is unchanged, for change of `self` see `intersect` - /// Can be called with operator `-` consuming both operands - /// - /// [`intersect`]: Federation::intersect - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let fed1 = Federation::init(); - /// let fed2 = Federation::zero(); - /// - /// let fed3 = fed1.intersection(&fed2); - /// // fed1 and fed2 remain unchanged - /// - /// assert_eq!(Federation::zero(), fed3); - /// ``` - #[must_use] - pub fn intersection(&self, other: &Self) -> Federation { - let mut result = self.clone(); - lib::rs_fed_intersect(&mut result, &other); - result - } - - /// Update the federation to contain the intersection of the federations - /// - /// `self` is changed, for unchanged `self` see [`intersection`]. - /// Can be called with operator `&=` consuming the other federation - /// - /// [`intersection`]: Federation::intersection - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut fed1 = Federation::init(); - /// let fed2 = Federation::zero(); - /// - /// fed1.intersect(&fed2); - /// // fed1 is changed and fed2 remains unchanged - /// - /// assert_eq!(Federation::zero(), fed1); - /// ``` - pub fn intersect(&mut self, other: &Self) { - //assert_eq!(self.dimension, other.dimension); - lib::rs_fed_intersect(self, other); - } - - /// Returns whether the intersection of the federations is non-empty - pub fn intersects(&self, other: &Self) -> bool { - lib::rs_fed_intersects(self, other) - } - - /// Update the federation to the temporal predecessor of this federation avoiding 'bad' - pub fn predt(&mut self, bad: &Self) { - lib::rs_fed_predt(self, bad); - } - - /// Update the federation to contain its inverse - /// - /// `self` is changed, for unchanged `self` see [`inverse`]. - /// Can be called with operator `!` consuming self - /// - /// [`inverse`]: Federation::inverse - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut fed1 = Federation::init(); - /// fed1.invert(); - /// fed1 is changed to contain its inverse - /// - /// assert_eq!(Federation::empty(), fed1); - /// ``` - pub fn invert(&mut self) { - lib::rs_fed_invert(self) - } - - /// Get a federation containing the inverse of the federation - /// - /// `self` is unchanged, for change of `self` see [`invert`]. - /// Can be called with operator `!` consuming self - /// - /// [`invert`]: Federation::invert - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let fed1 = Federation::init(); - /// let fed2 = fed1.inverse(); - /// fed1 remains unchanged - /// - /// assert_eq!(Federation::empty(), fed2); - /// ``` - #[must_use] - pub fn inverse(&self) -> Federation { - let mut result = self.clone(); - lib::rs_fed_invert(&mut result); - result - } - - /// Updates the federation to contain the (non-convex) union of the federations - /// - /// `self` is changed, for unchanged `self` see `with_added_fed` - /// Can be called with operator `+=` consuming the other federation - /// - /// [`with_added_fed`]: Federation::with_added_fed - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut fed1 = Federation::zero(); - /// let fed2 = !Federation::zero(); - /// - /// fed1.add_fed(&fed2); - /// // fed1 is changed and fed2 remains unchanged - /// - /// assert_eq!(Federation::init(), fed1); - /// ``` - pub fn add_fed(&mut self, fed: &Federation) { - lib::rs_fed_add_fed(self, fed); - } - - /// Get a federation containing the (non-convex) union of the federations - /// - /// `self` is unchanged, for change of `self` see `add_fed` - /// Can be called with operator `+` consuming both operands - /// - /// [`add_fed`]: Federation::add_fed - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let fed1 = Federation::zero(); - /// let fed2 = !Federation::zero(); - /// - /// let fed3 = fed1.with_added_fed(&fed2); - /// // fed1 and fed2 remain unchanged - /// assert_eq!(Federation::init(), fed3); - /// ``` - #[must_use] - pub fn with_added_fed(&self, fed: &Federation) -> Federation { - let mut result = self.clone(); - lib::rs_fed_add_fed(&mut result, fed); - result - } - - /// Checks whether the federation is empty - /// - /// Return `true` if all contained DBMs are empty, or there are no DBMs - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(Federation::empty().is_empty()); - /// assert!(!Federation::full().is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - lib::rs_fed_is_empty(self) - } - - /// Checks whether the federation is full / unrestrained - /// - /// Return `true` if all the federation is unrestrained - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(Federation::full().is_full()); - /// assert!((!Federation::empty()).is_full()); - /// ``` - pub fn is_full(&self) -> bool { - self.inverse().is_empty() - } - - /* - fn iter_zones(&self) -> impl Iterator + '_ { - self.get_zones().into_iter() - }*/ - - pub fn get_zones(&self) -> Vec { - let zones = lib::rs_fed_get_zones(self); - assert_eq!(zones.len(), self.num_zones()); - zones - } - - /// Get the number of zones in the federation - pub fn num_zones(&self) -> usize { - lib::rs_fed_size(self) - } - - /// Get the dimension of the federation - pub fn get_dimensions(&self) -> u32 { - lib::rs_fed_dimensions(self) - } - - pub fn reduce(&mut self, expensive: bool) { - lib::rs_fed_reduce(self, expensive); - } - - /// Get the constraints represented by the federation as a boolean expression - pub fn as_boolexpression( - &self, - clocks: Option<&HashMap>, - ) -> Option { - let mut clone = self.clone(); - clone.reduce(true); - let zones = clone.get_zones(); - let mut guard = BoolExpression::Bool(false); - - for zone in zones { - let zone_guard = build_guard_from_zone(&zone, clocks); - let g = match zone_guard { - Some(g) => g, - None => BoolExpression::Bool(true), - }; - guard = BoolExpression::OrOp(Box::new(guard), Box::new(g)); - } - guard.simplify(); - - if let BoolExpression::Bool(true) = guard { - None - } else { - Some(guard) - } - } - - /// Check whether the federation is valid (non-empty) - pub fn is_valid(&self) -> bool { - lib::rs_fed_is_valid(self) - } - - /// Perform the 'up' operation on all DBMs in the federation - pub fn up(&mut self) { - lib::rs_fed_up(self); - } - - /// Perform the 'down' operation on all DBMs in the federation - pub fn down(&mut self) { - lib::rs_fed_down(self); - } - - /// Extrapolate max bounds on all DBMs in the federation - pub fn extrapolate_max_bounds(&mut self, max_bounds: &MaxBounds) { - lib::rs_fed_extrapolate_max_bounds(self, max_bounds); - } - - /// Check whether the any DBM in the federation can delay indefinitely - pub fn can_delay_indefinitely(&self) -> bool { - lib::rs_fed_can_delay_indef(self) - } - - /// Sets the clock (clocks[clock_index]) to an integer value in all DBMs in the federation - pub fn update(&mut self, clock_index: u32, value: i32) { - lib::rs_fed_update_clock(self, clock_index, value); - } - - /// Removes the bounds on the clock (clocks[clock_index]) in all DBMs in the federation - pub fn free_clock(&mut self, clock_index: u32) { - lib::rs_fed_free_clock(self, clock_index); - } - - pub fn constrain( - &mut self, - var_index_i: u32, - var_index_j: u32, - bound: i32, - isStrict: bool, - ) -> bool { - lib::rs_fed_constrain(self, var_index_i, var_index_j, bound, isStrict) - } - - pub fn add_lte_constraint(&mut self, var_index_i: u32, var_index_j: u32, bound: i32) -> bool { - lib::rs_fed_add_LTE_constraint(self, var_index_i, var_index_j, bound) - } - - pub fn add_lt_constraint(&mut self, var_index_i: u32, var_index_j: u32, bound: i32) -> bool { - lib::rs_fed_add_LT_constraint(self, var_index_i, var_index_j, bound) - } - - pub fn add_eq_constraint(&mut self, var_index_i: u32, var_index_j: u32) -> bool { - lib::rs_fed_add_EQ_constraint(self, var_index_i, var_index_j) - } - - pub fn add_eq_const_constraint(&mut self, var_index: u32, bound: i32) -> bool { - lib::rs_fed_add_EQ_const_constraint(self, var_index, bound) - } - - pub fn constrain_var_to_val(&mut self, var_index: u32, value: i32) -> bool { - unimplemented!() - } -} - -impl ops::Add for Federation { - type Output = Self; - - /// Get a federation containing the (non-convex) union of the federations - fn add(mut self, other: Self) -> Self { - self.add_fed(&other); - self - } -} - -impl ops::Add for &Federation { - type Output = Federation; - - /// Get a federation containing the (non-convex) union of the federations - fn add(self, other: &Federation) -> Federation { - self.with_added_fed(other) - } -} - -impl ops::Sub for Federation { - type Output = Self; - - /// Get a federation containing the subtraction of the federations - fn sub(mut self, other: Self) -> Self { - self.subtract(&other); - self - } -} - -impl ops::Sub for &Federation { - type Output = Federation; - - /// Get a federation containing the subtraction of the federations - fn sub(self, other: &Federation) -> Federation { - self.subtraction(other) - } -} - -impl ops::BitAnd for Federation { - type Output = Self; - - /// Get a federation containing the intersection of the federations - fn bitand(mut self, other: Self) -> Self { - self.intersect(&other); - self - } -} - -impl ops::BitAnd for &Federation { - type Output = Federation; - - /// Get a federation containing the intersection of the federations - fn bitand(self, other: &Federation) -> Federation { - self.intersection(other) - } -} - -impl ops::AddAssign for Federation { - fn add_assign(&mut self, other: Federation) { - self.add_fed(&other); - } -} - -impl ops::SubAssign for Federation { - fn sub_assign(&mut self, other: Federation) { - self.subtract(&other); - } -} - -impl ops::BitAndAssign for Federation { - fn bitand_assign(&mut self, other: Self) { - self.intersect(&other); - } -} - -impl PartialOrd for Federation { - fn partial_cmp(&self, other: &Self) -> Option { - match lib::rs_fed_relation(self, other) { - Relation::Superset => Some(Ordering::Greater), - Relation::Subset => Some(Ordering::Less), - Relation::Equal => Some(Ordering::Equal), - Relation::Different => None, - } - } -} - -impl ops::Not for Federation { - type Output = Self; - - /// Get a federation containing the inverse of the federation - fn not(mut self) -> Self { - self.invert(); - self - } -} - -impl PartialEq for Federation { - fn eq(&self, other: &Self) -> bool { - lib::rs_fed_equals(self, other) - } -} - -impl Drop for Federation { - fn drop(&mut self) { - unsafe { - lib::rs_fed_destruct(self); - } - } -} - -impl Clone for Federation { - fn clone(&self) -> Federation { - lib::rs_fed_copy(self) - } -} - -impl Display for Federation { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - //return Ok(()); - write!( - f, - "{{{}}}", - self.as_boolexpression(None) - .unwrap_or(BoolExpression::Bool(true)) - )?; - /* for zone in self.get_zones() { - write!(f, "\n{}", zone)?; - } - write!(f, "}}")?; - */ - Ok(()) - } -} diff --git a/src/DBMLib/lib_dbm.rs b/src/DBMLib/lib_dbm.rs deleted file mode 100644 index a9f6e0e5..00000000 --- a/src/DBMLib/lib_dbm.rs +++ /dev/null @@ -1,442 +0,0 @@ -macro_rules! trace { - () => {{ - fn f() {} - fn type_name_of(_: T) -> &'static str { - std::any::type_name::() - } - if (DEBUG) { - let name = type_name_of(f); - println!("{}", &name[..name.len() - 3]); - } - }}; -} - -use crate::DBMLib::dbm::{Federation, Relation, Zone}; -use crate::ModelObjects::max_bounds::MaxBounds; -use std::convert::TryInto; - -mod UDBM { - #![allow(non_snake_case)] - #![allow(non_upper_case_globals)] - #![allow(non_camel_case_types)] - #![allow(dead_code)] - #![allow(improper_ctypes)] - #![allow(deref_nullptr)] - include!(concat!(env!("OUT_DIR"), "/bindings.rs")); -} - -use lazy_static::lazy_static; -use std::sync::{Mutex, RwLock}; -const DEBUG: bool = false; - -/// Max dim from dbm\build\UDBM\src\udbm\dbm\DBMAllocator.h:32:35 -/// If exceeded causes segmentation fault in c code -const MAX_DIM: u32 = 256; - -lazy_static! { - // static ref LIBRARY_LOCK: RwLock<()> = RwLock::new(()); - static ref LIBRARY_LOCK: Mutex = Mutex::new(0); -} - -/* -unsafe fn syncr(f: &mut dyn Fn() -> T) -> T { - let _l = LIBRARY_LOCK.read().unwrap(); - f() -}*/ - -unsafe fn syncw(f: &mut dyn FnMut() -> T) -> T { - let _l = LIBRARY_LOCK.lock().unwrap(); - f() -} - -#[cfg(feature = "single-threaded")] -macro_rules! sync { - ($arg:expr) => { - $arg - }; -} - -#[cfg(not(feature = "single-threaded"))] -macro_rules! sync { - ($arg:expr) => { - syncw(&mut || $arg) - }; -} - -pub const DBM_INF: i32 = i32::MAX - 1; - -pub type FedRaw = UDBM::dbm_fed_t; - -/// used in input enabler to check if the constraint is strictly bound e.g strictly less than -pub fn rs_raw_is_strict(raw: UDBM::raw_t) -> bool { - unsafe { UDBM::dbm_rawIsStrict_wrapper(raw) } -} - -///converts the bound from c++ to an usable rust type - used when input enabling -pub fn rs_raw_to_bound(raw: UDBM::raw_t) -> i32 { - unsafe { UDBM::dbm_raw2bound_wrapper(raw) } -} - -fn rs_bound_strict_to_raw(bound: i32, is_strict: bool) -> UDBM::raw_t { - unsafe { UDBM::dbm_boundbool2raw_wrapper(bound, is_strict) } -} - -/* BEGIN FEDERATION METHODS*/ - -pub fn rs_fed_get_zones(fed: &Federation) -> Vec { - trace!(); - let dim = fed.get_dimensions(); - let d = dim as usize; - let zones = fed.num_zones(); - let len = zones * d * d; - - if len == 0 { - return vec![]; - } - let mut out = Vec::::with_capacity(len); - unsafe { - sync!(UDBM::fed_get_dbm_vec( - &fed.raw, - out.as_mut_ptr(), - len as u64 - )); - out.set_len(len); - } - - out.chunks(d * d) - .into_iter() - .map(|v| Zone { - dimension: dim, - matrix: v.to_vec(), - }) - .collect() -} - -pub fn rs_fed_intersect(fed1: &mut Federation, fed2: &Federation) { - trace!(); - unsafe { - sync!(UDBM::fed_intersection(&mut fed1.raw, &fed2.raw)); - } -} - -pub fn rs_fed_predt(good: &mut Federation, bad: &Federation) { - trace!(); - unsafe { - sync!(UDBM::fed_predt(&mut good.raw, &bad.raw)); - } -} - -/// oda federation minus federation -pub fn rs_fed_subtract(fed1: &mut Federation, fed2: &Federation) { - trace!(); - unsafe { - sync!(UDBM::fed_subtraction(&mut fed1.raw, &fed2.raw)); - } - //May want to only do this optionally/not expensively? - rs_fed_reduce(fed1, true); -} - -pub fn rs_fed_is_valid(fed: &Federation) -> bool { - trace!(); - unsafe { !sync!(UDBM::fed_is_empty(&fed.raw)) } -} - -pub fn rs_fed_is_empty(fed: &Federation) -> bool { - trace!(); - unsafe { sync!(UDBM::fed_is_empty(&fed.raw)) } -} - -pub fn rs_fed_up(fed: &mut Federation) { - trace!(); - unsafe { - sync!(UDBM::fed_up(&mut fed.raw)); - }; -} - -pub fn rs_fed_down(fed: &mut Federation) { - trace!(); - unsafe { - sync!(UDBM::fed_down(&mut fed.raw)); - }; -} - -pub fn rs_fed_init(fed: &mut Federation) { - trace!(); - unsafe { - sync!(UDBM::fed_init(&mut fed.raw)); - }; -} - -pub fn rs_fed_zero(fed: &mut Federation) { - trace!(); - unsafe { - sync!(UDBM::fed_zero(&mut fed.raw)); - }; -} - -pub fn rs_fed_new(dim: UDBM::cindex_t) -> Federation { - trace!(); - assert!(dim > 0); - // Max dim from dbm\build\UDBM\src\udbm\dbm\DBMAllocator.h:32:35 - // If exceeded causes segmentation fault in c code - assert!(dim < MAX_DIM); - let raw = unsafe { sync!(UDBM::dbm_fed_t::new(dim)) }; - Federation { raw } -} - -/// Contrain Federation with one constraint. -/// * Federation must be non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `fed` - The Federation -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `bound` - The value which bounds the expression -/// * `isStrict` - Whether the inequality is strict (<) or not (<=) -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -pub fn rs_fed_constrain( - fed: &mut Federation, - var_index_i: u32, - var_index_j: u32, - bound: i32, - isStrict: bool, -) -> bool { - unsafe { - sync!(UDBM::fed_constrain( - &mut fed.raw, - var_index_i, - var_index_j, - bound, - isStrict - )) - } -} - -/// Contrain Federation with one <= constraint based on the bound. -/// * Federation must be non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `fed` - The Federation -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `bound` - The value which bounds the expression -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -pub fn rs_fed_add_LTE_constraint( - fed: &mut Federation, - var_index_i: u32, - var_index_j: u32, - bound: i32, -) -> bool { - trace!(); - rs_fed_constrain(fed, var_index_i, var_index_j, bound, false) -} - -/// Contrain Federation with one < constraint based on the bound. -/// * Federation must be non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `fed` - The Federation -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `bound` - The value which bounds the expression -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -pub fn rs_fed_add_LT_constraint( - fed: &mut Federation, - var_index_i: u32, - var_index_j: u32, - bound: i32, -) -> bool { - trace!(); - rs_fed_constrain(fed, var_index_i, var_index_j, bound, true) -} - -/// Contrain Federation such that clock[var_index_i] == clock[var_index_j] -/// * Federation must be non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `fed` - The Federation -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -pub fn rs_fed_add_EQ_constraint(fed: &mut Federation, var_index_i: u32, var_index_j: u32) -> bool { - trace!(); - let res1 = rs_fed_constrain(fed, var_index_i, var_index_j, 0, false); - let res2 = rs_fed_constrain(fed, var_index_j, var_index_i, 0, false); - res1 && res2 -} - -/// Contrain Federation such that clock[var_index_i] == bound -/// * Federation must be non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `fed` - The Federation -/// * `var_index` - The index of the variable representing the ith element -/// * `bound` - The constant bound the clock is set equal to -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -pub fn rs_fed_add_EQ_const_constraint(fed: &mut Federation, var_index: u32, bound: i32) -> bool { - trace!(); - let res1 = rs_fed_constrain(fed, var_index, 0, bound, false); - let res2 = rs_fed_constrain(fed, 0, var_index, -bound, false); - res1 && res2 -} - -pub fn rs_fed_update_clock(fed: &mut Federation, x: UDBM::cindex_t, v: i32) { - trace!(); - rs_fed_update(fed, x, 0, v); -} - -pub fn rs_fed_update(fed: &mut Federation, x: UDBM::cindex_t, y: UDBM::cindex_t, v: i32) { - trace!(); - unsafe { - sync!(UDBM::fed_update(&mut fed.raw, x, y, v)); - } -} - -pub fn rs_fed_free_clock(fed: &mut Federation, x: UDBM::cindex_t) { - trace!(); - unsafe { - sync!(UDBM::fed_free_clock(&mut fed.raw, x)); - } -} - -pub fn rs_fed_subset_eq(fed1: &Federation, fed2: &Federation) -> bool { - trace!(); - unsafe { sync!(UDBM::fed_subset_eq(&fed1.raw, &fed2.raw)) } -} - -pub fn rs_fed_intersects(fed1: &Federation, fed2: &Federation) -> bool { - trace!(); - unsafe { sync!(UDBM::fed_intersects(&fed1.raw, &fed2.raw)) } -} - -pub fn rs_fed_relation(fed1: &Federation, fed2: &Federation) -> Relation { - trace!(); - let rel: UDBM::relation_t = unsafe { sync!(UDBM::fed_exact_relation(&fed1.raw, &fed2.raw)) }; - - match rel { - 0 => Relation::Different, - 1 => Relation::Superset, - 2 => Relation::Subset, - 3 => Relation::Equal, - _ => panic!("Unknown relation {}", rel), - } -} - -pub fn rs_fed_equals(fed1: &Federation, fed2: &Federation) -> bool { - trace!(); - unsafe { sync!(UDBM::fed_exact_eq(&fed1.raw, &fed2.raw)) } -} - -pub fn rs_fed_reduce(fed: &mut Federation, expensive: bool) { - trace!(); - unsafe { - if expensive { - sync!(UDBM::fed_reduce(&mut fed.raw)); - } else { - sync!(UDBM::fed_expensive_reduce(&mut fed.raw)); - } - } -} - -pub fn rs_fed_can_delay_indef(fed: &Federation) -> bool { - trace!(); - unsafe { sync!(UDBM::fed_can_delay_indef(&fed.raw)) } -} - -pub fn rs_fed_extrapolate_max_bounds(fed: &mut Federation, bounds: &MaxBounds) { - trace!(); - //assert_eq!(fed.get_dimensions(), bounds.get_dimensions()); - unsafe { - sync!(UDBM::fed_extrapolate_max_bounds( - &mut fed.raw, - bounds.clock_bounds.as_ptr() - )); - } -} - -pub fn rs_fed_diagonal_extrapolate_max_bounds(fed: &mut Federation, bounds: &MaxBounds) { - trace!(); - assert_eq!(fed.get_dimensions(), bounds.get_dimensions()); - unsafe { - sync!(UDBM::fed_diagonal_extrapolate_max_bounds( - &mut fed.raw, - bounds.clock_bounds.as_ptr() - )); - } -} - -pub fn rs_fed_add_fed(fed: &mut Federation, other: &Federation) { - trace!(); - assert_eq!(fed.get_dimensions(), other.get_dimensions()); - unsafe { - sync!(UDBM::fed_add_fed(&mut fed.raw, &other.raw)); - } -} - -pub fn rs_fed_invert(fed: &mut Federation) { - trace!(); - unsafe { - sync!(UDBM::fed_invert(&mut fed.raw)); - } -} - -pub fn rs_fed_size(fed: &Federation) -> usize { - trace!(); - unsafe { sync!(UDBM::fed_size(&fed.raw)) } - .try_into() - .unwrap() -} - -pub unsafe fn rs_fed_destruct(fed: &mut Federation) { - sync!(UDBM::fed_destruct(&mut fed.raw)); -} - -pub fn rs_fed_copy(fed: &Federation) -> Federation { - trace!(); - let raw = unsafe { sync!(UDBM::dbm_fed_t::new1(&fed.raw)) }; - Federation { raw } -} - -pub fn rs_fed_dimensions(fed: &Federation) -> UDBM::cindex_t { - trace!(); - unsafe { sync!(UDBM::fed_dimension(&fed.raw)) } -} - -/* -pub fn rs_crash(dim: u32) { - unsafe { - sync!( UDBM::fed_crash(dim)); - } -}*/ - -/* END FEDERATION METHODS */ diff --git a/src/DBMLib/lib_stub.rs b/src/DBMLib/lib_stub.rs deleted file mode 100644 index 1e68c9ec..00000000 --- a/src/DBMLib/lib_stub.rs +++ /dev/null @@ -1,529 +0,0 @@ -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(dead_code)] - -use crate::DBMLib::dbm::Federation; - -//in DBM lib 0 is < and 1 is <= here in regards to constraint_index parameter useds -const LT: i32 = 0; -const LTE: i32 = 1; -pub const DBM_INF: i32 = i32::MAX - 1; - -// Taken from bindgen's definition of raw_t -type raw_t = i32; -// This type is unused, so we can just let it be the unit type -type dbm_fed_t = (); - -/// Checks DBMS validity -/// returns true or false -/// -/// # Arguments -/// -/// * `dbm` - A mutable pointer to an array, which will be the dbm -/// * `dimension` - The dimension of the dbm -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// ``` -pub fn rs_dbm_is_valid(_dbm: &mut [i32], _dimension: u32) -> bool { - unimplemented!() -} - -// pub fn rs_wrapped_dbm_is_valid(dbm: &mut[i32], dimension : u32) -> Result { -// match unsafe { let res = dbm_isValid(dbm.as_mut_ptr(), dimension); } { -// res => Ok(true), -// } -// } -/// Initializes a DBM with -/// * <= 0 on the diagonal and the first row -/// * <= infinity elsewhere -/// -/// # Arguments -/// -/// * `dbm` - A mutable pointer to an array, which will be the dbm -/// * `dimension` - The dimension of the dbm -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// ``` -pub fn rs_dbm_init(_dbm: &mut [i32], _dimension: u32) { - unimplemented!() -} - -/// Checks if `x_i - x_j < bound` is satisfied. -/// It does not modify the DBM -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `bound` - The value which bounds the expression -/// -/// # Return -/// Bool indicating if the dbm satisfied the restriction -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// rs_dbm_satisfies_i_LT_j(&mut dbm, 3, 1, 2, 10); -/// ``` -pub fn rs_dbm_satisfies_i_LT_j( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, - _bound: i32, -) -> bool { - unimplemented!() -} - -/// Checks if `x_i - x_j <= bound` is satisfied. -/// It does not modify the DBM -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `bound` - The value which bounds the expression -/// -/// # Return -/// Bool indicating if the dbm satisfied the restriction -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// rs_dbm_satisfies_i_LTE_j(&mut dbm, 3, 1, 2, 10); -/// ``` -pub fn rs_dbm_satisfies_i_LTE_j( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, - _bound: i32, -) -> bool { - unimplemented!() -} - -/// Checks if `x_i - x_j = 0` and `x_j - x_i = 0` is satisfied. -/// It does not modify the DBM -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// -/// # Return -/// Bool indicating if the dbm satisfied the restriction -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// rs_dbm_satisfies_i_EQUAL_j(&mut dbm, 3, 1, 2); -/// ``` -pub fn rs_dbm_satisfies_i_EQUAL_j( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, -) -> bool { - unimplemented!() -} - -/// Checks if `x_i - x_j = bound_j-bound_i` and `x_j - x_i = bound_i-bound_j` is satisfied. -/// It does not modify the DBM -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `bound_i` - The value affecting the variable i -/// * `bound_j` - The value affecting the variable j -/// -/// # Return -/// Bool indicating if the dbm satisfied the restriction -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// rs_dbm_satisfies_i_EQUAL_j_bounds(&mut dbm, 3, 1, 2, 10, 4); -/// ``` -pub fn rs_dbm_satisfies_i_EQUAL_j_bounds( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, - _bound_i: i32, - _bound_j: i32, -) -> bool { - unimplemented!() -} - -/// Contrain DBM with one constraint. -/// * DBM must be closed and non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `constraint` - Constraint for x_i - x_j to use -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -/// The resulting DBM is closed if it is non empty. -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// let constraint = dbm_boundbool2raw_exposed(10, false); -/// dbm_constrain1(dbm.as_mut_ptr(), 3, 1, 0, constraint); -/// ``` -pub fn rs_dbm_constrain1( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, - _constraint: i32, -) -> bool { - unimplemented!() -} - -/// Contrain DBM with one <= constraint based on the bound. -/// * DBM must be closed and non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `bound` - The value which bounds the expression -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -/// The resulting DBM is closed if it is non empty. -/// -/// # Examples -/// -/// ```use regex::internal::Input; - -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// rs_dbm_add_LTE_constraint(dbm.as_mut_ptr(), 3, 1, 2, 3); -/// ``` -pub fn rs_dbm_add_LTE_constraint( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, - _bound: i32, -) -> bool { - unimplemented!() -} - -/// Contrain DBM with one < constraint based on the bound. -/// * DBM must be closed and non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `bound` - The value which bounds the expression -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -/// The resulting DBM is closed if it is non empty. -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// rs_dbm_add_LT_constraint(dbm.as_mut_ptr(), 3, 1, 2, 3); -/// ``` -pub fn rs_dbm_add_LT_constraint( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, - _bound: i32, -) -> bool { - unimplemented!() -} - -/// Contrain DBM with one constraint based on the bound in both directions with bound 0. -/// -/// `x_i-x_j <= 0` and `x_j-x_i <= 0` -/// * DBM must be closed and non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -/// The resulting DBM is closed if it is non empty. -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// rs_dbm_add_EQ_constraint(dbm.as_mut_ptr(), 3, 1, 2); -/// ``` -pub fn rs_dbm_add_EQ_constraint( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, -) -> bool { - unimplemented!() -} - -/// Contrain DBM with one constraint based on the bound -/// -/// `x_i-0 <= 5` and `0-x_i <= -5` -/// * DBM must be closed and non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index` - The index of the variable representing the ith element -/// * `bound` - The constant bound the clock is set equal to -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -/// The resulting DBM is closed if it is non empty. -pub fn rs_dbm_add_EQ_const_constraint( - _dbm: &mut [i32], - _dimension: u32, - _var_index: u32, - _bound: i32, -) -> bool { - unimplemented!() -} - -/// Contrain DBM with two constraints both applied to the same variables. -/// * DBM must be closed and non empty -/// * dim > 1 induced by i < dim & j < dim & i != j -/// * as a consequence: i>=0 & j>=0 & i!=j => (i or j) > 0 and dim > (i or j) > 0 => dim > 1 -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index_i` - The index of the variable representing the ith element -/// * `var_index_j` - The index of the variable representing the jth element -/// * `constraint1` - First constraint for x_i - x_j to use -/// * `constraint2` - Second constraint for x_i - x_j to use -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -/// The resulting DBM is closed if it is non empty. -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// let constraint1 = dbm_boundbool2raw_exposed(10, false); -/// let constraint2 = dbm_boundbool2raw_exposed(15, true); -/// rs_dbm_add_and_constraint(dbm.as_mut_ptr(), 3, 1, 2, constraint1, constraint2); -/// ``` -pub fn rs_dbm_add_and_constraint( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, - _constraint1: i32, - _constraint2: i32, -) -> bool { - unimplemented!() -} - -/// Contrain DBM by setting variable to value. -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index` - The index of the variable -/// * `value` - the value to set the variable to -/// -/// # Return -/// Bool indicating if the constraint was applied sucessfully. -/// -/// The resulting DBM is closed if it is non empty. -/// -/// # Examples -/// -/// ``` -/// let mut dbm : [i32; 9] = [0; 9]; -/// dbm_init(dbm.as_mut_ptr(), 3); -/// rs_dbm_constrain_var_to_val(dbm.as_mut_ptr(), 3, 1, 0); -/// ``` -pub fn rs_dbm_constrain_var_to_val( - _dbm: &mut [i32], - _dimension: u32, - _var_index: u32, - _value: i32, -) -> bool { - unimplemented!() -} - -/// Used to check if dbms intersect and thus have overlapping moves -pub fn rs_dmb_intersection(_dbm1: &mut [i32], _dbm2: &mut [i32], _dimension: u32) -> bool { - unimplemented!() -} - -pub fn rs_dbm_update(_dbm: &mut [i32], _dimension: u32, _var_index: u32, _value: i32) { - unimplemented!() -} - -/// Free operation. Remove all constraints (lower and upper bounds) for a given clock, i.e., set them to infinity -/// -/// # Arguments -/// -/// * `dbm` - The DBM -/// * `dimension` - The dimension of the dbm -/// * `var_index` - The index of the clock to free -/// -pub fn rs_dbm_freeClock(_dbm: &mut [i32], _dimension: u32, _var_index: u32) { - unimplemented!() -} - -/** Test only if dbm1 <= dbm2. - * @param dbm1,dbm2: DBMs to be tested. - * @param dim: dimension of the DBMs. - * @pre - * - dbm1 and dbm2 have the same dimension - * - dbm_isValid for both DBMs - * @return TRUE if dbm1 <= dbm2, FALSE otherwise. - */ -pub fn rs_dbm_isSubsetEq(_dbm1: &mut [i32], _dbm2: &mut [i32], _dimension: u32) -> bool { - unimplemented!() -} - -/// oda federation minus federation -pub fn rs_dbm_fed_minus_fed( - _dbm_vec1: &mut Vec<*mut raw_t>, - _dbm_vec2: &mut Vec<*mut raw_t>, - _dim: u32, -) -> Federation { - unimplemented!() -} - -/// currently unused -pub fn rs_dbm_minus_dbm(_dbm1: &mut [i32], _dbm2: &mut [i32], _dim: u32) -> Federation { - unimplemented!() -} - -///Currently unused -pub fn rs_dbm_extrapolateMaxBounds(_dbm1: &mut [i32], _dim: u32, _maxbounds: *const i32) { - unimplemented!() -} - -pub fn rs_dbm_get_constraint( - _dbm: &mut [i32], - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, -) -> raw_t { - unimplemented!() -} - -///used by input enabler to get the upper and lower bounds for each clocks so that constraints can be created -pub fn rs_dbm_get_constraint_from_dbm_ptr( - _dbm: *const i32, - _dimension: u32, - _var_index_i: u32, - _var_index_j: u32, -) -> raw_t { - unimplemented!() -} - -/// used in input enabler to check if the constraint is strictly bound e.g strictly less than -pub fn rs_raw_is_strict(_raw: raw_t) -> bool { - unimplemented!() -} - -///converts the bound from c++ to an usable rust type - used when input enabling -pub fn rs_raw_to_bound(_raw: raw_t) -> i32 { - unimplemented!() -} - -pub fn rs_vec_to_fed(_dbm_vec: &mut Vec<*mut raw_t>, _dim: u32) -> dbm_fed_t { - unimplemented!() -} - -/// takes a c++ federation and convert it to a vector of pointers -pub fn rs_fed_to_vec(_fed: &mut dbm_fed_t) -> Vec<*const i32> { - unimplemented!() -} -///does a dbm up operation -pub fn rs_dbm_up(_dbm: &mut [i32], _dimension: u32) { - unimplemented!() -} - -///setup a slice to be a zero dbm -pub fn rs_dbm_zero(_dbm: &mut [i32], _dimension: u32) { - unimplemented!() -} - -/// test function taken from Jecdar -pub fn libtest() { - unimplemented!() -} - -/// test function taken from Jecdar -pub fn libtest2() { - unimplemented!() -} diff --git a/src/DBMLib/mod.rs b/src/DBMLib/mod.rs deleted file mode 100644 index 11a6d2e4..00000000 --- a/src/DBMLib/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[cfg(not(feature = "dbm-stub"))] -pub mod lib_dbm; -#[cfg(feature = "dbm-stub")] -pub mod lib_stub; - -#[cfg(not(feature = "dbm-stub"))] -pub use lib_dbm as lib; -#[cfg(feature = "dbm-stub")] -pub use lib_stub as lib; - -pub mod dbm; diff --git a/src/DataReader/parse_edge.rs b/src/DataReader/parse_edge.rs index afc70984..a15f4a67 100644 --- a/src/DataReader/parse_edge.rs +++ b/src/DataReader/parse_edge.rs @@ -8,6 +8,7 @@ use crate::{ DataReader::serialization::{encode_arithexpr, encode_boolexpr}, ModelObjects::component::Declarations, }; +use edbm::util::constraints::ClockIndex; use pest::error::Error; use pest::Parser; use serde::{Deserialize, Serialize}; @@ -53,8 +54,8 @@ impl Update { pub fn swap_clock_names( &mut self, - from_vars: &HashMap, - to_vars: &HashMap, + from_vars: &HashMap, + to_vars: &HashMap, ) { if let Some(index) = from_vars.get(&self.variable) { self.variable = to_vars[index].clone(); diff --git a/src/DataReader/serialization.rs b/src/DataReader/serialization.rs index 17365da1..dc41531f 100644 --- a/src/DataReader/serialization.rs +++ b/src/DataReader/serialization.rs @@ -5,6 +5,7 @@ use crate::ModelObjects::component::{ }; use crate::ModelObjects::representations; use crate::Simulation::graph_layout::layout_dummy_component; +use edbm::util::constraints::ClockIndex; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::collections::HashMap; use std::ops::Add; @@ -184,8 +185,8 @@ where //Split string into vector of strings let decls: Vec = s.split('\n').map(|s| s.into()).collect(); let mut ints: HashMap = HashMap::new(); - let mut clocks: HashMap = HashMap::new(); - let mut counter: u32 = 1; + let mut clocks: HashMap = HashMap::new(); + let mut counter: ClockIndex = 1; for string in decls { //skip comments if string.starts_with("//") || string.is_empty() { diff --git a/src/DataReader/xml_parser.rs b/src/DataReader/xml_parser.rs index 266c3305..33e8134b 100644 --- a/src/DataReader/xml_parser.rs +++ b/src/DataReader/xml_parser.rs @@ -3,6 +3,7 @@ use crate::DataReader::{parse_edge, parse_invariant}; use crate::ModelObjects::component::{Declarations, Edge, LocationType, SyncType}; use crate::ModelObjects::system_declarations::{SystemDeclarations, SystemSpecification}; use crate::ModelObjects::{component, queries, representations, system_declarations}; +use edbm::util::constraints::ClockIndex; use elementtree::{Element, FindChildren}; use std::collections::HashMap; use std::fs::File; @@ -169,8 +170,8 @@ fn parse_declarations(variables: &str) -> Declarations { //Split string into vector of strings let decls: Vec = variables.split('\n').map(|s| s.into()).collect(); let mut ints: HashMap = HashMap::new(); - let mut clocks: HashMap = HashMap::new(); - let mut counter: u32 = 1; + let mut clocks: HashMap = HashMap::new(); + let mut counter: ClockIndex = 1; for string in decls { //skip comments if string.starts_with("//") || string.is_empty() { diff --git a/src/DataTypes/statepair_list.rs b/src/DataTypes/statepair_list.rs index 1bef81e9..63d764ae 100644 --- a/src/DataTypes/statepair_list.rs +++ b/src/DataTypes/statepair_list.rs @@ -1,28 +1,29 @@ use std::collections::{HashMap, VecDeque}; -use crate::{ - DBMLib::dbm::Federation, ModelObjects::statepair::StatePair, TransitionSystems::LocationID, -}; +use edbm::zones::OwnedFederation; + +use crate::{ModelObjects::statepair::StatePair, TransitionSystems::LocationID}; pub type PassedStateList = PassedStateListFed; -type PassedStateListFed = HashMap<(LocationID, LocationID), Federation>; -type PassedStateListVec = HashMap<(LocationID, LocationID), Vec>; +type PassedStateListFed = HashMap<(LocationID, LocationID), OwnedFederation>; +type PassedStateListVec = HashMap<(LocationID, LocationID), Vec>; pub type WaitingStateList = DepthFirstWaitingStateList; pub struct DepthFirstWaitingStateList { queue: VecDeque, - map: HashMap<(LocationID, LocationID), VecDeque>, + map: HashMap<(LocationID, LocationID), VecDeque>, } pub trait PassedStateListExt { fn put(&mut self, pair: StatePair); fn has(&self, pair: &StatePair) -> bool; - fn zones(&self, key: &(LocationID, LocationID)) -> Vec<&Federation>; + fn zones(&self, key: &(LocationID, LocationID)) -> Vec<&OwnedFederation>; } impl PassedStateListExt for PassedStateListVec { - fn put(&mut self, pair: StatePair) { - let (loc1, loc2, fed) = (pair.locations1.id, pair.locations2.id, pair.zone); + fn put(&mut self, mut pair: StatePair) { + let fed = pair.take_zone(); + let (loc1, loc2) = (pair.locations1.id, pair.locations2.id); let key = (loc1, loc2); if let Some(vec) = self.get_mut(&key) { vec.push(fed); @@ -35,16 +36,16 @@ impl PassedStateListExt for PassedStateListVec { let (loc1, loc2, fed) = ( pair.locations1.id.clone(), pair.locations2.id.clone(), - &pair.zone, + pair.ref_zone(), ); let key = (loc1, loc2); match self.get(&key) { - Some(vec) => vec.iter().any(|f| fed.is_subset_eq(f)), + Some(vec) => vec.iter().any(|f| fed.subset_eq(f)), None => false, } } - fn zones(&self, key: &(LocationID, LocationID)) -> Vec<&Federation> { + fn zones(&self, key: &(LocationID, LocationID)) -> Vec<&OwnedFederation> { match self.get(key) { Some(vec) => vec.iter().collect(), None => panic!("No zones for key: {:?}", key), @@ -53,10 +54,10 @@ impl PassedStateListExt for PassedStateListVec { } impl PassedStateListExt for DepthFirstWaitingStateList { - fn put(&mut self, pair: StatePair) { + fn put(&mut self, mut pair: StatePair) { self.queue.push_front(pair.clone()); - - let (loc1, loc2, fed) = (pair.locations1.id, pair.locations2.id, pair.zone); + let fed = pair.take_zone(); + let (loc1, loc2) = (pair.locations1.id, pair.locations2.id); let key = (loc1, loc2); if let Some(vec) = self.map.get_mut(&key) { vec.push_front(fed); @@ -68,15 +69,15 @@ impl PassedStateListExt for DepthFirstWaitingStateList { let (loc1, loc2, fed) = ( pair.locations1.id.clone(), pair.locations2.id.clone(), - &pair.zone, + pair.ref_zone(), ); let key = (loc1, loc2); match self.map.get(&key) { - Some(vec) => vec.iter().any(|f| fed.is_subset_eq(f)), + Some(vec) => vec.iter().any(|f| fed.subset_eq(f)), None => false, } } - fn zones(&self, key: &(LocationID, LocationID)) -> Vec<&Federation> { + fn zones(&self, key: &(LocationID, LocationID)) -> Vec<&OwnedFederation> { match self.map.get(key) { Some(vec) => vec.iter().collect(), None => panic!("No zones for key: {:?}", key), @@ -111,31 +112,31 @@ impl DepthFirstWaitingStateList { } } impl PassedStateListExt for PassedStateListFed { - fn put(&mut self, pair: StatePair) { - let (loc1, loc2, fed) = (pair.locations1.id, pair.locations2.id, pair.zone); + fn put(&mut self, mut pair: StatePair) { + let mut fed = pair.take_zone(); + let (loc1, loc2) = (pair.locations1.id, pair.locations2.id); let key = (loc1, loc2); - if let Some(f) = self.get_mut(&key) { - f.add_fed(&fed); - f.reduce(true); - } else { - self.insert(key, fed); - }; + + if let Some(f) = self.get(&key) { + fed = fed.union(f).expensive_reduce(); + } + self.insert(key, fed); } fn has(&self, pair: &StatePair) -> bool { let (loc1, loc2, fed) = ( pair.locations1.id.clone(), pair.locations2.id.clone(), - &pair.zone, + pair.ref_zone(), ); let key = (loc1, loc2); match self.get(&key) { - Some(f) => fed.is_subset_eq(f), + Some(f) => fed.subset_eq(f), None => false, } } - fn zones(&self, key: &(LocationID, LocationID)) -> Vec<&Federation> { + fn zones(&self, key: &(LocationID, LocationID)) -> Vec<&OwnedFederation> { match self.get(key) { Some(f) => vec![f], None => panic!("No zones for key: {:?}", key), diff --git a/src/EdgeEval/constraint_applyer.rs b/src/EdgeEval/constraint_applyer.rs index 78d05309..dc96db2d 100644 --- a/src/EdgeEval/constraint_applyer.rs +++ b/src/EdgeEval/constraint_applyer.rs @@ -1,81 +1,75 @@ +use edbm::util::constraints::{ClockIndex, Inequality}; +use edbm::zones::OwnedFederation; + use crate::component::Declarations; -use crate::DBMLib::dbm::Federation; use crate::ModelObjects::component; use crate::ModelObjects::representations::{ArithExpression, BoolExpression, Clock}; use std::collections::HashMap; use std::convert::TryFrom; -pub fn apply_constraint( - constraint: &Option, - decls: &Declarations, - zone: &mut Federation, -) -> bool { - return if let Some(guards) = constraint { - apply_constraints_to_state(guards, decls, zone) - .expect(format!("Failed to apply constraint {:?}", guards).as_str()) - } else { - true - }; -} - pub fn apply_constraints_to_state( guard: &BoolExpression, decls: &Declarations, - zone: &mut Federation, -) -> Result { - apply_constraints_to_state_helper(guard, decls, zone) + fed: OwnedFederation, +) -> OwnedFederation { + apply_constraints_to_state_helper(guard, decls, fed) } -pub fn apply_constraints_to_state_helper( +fn apply_constraints_to_state_helper( guard: &BoolExpression, decls: &Declarations, - zone: &mut Federation, -) -> Result { + fed: OwnedFederation, +) -> OwnedFederation { + if fed.is_empty() { + return fed; + } + use Inequality::*; match guard { BoolExpression::AndOp(left, right) => { - Ok(apply_constraints_to_state_helper(left, decls, zone)? - && apply_constraints_to_state_helper(right, decls, zone)?) + let fed = apply_constraints_to_state_helper(left, decls, fed); + apply_constraints_to_state_helper(right, decls, fed) } BoolExpression::OrOp(left, right) => { - let mut clone = zone.clone(); - let res1 = apply_constraints_to_state_helper(left, decls, zone)?; - let res2 = apply_constraints_to_state_helper(right, decls, &mut clone)?; - *zone += clone; - Ok(res1 || res2) + let mut clone = fed.clone(); + let fed1 = apply_constraints_to_state_helper(left, decls, fed); + let fed2 = apply_constraints_to_state_helper(right, decls, clone); + fed1 + fed2 } BoolExpression::LessEQ(left, right) => { - let (i, j, c) = get_indices(left, right, decls)?; + let (i, j, c) = get_indices(left, right, decls).unwrap(); // i-j<=c - Ok(zone.constrain(i, j, c, false)) + fed.constrain(i, j, LE(c)) } BoolExpression::GreatEQ(left, right) => { - let (i, j, c) = get_indices(right, left, decls)?; + let (i, j, c) = get_indices(right, left, decls).unwrap(); // j-i <= -c -> c <= i-j - Ok(zone.constrain(i, j, c, false)) + fed.constrain(i, j, LE(c)) } BoolExpression::EQ(left, right) => { - let (i, j, c) = get_indices(left, right, decls)?; + let (i, j, c) = get_indices(left, right, decls).unwrap(); // i-j <= c && j-i <= -c -> c <= i-j - Ok(zone.constrain(i, j, c, false) && zone.constrain(j, i, -c, false)) + + // TODO: maybe use fed.constrain_many(...) + fed.constrain(i, j, LE(c)).constrain(j, i, LE(-c)) } BoolExpression::LessT(left, right) => { - let (i, j, c) = get_indices(left, right, decls)?; + let (i, j, c) = get_indices(left, right, decls).unwrap(); // i-j < c - Ok(zone.constrain(i, j, c, true)) + fed.constrain(i, j, LS(c)) } BoolExpression::GreatT(left, right) => { - let (i, j, c) = get_indices(right, left, decls)?; + let (i, j, c) = get_indices(right, left, decls).unwrap(); // j-i < -c -> c < i-j - Ok(zone.constrain(i, j, c, true)) + fed.constrain(i, j, LS(c)) } - BoolExpression::Parentheses(expr) => apply_constraints_to_state_helper(expr, decls, zone), + BoolExpression::Parentheses(expr) => apply_constraints_to_state_helper(expr, decls, fed), BoolExpression::Bool(val) => { if !*val { - *zone = Federation::empty(zone.get_dimensions()); + return fed.set_empty(); } - Ok(*val) + fed } - _ => Err(format!("Unexpected BoolExpression")), + _ => panic!("Unexpected BoolExpression"), } } @@ -84,7 +78,7 @@ fn get_indices( left: &ArithExpression, right: &ArithExpression, d: &Declarations, -) -> Result<(u32, u32, i32), String> { +) -> Result<(ClockIndex, ClockIndex, i32), String> { let left = &(replace_vars(left, d).simplify())?; let right = &(replace_vars(right, d).simplify())?; let (clocks_left, clocks_right) = (left.clock_var_count(), right.clock_var_count()); @@ -100,7 +94,7 @@ fn get_indices( let (left_const, right_const) = (get_const(left, d), get_const(right, d)); let constant = right_const - left_const; - let result: Result<(u32, u32, i32), String> = match (clocks_left, clocks_right) { + let result: Result<(ClockIndex, ClockIndex, i32), String> = match (clocks_left, clocks_right) { (1, 1) => { let (c1, c2) = ( get_clock_val(left, d, 1, false)?.0, @@ -201,7 +195,7 @@ fn combine_clocks( c2: Clock, constant: i32, same_sign: bool, -) -> Result<(u32, u32, i32), String> { +) -> Result<(ClockIndex, ClockIndex, i32), String> { if (same_sign && c1.negated != c2.negated) || (!same_sign && c1.negated == c2.negated) { Err(String::from("Same sign")) } else { diff --git a/src/EdgeEval/updater.rs b/src/EdgeEval/updater.rs index 61c63034..5314a97f 100644 --- a/src/EdgeEval/updater.rs +++ b/src/EdgeEval/updater.rs @@ -1,15 +1,16 @@ use std::collections::HashMap; use std::{arch, fmt}; -use crate::DBMLib::dbm::Federation; use crate::DataReader::parse_edge; use crate::ModelObjects::component::{self, Declarations}; use crate::ModelObjects::representations::{ArithExpression, BoolExpression}; use colored::Colorize; +use edbm::util::constraints::ClockIndex; +use edbm::zones::OwnedFederation; #[derive(Debug, Clone)] pub struct CompiledUpdate { - pub clock_index: u32, + pub clock_index: ClockIndex, pub value: i32, } @@ -53,12 +54,12 @@ impl CompiledUpdate { } } - pub fn apply(&self, zone: &mut Federation) { - zone.update(self.clock_index, self.value); + pub fn apply(&self, mut fed: OwnedFederation) -> OwnedFederation { + fed.update_clock_val(self.clock_index, self.value) } - pub fn as_update(&self, clocks: &HashMap) -> parse_edge::Update { - let map: HashMap = clocks.clone().into_iter().map(|(l, r)| (r, l)).collect(); + pub fn as_update(&self, clocks: &HashMap) -> parse_edge::Update { + let map: HashMap = clocks.clone().into_iter().map(|(l, r)| (r, l)).collect(); parse_edge::Update { variable: map.get(&self.clock_index).unwrap().clone(), @@ -66,11 +67,11 @@ impl CompiledUpdate { } } - pub fn apply_as_free(&self, zone: &mut Federation) { - zone.free_clock(self.clock_index); + pub fn apply_as_free(&self, fed: OwnedFederation) -> OwnedFederation { + fed.free_clock(self.clock_index) } - pub fn apply_as_guard(&self, zone: &mut Federation) { - zone.add_eq_const_constraint(self.clock_index, self.value); + pub fn apply_as_guard(&self, fed: OwnedFederation) -> OwnedFederation { + fed.constrain_eq(self.clock_index, self.value) } } diff --git a/src/ModelObjects/component.rs b/src/ModelObjects/component.rs index f47cf9e5..f8764c7c 100644 --- a/src/ModelObjects/component.rs +++ b/src/ModelObjects/component.rs @@ -1,4 +1,3 @@ -use crate::DBMLib::dbm::Federation; use crate::DataReader::parse_edge; use crate::DataReader::serialization::{ @@ -8,12 +7,15 @@ use crate::DataReader::serialization::{ use crate::EdgeEval::constraint_applyer; use crate::EdgeEval::constraint_applyer::apply_constraints_to_state; use crate::EdgeEval::updater::CompiledUpdate; -use crate::ModelObjects::max_bounds::MaxBounds; +use edbm::util::bounds::Bounds; +use edbm::util::constraints::ClockIndex; + use crate::ModelObjects::representations; use crate::ModelObjects::representations::BoolExpression; use crate::TransitionSystems::{CompositionType, LocationID, TransitionSystem}; use crate::TransitionSystems::{LocationTuple, TransitionSystemPtr}; +use edbm::zones::OwnedFederation; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fmt; @@ -45,7 +47,7 @@ impl DeclarationProvider for Component { #[allow(dead_code)] impl Component { - pub fn set_clock_indices(&mut self, indices: &mut u32) { + pub fn set_clock_indices(&mut self, indices: &mut ClockIndex) { self.declarations.set_clock_indices(*indices); *indices += self.declarations.get_clock_count(); } @@ -210,8 +212,8 @@ impl Component { result } - pub fn get_max_bounds(&self, dimensions: u32) -> MaxBounds { - let mut max_bounds = MaxBounds::create(dimensions); + pub fn get_max_bounds(&self, dimensions: ClockIndex) -> Bounds { + let mut max_bounds = Bounds::new(dimensions); for (clock_name, clock_id) in &self.declarations.clocks { let mut max_bound = 0; for edge in &self.edges { @@ -232,7 +234,9 @@ impl Component { } } - max_bounds.add_bound(*clock_id, max_bound); + // TODO: find more precise upper and lower bounds for clocks + max_bounds.add_lower(*clock_id, max_bound); + max_bounds.add_upper(*clock_id, max_bound); } max_bounds @@ -253,212 +257,6 @@ impl Component { self.output_edges = Some(o_edges); self.input_edges = Some(i_edges); } - - /// method to verify that component is deterministic, remember to verify the clock indices before calling this - check call in refinement.rs for reference - pub fn is_deterministic(&self, dim: u32) -> bool { - let mut passed_list: Vec = vec![]; - let mut waiting_list: Vec = vec![]; - - let maybe_loc = self.get_initial_location(); - if maybe_loc.is_none() { - println!("No initial location."); - return true; - } - let initial_loc = maybe_loc.unwrap(); - - let dimension = dim; - - let state = create_state(initial_loc, &self.declarations, Federation::init(dimension)); - add_state_to_wl(&mut waiting_list, state); - - while !waiting_list.is_empty() { - if let Some(state) = waiting_list.pop() { - let mut full_state = state; - let mut edges: Vec<&Edge> = vec![]; - let loc = if let LocationID::Simple(name) = &full_state.get_location().id { - self.get_location_by_name(&name) - } else { - panic!("Component should only have simple locations.") - }; - for input_action in self.get_input_actions() { - edges.append(&mut self.get_next_edges( - &loc, - input_action.get_name(), - SyncType::Input, - )); - } - if self.check_moves_overlap(&edges, &mut full_state) { - return false; - } - let mut edges: Vec<&Edge> = vec![]; - for output_action in self.get_output_actions() { - edges.append(&mut self.get_next_edges( - &loc, - output_action.get_name(), - SyncType::Output, - )); - } - - if self.check_moves_overlap(&edges, &mut full_state) { - return false; - } else { - for edge in edges { - //apply the guard and updates from the edge to a cloned zone and add the new zone and location to the waiting list - let full_new_zone = full_state.zone.clone(); - let loc = self.get_location_by_name(&edge.target_location); - let mut new_state = create_state(loc, &self.declarations, full_new_zone); - if !constraint_applyer::apply_constraint( - edge.get_guard(), - &self.declarations, - &mut new_state.zone, - ) { - //If the constraint cannot be applied, continue. - continue; - } - if let Some(updates) = edge.get_update() { - for update in updates { - update - .compiled(self.get_declarations()) - .apply(&mut new_state.zone) - } - } - - if is_new_state(&mut new_state, &mut passed_list) - && is_new_state(&mut new_state, &mut waiting_list) - { - add_state_to_wl(&mut waiting_list, new_state); - } - } - } - add_state_to_pl(&mut passed_list, full_state); - } else { - panic!("Unable to pop state from waiting list") - } - } - - true - } - - /// Method to check if moves are overlapping to for instance to verify that component is deterministic - fn check_moves_overlap(&self, edges: &[&Edge], state: &mut State) -> bool { - if edges.len() < 2 { - return false; - } - - for i in 0..edges.len() { - for j in i + 1..edges.len() { - if edges[i].get_target_location() == edges[j].get_target_location() { - if let Some(update_i) = edges[i].get_update() { - if let Some(update_j) = edges[j].get_update() { - if update_i == update_j { - continue; - } - } - } - } - - if edges[i].get_sync() != edges[j].get_sync() { - continue; - } - let location_source = self - .get_locations() - .iter() - .find(|l| (l.get_id() == edges[i].get_source_location())) - .unwrap(); - let location_i = self - .get_locations() - .iter() - .find(|l| (l.get_id() == edges[i].get_target_location())) - .unwrap(); - let location_j = self - .get_locations() - .iter() - .find(|l| (l.get_id() == edges[j].get_target_location())) - .unwrap(); - - let mut state_i = state.clone(); - if !constraint_applyer::apply_constraint( - location_source.get_invariant(), - &self.declarations, - &mut state_i.zone, - ) { - continue; - } - - if !constraint_applyer::apply_constraint( - &edges[i].guard, - &self.declarations, - &mut state_i.zone, - ) { - continue; - } - - if !constraint_applyer::apply_constraint( - location_i.get_invariant(), - &self.declarations, - &mut state_i.zone, - ) { - continue; - } - - let mut state_j = state.clone(); - if !constraint_applyer::apply_constraint( - location_source.get_invariant(), - &self.declarations, - &mut state_j.zone, - ) { - continue; - } - - if !constraint_applyer::apply_constraint( - &edges[j].guard, - &self.declarations, - &mut state_j.zone, - ) { - continue; - } - - if !constraint_applyer::apply_constraint( - location_j.get_invariant(), - &self.declarations, - &mut state_j.zone, - ) { - continue; - } - - //TODO: this should consider resets, inv(target)[r|->0] - - if state_i.zone.is_valid() && state_j.zone.is_valid() { - if state_i.zone.intersects(&state_j.zone) { - println!( - "Edges {} and {} overlap with zones {} and {}", - edges[i], edges[j], state_i.zone, state_j.zone - ); - return true; - } - } - } - } - - false - } -} - -/// Function to check if a state is contained in the passed list, similar to the method impl by component -fn is_new_state(state: &mut State, passed_list: &mut Vec) -> bool { - for passed_state_pair in passed_list { - if state.get_location().id != passed_state_pair.get_location().id { - continue; - } - if state.zone.get_dimensions() != passed_state_pair.zone.get_dimensions() { - panic!("dimensions of dbm didn't match - fatal error") - } - if state.zone.is_subset_eq(&passed_state_pair.zone) { - return false; - } - } - - true } pub fn contain(channels: &[Channel], channel: &str) -> bool { @@ -471,49 +269,66 @@ pub fn contain(channels: &[Channel], channel: &str) -> bool { false } -fn create_state(location: &Location, decl: &Declarations, zone: Federation) -> State { - State { - decorated_locations: LocationTuple::simple(location, decl, zone.get_dimensions()), - zone, - } +fn create_state(location: &Location, decl: &Declarations, zone: OwnedFederation) -> State { + State::create(LocationTuple::simple(location, decl, zone.dim()), zone) } /// FullState is a struct used for initial verification of consistency, and determinism as a state that also hols a dbm /// This is done as the type used in refinement state pair assumes to sides of an operation /// this should probably be refactored as it causes unnecessary confusion -#[derive(Clone, PartialEq)] +#[derive(Clone)] pub struct State { pub decorated_locations: LocationTuple, - pub zone: Federation, + zone_sentinel: Option, } impl State { - pub fn create(decorated_locations: LocationTuple, zone: Federation) -> Self { + pub fn create(decorated_locations: LocationTuple, zone: OwnedFederation) -> Self { State { decorated_locations, - zone, + zone_sentinel: Some(zone), } } - pub fn from_location(decorated_locations: LocationTuple, dimensions: u32) -> Option { - let mut zone = Federation::init(dimensions); + pub fn is_contained_in_list(&self, list: &Vec) -> bool { + list.iter().any(|s| self.is_subset_of(s)) + } - if !decorated_locations.apply_invariants(&mut zone) { + pub fn from_location( + decorated_locations: LocationTuple, + dimensions: ClockIndex, + ) -> Option { + let mut fed = OwnedFederation::init(dimensions); + + fed = decorated_locations.apply_invariants(fed); + if fed.is_empty() { return None; } Some(State { decorated_locations, - zone, + zone_sentinel: Some(fed), }) } + pub fn zone_ref(&self) -> &OwnedFederation { + self.zone_sentinel.as_ref().unwrap() + } + + pub fn take_zone(&mut self) -> OwnedFederation { + self.zone_sentinel.take().unwrap() + } + + pub fn set_zone(&mut self, zone: OwnedFederation) { + self.zone_sentinel = Some(zone); + } + pub fn is_subset_of(&self, other: &Self) -> bool { if self.decorated_locations != other.decorated_locations { return false; } - self.zone.is_subset_eq(&other.zone) + self.zone_ref().subset_eq(other.zone_ref()) } pub fn get_location(&self) -> &LocationTuple { @@ -522,7 +337,8 @@ impl State { pub fn extrapolate_max_bounds(&mut self, system: &dyn TransitionSystem) { let bounds = system.get_local_max_bounds(&self.decorated_locations); - self.zone.extrapolate_max_bounds(&bounds); + let zone = self.take_zone().extrapolate_max_bounds(&bounds); + self.set_zone(zone); } } @@ -577,20 +393,20 @@ pub enum SyncType { //Represents a single transition from taking edges in multiple components #[derive(Debug, Clone)] pub struct Transition { - pub guard_zone: Federation, + pub guard_zone: OwnedFederation, pub target_locations: LocationTuple, pub updates: Vec, } impl Transition { - pub fn new(target_locations: &LocationTuple, dim: u32) -> Transition { + pub fn new(target_locations: &LocationTuple, dim: ClockIndex) -> Transition { Transition { - guard_zone: Federation::full(dim), + guard_zone: OwnedFederation::universe(dim), target_locations: target_locations.clone(), updates: vec![], } } - pub fn from(comp: &Component, edge: &Edge, dim: u32) -> Transition { + pub fn from(comp: &Component, edge: &Edge, dim: ClockIndex) -> Transition { //let (comp, edge) = edges; let target_loc_name = &edge.target_location; @@ -614,15 +430,18 @@ impl Transition { } pub fn use_transition(&self, state: &mut State) -> bool { - if self.apply_guards(&mut state.zone) { - self.apply_updates(&mut state.zone); + let mut zone = state.take_zone(); + zone = self.apply_guards(zone); + if !zone.is_empty() { + zone = self.apply_updates(zone).up(); self.move_locations(&mut state.decorated_locations); - state.zone.up(); - if state.decorated_locations.apply_invariants(&mut state.zone) { + zone = state.decorated_locations.apply_invariants(zone); + if !zone.is_empty() { + state.set_zone(zone); return true; } } - + state.set_zone(zone); false } @@ -637,7 +456,7 @@ impl Transition { let target_locations = LocationTuple::compose(&l.target_locations, &r.target_locations, comp); - let guard_zone = l.guard_zone.intersection(&r.guard_zone); + let guard_zone = l.guard_zone.clone().intersection(&r.guard_zone); let mut updates = l.updates.clone(); updates.append(&mut r.updates.clone()); @@ -653,82 +472,86 @@ impl Transition { out } - pub fn apply_updates(&self, zone: &mut Federation) { + pub fn apply_updates(&self, mut fed: OwnedFederation) -> OwnedFederation { for update in &self.updates { - update.apply(zone); + fed = update.apply(fed); } + + fed } - pub fn inverse_apply_updates(&self, zone: &mut Federation) { + pub fn inverse_apply_updates(&self, mut fed: OwnedFederation) -> OwnedFederation { for update in &self.updates { - update.apply_as_guard(zone); + fed = update.apply_as_guard(fed); } for update in &self.updates { - update.apply_as_free(zone); + fed = update.apply_as_free(fed); } + + fed } fn get_guard_from_allowed( from_loc: &LocationTuple, to_loc: &LocationTuple, updates: Vec, - guard: Option, - dim: u32, - ) -> Federation { + guard: Option, + dim: ClockIndex, + ) -> OwnedFederation { let mut fed = match to_loc.get_invariants() { Some(fed) => fed.clone(), - None => Federation::full(dim), + None => OwnedFederation::universe(dim), }; for update in &updates { - update.apply_as_guard(&mut fed); + fed = update.apply_as_guard(fed); } for update in &updates { - update.apply_as_free(&mut fed); + fed = update.apply_as_free(fed); } if let Some(g) = guard { - fed.intersect(&g); + fed = fed.intersection(&g); } - from_loc.apply_invariants(&mut fed); - fed + from_loc.apply_invariants(fed) } - pub fn get_allowed_federation(&self) -> Federation { + pub fn get_allowed_federation(&self) -> OwnedFederation { let mut fed = match self.target_locations.get_invariants() { Some(fed) => fed.clone(), - None => Federation::full(self.guard_zone.get_dimensions()), + None => OwnedFederation::universe(self.guard_zone.dim()), }; - self.inverse_apply_updates(&mut fed); - self.apply_guards(&mut fed); - fed + fed = self.inverse_apply_updates(fed); + self.apply_guards(fed) } - pub fn apply_guards(&self, zone: &mut Federation) -> bool { - zone.intersect(&self.guard_zone); - zone.is_valid() + pub fn apply_guards(&self, mut zone: OwnedFederation) -> OwnedFederation { + zone.intersection(&self.guard_zone) } pub fn move_locations(&self, locations: &mut LocationTuple) { *locations = self.target_locations.clone(); } - pub fn combine_edge_guards(edges: &Vec<(&Component, &Edge)>, dim: u32) -> Federation { - let mut zone = Federation::full(dim); + pub fn combine_edge_guards( + edges: &Vec<(&Component, &Edge)>, + dim: ClockIndex, + ) -> OwnedFederation { + let mut fed = OwnedFederation::universe(dim); for (comp, edge) in edges { - edge.apply_guard(comp.get_declarations(), &mut zone); + fed = edge.apply_guard(comp.get_declarations(), fed); } - zone + fed } pub fn get_renamed_guard_expression( &self, - naming: &HashMap, + naming: &HashMap, ) -> Option { - self.guard_zone.as_boolexpression(Some(naming)) + BoolExpression::from_disjunction(&self.guard_zone.minimal_constraints(), naming) } pub fn get_renamed_updates( &self, - naming: &HashMap, + naming: &HashMap, ) -> Option> { let updates: Vec<_> = self.updates.iter().map(|u| u.as_update(naming)).collect(); @@ -810,24 +633,23 @@ impl Edge { pub fn apply_update( &self, decl: &Declarations, //Will eventually be mutable - zone: &mut Federation, - ) { + mut fed: OwnedFederation, + ) -> OwnedFederation { if let Some(updates) = self.get_update() { for update in updates { - update.compiled(decl).apply(zone); + fed = update.compiled(decl).apply(fed); } } + + fed } - pub fn apply_guard(&self, decl: &Declarations, zone: &mut Federation) -> bool { - return if let Some(guards) = self.get_guard() { - match apply_constraints_to_state(guards, decl, zone) { - Ok(x) => x, - Err(e) => panic!("Error du to: {}", e), - } - } else { - true + pub fn apply_guard(&self, decl: &Declarations, mut fed: OwnedFederation) -> OwnedFederation { + if let Some(guards) = self.get_guard() { + fed = apply_constraints_to_state(guards, decl, fed); }; + + fed } pub fn get_source_location(&self) -> &String { @@ -895,15 +717,12 @@ impl<'a> DecoratedLocation<'a> { DecoratedLocation { location, decls } } - pub fn apply_invariant(&self, zone: &mut Federation) -> bool { + pub fn apply_invariant(&self, mut fed: OwnedFederation) -> OwnedFederation { if let Some(inv) = self.get_location().get_invariant() { - match apply_constraints_to_state(&inv, self.decls, zone) { - Ok(x) => x, - Err(e) => panic!("Erorr due to: {}", e), - } - } else { - true + fed = apply_constraints_to_state(&inv, self.decls, fed); } + + fed } pub fn get_invariant(&self) -> &Option { @@ -922,7 +741,7 @@ impl<'a> DecoratedLocation<'a> { self.location = location; } - pub fn get_clock_count(&self) -> u32 { + pub fn get_clock_count(&self) -> ClockIndex { self.get_declarations().get_clock_count() } } @@ -935,7 +754,7 @@ pub trait DeclarationProvider { #[derive(Debug, Deserialize, Clone, PartialEq, Serialize)] pub struct Declarations { pub ints: HashMap, - pub clocks: HashMap, + pub clocks: HashMap, } #[allow(dead_code)] @@ -955,25 +774,25 @@ impl Declarations { &mut self.ints } - pub fn get_clocks(&self) -> &HashMap { + pub fn get_clocks(&self) -> &HashMap { &self.clocks } - pub fn get_clock_count(&self) -> u32 { - self.clocks.len() as u32 + pub fn get_clock_count(&self) -> usize { + self.clocks.len() } - pub fn get_max_clock_index(&self) -> u32 { + pub fn get_max_clock_index(&self) -> ClockIndex { *self.clocks.values().max().unwrap_or(&0) } - pub fn set_clock_indices(&mut self, start_index: u32) { + pub fn set_clock_indices(&mut self, start_index: ClockIndex) { for (_, v) in self.clocks.iter_mut() { *v += start_index } } - pub fn update_clock_indices(&mut self, start_index: u32, old_offset: u32) { + pub fn update_clock_indices(&mut self, start_index: ClockIndex, old_offset: ClockIndex) { for (_, v) in self.clocks.iter_mut() { *v -= old_offset; *v += start_index; @@ -988,7 +807,7 @@ impl Declarations { } } - pub fn get_clock_index_by_name(&self, name: &str) -> Option<&u32> { + pub fn get_clock_index_by_name(&self, name: &str) -> Option<&ClockIndex> { self.get_clocks().get(name) } } diff --git a/src/ModelObjects/representations.rs b/src/ModelObjects/representations.rs index 2778d979..16c307db 100644 --- a/src/ModelObjects/representations.rs +++ b/src/ModelObjects/representations.rs @@ -1,7 +1,7 @@ -use crate::DBMLib::dbm::Zone; use crate::ModelObjects::statepair::StatePair; use boolean_expression::CubeVar::False; use colored::Colorize; +use edbm::util::constraints::{ClockIndex, Conjunction, Constraint, Disjunction}; use generic_array::arr_impl; use serde::Deserialize; use std::borrow::BorrowMut; @@ -31,8 +31,8 @@ pub enum BoolExpression { impl BoolExpression { pub fn swap_clock_names( &self, - from_vars: &HashMap, - to_vars: &HashMap, + from_vars: &HashMap, + to_vars: &HashMap, ) -> BoolExpression { match self { BoolExpression::AndOp(left, right) => BoolExpression::AndOp( @@ -110,7 +110,131 @@ impl BoolExpression { } } - pub fn get_max_constant(&self, clock: u32, clock_name: &str) -> i32 { + pub fn from_disjunction( + disjunction: &Disjunction, + naming: &HashMap, + ) -> Option { + let naming = naming + .iter() + .map(|(name, index)| (*index, name.clone())) + .collect(); + if disjunction.conjunctions.is_empty() { + Some(BoolExpression::Bool(false)) + } else if disjunction.conjunctions.len() == 1 { + BoolExpression::from_conjunction(&disjunction.conjunctions[0], &naming) + } else { + let mut result = None; + + for conjunction in &disjunction.conjunctions { + let expr = BoolExpression::from_conjunction(conjunction, &naming); + if expr.is_none() { + // If any is None (true), the disjuntion is None (true) + return None; + } + let expr = expr.unwrap(); + match result { + None => result = Some(expr), + Some(res) => result = Some(BoolExpression::OrOp(Box::new(res), Box::new(expr))), + } + } + + result + } + } + + pub fn from_conjunction( + conjunction: &Conjunction, + naming: &HashMap, + ) -> Option { + if conjunction.constraints.is_empty() { + //BoolExpression::Bool(true) + None + } else if conjunction.constraints.len() == 1 { + Some(BoolExpression::from_constraint( + &conjunction.constraints[0], + naming, + )) + } else { + let mut result = None; + + for constraint in &conjunction.constraints { + let expr = BoolExpression::from_constraint(constraint, naming); + match result { + None => result = Some(expr), + Some(res) => { + result = Some(BoolExpression::AndOp(Box::new(res), Box::new(expr))) + } + } + } + + result + } + } + + pub fn from_constraint(constraint: &Constraint, naming: &HashMap) -> Self { + let ineq = constraint.ineq(); + let is_strict = ineq.is_strict(); + let bound = ineq.bound(); + let i = constraint.i; + let j = constraint.j; + + match (i, j) { + (0, 0) => { + unreachable!("Constraint with i == 0 and j == 0 is not allowed"); + } + (0, j) => { + // negated lower bound + match is_strict { + true => { + BoolExpression::GreatT(var_from_naming(naming, j), arith_from_int(-bound)) + } + false => { + BoolExpression::GreatEQ(var_from_naming(naming, j), arith_from_int(-bound)) + } + } + } + (i, 0) => { + // upper bound + match is_strict { + true => { + BoolExpression::LessT(var_from_naming(naming, i), arith_from_int(bound)) + } + false => { + BoolExpression::LessEQ(var_from_naming(naming, i), arith_from_int(bound)) + } + } + } + (i, j) => { + // difference + if bound == 0 { + // i-j<=0 -> i <= 0+j + match is_strict { + true => BoolExpression::LessT( + var_from_naming(naming, i), + var_from_naming(naming, j), + ), + false => BoolExpression::LessEQ( + var_from_naming(naming, i), + var_from_naming(naming, j), + ), + } + } else { + match is_strict { + true => BoolExpression::LessT( + var_diff_from_naming(naming, i, j), + arith_from_int(bound), + ), + false => BoolExpression::LessEQ( + var_diff_from_naming(naming, i, j), + arith_from_int(bound), + ), + } + } + } + } + } + + pub fn get_max_constant(&self, clock: ClockIndex, clock_name: &str) -> i32 { let mut new_constraint = 0; self.iterate_constraints(&mut |left, right| { @@ -122,7 +246,7 @@ impl BoolExpression { } }); - new_constraint // * 2 + 1 // This should not actually be a dbm_raw, as it is converted from bound to raw in the c code + new_constraint } pub fn swap_var_name(&mut self, from_name: &str, to_name: &str) { @@ -320,6 +444,30 @@ impl BoolExpression { } } +fn var_from_naming( + naming: &HashMap, + index: ClockIndex, +) -> Box { + Box::new(ArithExpression::VarName( + naming.get(&index).unwrap().to_string(), + )) +} + +fn var_diff_from_naming( + naming: &HashMap, + i: ClockIndex, + j: ClockIndex, +) -> Box { + Box::new(ArithExpression::Difference( + var_from_naming(naming, i), + var_from_naming(naming, j), + )) +} + +fn arith_from_int(value: i32) -> Box { + Box::new(ArithExpression::Int(value)) +} + impl ops::BitAnd for BoolExpression { type Output = Self; @@ -437,7 +585,7 @@ pub enum ArithExpression { Multiplication(Box, Box), Division(Box, Box), Modulo(Box, Box), - Clock(u32), + Clock(ClockIndex), VarName(String), Int(i32), } @@ -445,8 +593,8 @@ pub enum ArithExpression { impl ArithExpression { pub fn swap_clock_names( &self, - from_vars: &HashMap, - to_vars: &HashMap, + from_vars: &HashMap, + to_vars: &HashMap, ) -> ArithExpression { match self { ArithExpression::Difference(left, right) => ArithExpression::Difference( @@ -504,7 +652,7 @@ impl ArithExpression { } } - pub fn get_max_constant(&self, clock: u32, clock_name: &str) -> i32 { + pub fn get_max_constant(&self, clock: ClockIndex, clock_name: &str) -> i32 { let mut new_constraint = 0; self.iterate_constraints(&mut |left, right| { @@ -554,7 +702,7 @@ impl ArithExpression { } } - pub fn get_constant(left: &Self, right: &Self, clock: u32, clock_name: &str) -> i32 { + pub fn get_constant(left: &Self, right: &Self, clock: ClockIndex, clock_name: &str) -> i32 { match left { ArithExpression::Clock(clock_id) => { if *clock_id == clock { @@ -982,26 +1130,26 @@ impl Operation { } pub struct Clock { - pub value: u32, + pub value: ClockIndex, pub negated: bool, } impl Clock { - pub fn new(v: u32, n: bool) -> Clock { + pub fn new(v: ClockIndex, n: bool) -> Clock { Clock { value: v, negated: n, } } - pub fn neg(v: u32) -> Clock { + pub fn neg(v: ClockIndex) -> Clock { Clock { value: v, negated: true, } } - pub fn pos(v: u32) -> Clock { + pub fn pos(v: ClockIndex) -> Clock { Clock { value: v, negated: false, @@ -1023,8 +1171,8 @@ fn get_op(exp: &Box) -> Option { } fn var_from_index( - index: u32, - clocks: &Option<&HashMap>, + index: ClockIndex, + clocks: &Option<&HashMap>, ) -> Option> { let var = if let Some(c) = clocks { //If the index exists in dbm it must be in the map, so we unwrap @@ -1039,7 +1187,7 @@ fn var_from_index( }; var } - +/* fn get_groups_from_zone(zone: &Zone, clocks: &Option<&HashMap>) -> Vec> { let mut groups: Vec> = vec![]; let mut grouped: Vec = vec![]; @@ -1147,6 +1295,7 @@ pub fn build_guard_from_zone( Some(res) } + fn add_diagonal_constraints( zone: &Zone, index_i: u32, @@ -1184,6 +1333,7 @@ fn add_diagonal_constraints( } } + fn is_equal(zone: &Zone, index_i: u32, index_j: u32) -> bool { let d1 = zone.get_constraint(index_i, index_j); let d2 = zone.get_constraint(index_j, index_i); @@ -1222,6 +1372,7 @@ fn constraint_sum(c1_strict: bool, c1: i32, c2_strict: bool, c2: i32) -> (bool, let c = c1 + c2; (strict, c) } +*/ fn build_guard_from_zone_helper(guards: &mut Vec) -> BoolExpression { let num_guards = guards.len(); diff --git a/src/ModelObjects/state.rs b/src/ModelObjects/state.rs index 7f0e36ee..43bd85d8 100644 --- a/src/ModelObjects/state.rs +++ b/src/ModelObjects/state.rs @@ -33,7 +33,7 @@ impl<'a> State<'a> { return false; } - self.zone.is_subset_eq(&other.zone) + self.zone.subset_eq(&other.zone) } pub fn get_location(&self, index: usize) -> &Location { diff --git a/src/ModelObjects/statepair.rs b/src/ModelObjects/statepair.rs index 92960fc7..730fc92c 100644 --- a/src/ModelObjects/statepair.rs +++ b/src/ModelObjects/statepair.rs @@ -1,5 +1,6 @@ -use crate::DBMLib::dbm::Federation; -use crate::ModelObjects::max_bounds::MaxBounds; +use edbm::util::{bounds::Bounds, constraints::ClockIndex}; +use edbm::zones::OwnedFederation; + use crate::TransitionSystems::{LocationTuple, TransitionSystemPtr}; use std::fmt::{Display, Formatter}; @@ -7,27 +8,27 @@ use std::fmt::{Display, Formatter}; pub struct StatePair { pub locations1: LocationTuple, pub locations2: LocationTuple, - pub zone: Federation, + /// The sentinel (Option) allows us to take ownership of the internal fed from a mutable reference + zone_sentinel: Option, } impl StatePair { pub fn create( - dimensions: u32, + dimensions: usize, locations1: LocationTuple, locations2: LocationTuple, ) -> StatePair { - let mut zone = Federation::zero(dimensions); - zone.up(); + let mut zone = OwnedFederation::init(dimensions); StatePair { locations1, locations2, - zone, + zone_sentinel: Some(zone), } } - pub fn get_dimensions(&self) -> u32 { - self.zone.get_dimensions() + pub fn dim(&self) -> ClockIndex { + self.ref_zone().dim() } pub fn get_locations1(&self) -> &LocationTuple { @@ -55,6 +56,22 @@ impl StatePair { } } + pub fn clone_zone(&self) -> OwnedFederation { + self.ref_zone().clone() + } + + pub fn ref_zone(&self) -> &OwnedFederation { + self.zone_sentinel.as_ref().unwrap() + } + + pub fn take_zone(&mut self) -> OwnedFederation { + self.zone_sentinel.take().unwrap() + } + + pub fn set_zone(&mut self, zone: OwnedFederation) { + self.zone_sentinel = Some(zone); + } + pub fn extrapolate_max_bounds( &mut self, sys1: &TransitionSystemPtr, @@ -62,7 +79,8 @@ impl StatePair { ) { let mut bounds = sys1.get_local_max_bounds(&self.locations1); bounds.add_bounds(&sys2.get_local_max_bounds(&self.locations2)); - self.zone.extrapolate_max_bounds(&bounds); + let zone = self.take_zone().extrapolate_max_bounds(&bounds); + self.set_zone(zone); } } @@ -80,7 +98,7 @@ impl Display for StatePair { .get_invariants() .map(|f| f.to_string()) .unwrap_or("no invariant".to_string()), - self.zone + self.ref_zone() ))?; Ok(()) diff --git a/src/System/extract_system_rep.rs b/src/System/extract_system_rep.rs index 4b527396..942a4a9a 100644 --- a/src/System/extract_system_rep.rs +++ b/src/System/extract_system_rep.rs @@ -12,6 +12,7 @@ use crate::TransitionSystems::{ }; use crate::System::pruning; +use edbm::util::constraints::ClockIndex; use simple_error::bail; use std::borrow::BorrowMut; use std::error::Error; @@ -22,7 +23,7 @@ pub fn create_executable_query<'a>( full_query: &Query, component_loader: &'a mut (dyn ComponentLoader + 'static), ) -> Result, Box> { - let mut dim: u32 = 0; + let mut dim: ClockIndex = 0; if let Some(query) = full_query.get_query() { match query { @@ -87,12 +88,12 @@ pub fn create_executable_query<'a>( pub enum SystemRecipe { Composition(Box, Box), Conjunction(Box, Box), - Quotient(Box, Box, u32), + Quotient(Box, Box, ClockIndex), Component(Box), } impl SystemRecipe { - pub fn compile(self, dim: u32) -> Result { + pub fn compile(self, dim: ClockIndex) -> Result { match self { SystemRecipe::Composition(left, right) => { Composition::new(left.compile(dim)?, right.compile(dim)?, dim + 1) @@ -117,7 +118,7 @@ impl SystemRecipe { pub fn get_system_recipe( side: &QueryExpression, component_loader: &mut dyn ComponentLoader, - clock_index: &mut u32, + clock_index: &mut ClockIndex, ) -> Box { match side { QueryExpression::Parentheses(expression) => { diff --git a/src/System/input_enabler.rs b/src/System/input_enabler.rs index 4b74bad3..ee572999 100644 --- a/src/System/input_enabler.rs +++ b/src/System/input_enabler.rs @@ -1,7 +1,9 @@ -use crate::DBMLib::dbm::Federation; +use edbm::zones::OwnedFederation; + use crate::EdgeEval::constraint_applyer; use crate::ModelObjects::component; use crate::ModelObjects::component::DeclarationProvider; +use crate::ModelObjects::representations::BoolExpression; use crate::TransitionSystems::TransitionSystem; pub fn make_input_enabled(component: &mut component::Component, inputs: &[String]) { @@ -9,13 +11,13 @@ pub fn make_input_enabled(component: &mut component::Component, inputs: &[String let mut new_edges: Vec = vec![]; for location in component.get_locations() { - let mut location_inv_zone = Federation::full(dimension); + let mut location_inv_zone = OwnedFederation::universe(dimension); if let Some(invariant) = location.get_invariant() { - constraint_applyer::apply_constraints_to_state( + location_inv_zone = constraint_applyer::apply_constraints_to_state( invariant, component.get_declarations(), - &mut location_inv_zone, + location_inv_zone, ); } @@ -24,43 +26,41 @@ pub fn make_input_enabled(component: &mut component::Component, inputs: &[String for input in inputs { let input_edges = component.get_next_edges(location, input, component::SyncType::Input); - let mut zones_federation = Federation::empty(dimension); + let mut zones_federation = OwnedFederation::empty(dimension); for edge in input_edges { - let mut guard_zone = Federation::full(dimension); + let mut guard_zone = OwnedFederation::universe(dimension); if let Some(target_invariant) = component .get_location_by_name(edge.get_target_location()) .get_invariant() { - constraint_applyer::apply_constraints_to_state( + guard_zone = constraint_applyer::apply_constraints_to_state( target_invariant, component.get_declarations(), - &mut guard_zone, + guard_zone, ); } if let Some(updates) = edge.get_update() { for update in updates { let cu = update.compiled(component.get_declarations()); - cu.apply_as_guard(&mut guard_zone); - cu.apply_as_free(&mut guard_zone); + guard_zone = cu.apply_as_guard(guard_zone); + guard_zone = cu.apply_as_free(guard_zone); } } if let Some(guard) = edge.get_guard() { - constraint_applyer::apply_constraints_to_state( + guard_zone = constraint_applyer::apply_constraints_to_state( guard, component.get_declarations(), - &mut guard_zone, + guard_zone, ); } - guard_zone.intersect(&location_inv_zone); - - zones_federation.add_fed(&guard_zone); + zones_federation += guard_zone.intersection(&location_inv_zone); } - let result_federation = full_federation.subtraction(&zones_federation); + let result_federation = full_federation.clone().subtraction(&zones_federation); if result_federation.is_empty() { continue; @@ -71,8 +71,10 @@ pub fn make_input_enabled(component: &mut component::Component, inputs: &[String source_location: location.get_id().to_string(), target_location: location.get_id().to_string(), sync_type: component::SyncType::Input, - guard: result_federation - .as_boolexpression(Some(component.get_declarations().get_clocks())), + guard: BoolExpression::from_disjunction( + &result_federation.minimal_constraints(), + component.get_declarations().get_clocks(), + ), update: None, sync: input.to_string(), }); diff --git a/src/System/local_consistency.rs b/src/System/local_consistency.rs index 3c9eeb46..fb4978a0 100644 --- a/src/System/local_consistency.rs +++ b/src/System/local_consistency.rs @@ -1,4 +1,5 @@ -use crate::DBMLib::dbm::Federation; +use edbm::zones::OwnedFederation; + use crate::ModelObjects::component::State; use crate::TransitionSystems::{TransitionSystem, TransitionSystemPtr}; @@ -31,7 +32,7 @@ pub fn is_deterministic(system: &dyn TransitionSystem) -> bool { return true; } let mut state = state.unwrap(); - state.zone = Federation::full(system.get_dim()); + state.set_zone(OwnedFederation::universe(system.get_dim())); let res = is_deterministic_helper(state, &mut passed, system); @@ -43,21 +44,21 @@ fn is_deterministic_helper( passed_list: &mut Vec, system: &dyn TransitionSystem, ) -> bool { - if passed_list.contains(&state) { + if state.is_contained_in_list(passed_list) { return true; } passed_list.push(state.clone()); for action in system.get_actions() { - let mut location_fed = Federation::empty(system.get_dim()); + let mut location_fed = OwnedFederation::empty(system.get_dim()); for transition in &system.next_transitions(&state.decorated_locations, &action) { let mut new_state = state.clone(); if transition.use_transition(&mut new_state) { let mut allowed_fed = transition.get_allowed_federation(); - state.decorated_locations.apply_invariants(&mut allowed_fed); - if allowed_fed.intersects(&location_fed) { + allowed_fed = state.decorated_locations.apply_invariants(allowed_fed); + if allowed_fed.has_intersection(&location_fed) { println!( "Not deterministic from location {}", state.get_location().id @@ -96,7 +97,7 @@ pub fn consistency_least_helper( passed_list: &mut Vec, system: &dyn TransitionSystem, ) -> bool { - if passed_list.contains(&state) { + if state.is_contained_in_list(passed_list) { return true; } if state.decorated_locations.is_universal() { @@ -124,7 +125,7 @@ pub fn consistency_least_helper( } } - if state.zone.can_delay_indefinitely() { + if state.zone_ref().can_delay_indefinitely() { return true; } @@ -150,7 +151,7 @@ fn consistency_fully_helper( passed_list: &mut Vec, system: &dyn TransitionSystem, ) -> bool { - if passed_list.contains(&state) { + if state.is_contained_in_list(passed_list) { return true; } passed_list.push(state.clone()); @@ -192,6 +193,10 @@ fn consistency_fully_helper( if output_existed { true } else { - passed_list.last().unwrap().zone.can_delay_indefinitely() + passed_list + .last() + .unwrap() + .zone_ref() + .can_delay_indefinitely() } } diff --git a/src/System/pruning.rs b/src/System/pruning.rs index 22e14565..8cdb1c6b 100644 --- a/src/System/pruning.rs +++ b/src/System/pruning.rs @@ -1,5 +1,7 @@ -use crate::DBMLib::dbm::Federation; -use crate::EdgeEval::constraint_applyer::{apply_constraint, apply_constraints_to_state}; +use edbm::util::constraints::ClockIndex; +use edbm::zones::OwnedFederation; + +use crate::EdgeEval::constraint_applyer::apply_constraints_to_state; use crate::ModelObjects::component::{ Component, DeclarationProvider, Declarations, Edge, Location, SyncType, Transition, }; @@ -14,7 +16,7 @@ use std::hash::{Hash, Hasher}; use super::save_component::PruningStrategy; -pub fn prune_system(ts: TransitionSystemPtr, dim: u32) -> TransitionSystemPtr { +pub fn prune_system(ts: TransitionSystemPtr, dim: ClockIndex) -> TransitionSystemPtr { let inputs = ts.get_input_actions(); let outputs = ts.get_output_actions(); let comp = combine_components(&ts, PruningStrategy::NoPruning); @@ -43,9 +45,9 @@ pub fn prune_system(ts: TransitionSystemPtr, dim: u32) -> TransitionSystemPtr { struct PruneContext { comp: Component, inconsistent_locs: Vec, - inconsistent_parts: HashMap, - passed_pairs: Vec<(String, Federation)>, - dim: u32, + inconsistent_parts: HashMap, + passed_pairs: Vec<(String, OwnedFederation)>, + dim: ClockIndex, } impl PruneContext { @@ -57,11 +59,11 @@ impl PruneContext { self.comp.get_location_by_name(name) } - fn try_get_incons(&self, name: &str) -> Option<&Federation> { + fn try_get_incons(&self, name: &str) -> Option<&OwnedFederation> { self.inconsistent_parts.get(name) } - fn get_incons(&self, name: &str) -> &Federation { + fn get_incons(&self, name: &str) -> &OwnedFederation { self.inconsistent_parts.get(name).unwrap() } @@ -73,9 +75,12 @@ impl PruneContext { } } - fn update_edge_guard(&mut self, edge: &Edge, guard_fed: &Federation) { + fn update_edge_guard(&mut self, edge: &Edge, guard_fed: &OwnedFederation) { if let Some(index) = self.comp.edges.iter().position(|e| *e == *edge) { - let guard = guard_fed.as_boolexpression(Some(&self.decl().clocks)); + let guard = BoolExpression::from_disjunction( + &guard_fed.minimal_constraints(), + &self.decl().clocks, + ); println!( "Updating {} with guard {}", @@ -87,14 +92,14 @@ impl PruneContext { } } - fn finish(self) -> (Component, HashMap) { + fn finish(self) -> (Component, HashMap) { (self.comp, self.inconsistent_parts) } } pub fn prune( comp: &Component, - dim: u32, + dim: ClockIndex, inputs: HashSet, outputs: HashSet, decl: &SystemDeclarations, @@ -107,9 +112,9 @@ pub fn prune( .filter(|l| is_immediately_inconsistent(l, comp, dim)) .map(|l| l.id.clone()) .collect(); - let inconsistent_parts: HashMap = inconsistent_locs + let inconsistent_parts: HashMap = inconsistent_locs .iter() - .map(|id| (id.clone(), Federation::full(dim))) + .map(|id| (id.clone(), OwnedFederation::universe(dim))) .collect(); println!("Inconsistent locs: {:?}", inconsistent_locs); @@ -165,21 +170,24 @@ pub fn prune( fn add_inconsistent_parts_to_invariants( comp: &mut Component, - incons_parts: HashMap, - dim: u32, + incons_parts: HashMap, + dim: ClockIndex, ) { let decls = comp.get_declarations().clone(); for location in &mut comp.locations { if let Some(incons) = incons_parts.get(&location.id) { // get invariant - let mut invariant_fed = Federation::full(dim); + let mut invariant_fed = OwnedFederation::universe(dim); if let Some(inv) = location.get_invariant() { - apply_constraints_to_state(inv, &decls, &mut invariant_fed); + invariant_fed = apply_constraints_to_state(inv, &decls, invariant_fed); } // Remove inconsistent part - invariant_fed.subtract(incons); + invariant_fed = invariant_fed.subtraction(incons); // Set the new invariant - location.invariant = invariant_fed.as_boolexpression(Some(&decls.clocks)); + location.invariant = BoolExpression::from_disjunction( + &invariant_fed.minimal_constraints(), + &decls.clocks, + ); } } } @@ -190,14 +198,14 @@ fn handle_input(edge: &Edge, context: &mut PruneContext) { // apply target invariant if let Some(inv) = target_loc.get_invariant() { - apply_constraints_to_state(inv, context.decl(), &mut inconsistent_part); + inconsistent_part = apply_constraints_to_state(inv, context.decl(), inconsistent_part); } // apply updates as guard if let Some(updates) = edge.get_update() { for update in updates { - update + inconsistent_part = update .compiled(context.decl()) - .apply_as_guard(&mut inconsistent_part); + .apply_as_guard(inconsistent_part); } } @@ -217,65 +225,64 @@ fn handle_input(edge: &Edge, context: &mut PruneContext) { let copy = inconsistent_part.clone(); let mut inconsistent_part = predt_of_all_outputs(&target_loc, inconsistent_part, context); - if copy == inconsistent_part { - inconsistent_part.down(); + if copy.equals(&inconsistent_part) { + inconsistent_part = inconsistent_part.down(); // apply source invariant let source_loc = context.get_loc(edge.get_source_location()); if let Some(inv) = source_loc.get_invariant() { - apply_constraints_to_state(inv, context.decl(), &mut inconsistent_part); + inconsistent_part = + apply_constraints_to_state(inv, context.decl(), inconsistent_part); } } - process_source_location(edge.get_source_location(), &mut inconsistent_part, context); + process_source_location(edge.get_source_location(), inconsistent_part, context); } remove_transition_if_unsat(edge, context); } fn remove_transition_if_unsat(edge: &Edge, context: &mut PruneContext) { - let mut edge_fed = Federation::full(context.dim); + let mut edge_fed = OwnedFederation::universe(context.dim); // apply target invariant let target_loc = context.get_loc(edge.get_target_location()); if let Some(inv) = target_loc.get_invariant() { - apply_constraints_to_state(inv, context.decl(), &mut edge_fed); + edge_fed = apply_constraints_to_state(inv, context.decl(), edge_fed); } // Subtract target inconsistent part if let Some(incons) = context.try_get_incons(edge.get_target_location()) { - edge_fed.subtract(incons); + edge_fed = edge_fed.subtraction(incons); } if let Some(updates) = edge.get_update() { // apply updates as guard for update in updates { - update - .compiled(context.decl()) - .apply_as_guard(&mut edge_fed); + edge_fed = update.compiled(context.decl()).apply_as_guard(edge_fed); } // apply updates as free if !edge_fed.is_empty() { for update in updates { - update.compiled(context.decl()).apply_as_free(&mut edge_fed); + edge_fed = update.compiled(context.decl()).apply_as_free(edge_fed); } } } // Apply guards if let Some(guard) = edge.get_guard() { - apply_constraints_to_state(guard, context.decl(), &mut edge_fed); + edge_fed = apply_constraints_to_state(guard, context.decl(), edge_fed); } // Apply source invariant let source_loc = context.get_loc(edge.get_source_location()); if let Some(inv) = source_loc.get_invariant() { - apply_constraints_to_state(inv, context.decl(), &mut edge_fed); + edge_fed = apply_constraints_to_state(inv, context.decl(), edge_fed); } // Subtract source inconsistent part if let Some(incons) = context.try_get_incons(edge.get_source_location()) { - edge_fed.subtract(incons); + edge_fed = edge_fed.subtraction(incons); } if edge_fed.is_empty() { @@ -285,27 +292,27 @@ fn remove_transition_if_unsat(edge: &Edge, context: &mut PruneContext) { fn process_source_location( source_loc: &String, - inconsistent_part: &Federation, + mut inconsistent_part: OwnedFederation, context: &mut PruneContext, ) { if !inconsistent_part.is_empty() { - match context.inconsistent_parts.get_mut(source_loc) { - Some(part) => part.add_fed(&inconsistent_part), - None => { - context - .inconsistent_parts - .insert(source_loc.clone(), inconsistent_part.clone()); - } + if let Some(part) = context.inconsistent_parts.get(source_loc) { + inconsistent_part = inconsistent_part.union(part); }; + context + .inconsistent_parts + .insert(source_loc.clone(), inconsistent_part.clone()); + if !context .passed_pairs .iter() - .any(|(id, fed)| *id == *source_loc && *fed == *inconsistent_part) + .any(|(id, fed)| *id == *source_loc && fed.equals(&inconsistent_part)) + // Can this be fed.subset_eq(...) instead? it would be ~twice as fast { context .passed_pairs - .push((source_loc.clone(), inconsistent_part.clone())); + .push((source_loc.clone(), inconsistent_part)); context.inconsistent_locs.push(source_loc.clone()); } } @@ -313,9 +320,9 @@ fn process_source_location( fn predt_of_all_outputs( source_loc: &Location, - inconsistent_part: Federation, + inconsistent_part: OwnedFederation, context: &mut PruneContext, -) -> Federation { +) -> OwnedFederation { let mut incons_fed = inconsistent_part; for other_edge in context .comp @@ -325,10 +332,10 @@ fn predt_of_all_outputs( { let target_loc = context.get_loc(other_edge.get_target_location()); - let mut saving_fed = Federation::full(context.dim); + let mut saving_fed = OwnedFederation::universe(context.dim); // apply target invariant if let Some(inv) = target_loc.get_invariant() { - apply_constraints_to_state(inv, context.decl(), &mut saving_fed); + saving_fed = apply_constraints_to_state(inv, context.decl(), saving_fed); } // remove the parts of the target transition that are inconsistent. @@ -337,28 +344,27 @@ fn predt_of_all_outputs( .iter() .any(|id| *id == target_loc.id) { - saving_fed.subtract(context.get_incons(other_edge.get_target_location())) + saving_fed = + saving_fed.subtraction(context.get_incons(other_edge.get_target_location())) } // apply updates via free if !saving_fed.is_empty() { if let Some(updates) = other_edge.get_update() { for update in updates { - update - .compiled(context.decl()) - .apply_as_free(&mut saving_fed); + saving_fed = update.compiled(context.decl()).apply_as_free(saving_fed); } } } // apply edge guard if let Some(guard) = other_edge.get_guard() { - apply_constraints_to_state(guard, context.decl(), &mut saving_fed); + saving_fed = apply_constraints_to_state(guard, context.decl(), saving_fed); } // apply source invariant if let Some(inv) = source_loc.get_invariant() { - apply_constraints_to_state(inv, context.decl(), &mut saving_fed); + saving_fed = apply_constraints_to_state(inv, context.decl(), saving_fed); } // do temporal predecessor avoiding saving fed @@ -372,27 +378,27 @@ fn predt_of_all_outputs( fn back_exploration_on_transition( edge: &Edge, - mut inconsistent_part: Federation, + mut inconsistent_part: OwnedFederation, context: &mut PruneContext, -) -> Federation { +) -> OwnedFederation { // apply updates via free if let Some(updates) = edge.get_update() { for update in updates { - update + inconsistent_part = update .compiled(context.decl()) - .apply_as_free(&mut inconsistent_part); + .apply_as_free(inconsistent_part); } } // apply edge guard if let Some(guard) = edge.get_guard() { - apply_constraints_to_state(guard, context.decl(), &mut inconsistent_part); + inconsistent_part = apply_constraints_to_state(guard, context.decl(), inconsistent_part); } // apply source invariant let source = context.get_loc(edge.get_source_location()); if let Some(inv) = source.get_invariant() { - apply_constraints_to_state(inv, context.decl(), &mut inconsistent_part); + inconsistent_part = apply_constraints_to_state(inv, context.decl(), inconsistent_part); } return inconsistent_part; @@ -400,7 +406,7 @@ fn back_exploration_on_transition( fn handle_output(edge: &Edge, context: &mut PruneContext) { let target_incons = context.get_incons(edge.get_target_location()); - if target_incons.is_full() { + if target_incons.is_universe() { // Fully inconsistent target context.remove_edge(edge); } else { @@ -410,26 +416,26 @@ fn handle_output(edge: &Edge, context: &mut PruneContext) { // TODO: this is different from J-ecdar // apply updates as guard for update in updates { - update + incons_after_reset = update .compiled(context.decl()) - .apply_as_guard(&mut incons_after_reset); + .apply_as_guard(incons_after_reset); } // apply updates as free if !incons_after_reset.is_empty() { for update in updates { - update + incons_after_reset = update .compiled(context.decl()) - .apply_as_free(&mut incons_after_reset); + .apply_as_free(incons_after_reset); } } } - let mut guard_fed = Federation::full(context.dim); + let mut guard_fed = OwnedFederation::universe(context.dim); // Apply guards if let Some(guard) = edge.get_guard() { - apply_constraints_to_state(guard, context.decl(), &mut guard_fed); + guard_fed = apply_constraints_to_state(guard, context.decl(), guard_fed); } - guard_fed.subtract(&incons_after_reset); + guard_fed = guard_fed.subtraction(&incons_after_reset); if guard_fed.is_empty() { context.remove_edge(edge); @@ -439,16 +445,16 @@ fn handle_output(edge: &Edge, context: &mut PruneContext) { } // get source invariant - let mut source_invariant = Federation::full(context.dim); + let mut source_invariant = OwnedFederation::universe(context.dim); let source_loc = context.get_loc(edge.get_source_location()); if let Some(inv) = source_loc.get_invariant() { - apply_constraints_to_state(inv, context.decl(), &mut source_invariant); + source_invariant = apply_constraints_to_state(inv, context.decl(), source_invariant); } if source_invariant.can_delay_indefinitely() { // Source is not inconsistent, nothing more to do } else { - let mut fed_that_saves_us = Federation::empty(context.dim); + let mut fed_that_saves_us = OwnedFederation::empty(context.dim); for other_edge in context .comp .edges @@ -461,53 +467,52 @@ fn handle_output(edge: &Edge, context: &mut PruneContext) { // calculate and backtrack the part that is NOT inconsistent // get target invariant - let mut good_part = Federation::full(context.dim); + let mut good_part = OwnedFederation::universe(context.dim); let target_loc = context.get_loc(other_edge.get_target_location()); if let Some(inv) = target_loc.get_invariant() { - apply_constraints_to_state(inv, context.decl(), &mut good_part); + good_part = apply_constraints_to_state(inv, context.decl(), good_part); } // If target is inconsistent we must avoid that part if let Some(incons) = context.try_get_incons(other_edge.get_target_location()) { - good_part.subtract(incons); + good_part = good_part.subtraction(incons); } if let Some(updates) = other_edge.get_update() { // TODO: this is different from J-ecdar // apply updates as guard for update in updates { - update - .compiled(context.decl()) - .apply_as_guard(&mut good_part); + good_part = update.compiled(context.decl()).apply_as_guard(good_part); } // apply updates as free if !good_part.is_empty() { for update in updates { - update - .compiled(context.decl()) - .apply_as_free(&mut good_part); + good_part = update.compiled(context.decl()).apply_as_free(good_part); } } } // Apply guards if let Some(guard) = other_edge.get_guard() { - apply_constraints_to_state(guard, context.decl(), &mut good_part); + good_part = apply_constraints_to_state(guard, context.decl(), good_part); } - - good_part.down(); // We are allowed to delay into outputs - good_part.intersect(&source_invariant); + // We are allowed to delay into outputs + good_part = good_part.down().intersection(&source_invariant); fed_that_saves_us += good_part; } - let new_incon_part = source_invariant - fed_that_saves_us; - process_source_location(edge.get_source_location(), &new_incon_part, context) + let new_incon_part = source_invariant.subtraction(&fed_that_saves_us); + process_source_location(edge.get_source_location(), new_incon_part, context) } } -fn is_immediately_inconsistent(location: &Location, comp: &Component, dimensions: u32) -> bool { +fn is_immediately_inconsistent( + location: &Location, + comp: &Component, + dimensions: ClockIndex, +) -> bool { let loc = LocationTuple::simple(location, &comp.declarations, dimensions); return loc.is_inconsistent(); diff --git a/src/System/refine.rs b/src/System/refine.rs index d431fcb0..89686f2a 100644 --- a/src/System/refine.rs +++ b/src/System/refine.rs @@ -1,8 +1,10 @@ +use edbm::zones::OwnedFederation; + use crate::debug_print; -use crate::DBMLib::dbm::Federation; + use crate::DataTypes::{PassedStateList, PassedStateListExt, WaitingStateList}; use crate::ModelObjects::component::Transition; -use crate::ModelObjects::max_bounds::MaxBounds; + use crate::ModelObjects::statepair::StatePair; use crate::TransitionSystems::LocationID; use crate::TransitionSystems::{LocationTuple, TransitionSystemPtr}; @@ -272,27 +274,27 @@ fn get_guard_fed_for_sides( transitions2: &[Transition], curr_pair: &StatePair, is_state1: bool, -) -> (Federation, Federation) { - let dim = curr_pair.zone.get_dimensions(); +) -> (OwnedFederation, OwnedFederation) { + let dim = curr_pair.ref_zone().dim(); - let pair_zone = &curr_pair.zone; + let pair_zone = curr_pair.ref_zone(); debug_print!("Zone: {}", pair_zone); //create guard zones left - let mut feds = Federation::empty(dim); + let mut feds = OwnedFederation::empty(dim); debug_print!("{}", if is_state1 { "Left:" } else { "Right:" }); for transition in transitions1 { debug_print!("{}", transition); - feds.add_fed(&transition.get_allowed_federation()); + feds += transition.get_allowed_federation(); } let fed1 = feds.intersection(pair_zone); debug_print!("{}", fed1); debug_print!("{}", if is_state1 { "Right:" } else { "Left:" }); //Create guard zones right - let mut feds = Federation::empty(dim); + let mut feds = OwnedFederation::empty(dim); for transition in transitions2 { debug_print!("{}", transition); - feds.add_fed(&transition.get_allowed_federation()); + feds += transition.get_allowed_federation(); } let fed2 = feds.intersection(pair_zone); debug_print!("{}", fed2); @@ -334,32 +336,28 @@ fn build_state_pair( is_state1: bool, ) -> BuildResult { //Creates new state pair - let mut new_sp: StatePair = StatePair::create( - curr_pair.get_dimensions(), - curr_pair.locations1.clone(), - curr_pair.locations2.clone(), - ); + let mut new_sp: StatePair = curr_pair.clone(); //Creates DBM for that state pair - let mut new_sp_zone = curr_pair.zone.clone(); + let mut new_sp_zone = new_sp.take_zone(); //Apply guards on both sides let (locations1, locations2) = new_sp.get_mut_states(is_state1); //Applies the left side guards and checks if zone is valid - let g1_success = transition1.apply_guards(&mut new_sp_zone); + new_sp_zone = transition1.apply_guards(new_sp_zone); //Applies the right side guards and checks if zone is valid - let g2_success = transition2.apply_guards(&mut new_sp_zone); + new_sp_zone = transition2.apply_guards(new_sp_zone); // Continue to the next transition pair if the zone is empty - if !g1_success || !g2_success { + if new_sp_zone.is_empty() { return BuildResult::Success; } //Apply updates on both sides - transition1.apply_updates(&mut new_sp_zone); - transition2.apply_updates(&mut new_sp_zone); + new_sp_zone = transition1.apply_updates(new_sp_zone); + new_sp_zone = transition2.apply_updates(new_sp_zone); //Perform a delay on the zone after the updates were applied - new_sp_zone.up(); + new_sp_zone = new_sp_zone.up(); //Update locations in states @@ -375,30 +373,26 @@ fn build_state_pair( (locations2, locations1) }; - let inv_success1 = left_loc.apply_invariants(&mut new_sp_zone); - - // Perform a copy of the zone and apply right side invariants on the copied zone - let s_invariant = new_sp_zone.clone(); + new_sp_zone = left_loc.apply_invariants(new_sp_zone); + // Apply right side invariants on a copy of the zone + let s_invariant = right_loc.apply_invariants(new_sp_zone.clone()); // Maybe apply inv_t, then up, then inv_s? - let inv_success2 = right_loc.apply_invariants(&mut new_sp_zone); - // Continue to the next transition pair if the newly built zones are empty - if !(inv_success1 && inv_success2) { + if new_sp_zone.is_empty() || s_invariant.is_empty() { return BuildResult::Success; } - let mut t_invariant = new_sp_zone.clone(); + let mut t_invariant = new_sp_zone.clone().down(); // inv_s = x<10, inv_t = x>2 -> t cuts solutions but not delays, so it is fine and we can call down: - t_invariant.down(); // Check if the invariant of T (right) cuts delay solutions from S (left) and if so, report failure - if !(s_invariant.is_subset_eq(&t_invariant)) { + if !(s_invariant.subset_eq(&t_invariant)) { return BuildResult::Failure; } - new_sp.zone = new_sp_zone; + new_sp.set_zone(new_sp_zone); new_sp.extrapolate_max_bounds(context.sys1, context.sys2); @@ -416,8 +410,13 @@ fn prepare_init_state( initial_locations_1: LocationTuple, initial_locations_2: LocationTuple, ) -> bool { - initial_locations_1.apply_invariants(&mut initial_pair.zone) - && initial_locations_2.apply_invariants(&mut initial_pair.zone) + let mut sp_zone = initial_pair.take_zone(); + sp_zone = initial_locations_1.apply_invariants(sp_zone); + sp_zone = initial_locations_2.apply_invariants(sp_zone); + + initial_pair.set_zone(sp_zone); + + !initial_pair.ref_zone().is_empty() } fn check_preconditions(sys1: &TransitionSystemPtr, sys2: &TransitionSystemPtr) -> bool { diff --git a/src/System/save_component.rs b/src/System/save_component.rs index a62f4863..2020f62a 100644 --- a/src/System/save_component.rs +++ b/src/System/save_component.rs @@ -10,6 +10,7 @@ pub enum PruningStrategy { NoPruning, } +use edbm::util::constraints::ClockIndex; use PruningStrategy::*; pub fn combine_components( @@ -51,15 +52,15 @@ pub fn combine_components( fn get_locations_from_tuples( location_tuples: &Vec, - clock_map: &HashMap, + clock_map: &HashMap, ) -> Vec { location_tuples .iter() .cloned() .map(|loc_vec| { - let invariant: Option = loc_vec - .get_invariants() - .map_or(None, |fed| fed.as_boolexpression(Some(clock_map))); + let invariant: Option = loc_vec.get_invariants().map_or(None, |fed| { + BoolExpression::from_disjunction(&fed.minimal_constraints(), clock_map) + }); Location { id: loc_vec.id.to_string(), @@ -71,7 +72,7 @@ fn get_locations_from_tuples( .collect() } -fn get_clock_map(sysrep: &TransitionSystemPtr) -> HashMap { +fn get_clock_map(sysrep: &TransitionSystemPtr) -> HashMap { let mut clocks = HashMap::new(); let decls = sysrep.get_decls(); @@ -95,8 +96,8 @@ fn collect_all_edges_and_locations<'a>( representation: &'a TransitionSystemPtr, locations: &mut Vec, edges: &mut Vec, - clock_map: &HashMap, - dim: u32, + clock_map: &HashMap, + dim: ClockIndex, ) { let l = representation.get_all_locations(); locations.extend(l); @@ -109,8 +110,8 @@ fn collect_reachable_edges_and_locations<'a>( representation: &'a TransitionSystemPtr, locations: &mut Vec, edges: &mut Vec, - clock_map: &HashMap, - dim: u32, + clock_map: &HashMap, + dim: ClockIndex, ) { let l = representation.get_initial_location(); @@ -158,8 +159,8 @@ fn collect_edges_from_location( location: &LocationTuple, representation: &TransitionSystemPtr, edges: &mut Vec, - clock_map: &HashMap, - dim: u32, + clock_map: &HashMap, + dim: ClockIndex, ) { collect_specific_edges_from_location(location, representation, edges, true, clock_map, dim); collect_specific_edges_from_location(location, representation, edges, false, clock_map, dim); @@ -170,8 +171,8 @@ fn collect_specific_edges_from_location( representation: &TransitionSystemPtr, edges: &mut Vec, input: bool, - clock_map: &HashMap, - dim: u32, + clock_map: &HashMap, + dim: ClockIndex, ) { for sync in if input { representation.get_input_actions() diff --git a/src/TransitionSystems/common.rs b/src/TransitionSystems/common.rs index f5e5b9e8..28b92721 100644 --- a/src/TransitionSystems/common.rs +++ b/src/TransitionSystems/common.rs @@ -1,6 +1,6 @@ macro_rules! default_composition { () => { - fn get_dim(&self) -> u32 { + fn get_dim(&self) -> ClockIndex { self.dim } @@ -17,9 +17,9 @@ macro_rules! default_composition { .collect() } - fn get_local_max_bounds(&self, loc: &LocationTuple) -> MaxBounds { + fn get_local_max_bounds(&self, loc: &LocationTuple) -> Bounds { if loc.is_universal() || loc.is_inconsistent() { - MaxBounds::create(self.get_dim()) + Bounds::new(self.get_dim()) } else { let (left, right) = self.get_children(); let loc_l = loc.get_left(); @@ -65,16 +65,15 @@ macro_rules! default_composition { fn get_initial_state(&self) -> Option { let init_loc = self.get_initial_location().unwrap(); - let mut zone = Federation::init(self.dim); - if !init_loc.apply_invariants(&mut zone) { + let mut zone = OwnedFederation::init(self.dim); + + zone = init_loc.apply_invariants(zone); + if zone.is_empty() { println!("Empty initial state"); return None; } - Some(State { - decorated_locations: init_loc, - zone, - }) + Some(State::create(init_loc, zone)) } }; } diff --git a/src/TransitionSystems/compiled_component.rs b/src/TransitionSystems/compiled_component.rs index 4bf141dd..2f57dc4e 100644 --- a/src/TransitionSystems/compiled_component.rs +++ b/src/TransitionSystems/compiled_component.rs @@ -1,9 +1,10 @@ -use crate::DBMLib::dbm::Federation; use crate::EdgeEval::constraint_applyer; use crate::ModelObjects::component::{ Component, DeclarationProvider, Declarations, LocationType, State, SyncType, Transition, }; -use crate::ModelObjects::max_bounds::MaxBounds; +use edbm::util::bounds::Bounds; +use edbm::util::constraints::ClockIndex; + use crate::System::local_consistency; use crate::TransitionSystems::{LocationTuple, TransitionSystem, TransitionSystemPtr}; use std::collections::hash_set::HashSet; @@ -17,8 +18,7 @@ type Action = String; struct ComponentInfo { name: String, declarations: Declarations, - max_bounds: MaxBounds, - deterministic: bool, + max_bounds: Bounds, } #[derive(Clone)] @@ -29,7 +29,7 @@ pub struct CompiledComponent { location_edges: HashMap>, initial_location: Option, comp_info: ComponentInfo, - dim: u32, + dim: ClockIndex, } impl CompiledComponent { @@ -37,7 +37,7 @@ impl CompiledComponent { component: Component, inputs: HashSet, outputs: HashSet, - dim: u32, + dim: ClockIndex, ) -> Result, String> { if !inputs.is_disjoint(&outputs) { return Err("Inputs and outputs must be disjoint in component".to_string()); @@ -67,7 +67,6 @@ impl CompiledComponent { let initial_location = locations.values().find(|loc| loc.is_initial()).cloned(); let max_bounds = component.get_max_bounds(dim); - let deterministic = component.is_deterministic(dim); Ok(Box::new(CompiledComponent { inputs, outputs, @@ -79,12 +78,11 @@ impl CompiledComponent { name: component.name, declarations: component.declarations, max_bounds, - deterministic, }, })) } - pub fn compile(component: Component, dim: u32) -> Result, String> { + pub fn compile(component: Component, dim: ClockIndex) -> Result, String> { let inputs: HashSet<_> = component .get_input_actions() .iter() @@ -101,9 +99,9 @@ impl CompiledComponent { } impl TransitionSystem for CompiledComponent { - fn get_local_max_bounds(&self, loc: &LocationTuple) -> MaxBounds { + fn get_local_max_bounds(&self, loc: &LocationTuple) -> Bounds { if loc.is_universal() || loc.is_inconsistent() { - MaxBounds::create(self.get_dim()) + Bounds::new(self.get_dim()) } else { self.comp_info.max_bounds.clone() } @@ -192,7 +190,7 @@ impl TransitionSystem for CompiledComponent { local_consistency::is_least_consistent(self) } - fn get_dim(&self) -> u32 { + fn get_dim(&self) -> ClockIndex { self.dim } } diff --git a/src/TransitionSystems/composition.rs b/src/TransitionSystems/composition.rs index 835141c1..7263bcee 100644 --- a/src/TransitionSystems/composition.rs +++ b/src/TransitionSystems/composition.rs @@ -1,6 +1,8 @@ -use crate::DBMLib::dbm::Federation; +use edbm::util::bounds::Bounds; +use edbm::util::constraints::ClockIndex; +use edbm::zones::OwnedFederation; + use crate::ModelObjects::component::{Declarations, State, Transition}; -use crate::ModelObjects::max_bounds::MaxBounds; use crate::TransitionSystems::{LocationTuple, TransitionSystem, TransitionSystemPtr}; use std::collections::hash_set::HashSet; @@ -17,14 +19,14 @@ pub struct Composition { right_unique_actions: HashSet, common_actions: HashSet, - dim: u32, + dim: ClockIndex, } impl Composition { pub fn new( left: TransitionSystemPtr, right: TransitionSystemPtr, - dim: u32, + dim: ClockIndex, ) -> Result { let left_in = left.get_input_actions(); let left_out = left.get_output_actions(); diff --git a/src/TransitionSystems/conjunction.rs b/src/TransitionSystems/conjunction.rs index 9891d0b4..f0b782f3 100644 --- a/src/TransitionSystems/conjunction.rs +++ b/src/TransitionSystems/conjunction.rs @@ -1,6 +1,8 @@ -use crate::DBMLib::dbm::Federation; use crate::ModelObjects::component::{Declarations, State, Transition}; -use crate::ModelObjects::max_bounds::MaxBounds; +use edbm::util::bounds::Bounds; +use edbm::util::constraints::ClockIndex; +use edbm::zones::OwnedFederation; + use crate::System::local_consistency; use crate::TransitionSystems::{ CompositionType, LocationTuple, TransitionSystem, TransitionSystemPtr, @@ -13,14 +15,14 @@ pub struct Conjunction { right: TransitionSystemPtr, inputs: HashSet, outputs: HashSet, - dim: u32, + dim: ClockIndex, } impl Conjunction { pub fn new( left: TransitionSystemPtr, right: TransitionSystemPtr, - dim: u32, + dim: ClockIndex, ) -> Result { let left_in = left.get_input_actions(); let left_out = left.get_output_actions(); diff --git a/src/TransitionSystems/location_tuple.rs b/src/TransitionSystems/location_tuple.rs index f6bf52b9..1e2636bc 100644 --- a/src/TransitionSystems/location_tuple.rs +++ b/src/TransitionSystems/location_tuple.rs @@ -1,5 +1,6 @@ +use edbm::{util::constraints::ClockIndex, zones::OwnedFederation}; + use crate::{ - DBMLib::dbm::Federation, EdgeEval::constraint_applyer::apply_constraints_to_state, ModelObjects::component::{Declarations, Location, LocationType}, }; @@ -13,10 +14,10 @@ pub enum CompositionType { Quotient, } -#[derive(Debug, Clone)] +#[derive(Clone, Debug)] pub struct LocationTuple { pub id: LocationID, - invariant: Option, + invariant: Option, pub loc_type: LocationType, left: Option>, right: Option>, @@ -29,10 +30,10 @@ impl PartialEq for LocationTuple { } impl LocationTuple { - pub fn simple(location: &Location, decls: &Declarations, dim: u32) -> Self { + pub fn simple(location: &Location, decls: &Declarations, dim: ClockIndex) -> Self { let invariant = if let Some(inv) = location.get_invariant() { - let mut fed = Federation::full(dim); - apply_constraints_to_state(&inv, decls, &mut fed); + let mut fed = OwnedFederation::universe(dim); + fed = apply_constraints_to_state(&inv, decls, fed); Some(fed) } else { None @@ -91,7 +92,7 @@ impl LocationTuple { let invariant = if let Some(inv1) = &left.invariant { if let Some(inv2) = &right.invariant { - Some(inv1.intersection(inv2)) + Some(inv1.clone().intersection(inv2)) } else { Some(inv1.clone()) } @@ -115,15 +116,15 @@ impl LocationTuple { } } - pub fn get_invariants(&self) -> Option<&Federation> { + pub fn get_invariants(&self) -> Option<&OwnedFederation> { self.invariant.as_ref() } - pub fn apply_invariants(&self, zone: &mut Federation) -> bool { + pub fn apply_invariants(&self, mut fed: OwnedFederation) -> OwnedFederation { if let Some(inv) = &self.invariant { - zone.intersect(&inv); + fed = fed.intersection(&inv); } - zone.is_valid() + fed } pub fn get_left(&self) -> &LocationTuple { diff --git a/src/TransitionSystems/quotient.rs b/src/TransitionSystems/quotient.rs index 7552ce6f..241afe0b 100644 --- a/src/TransitionSystems/quotient.rs +++ b/src/TransitionSystems/quotient.rs @@ -1,9 +1,11 @@ -use crate::DBMLib::dbm::Federation; +use edbm::util::constraints::ClockIndex; +use edbm::zones::OwnedFederation; use crate::EdgeEval::updater::CompiledUpdate; use crate::ModelObjects::component::Declarations; use crate::ModelObjects::component::{Location, LocationType, State, Transition}; -use crate::ModelObjects::max_bounds::MaxBounds; +use edbm::util::bounds::Bounds; + use crate::ModelObjects::representations::{ArithExpression, BoolExpression}; use crate::TransitionSystems::{LocationTuple, TransitionSystem, TransitionSystemPtr}; @@ -20,10 +22,10 @@ pub struct Quotient { universal_location: Location, inconsistent_location: Location, decls: Declarations, - new_clock_index: u32, + new_clock_index: ClockIndex, new_input_name: String, - dim: u32, + dim: ClockIndex, } static INCONSISTENT_LOC_NAME: &str = "Inconsistent"; @@ -32,8 +34,8 @@ impl Quotient { pub fn new( T: TransitionSystemPtr, S: TransitionSystemPtr, - new_clock_index: u32, - dim: u32, + new_clock_index: ClockIndex, + dim: ClockIndex, ) -> Result { if !S.get_output_actions().is_disjoint(&T.get_input_actions()) { return Err(format!( @@ -132,9 +134,9 @@ impl Quotient { } impl TransitionSystem for Quotient { - fn get_local_max_bounds(&self, loc: &LocationTuple) -> MaxBounds { + fn get_local_max_bounds(&self, loc: &LocationTuple) -> Bounds { if loc.is_universal() || loc.is_inconsistent() { - MaxBounds::create(self.get_dim()) + Bounds::new(self.get_dim()) } else { let (left, right) = self.get_children(); let loc_l = loc.get_left(); @@ -158,9 +160,7 @@ impl TransitionSystem for Quotient { //Rule 10 if is_input { let mut transition = Transition::new(location, self.dim); - transition - .guard_zone - .add_eq_const_constraint(self.new_clock_index, 0); + transition.guard_zone = transition.guard_zone.constrain_eq(self.new_clock_index, 0); transitions.push(transition); } return transitions; @@ -187,11 +187,9 @@ impl TransitionSystem for Quotient { for t_transition in &t { for s_transition in &s { // In the following comments we use ϕ to symbolize the guard of the transition - // ϕ_T ∧ Inv(l2_t)[r |-> 0] ∧ Inv(l1_t) - let mut guard_zone = get_allowed_fed(&loc_t, t_transition); - // ϕ_T ∧ Inv(l2_t)[r |-> 0] ∧ Inv(l1_t) ∧ ϕ_S ∧ Inv(l2_s)[r |-> 0] ∧ Inv(l1_s) - guard_zone.intersect(&get_allowed_fed(&loc_s, s_transition)); + let mut guard_zone = get_allowed_fed(&loc_t, t_transition) + .intersection(&get_allowed_fed(&loc_s, s_transition)); let target_locations = merge( &t_transition.target_locations, @@ -229,16 +227,15 @@ impl TransitionSystem for Quotient { if self.S.get_output_actions().contains(action) { // new Rule 3 (includes rule 4 by de-morgan) - let mut g_s = Federation::empty(self.dim); + let mut g_s = OwnedFederation::empty(self.dim); for s_transition in &s { let allowed_fed = get_allowed_fed(&loc_s, s_transition); - g_s.add_fed(&allowed_fed); + g_s += allowed_fed; } // Rule 5 when Rule 3 applies - let mut inv_l_s = Federation::full(self.dim); - loc_s.apply_invariants(&mut inv_l_s); + let mut inv_l_s = loc_s.apply_invariants(OwnedFederation::universe(self.dim)); transitions.push(Transition { guard_zone: (!inv_l_s) + (!g_s), @@ -247,8 +244,7 @@ impl TransitionSystem for Quotient { }); } else { // Rule 5 when Rule 3 does not apply - let mut inv_l_s = Federation::full(self.dim); - loc_s.apply_invariants(&mut inv_l_s); + let mut inv_l_s = loc_s.apply_invariants(OwnedFederation::universe(self.dim)); transitions.push(Transition { guard_zone: !inv_l_s, @@ -262,20 +258,17 @@ impl TransitionSystem for Quotient { && self.T.get_output_actions().contains(action) { //Calculate inverse G_T - let mut g_t = Federation::empty(self.dim); + let mut g_t = OwnedFederation::empty(self.dim); for t_transition in &t { - let allowed_fed = get_allowed_fed(&loc_t, t_transition); - g_t.add_fed(&allowed_fed); + g_t = g_t.union(&get_allowed_fed(&loc_t, t_transition)); } - let inverse_g_t = !g_t; + let inverse_g_t = g_t.inverse(); for s_transition in &s { // In the following comments we use ϕ to symbolize the guard of the transition - // ϕ_S ∧ Inv(l2_s)[r |-> 0] ∧ Inv(l1_s) - let mut guard_zone = get_allowed_fed(&loc_s, s_transition); - // ϕ_S ∧ Inv(l2_s)[r |-> 0] ∧ Inv(l1_s) ∧ ¬G_T - guard_zone.intersect(&inverse_g_t); + let mut guard_zone = + get_allowed_fed(&loc_s, s_transition).intersection(&inverse_g_t); let updates = vec![CompiledUpdate { clock_index: self.new_clock_index, @@ -292,7 +285,7 @@ impl TransitionSystem for Quotient { //Rule 7 if action == self.new_input_name { - let inverse_t_invariant = !get_invariant(loc_t, self.dim); + let inverse_t_invariant = get_invariant(loc_t, self.dim).inverse(); let s_invariant = get_invariant(loc_s, self.dim); let guard_zone = inverse_t_invariant.intersection(&s_invariant); @@ -312,7 +305,7 @@ impl TransitionSystem for Quotient { for t_transition in &t { let mut guard_zone = get_allowed_fed(&loc_t, t_transition); - loc_s.apply_invariants(&mut guard_zone); + guard_zone = loc_s.apply_invariants(guard_zone); let target_locations = merge(&t_transition.target_locations, &loc_s); let updates = t_transition.updates.clone(); @@ -327,7 +320,7 @@ impl TransitionSystem for Quotient { transitions .into_iter() - .filter(|e| e.guard_zone.is_valid()) + .filter(|e| !e.guard_zone.is_empty()) .collect() } @@ -400,11 +393,8 @@ impl TransitionSystem for Quotient { fn get_initial_state(&self) -> Option { let mut init_loc = self.get_initial_location()?; - let zone = Federation::init(self.dim); - Some(State { - decorated_locations: init_loc, - zone, - }) + let zone = OwnedFederation::init(self.dim); + Some(State::create(init_loc, zone)) } fn get_children(&self) -> (&TransitionSystemPtr, &TransitionSystemPtr) { @@ -415,7 +405,7 @@ impl TransitionSystem for Quotient { CompositionType::Quotient } - fn get_dim(&self) -> u32 { + fn get_dim(&self) -> ClockIndex { self.dim } } @@ -424,15 +414,14 @@ fn merge(t: &LocationTuple, s: &LocationTuple) -> LocationTuple { LocationTuple::merge_as_quotient(t, s) } -fn get_allowed_fed(from: &LocationTuple, transition: &Transition) -> Federation { - let mut fed = transition.get_allowed_federation(); - from.apply_invariants(&mut fed); - fed +fn get_allowed_fed(from: &LocationTuple, transition: &Transition) -> OwnedFederation { + let fed = transition.get_allowed_federation(); + from.apply_invariants(fed) } -fn get_invariant(loc: &LocationTuple, dim: u32) -> Federation { +fn get_invariant(loc: &LocationTuple, dim: ClockIndex) -> OwnedFederation { match loc.get_invariants() { Some(inv) => inv.clone(), - None => Federation::full(dim), + None => OwnedFederation::universe(dim), } } diff --git a/src/TransitionSystems/transition_system.rs b/src/TransitionSystems/transition_system.rs index 18a883d9..9d415f9b 100644 --- a/src/TransitionSystems/transition_system.rs +++ b/src/TransitionSystems/transition_system.rs @@ -1,15 +1,15 @@ use super::{CompositionType, LocationTuple}; use crate::ModelObjects::component::{Declarations, State, Transition}; -use crate::ModelObjects::max_bounds::MaxBounds; use dyn_clone::{clone_trait_object, DynClone}; +use edbm::util::{bounds::Bounds, constraints::ClockIndex}; use std::collections::hash_set::HashSet; pub type TransitionSystemPtr = Box; pub trait TransitionSystem: DynClone { - fn get_local_max_bounds(&self, loc: &LocationTuple) -> MaxBounds; + fn get_local_max_bounds(&self, loc: &LocationTuple) -> Bounds; - fn get_dim(&self) -> u32; + fn get_dim(&self) -> ClockIndex; fn next_transitions_if_available( &self, diff --git a/src/build.rs b/src/build.rs index d7583a9f..79a2f657 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,85 +1,5 @@ -extern crate bindgen; - -use tonic_build; - -use std::env; -use std::path::PathBuf; - fn main() { - if cfg!(feature = "dbm-stub") { - println!("cargo:warning=Using stub instead of DBM library"); - return; - } - tonic_build::compile_protos("Ecdar-ProtoBuf/services.proto").unwrap(); // Tell cargo to invalidate the crate when the protobuf repository changes println!("cargo:rerun-if-changed=Ecdar-ProtoBuf"); - - let host = std::env::var("HOST").unwrap(); - let target = std::env::var("TARGET").unwrap(); - - // Tell cargo to tell rustc to link the DBM - // shared library. - if host == target { - println!("cargo:rustc-link-search=all=dbm/out/"); - } else { - println!("cargo:rustc-link-search=all=dbm/out/{}/", target); - } - - println!("cargo:rustc-link-lib=static=udbmwrapper"); - println!("cargo:rustc-link-lib=static=dbm"); - println!("cargo:rustc-link-lib=static=hash"); - println!("cargo:rustc-link-lib=static=udebug"); - println!("cargo:rustc-link-lib=static=base"); - println!("cargo:rustc-link-lib=stdc++"); - - // Tell cargo to invalidate the built crate whenever the wrapper changes - println!("cargo:rerun-if-changed=dbm/wrapper.h"); - println!("cargo:rerun-if-changed=dbm/out"); - - // cc::Build::new() - // .cpp(true) - // .file("dbm.cpp") - // .compile("dbm"); - // The bindgen::Builder is the main entry point - // to bindgen, and lets you build up options for - // the resulting bindings. - let bindings = bindgen::Builder::default() - // The input header we would like to generate - // bindings for. - .header("dbm/include/dbm/dbm.h") - .header("dbm/include/dbm/fed.h") - .header("dbm/wrapper.h") - .trust_clang_mangling(true) - .clang_args(&[ - "-x", - "c++", - "-std=c++14", - "-fno-inline-functions", - "-Idbm/include/", - ]) - .allowlist_recursively(true) - .generate_inline_functions(true) - // Tell cargo to invalidate the built crate whenever any of the - // included header files changed. - .parse_callbacks(Box::new(bindgen::CargoCallbacks)) - //avoid generating bindings for unused code that produces errors - .opaque_type("namespace") - .opaque_type("std::.*") - //whitelist only relevant functions - .allowlist_function("dbm_.*") - .allowlist_function("fed_.*") - // Enable comments for generated bindings - .generate_comments(true) - .detect_include_paths(true) - // Finish the builder and generate the bindings. - .generate() - // Unwrap the Result and panic on failure. - .expect("Unable to generate bindings"); - - // Write the bindings to the $OUT_DIR/bindings.rs file. - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - bindings - .write_to_file(out_path.join("bindings.rs")) - .expect("Couldn't write bindings!"); } diff --git a/src/main.rs b/src/main.rs index bed76e96..08d1c1d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,5 @@ #![allow(non_snake_case)] -mod DBMLib; mod DataReader; mod DataTypes; mod EdgeEval; diff --git a/src/tests/ModelObjects/max_bounds.rs b/src/tests/ModelObjects/max_bounds.rs deleted file mode 100644 index 3cd9f1f9..00000000 --- a/src/tests/ModelObjects/max_bounds.rs +++ /dev/null @@ -1,59 +0,0 @@ -#[cfg(test)] -mod max_bounds { - use crate::{DBMLib::dbm::Federation, ModelObjects::max_bounds::MaxBounds}; - - const DIM: u32 = 10; - #[test] - fn extrapolate_test1() { - let lt = 10; - let bound = 9; - - let mut fed = Federation::init(DIM); - - fed.add_lt_constraint(1, 0, lt); - let pre_fed = fed.clone(); - - println!("Before {}", pre_fed); - - let mut bounds = MaxBounds::create(DIM); - - println!("Bound {}", bound); - for i in 1..DIM { - bounds.add_bound(i, bound); - } - - let mut post_fed = fed; - - post_fed.extrapolate_max_bounds(&bounds); - println!("After {}", post_fed); - - assert!(post_fed == Federation::init(DIM)); - } - - #[test] - fn extrapolate_test2() { - let lt = 9; - let bound = 10; - - let mut fed = Federation::init(DIM); - - fed.add_lt_constraint(1, 0, lt); - let pre_fed = fed.clone(); - - println!("Before {}", pre_fed); - - let mut bounds = MaxBounds::create(DIM); - - println!("Bound {}", bound); - for i in 1..DIM { - bounds.add_bound(i, bound); - } - - let mut post_fed = fed; - - post_fed.extrapolate_max_bounds(&bounds); - println!("After {}", post_fed); - - assert!(post_fed == pre_fed); - } -} diff --git a/src/tests/ModelObjects/mod.rs b/src/tests/ModelObjects/mod.rs index a418f655..5d79c75c 100644 --- a/src/tests/ModelObjects/mod.rs +++ b/src/tests/ModelObjects/mod.rs @@ -1,3 +1,2 @@ pub mod arith_expression; pub mod bool_expression; -pub mod max_bounds; diff --git a/src/tests/dbm/federation.rs b/src/tests/dbm/federation.rs deleted file mode 100644 index 60c5db80..00000000 --- a/src/tests/dbm/federation.rs +++ /dev/null @@ -1,124 +0,0 @@ -#[cfg(test)] -pub mod test { - use crate::DBMLib::dbm::Federation; - - const DIM: u32 = 5; - - #[test] - pub fn fed_is_empty() { - assert!(Federation::empty(DIM).is_empty()); - } - - #[test] - fn fed_with_added_fed() { - let fed1 = Federation::zero(DIM); - let fed2 = !Federation::zero(DIM); - - let fed3 = fed1.with_added_fed(&fed2); - // fed1 and fed2 remain unchanged - - println!("fed1: {}", fed1); - println!("fed2: {}", fed2); - println!("fed3: {}", fed3); - - assert_eq!(Federation::full(DIM), fed3); - assert_eq!(fed3, fed1 + fed2); - } - - #[test] - fn fed_add_fed() { - let mut fed1 = Federation::zero(DIM); - let fed2 = !Federation::zero(DIM); - - fed1.add_fed(&fed2); - // fed1 is changed and fed2 remains unchanged - - println!("fed1: {}", fed1); - println!("fed2: {}", fed2); - - assert_eq!(Federation::full(DIM), fed1); - } - #[test] - fn fed_inverse() { - let fed1 = Federation::full(DIM); - let fed2 = fed1.inverse(); - // fed1 remains unchanged - - println!("fed1: {}", fed1); - println!("fed2: {}", fed2); - - assert_eq!(Federation::empty(DIM), fed2); - assert_eq!(fed2, !fed1); - } - - #[test] - fn fed_invert() { - let mut fed1 = Federation::full(DIM); - fed1.invert(); - // fed1 is changed to contain its inverse - - println!("fed1: {}", fed1); - - assert_eq!(Federation::empty(DIM), fed1); - } - - #[test] - fn fed_intersect() { - let mut fed1 = Federation::full(DIM); - let fed2 = Federation::zero(DIM); - - fed1.intersect(&fed2); - // fed1 is changed and fed2 remains unchanged - - println!("fed1: {}", fed1); - println!("fed2: {}", fed2); - - assert_eq!(Federation::zero(DIM), fed1); - } - - #[test] - fn fed_intersection() { - let fed1 = Federation::full(DIM); - let fed2 = Federation::zero(DIM); - - let fed3 = fed1.intersection(&fed2); - // fed1 and fed2 remain unchanged - - println!("fed1: {}", fed1); - println!("fed2: {}", fed2); - println!("fed3: {}", fed3); - - assert_eq!(Federation::zero(DIM), fed3); - assert_eq!(fed3, fed1 & fed2); - } - - #[test] - fn fed_subtract() { - let mut fed1 = Federation::zero(DIM); - let fed2 = Federation::full(DIM); - - fed1.subtract(&fed2); - // fed1 is changed and fed2 remains unchanged - - println!("fed1: {}", fed1); - println!("fed2: {}", fed2); - - assert_eq!(Federation::empty(DIM), fed1); - } - - #[test] - fn fed_subtraction() { - let fed1 = Federation::zero(DIM); - let fed2 = Federation::full(DIM); - - let fed3 = fed1.subtraction(&fed2); - // fed1 and fed2 remain unchanged - - println!("fed1: {}", fed1); - println!("fed2: {}", fed2); - println!("fed3: {}", fed3); - - assert_eq!(Federation::empty(DIM), fed3); - assert_eq!(fed3, fed1 - fed2); - } -} diff --git a/src/tests/dbm/mod.rs b/src/tests/dbm/mod.rs deleted file mode 100644 index 6209adc0..00000000 --- a/src/tests/dbm/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod federation; diff --git a/src/tests/mod.rs b/src/tests/mod.rs index e793a7a8..716ec1af 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,5 +1,4 @@ pub mod ModelObjects; -pub mod dbm; pub mod grpc; pub mod refinement; pub mod sample; diff --git a/src/tests/save_component/save_comp_helper.rs b/src/tests/save_component/save_comp_helper.rs index 7b0ffd66..99b2ba1e 100644 --- a/src/tests/save_component/save_comp_helper.rs +++ b/src/tests/save_component/save_comp_helper.rs @@ -12,6 +12,7 @@ pub mod save_comp_helper { use crate::System::save_component::PruningStrategy; use crate::TransitionSystems::CompiledComponent; use crate::TransitionSystems::TransitionSystem; + use edbm::util::constraints::ClockIndex; pub fn json_reconstructed_component_refines_base_self(input_path: &str, system: &str) { let project_loader = JsonProjectLoader::new(String::from(input_path)); @@ -21,7 +22,7 @@ pub mod save_comp_helper { let str_query = format!("get-component: {} save-as test", system); let query = parse_queries::parse_to_expression_tree(str_query.as_str()).remove(0); - let mut dim: u32 = 0; + let mut dim: ClockIndex = 0; let (base_system, new_system) = if let QueryExpression::GetComponent(expr) = &query { let mut comp_loader = project_loader.to_comp_loader(); ( From c531eaa2b5ee124dc5af304c0eee10ed6a3443e3 Mon Sep 17 00:00:00 2001 From: Sebastian Lund Date: Thu, 1 Sep 2022 20:35:44 +0200 Subject: [PATCH 2/8] Minor fixes --- src/ModelObjects/max_bounds.rs | 34 ---------------------------------- src/ModelObjects/mod.rs | 1 - src/System/pruning.rs | 4 ++-- 3 files changed, 2 insertions(+), 37 deletions(-) delete mode 100644 src/ModelObjects/max_bounds.rs diff --git a/src/ModelObjects/max_bounds.rs b/src/ModelObjects/max_bounds.rs deleted file mode 100644 index b4123ea8..00000000 --- a/src/ModelObjects/max_bounds.rs +++ /dev/null @@ -1,34 +0,0 @@ -#[derive(Clone, Debug)] -pub struct MaxBounds { - pub clock_bounds: Vec, - dimensions: u32, -} - -impl MaxBounds { - pub fn create(dimensions: u32) -> Self { - MaxBounds { - clock_bounds: vec![0; dimensions as usize], - dimensions, - } - } - - pub fn add_bound(&mut self, clock: u32, bound: i32) { - if self.clock_bounds[clock as usize] < bound { - self.clock_bounds[clock as usize] = bound; - } - } - - pub fn add_bounds(&mut self, bounds: &MaxBounds) { - for clock in 0..bounds.clock_bounds.len() { - self.add_bound(clock as u32, bounds.get(clock)); - } - } - - pub fn get_dimensions(&self) -> u32 { - self.dimensions - } - - fn get(&self, clock: usize) -> i32 { - self.clock_bounds[clock] - } -} diff --git a/src/ModelObjects/mod.rs b/src/ModelObjects/mod.rs index 77105a78..b6790e28 100644 --- a/src/ModelObjects/mod.rs +++ b/src/ModelObjects/mod.rs @@ -1,5 +1,4 @@ pub mod component; -pub mod max_bounds; pub mod queries; pub mod representations; pub mod statepair; diff --git a/src/System/pruning.rs b/src/System/pruning.rs index 8cdb1c6b..bda8a519 100644 --- a/src/System/pruning.rs +++ b/src/System/pruning.rs @@ -368,8 +368,8 @@ fn predt_of_all_outputs( } // do temporal predecessor avoiding saving fed - let mut predt_fed = incons_fed.clone(); - predt_fed.predt(&saving_fed); + let predt_fed = incons_fed.predt(&saving_fed); + incons_fed += predt_fed; } From 12c9e8d83a76b0f2772743670961e55f8cd8a637 Mon Sep 17 00:00:00 2001 From: Sebastian Lund Date: Thu, 1 Sep 2022 20:36:24 +0200 Subject: [PATCH 3/8] Appease clippy: Fix all clippy warnings --- src/DataReader/component_loader.rs | 22 +- src/DataReader/mod.rs | 2 - src/DataReader/parse_edge.rs | 12 +- src/DataReader/parse_queries.rs | 8 +- src/DataReader/serialization.rs | 31 +-- src/DataReader/xml_parser.rs | 22 +- src/DataTypes/statepair_list.rs | 3 - src/EdgeEval/constraint_applyer.rs | 52 ++-- src/EdgeEval/updater.rs | 8 +- src/ModelObjects/component.rs | 89 +----- src/ModelObjects/queries.rs | 2 +- src/ModelObjects/representations.rs | 263 ++---------------- src/ModelObjects/statepair.rs | 13 +- src/ModelObjects/system_declarations.rs | 14 +- .../ecdar_requests/send_query.rs | 5 +- .../ecdar_requests/update_components.rs | 4 +- src/Simulation/graph_layout.rs | 2 +- src/System/extract_system_rep.rs | 11 +- src/System/input_enabler.rs | 1 - src/System/local_consistency.rs | 12 +- src/System/pruning.rs | 47 +--- src/System/refine.rs | 21 +- src/System/save_component.rs | 39 +-- src/TransitionSystems/compiled_component.rs | 7 +- src/TransitionSystems/composition.rs | 17 +- src/TransitionSystems/conjunction.rs | 9 +- src/TransitionSystems/location_tuple.rs | 8 +- src/TransitionSystems/quotient.rs | 42 +-- src/tests/ModelObjects/arith_expression.rs | 50 ++-- src/tests/ModelObjects/bool_expression.rs | 2 +- src/tests/grpc/send_query.rs | 14 +- src/tests/grpc/update_components.rs | 4 +- src/tests/refinement/AG_Tests.rs | 2 +- src/tests/refinement/Big_Refinement.rs | 2 +- .../refinement/Conjunction_refinement.rs | 2 +- src/tests/refinement/Helper.rs | 4 +- src/tests/refinement/Refinement_delay_add.rs | 2 +- src/tests/refinement/Refinement_university.rs | 2 +- src/tests/refinement/Refinement_unspec.rs | 2 +- src/tests/refinement/xml/conjunction_tests.rs | 2 +- src/tests/refinement/xml/consistency_tests.rs | 2 +- src/tests/refinement/xml/delay_refinement.rs | 2 +- src/tests/refinement/xml/determinism_tests.rs | 2 +- .../refinement/xml/extrapolation_tests.rs | 9 +- src/tests/refinement/xml/misc_tests.rs | 2 +- src/tests/save_component/composition_tests.rs | 6 +- src/tests/save_component/conjunction_tests.rs | 2 +- .../save_component/no_operation_tests.rs | 4 +- src/tests/save_component/save_comp_helper.rs | 9 +- 49 files changed, 259 insertions(+), 633 deletions(-) diff --git a/src/DataReader/component_loader.rs b/src/DataReader/component_loader.rs index ae853bb1..fb12b637 100644 --- a/src/DataReader/component_loader.rs +++ b/src/DataReader/component_loader.rs @@ -21,7 +21,7 @@ pub struct ComponentContainer { impl ComponentLoader for ComponentContainer { fn get_component(&mut self, component_name: &str) -> &Component { if let Some(component) = self.loaded_components.get(component_name) { - &component + component } else { panic!("The component '{}' could not be retrieved", component_name); } @@ -36,13 +36,7 @@ impl ComponentLoader for ComponentContainer { } } -impl ComponentContainer { - pub fn input_enable_components(&mut self, inputs: &[String]) { - for (_, comp) in &mut self.loaded_components { - input_enabler::make_input_enabled(comp, inputs); - } - } -} +impl ComponentContainer {} pub trait ProjectLoader: ComponentLoader { fn get_declarations(&self) -> &SystemDeclarations; @@ -65,7 +59,7 @@ impl ComponentLoader for JsonProjectLoader { } if let Some(component) = self.loaded_components.get(component_name) { - &component + component } else { panic!("The component '{}' could not be retrieved", component_name); } @@ -102,6 +96,7 @@ impl ProjectLoader for JsonProjectLoader { } impl JsonProjectLoader { + #[allow(clippy::new_ret_no_self)] pub fn new(project_path: String) -> Box { let system_declarations = json_reader::read_system_declarations(&project_path).unwrap(); let queries = json_reader::read_queries(&project_path).unwrap(); @@ -123,7 +118,7 @@ impl JsonProjectLoader { .get_declarations() .get_component_inputs(component.get_name()); if let Some(inputs) = opt_inputs { - input_enabler::make_input_enabled(&mut component, &inputs); + input_enabler::make_input_enabled(&mut component, inputs); } self.loaded_components @@ -145,7 +140,7 @@ pub struct XmlProjectLoader { impl ComponentLoader for XmlProjectLoader { fn get_component(&mut self, component_name: &str) -> &Component { if let Some(component) = self.loaded_components.get(component_name) { - &component + component } else { panic!("The component '{}' could not be retrieved", component_name); } @@ -179,6 +174,7 @@ impl ProjectLoader for XmlProjectLoader { } impl XmlProjectLoader { + #[allow(clippy::new_ret_no_self)] pub fn new(project_path: String) -> Box { let (comps, system_declarations, queries) = parse_xml_from_file(&project_path); @@ -187,8 +183,8 @@ impl XmlProjectLoader { component.create_edge_io_split(); let opt_inputs = system_declarations.get_component_inputs(component.get_name()); - if opt_inputs.is_some() { - input_enabler::make_input_enabled(&mut component, opt_inputs.unwrap()); + if let Some(opt_inputs) = opt_inputs { + input_enabler::make_input_enabled(&mut component, opt_inputs); } let name = String::from(component.get_name()); diff --git a/src/DataReader/mod.rs b/src/DataReader/mod.rs index 9175ce5f..79146a8d 100644 --- a/src/DataReader/mod.rs +++ b/src/DataReader/mod.rs @@ -6,5 +6,3 @@ pub mod parse_invariant; pub mod parse_queries; pub mod serialization; pub mod xml_parser; - -use serialization::{DummyComponent, DummyEdge, DummyLocation}; diff --git a/src/DataReader/parse_edge.rs b/src/DataReader/parse_edge.rs index a15f4a67..d88944a5 100644 --- a/src/DataReader/parse_edge.rs +++ b/src/DataReader/parse_edge.rs @@ -1,19 +1,15 @@ extern crate pest; -use crate::component::Component; + use crate::EdgeEval::updater::CompiledUpdate; -use crate::ModelObjects::representations::BoolExpression::Bool; + use crate::ModelObjects::representations::{ArithExpression, BoolExpression}; -use crate::ModelObjects::system_declarations::SystemDeclarations; -use crate::{ - DataReader::serialization::{encode_arithexpr, encode_boolexpr}, - ModelObjects::component::Declarations, -}; + +use crate::{DataReader::serialization::encode_boolexpr, ModelObjects::component::Declarations}; use edbm::util::constraints::ClockIndex; use pest::error::Error; use pest::Parser; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use std::panic::resume_unwind; ///This file handles parsing the edges based on the abstract syntax described in the .pest files in the grammar folder ///For clarification see documentation on pest crate diff --git a/src/DataReader/parse_queries.rs b/src/DataReader/parse_queries.rs index 4878ef5c..ad99c738 100644 --- a/src/DataReader/parse_queries.rs +++ b/src/DataReader/parse_queries.rs @@ -1,7 +1,7 @@ extern crate pest; use crate::ModelObjects::queries::Query; use crate::ModelObjects::representations::QueryExpression; -use pest::iterators::Pair; + use pest::prec_climber::{Assoc, Operator, PrecClimber}; use pest::Parser; @@ -136,9 +136,9 @@ fn build_expression_from_pair(pair: pest::iterators::Pair) -> QueryExpress Operator::new(Rule::composition_op, Assoc::Left), Operator::new(Rule::conjunction_op, Assoc::Left), ]); - let primary = |pair| build_expression_from_pair(pair); - let inner: Vec> = pair.into_inner().collect(); - precedence_climber.climb(inner.into_iter(), primary, |lhs, op, rhs| { + let primary = build_expression_from_pair; + + precedence_climber.climb(pair.into_inner(), primary, |lhs, op, rhs| { match op.as_rule() { Rule::composition_op => { QueryExpression::Composition(Box::new(lhs), Box::new(rhs)) diff --git a/src/DataReader/serialization.rs b/src/DataReader/serialization.rs index dc41531f..98d9fd9e 100644 --- a/src/DataReader/serialization.rs +++ b/src/DataReader/serialization.rs @@ -220,7 +220,7 @@ where } } else { let mut error_string = "not implemented read for type: ".to_string(); - error_string.push_str(&variable_type.to_string()); + error_string.push_str(variable_type); println!("Variable type: {:?}", variable_type); panic!("{}", error_string); } @@ -319,10 +319,10 @@ where { let s = String::deserialize(deserializer)?; if s.contains('!') { - let res = s.replace("!", ""); + let res = s.replace('!', ""); Ok(res) } else if s.contains('?') { - let res = s.replace("?", ""); + let res = s.replace('?', ""); Ok(res) } else { Ok(s) @@ -367,7 +367,7 @@ where let mut output = String::from("clock "); let mut it = decls.clocks.iter(); if let Some((first_clock, _)) = it.next() { - output = output.add(&first_clock.to_string()); + output = output.add(first_clock); for (clock, _) in it { output = output.add(&format!(", {}", clock)); @@ -403,29 +403,6 @@ where serializer.serialize_str(&expr.encode_expr()) } -pub fn encode_opt_arithexpr( - opt_expr: &Option, - serializer: S, -) -> Result -where - S: Serializer, -{ - if let Some(expr) = opt_expr { - encode_arithexpr(expr, serializer) - } else { - serializer.serialize_str("") - } -} -pub fn encode_arithexpr( - expr: &representations::ArithExpression, - serializer: S, -) -> Result -where - S: Serializer, -{ - serializer.serialize_str(&expr.encode_expr()) -} - pub fn encode_opt_updates( opt_updates: &Option>, serializer: S, diff --git a/src/DataReader/xml_parser.rs b/src/DataReader/xml_parser.rs index 33e8134b..94a1c047 100644 --- a/src/DataReader/xml_parser.rs +++ b/src/DataReader/xml_parser.rs @@ -78,7 +78,7 @@ fn parse_xml( } let system_declarations = SystemDeclarations { - name: "".to_string(), + //name: "".to_string(), declarations: decode_sync_type(root.find("system").unwrap().text()), }; @@ -158,7 +158,7 @@ fn collect_edges(xml_edges: FindChildren) -> Vec { }, guard, update: updates, - sync: sync.replace("!", "").replace("?", ""), + sync: sync.replace('!', "").replace('?', ""), }; edges.push(edge); } @@ -180,7 +180,7 @@ fn parse_declarations(variables: &str) -> Declarations { let sub_decls: Vec = string.split(';').map(|s| s.into()).collect(); for mut sub_decl in sub_decls { - sub_decl = sub_decl.replace("\r", ""); + sub_decl = sub_decl.replace('\r', ""); if !sub_decl.is_empty() { let split_string: Vec = sub_decl.split(' ').map(|s| s.into()).collect(); @@ -242,8 +242,8 @@ fn decode_sync_type(global_decl: &str) -> SystemSpecification { if component_names[0] == "system" { //do not include element 0 as that is the system keyword for name in component_names.iter_mut().skip(1) { - let s = name.replace(",", ""); - let s_cleaned = s.replace(";", ""); + let s = name.replace(',', ""); + let s_cleaned = s.replace(';', ""); *name = s_cleaned.clone(); components.push(s_cleaned); } @@ -259,17 +259,17 @@ fn decode_sync_type(global_decl: &str) -> SystemSpecification { if component_names.contains(&component_name) { for split_str in split_string.iter().skip(2) { - let mut s = split_str.replace("{", ""); - s = s.replace("\r", ""); - s = s.replace("\n", ""); - let p = s.replace("}", ""); + let mut s = split_str.replace('{', ""); + s = s.replace('\r', ""); + s = s.replace('\n', ""); + let p = s.replace('}', ""); let comp_actions: Vec = p.split(',').map(|s| s.into()).collect(); for action in comp_actions { if action.is_empty() { continue; } if action.ends_with('?') { - let r = action.replace("?", ""); + let r = action.replace('?', ""); if let Some(Channel_vec) = input_actions.get_mut(&component_name) { Channel_vec.push(r) } else { @@ -277,7 +277,7 @@ fn decode_sync_type(global_decl: &str) -> SystemSpecification { input_actions.insert(component_name.clone(), Channel_vec); } } else if action.ends_with('!') { - let r = action.replace("!", ""); + let r = action.replace('!', ""); if let Some(Channel_vec) = output_actions.get_mut(&component_name) { Channel_vec.push(r.clone()) } else { diff --git a/src/DataTypes/statepair_list.rs b/src/DataTypes/statepair_list.rs index 63d764ae..aba807f0 100644 --- a/src/DataTypes/statepair_list.rs +++ b/src/DataTypes/statepair_list.rs @@ -107,9 +107,6 @@ impl DepthFirstWaitingStateList { pub fn is_empty(&self) -> bool { self.queue.is_empty() } - pub fn len(&self) -> usize { - self.queue.len() - } } impl PassedStateListExt for PassedStateListFed { fn put(&mut self, mut pair: StatePair) { diff --git a/src/EdgeEval/constraint_applyer.rs b/src/EdgeEval/constraint_applyer.rs index dc96db2d..1232790f 100644 --- a/src/EdgeEval/constraint_applyer.rs +++ b/src/EdgeEval/constraint_applyer.rs @@ -2,10 +2,8 @@ use edbm::util::constraints::{ClockIndex, Inequality}; use edbm::zones::OwnedFederation; use crate::component::Declarations; -use crate::ModelObjects::component; + use crate::ModelObjects::representations::{ArithExpression, BoolExpression, Clock}; -use std::collections::HashMap; -use std::convert::TryFrom; pub fn apply_constraints_to_state( guard: &BoolExpression, @@ -30,7 +28,7 @@ fn apply_constraints_to_state_helper( apply_constraints_to_state_helper(right, decls, fed) } BoolExpression::OrOp(left, right) => { - let mut clone = fed.clone(); + let clone = fed.clone(); let fed1 = apply_constraints_to_state_helper(left, decls, fed); let fed2 = apply_constraints_to_state_helper(right, decls, clone); fed1 + fed2 @@ -137,34 +135,28 @@ fn get_indices( fn replace_vars(expr: &ArithExpression, decls: &Declarations) -> ArithExpression { //let mut out = expr.clone(); match expr { - ArithExpression::Parentheses(inner) => replace_vars(&inner, decls), + ArithExpression::Parentheses(inner) => replace_vars(inner, decls), ArithExpression::Difference(l, r) => { - ArithExpression::ADif(replace_vars(&l, decls), replace_vars(&r, decls)) + ArithExpression::ADif(replace_vars(l, decls), replace_vars(r, decls)) } ArithExpression::Addition(l, r) => { - ArithExpression::AAdd(replace_vars(&l, decls), replace_vars(&r, decls)) + ArithExpression::AAdd(replace_vars(l, decls), replace_vars(r, decls)) } ArithExpression::Multiplication(l, r) => { - ArithExpression::AMul(replace_vars(&l, decls), replace_vars(&r, decls)) + ArithExpression::AMul(replace_vars(l, decls), replace_vars(r, decls)) } ArithExpression::Division(l, r) => { - ArithExpression::ADiv(replace_vars(&l, decls), replace_vars(&r, decls)) + ArithExpression::ADiv(replace_vars(l, decls), replace_vars(r, decls)) } ArithExpression::Modulo(l, r) => { - ArithExpression::AMod(replace_vars(&l, decls), replace_vars(&r, decls)) + ArithExpression::AMod(replace_vars(l, decls), replace_vars(r, decls)) } ArithExpression::Clock(x) => ArithExpression::Clock(*x), ArithExpression::VarName(name) => { - if let Some(x) = decls.get_clocks().get(name.as_str()).and_then(|o| Some(*o)) { + if let Some(x) = decls.get_clocks().get(name.as_str()).copied() { ArithExpression::Clock(x) } else { - ArithExpression::Int( - decls - .get_ints() - .get(name.as_str()) - .and_then(|o| Some(*o)) - .unwrap(), - ) + ArithExpression::Int(decls.get_ints().get(name.as_str()).copied().unwrap()) } } ArithExpression::Int(i) => ArithExpression::Int(*i), @@ -175,18 +167,13 @@ fn get_const(expr: &ArithExpression, decls: &Declarations) -> i32 { match expr { ArithExpression::Int(x) => *x, ArithExpression::Clock(_) => 0, - ArithExpression::VarName(name) => decls - .get_ints() - .get(name) - .and_then(|o| Some(*o)) - .unwrap_or(0), + ArithExpression::VarName(name) => decls.get_ints().get(name).copied().unwrap_or(0), ArithExpression::Parentheses(x) => get_const(x, decls), ArithExpression::Difference(l, r) => get_const(l, decls) - get_const(r, decls), ArithExpression::Addition(l, r) => get_const(l, decls) + get_const(r, decls), ArithExpression::Multiplication(l, r) => get_const(l, decls) * get_const(r, decls), ArithExpression::Division(l, r) => get_const(l, decls) / get_const(r, decls), ArithExpression::Modulo(l, r) => get_const(l, decls) % get_const(r, decls), - _ => 0, } } @@ -198,12 +185,10 @@ fn combine_clocks( ) -> Result<(ClockIndex, ClockIndex, i32), String> { if (same_sign && c1.negated != c2.negated) || (!same_sign && c1.negated == c2.negated) { Err(String::from("Same sign")) + } else if !c1.negated { + Ok((c1.value, c2.value, constant)) } else { - if c1.negated == false { - Ok((c1.value, c2.value, constant)) - } else { - Ok((c2.value, c1.value, constant)) - } + Ok((c2.value, c1.value, constant)) } } @@ -243,7 +228,7 @@ fn get_clock_val( ArithExpression::Multiplication(_, _) | ArithExpression::Division(_, _) | ArithExpression::Modulo(_, _) => { - return Err(format!("Multiplication with clock is illegal")); + return Err("Multiplication with clock is illegal".to_string()); } ArithExpression::Clock(x) => Clock::new(*x, negated), _ => return Err(String::from("No Clocks")), @@ -259,6 +244,7 @@ fn get_clock_val( } } +#[cfg(test)] mod test { use super::get_indices; use crate::component::Declarations; @@ -597,7 +583,7 @@ mod test { clocks: HashMap::new(), ints: HashMap::new(), }; - let mut left = ArithExpression::ADif( + let left = ArithExpression::ADif( // = 4 ArithExpression::Int(10), ArithExpression::ADif( @@ -634,7 +620,7 @@ mod test { clocks: HashMap::new(), ints: HashMap::new(), }; - let mut left = ArithExpression::ADif( + let left = ArithExpression::ADif( ArithExpression::Multiplication( Box::new(ArithExpression::Clock(3)), Box::new(ArithExpression::Int(3)), @@ -645,7 +631,7 @@ mod test { //Testing: left < right assert_eq!(get_indices(&left, &right, &decl).ok(), None); - let mut left = ArithExpression::ADif( + let left = ArithExpression::ADif( ArithExpression::Multiplication( Box::new(ArithExpression::Int(3)), Box::new(ArithExpression::Int(3)), diff --git a/src/EdgeEval/updater.rs b/src/EdgeEval/updater.rs index 5314a97f..2efc03e6 100644 --- a/src/EdgeEval/updater.rs +++ b/src/EdgeEval/updater.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use std::{arch, fmt}; +use std::fmt; use crate::DataReader::parse_edge; -use crate::ModelObjects::component::{self, Declarations}; +use crate::ModelObjects::component::Declarations; use crate::ModelObjects::representations::{ArithExpression, BoolExpression}; use colored::Colorize; use edbm::util::constraints::ClockIndex; @@ -18,7 +18,7 @@ impl fmt::Display for CompiledUpdate { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_fmt(format_args!( "{}:={}", - format!("c:{}", self.clock_index).to_string().magenta(), + format!("c:{}", self.clock_index).magenta(), self.value ))?; Ok(()) @@ -54,7 +54,7 @@ impl CompiledUpdate { } } - pub fn apply(&self, mut fed: OwnedFederation) -> OwnedFederation { + pub fn apply(&self, fed: OwnedFederation) -> OwnedFederation { fed.update_clock_val(self.clock_index, self.value) } diff --git a/src/ModelObjects/component.rs b/src/ModelObjects/component.rs index f8764c7c..55139d3d 100644 --- a/src/ModelObjects/component.rs +++ b/src/ModelObjects/component.rs @@ -4,17 +4,15 @@ use crate::DataReader::serialization::{ decode_declarations, decode_guard, decode_invariant, decode_location_type, decode_sync, decode_sync_type, decode_update, DummyComponent, DummyEdge, DummyLocation, }; -use crate::EdgeEval::constraint_applyer; + use crate::EdgeEval::constraint_applyer::apply_constraints_to_state; use crate::EdgeEval::updater::CompiledUpdate; use edbm::util::bounds::Bounds; use edbm::util::constraints::ClockIndex; -use crate::ModelObjects::representations; - use crate::ModelObjects::representations::BoolExpression; -use crate::TransitionSystems::{CompositionType, LocationID, TransitionSystem}; -use crate::TransitionSystems::{LocationTuple, TransitionSystemPtr}; +use crate::TransitionSystems::LocationTuple; +use crate::TransitionSystems::{CompositionType, TransitionSystem}; use edbm::zones::OwnedFederation; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -122,7 +120,7 @@ impl Component { .filter(|location| location.get_location_type() == &LocationType::Initial) .collect(); - vec.first().map(|l| *l) + vec.first().copied() } pub fn get_actions(&self) -> Vec { @@ -269,10 +267,6 @@ pub fn contain(channels: &[Channel], channel: &str) -> bool { false } -fn create_state(location: &Location, decl: &Declarations, zone: OwnedFederation) -> State { - State::create(LocationTuple::simple(location, decl, zone.dim()), zone) -} - /// FullState is a struct used for initial verification of consistency, and determinism as a state that also hols a dbm /// This is done as the type used in refinement state pair assumes to sides of an operation /// this should probably be refactored as it causes unnecessary confusion @@ -290,7 +284,7 @@ impl State { } } - pub fn is_contained_in_list(&self, list: &Vec) -> bool { + pub fn is_contained_in_list(&self, list: &[State]) -> bool { list.iter().any(|s| self.is_subset_of(s)) } @@ -491,6 +485,8 @@ impl Transition { fed } + // TODO: will we ever need this method? + #[allow(dead_code)] fn get_guard_from_allowed( from_loc: &LocationTuple, to_loc: &LocationTuple, @@ -523,7 +519,7 @@ impl Transition { self.apply_guards(fed) } - pub fn apply_guards(&self, mut zone: OwnedFederation) -> OwnedFederation { + pub fn apply_guards(&self, zone: OwnedFederation) -> OwnedFederation { zone.intersection(&self.guard_zone) } @@ -572,7 +568,7 @@ impl fmt::Display for Transition { self.target_locations .get_invariants() .map(|f| format!("invariant is {}", f)) - .unwrap_or("no invariant".to_string()), + .unwrap_or_else(|| "no invariant".to_string()), self.updates .iter() .map(|u| u.to_string()) @@ -719,7 +715,7 @@ impl<'a> DecoratedLocation<'a> { pub fn apply_invariant(&self, mut fed: OwnedFederation) -> OwnedFederation { if let Some(inv) = self.get_location().get_invariant() { - fed = apply_constraints_to_state(&inv, self.decls, fed); + fed = apply_constraints_to_state(inv, self.decls, fed); } fed @@ -730,11 +726,11 @@ impl<'a> DecoratedLocation<'a> { } pub fn get_declarations(&self) -> &Declarations { - &self.decls + self.decls } pub fn get_location(&self) -> &Location { - &self.location + self.location } pub fn set_location(&mut self, location: &'a Location) { @@ -811,64 +807,3 @@ impl Declarations { self.get_clocks().get(name) } } - -fn add_state_to_wl(wl: &mut Vec, state: State) { - wl.push(state) -} - -fn add_state_to_pl(wl: &mut Vec, state: State) { - wl.push(state) -} - -pub fn get_dummy_component(name: String, inputs: &[String], outputs: &[String]) -> Component { - let location = Location { - id: "EXTRA".to_string(), - invariant: None, - location_type: LocationType::Initial, - urgency: "".to_string(), - }; - - let mut input_edges = vec![]; - - for input in inputs { - input_edges.push(Edge { - guard: None, - source_location: "EXTRA".to_string(), - target_location: "EXTRA".to_string(), - sync: input.clone(), - sync_type: SyncType::Input, - update: None, - }) - } - - let mut output_edges = vec![]; - - for output in outputs { - output_edges.push(Edge { - guard: None, - source_location: "EXTRA".to_string(), - target_location: "EXTRA".to_string(), - sync: output.clone(), - sync_type: SyncType::Output, - update: None, - }) - } - - let edges: Vec = input_edges - .iter() - .cloned() - .chain(output_edges.iter().cloned()) - .collect(); - - Component { - name, - declarations: Declarations { - ints: HashMap::new(), - clocks: HashMap::new(), - }, - locations: vec![location], - edges, - input_edges: Some(input_edges), - output_edges: Some(output_edges), - } -} diff --git a/src/ModelObjects/queries.rs b/src/ModelObjects/queries.rs index fa88ff0e..184b88bd 100644 --- a/src/ModelObjects/queries.rs +++ b/src/ModelObjects/queries.rs @@ -31,7 +31,7 @@ where let queries = parse_queries::parse_to_expression_tree(&s); if queries.len() > 1 { panic!("Could not parse query {} contains multiple queries", s); - } else if queries.len() == 0 { + } else if queries.is_empty() { panic!("Could not parse query {} contains no queries", s); } else { Ok(queries.into_iter().next()) diff --git a/src/ModelObjects/representations.rs b/src/ModelObjects/representations.rs index 16c307db..885121b7 100644 --- a/src/ModelObjects/representations.rs +++ b/src/ModelObjects/representations.rs @@ -1,15 +1,12 @@ -use crate::ModelObjects::statepair::StatePair; -use boolean_expression::CubeVar::False; use colored::Colorize; use edbm::util::constraints::{ClockIndex, Conjunction, Constraint, Disjunction}; -use generic_array::arr_impl; + use serde::Deserialize; -use std::borrow::BorrowMut; + use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::ops; //use serde::de::Unexpected::Option; -use serde_json::Value; /// This file contains the nested enums used to represent systems on each side of refinement as well as all guards, updates etc /// note that the enum contains a box (pointer) to an object as they can only hold pointers to data on the heap @@ -66,7 +63,7 @@ impl BoolExpression { BoolExpression::Parentheses(body) => { BoolExpression::Parentheses(Box::new(body.swap_clock_names(from_vars, to_vars))) } - BoolExpression::Bool(val) => BoolExpression::Bool(val.clone()), + BoolExpression::Bool(val) => BoolExpression::Bool(*val), BoolExpression::Arithmetic(x) => { BoolExpression::Arithmetic(Box::new(x.swap_clock_names(from_vars, to_vars))) } @@ -126,12 +123,9 @@ impl BoolExpression { let mut result = None; for conjunction in &disjunction.conjunctions { - let expr = BoolExpression::from_conjunction(conjunction, &naming); - if expr.is_none() { - // If any is None (true), the disjuntion is None (true) - return None; - } - let expr = expr.unwrap(); + // If any is None (true), the disjuntion is None (true) so we use ? + let expr = BoolExpression::from_conjunction(conjunction, &naming)?; + match result { None => result = Some(expr), Some(res) => result = Some(BoolExpression::OrOp(Box::new(res), Box::new(expr))), @@ -570,7 +564,7 @@ impl Display for BoolExpression { } } BoolExpression::Arithmetic(x) => { - write!(f, "{}", x.encode_expr()); + write!(f, "{}", x.encode_expr())?; } } Ok(()) @@ -623,7 +617,7 @@ impl ArithExpression { let new_name = to_vars[index].clone(); ArithExpression::VarName(new_name) }, - ArithExpression::Int(val) => ArithExpression::Int(val.clone()), + ArithExpression::Int(val) => ArithExpression::Int(*val), ArithExpression::Parentheses(inner) => inner.swap_clock_names(from_vars, to_vars), } } @@ -899,18 +893,18 @@ impl ArithExpression { } fn clone_expr( - checker: &Box, - cloner: &Box, + checker: &ArithExpression, + cloner: &ArithExpression, err_msg: Option<&str>, ) -> Result, String> { - if let ArithExpression::Clock(_) = **checker { + if let ArithExpression::Clock(_) = *checker { if let Some(e) = err_msg { Err(e.to_string()) } else { - Ok(Some(*cloner.clone())) + Ok(Some(cloner.clone())) } - } else if let ArithExpression::VarName(_) = **checker { - Ok(Some(*cloner.clone())) + } else if let ArithExpression::VarName(_) = *checker { + Ok(Some(cloner.clone())) } else { Ok(None) } @@ -1067,7 +1061,7 @@ impl Display for ArithExpression { write!(f, "{}{}{}", l_par, expr, r_par)?; } ArithExpression::Clock(id) => { - write!(f, "{}", format!("c:{}", id).to_string().magenta())?; + write!(f, "{}", format!("c:{}", id).magenta())?; } ArithExpression::VarName(name) => { write!(f, "{}", name.to_string().blue())?; @@ -1105,6 +1099,8 @@ enum Operation { Mod(bool), None, } + +#[allow(dead_code)] impl Operation { pub fn left(&self) -> Operation { match self { @@ -1161,8 +1157,8 @@ impl Clock { } } -fn get_op(exp: &Box) -> Option { - match exp.as_ref() { +fn get_op(exp: &BoolExpression) -> Option { + match exp { BoolExpression::EQ(_, _) => Some("=".to_string()), BoolExpression::LessEQ(_, _) => Some("≤".to_string()), BoolExpression::LessT(_, _) => Some("<".to_string()), @@ -1170,227 +1166,6 @@ fn get_op(exp: &Box) -> Option { } } -fn var_from_index( - index: ClockIndex, - clocks: &Option<&HashMap>, -) -> Option> { - let var = if let Some(c) = clocks { - //If the index exists in dbm it must be in the map, so we unwrap - let clock = c.keys().find(|&x| *c.get(x).unwrap() == index); - - match clock { - Some(c) => Some(Box::new(ArithExpression::VarName(c.clone()))), - None => None, - } - } else { - Some(Box::new(ArithExpression::Clock(index))) - }; - var -} -/* -fn get_groups_from_zone(zone: &Zone, clocks: &Option<&HashMap>) -> Vec> { - let mut groups: Vec> = vec![]; - let mut grouped: Vec = vec![]; - for index_i in 1..zone.dimension { - if grouped.contains(&index_i) { - continue; - } - - if var_from_index(index_i, &clocks).is_none() { - continue; - } - - let mut group = vec![index_i]; - - // Find next equal - for index_j in index_i + 1..zone.dimension { - if var_from_index(index_j, &clocks).is_none() { - continue; - } - if is_equal(zone, index_i, index_j) { - group.push(index_j); - grouped.push(index_j); - } - } - - groups.push(group); - } - groups -} - -pub fn build_guard_from_zone( - zone: &Zone, - clocks: Option<&HashMap>, -) -> Option { - let mut guards: Vec = vec![]; - let groups = get_groups_from_zone(zone, &clocks); - - for group in &groups { - let first = *group.first().unwrap(); - let last = *group.last().unwrap(); - let first_var = var_from_index(first, &clocks).unwrap(); - let last_var = var_from_index(last, &clocks).unwrap(); - - let (upper_is_strict, upper_val) = zone.get_constraint(first, 0); - let (lower_is_strict, lower_val) = zone.get_constraint(0, first); - - // if lower bound is different from (>=, 0) - if lower_is_strict || lower_val != 0 { - if lower_is_strict { - guards.push(BoolExpression::LessT( - Box::new(ArithExpression::Int(-lower_val)), - first_var, - )); - } else { - guards.push(BoolExpression::LessEQ( - Box::new(ArithExpression::Int(-lower_val)), - first_var, - )); - } - } - - for index in 0..group.len() - 1 { - let (a, b) = (group[index], group[index + 1]); - let (a, b) = ( - var_from_index(a, &clocks).unwrap(), - var_from_index(b, &clocks).unwrap(), - ); - guards.push(BoolExpression::EQ(a, b)); - } - - // Upper bound - if !zone.is_constraint_infinity(last, 0) { - if upper_is_strict { - guards.push(BoolExpression::LessT( - last_var, - Box::new(ArithExpression::Int(upper_val)), - )); - } else { - guards.push(BoolExpression::LessEQ( - last_var, - Box::new(ArithExpression::Int(upper_val)), - )); - } - } - - for other_group in &groups { - let other_first = *other_group.first().unwrap(); - if other_first == first { - continue; - } - - add_diagonal_constraints( - zone, - other_first, - first, - var_from_index(other_first, &clocks).unwrap(), - var_from_index(first, &clocks).unwrap(), - &mut guards, - ); - } - } - guards.reverse(); - - let res = build_guard_from_zone_helper(&mut guards); - Some(res) -} - - -fn add_diagonal_constraints( - zone: &Zone, - index_i: u32, - index_j: u32, - var_i: Box, - var_j: Box, - guards: &mut Vec, -) { - if !zone.is_constraint_infinity(index_i, index_j) { - if is_constraint_unnecessary(zone, index_i, index_j) { - return; - } - // i-j <= c - let (is_strict, val) = zone.get_constraint(index_i, index_j); - /*if val == 0 { - if is_strict { - guards.push(BoolExpression::BLessT(*var_i, *var_j)) - } else { - guards.push(BoolExpression::BLessEQ(*var_i, *var_j)) - } - } else*/ - { - if is_strict { - guards.push(BoolExpression::BLessT( - ArithExpression::Difference(var_i, var_j), - ArithExpression::Int(val), - )) - } else { - guards.push(BoolExpression::BLessEQ( - ArithExpression::Difference(var_i, var_j), - ArithExpression::Int(val), - )) - } - } - } -} - - -fn is_equal(zone: &Zone, index_i: u32, index_j: u32) -> bool { - let d1 = zone.get_constraint(index_i, index_j); - let d2 = zone.get_constraint(index_j, index_i); - - const EQ_ZERO: (bool, i32) = (false, 0); - - d1 == EQ_ZERO && d2 == EQ_ZERO -} - -fn is_constraint_unnecessary(zone: &Zone, index_i: u32, index_j: u32) -> bool { - let max_i = zone.get_constraint(index_i, 0); - let min_j = zone.get_constraint(0, index_j); - - // let max_j = zone.get_constraint(index_j, 0); - // let min_i = zone.get_constraint(0, index_i); - - // i-j <= c - let c = zone.get_constraint(index_i, index_j); - - if zone.is_constraint_infinity(index_i, 0) { - return true; - } - - // max(i)-min(j) max(i) (bool, i32) { - let strict = c1_strict || c2_strict; - let c = c1 + c2; - (strict, c) -} -*/ - -fn build_guard_from_zone_helper(guards: &mut Vec) -> BoolExpression { - let num_guards = guards.len(); - - if let Some(guard) = guards.pop() { - if num_guards == 1 { - guard - } else { - BoolExpression::AndOp( - Box::new(guard), - Box::new(build_guard_from_zone_helper(guards)), - ) - } - } else { - BoolExpression::Bool(true) - } -} - #[derive(Debug, Clone, Deserialize)] pub enum QueryExpression { Refinement(Box, Box), diff --git a/src/ModelObjects/statepair.rs b/src/ModelObjects/statepair.rs index 730fc92c..12daa3c9 100644 --- a/src/ModelObjects/statepair.rs +++ b/src/ModelObjects/statepair.rs @@ -1,4 +1,3 @@ -use edbm::util::{bounds::Bounds, constraints::ClockIndex}; use edbm::zones::OwnedFederation; use crate::TransitionSystems::{LocationTuple, TransitionSystemPtr}; @@ -18,7 +17,7 @@ impl StatePair { locations1: LocationTuple, locations2: LocationTuple, ) -> StatePair { - let mut zone = OwnedFederation::init(dimensions); + let zone = OwnedFederation::init(dimensions); StatePair { locations1, @@ -27,10 +26,6 @@ impl StatePair { } } - pub fn dim(&self) -> ClockIndex { - self.ref_zone().dim() - } - pub fn get_locations1(&self) -> &LocationTuple { &self.locations1 } @@ -48,6 +43,7 @@ impl StatePair { } } + #[allow(dead_code)] pub fn get_locations(&self, is_states1: bool) -> (&LocationTuple, &LocationTuple) { if is_states1 { (&self.locations1, &self.locations2) @@ -56,6 +52,7 @@ impl StatePair { } } + #[allow(dead_code)] pub fn clone_zone(&self) -> OwnedFederation { self.ref_zone().clone() } @@ -92,12 +89,12 @@ impl Display for StatePair { self.locations1 .get_invariants() .map(|f| f.to_string()) - .unwrap_or("no invariant".to_string()), + .unwrap_or_else(|| "no invariant".to_string()), self.locations2.id, self.locations2 .get_invariants() .map(|f| f.to_string()) - .unwrap_or("no invariant".to_string()), + .unwrap_or_else(|| "no invariant".to_string()), self.ref_zone() ))?; diff --git a/src/ModelObjects/system_declarations.rs b/src/ModelObjects/system_declarations.rs index faa8bdd0..614488e1 100644 --- a/src/ModelObjects/system_declarations.rs +++ b/src/ModelObjects/system_declarations.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; #[derive(Debug, Deserialize, Clone)] pub struct SystemDeclarations { - pub(crate) name: String, + //pub(crate) name: String, #[serde(deserialize_with = "decode_sync_type")] pub(crate) declarations: SystemSpecification, } @@ -96,8 +96,8 @@ where if component_names[0] == "system" { //do not include element 0 as that is the system keyword for name in component_names.iter_mut().skip(1) { - let s = name.replace(",", ""); - let s_cleaned = s.replace(";", ""); + let s = name.replace(',', ""); + let s_cleaned = s.replace(';', ""); *name = s_cleaned.clone(); components.push(s_cleaned); } @@ -113,15 +113,15 @@ where if component_names.contains(&component_name) { for split_str in split_string.iter().skip(2) { - let s = split_str.replace("{", ""); - let p = s.replace("}", ""); + let s = split_str.replace('{', ""); + let p = s.replace('}', ""); let comp_actions: Vec = p.split(',').map(|s| s.into()).collect(); for action in comp_actions { if action.is_empty() { continue; } if action.ends_with('?') { - let r = action.replace("?", ""); + let r = action.replace('?', ""); if let Some(Channel_vec) = input_actions.get_mut(&component_name) { Channel_vec.push(r) } else { @@ -129,7 +129,7 @@ where input_actions.insert(component_name.clone(), Channel_vec); } } else if action.ends_with('!') { - let r = action.replace("!", ""); + let r = action.replace('!', ""); if let Some(Channel_vec) = output_actions.get_mut(&component_name) { Channel_vec.push(r.clone()) } else { diff --git a/src/ProtobufServer/ecdar_requests/send_query.rs b/src/ProtobufServer/ecdar_requests/send_query.rs index 2a603ccc..2266cfdd 100644 --- a/src/ProtobufServer/ecdar_requests/send_query.rs +++ b/src/ProtobufServer/ecdar_requests/send_query.rs @@ -76,7 +76,7 @@ fn convert_ecdar_result(query_result: &QueryResult) -> Option { })), QueryResult::GetComponent(comp) => Some(ProtobufResult::Component(ComponentResult { component: Some(Component { - rep: Some(Rep::Json(component_to_json(&comp))), + rep: Some(Rep::Json(component_to_json(comp))), }), })), QueryResult::Consistency(is_consistent) => { @@ -90,8 +90,5 @@ fn convert_ecdar_result(query_result: &QueryResult) -> Option { })) } QueryResult::Error(message) => Some(ProtobufResult::Error(message.clone())), - _ => Some(ProtobufResult::Error(String::from( - "Unsupported query type", - ))), } } diff --git a/src/ProtobufServer/ecdar_requests/update_components.rs b/src/ProtobufServer/ecdar_requests/update_components.rs index 7a589556..1817d0eb 100644 --- a/src/ProtobufServer/ecdar_requests/update_components.rs +++ b/src/ProtobufServer/ecdar_requests/update_components.rs @@ -45,12 +45,12 @@ impl ConcreteEcdarBackend { } fn parse_json_component(json: &str) -> Result, tonic::Status> { - return match json_to_component(json) { + match json_to_component(json) { Ok(comp) => Ok(vec![comp]), Err(_) => Err(tonic::Status::invalid_argument( "Failed to parse json component", )), - }; + } } fn parse_xml_components(xml: &str) -> Vec { diff --git a/src/Simulation/graph_layout.rs b/src/Simulation/graph_layout.rs index fc13803e..b7ec434c 100644 --- a/src/Simulation/graph_layout.rs +++ b/src/Simulation/graph_layout.rs @@ -1,5 +1,5 @@ use crate::DataReader::serialization::DummyComponent; -use force_graph::{DefaultNodeIdx, ForceGraph, Node, NodeData}; +use force_graph::{DefaultNodeIdx, ForceGraph, NodeData}; use rand::Rng; use serde::Deserialize; use std::collections::HashMap; diff --git a/src/System/extract_system_rep.rs b/src/System/extract_system_rep.rs index 942a4a9a..a0ab8985 100644 --- a/src/System/extract_system_rep.rs +++ b/src/System/extract_system_rep.rs @@ -6,15 +6,15 @@ use crate::System::executable_query::{ ConsistencyExecutor, DeterminismExecutor, ExecutableQuery, GetComponentExecutor, RefinementExecutor, }; -use crate::System::save_component::combine_components; + use crate::TransitionSystems::{ - CompiledComponent, Composition, Conjunction, Quotient, TransitionSystem, TransitionSystemPtr, + CompiledComponent, Composition, Conjunction, Quotient, TransitionSystemPtr, }; use crate::System::pruning; use edbm::util::constraints::ClockIndex; use simple_error::bail; -use std::borrow::BorrowMut; + use std::error::Error; /// This function fetches the appropriate components based on the structure of the query and makes the enum structure match the query @@ -136,7 +136,7 @@ pub fn get_system_recipe( let left = get_system_recipe(left, component_loader, clock_index); let right = get_system_recipe(right, component_loader, clock_index); *clock_index += 1; - let mut quotient = Box::new(SystemRecipe::Quotient(left, right, *clock_index)); + let quotient = Box::new(SystemRecipe::Quotient(left, right, *clock_index)); println!("Quotient clock index: {}", *clock_index); quotient } @@ -144,7 +144,8 @@ pub fn get_system_recipe( let mut component = component_loader.get_component(name).clone(); component.set_clock_indices(clock_index); println!("{} Clocks: {:?}", name, component.declarations.clocks); - return Box::new(SystemRecipe::Component(Box::new(component))); + + Box::new(SystemRecipe::Component(Box::new(component))) } QueryExpression::SaveAs(comp, _) => get_system_recipe(comp, component_loader, clock_index), _ => panic!("Got unexpected query side: {:?}", side), diff --git a/src/System/input_enabler.rs b/src/System/input_enabler.rs index ee572999..4600d482 100644 --- a/src/System/input_enabler.rs +++ b/src/System/input_enabler.rs @@ -4,7 +4,6 @@ use crate::EdgeEval::constraint_applyer; use crate::ModelObjects::component; use crate::ModelObjects::component::DeclarationProvider; use crate::ModelObjects::representations::BoolExpression; -use crate::TransitionSystems::TransitionSystem; pub fn make_input_enabled(component: &mut component::Component, inputs: &[String]) { let dimension = component.declarations.get_clock_count() + 1; diff --git a/src/System/local_consistency.rs b/src/System/local_consistency.rs index fb4978a0..a5ac7c52 100644 --- a/src/System/local_consistency.rs +++ b/src/System/local_consistency.rs @@ -1,7 +1,7 @@ use edbm::zones::OwnedFederation; use crate::ModelObjects::component::State; -use crate::TransitionSystems::{TransitionSystem, TransitionSystemPtr}; +use crate::TransitionSystems::TransitionSystem; //Local consistency check WITH pruning pub fn is_least_consistent(system: &dyn TransitionSystem) -> bool { @@ -34,9 +34,7 @@ pub fn is_deterministic(system: &dyn TransitionSystem) -> bool { let mut state = state.unwrap(); state.set_zone(OwnedFederation::universe(system.get_dim())); - let res = is_deterministic_helper(state, &mut passed, system); - - res + is_deterministic_helper(state, &mut passed, system) } fn is_deterministic_helper( @@ -77,8 +75,9 @@ fn is_deterministic_helper( true } -//Local consistency check WITHOUT pruning -pub fn is_fully_consistent(system: &dyn TransitionSystem, dimensions: u32) -> bool { +/// Local consistency check WITHOUT pruning +#[allow(dead_code)] +pub fn is_fully_consistent(system: &dyn TransitionSystem) -> bool { if system.get_initial_location() == None { return false; } @@ -146,6 +145,7 @@ pub fn consistency_least_helper( false } +#[allow(dead_code)] fn consistency_fully_helper( state: State, passed_list: &mut Vec, diff --git a/src/System/pruning.rs b/src/System/pruning.rs index bda8a519..ff421b94 100644 --- a/src/System/pruning.rs +++ b/src/System/pruning.rs @@ -3,16 +3,14 @@ use edbm::zones::OwnedFederation; use crate::EdgeEval::constraint_applyer::apply_constraints_to_state; use crate::ModelObjects::component::{ - Component, DeclarationProvider, Declarations, Edge, Location, SyncType, Transition, + Component, DeclarationProvider, Declarations, Edge, Location, SyncType, }; use crate::ModelObjects::representations::BoolExpression; -use crate::ModelObjects::system_declarations::{SystemDeclarations, SystemSpecification}; use crate::System::save_component::combine_components; +use crate::TransitionSystems::TransitionSystemPtr; use crate::TransitionSystems::{CompiledComponent, LocationTuple}; -use crate::TransitionSystems::{TransitionSystem, TransitionSystemPtr}; -use std::collections::hash_map::DefaultHasher; + use std::collections::{HashMap, HashSet}; -use std::hash::{Hash, Hasher}; use super::save_component::PruningStrategy; @@ -28,16 +26,7 @@ pub fn prune_system(ts: TransitionSystemPtr, dim: ClockIndex) -> TransitionSyste let mut input_map: HashMap> = HashMap::new(); input_map.insert(comp.get_name().clone(), inputs.iter().cloned().collect()); - let sys_decl = SystemDeclarations { - name: "".to_string(), - declarations: SystemSpecification { - components: vec![comp.get_name().clone()], - input_actions: input_map, - output_actions: HashMap::new(), - }, - }; - - let result = prune(&comp, dim, inputs, outputs, &sys_decl); + let result = prune(&comp, dim, inputs, outputs); result.unwrap() } @@ -102,7 +91,6 @@ pub fn prune( dim: ClockIndex, inputs: HashSet, outputs: HashSet, - decl: &SystemDeclarations, ) -> Result, String> { let mut new_comp = comp.clone(); new_comp.create_edge_io_split(); @@ -135,15 +123,11 @@ pub fn prune( .edges .iter() .filter(|e| e.target_location == target_loc) - .cloned() { if *edge.get_sync_type() == SyncType::Input { - handle_input(&edge, &mut context); - } else - // If output - { - handle_output(&edge, &mut context); + handle_input(edge, &mut context); } + handle_output(edge, &mut context); } println!( @@ -401,7 +385,7 @@ fn back_exploration_on_transition( inconsistent_part = apply_constraints_to_state(inv, context.decl(), inconsistent_part); } - return inconsistent_part; + inconsistent_part } fn handle_output(edge: &Edge, context: &mut PruneContext) { @@ -455,15 +439,9 @@ fn handle_output(edge: &Edge, context: &mut PruneContext) { // Source is not inconsistent, nothing more to do } else { let mut fed_that_saves_us = OwnedFederation::empty(context.dim); - for other_edge in context - .comp - .edges - .iter() - .filter(|e| { - e.source_location == edge.source_location && *e.get_sync_type() == SyncType::Output - }) - .cloned() - { + for other_edge in context.comp.edges.iter().filter(|e| { + e.source_location == edge.source_location && *e.get_sync_type() == SyncType::Output + }) { // calculate and backtrack the part that is NOT inconsistent // get target invariant @@ -515,7 +493,9 @@ fn is_immediately_inconsistent( ) -> bool { let loc = LocationTuple::simple(location, &comp.declarations, dimensions); - return loc.is_inconsistent(); + loc.is_inconsistent() + + /* let fed = loc.get_invariants(); let res = match fed { Some(fed) => !fed.can_delay_indefinitely(), @@ -530,4 +510,5 @@ fn is_immediately_inconsistent( } res + */ } diff --git a/src/System/refine.rs b/src/System/refine.rs index 89686f2a..f2f0a995 100644 --- a/src/System/refine.rs +++ b/src/System/refine.rs @@ -6,7 +6,6 @@ use crate::DataTypes::{PassedStateList, PassedStateListExt, WaitingStateList}; use crate::ModelObjects::component::Transition; use crate::ModelObjects::statepair::StatePair; -use crate::TransitionSystems::LocationID; use crate::TransitionSystems::{LocationTuple, TransitionSystemPtr}; use std::collections::HashSet; @@ -52,8 +51,8 @@ impl<'a> RefinementContext<'a> { RefinementContext { passed_list: PassedStateList::new(), waiting_list: WaitingStateList::new(), - sys1: sys1, - sys2: sys2, + sys1, + sys2, } } } @@ -212,6 +211,7 @@ pub fn check_refinement( Ok(true) } +#[cfg(feature = "verbose")] fn print_relation(passed_list: &PassedStateList) { let verbose = false; @@ -233,6 +233,9 @@ fn print_relation(passed_list: &PassedStateList) { } } +#[cfg(not(feature = "verbose"))] +fn print_relation(_passed_list: &PassedStateList) {} + fn has_valid_state_pairs( transitions1: &[Transition], transitions2: &[Transition], @@ -240,7 +243,13 @@ fn has_valid_state_pairs( context: &mut RefinementContext, is_state1: bool, ) -> bool { - let (fed1, fed2) = get_guard_fed_for_sides(transitions1, transitions2, curr_pair, is_state1); + let (fed1, fed2) = get_guard_fed_for_sides( + transitions1, + transitions2, + curr_pair, + #[cfg(feature = "verbose")] + is_state1, + ); // If there are no valid transition1s, continue if fed1.is_empty() { @@ -273,7 +282,7 @@ fn get_guard_fed_for_sides( transitions1: &[Transition], transitions2: &[Transition], curr_pair: &StatePair, - is_state1: bool, + #[cfg(feature = "verbose")] is_state1: bool, ) -> (OwnedFederation, OwnedFederation) { let dim = curr_pair.ref_zone().dim(); @@ -384,7 +393,7 @@ fn build_state_pair( return BuildResult::Success; } - let mut t_invariant = new_sp_zone.clone().down(); + let t_invariant = new_sp_zone.clone().down(); // inv_s = x<10, inv_t = x>2 -> t cuts solutions but not delays, so it is fine and we can call down: // Check if the invariant of T (right) cuts delay solutions from S (left) and if so, report failure diff --git a/src/System/save_component.rs b/src/System/save_component.rs index 2020f62a..31e29525 100644 --- a/src/System/save_component.rs +++ b/src/System/save_component.rs @@ -1,6 +1,4 @@ -use crate::ModelObjects::component::{ - Component, DeclarationProvider, Declarations, Edge, Location, LocationType, SyncType, -}; +use crate::ModelObjects::component::{Component, Declarations, Edge, Location, SyncType}; use crate::ModelObjects::representations::BoolExpression; use crate::TransitionSystems::{LocationTuple, TransitionSystemPtr}; use std::collections::HashMap; @@ -20,17 +18,12 @@ pub fn combine_components( let mut location_tuples = vec![]; let mut edges = vec![]; let clocks = get_clock_map(system); - let dim = system.get_dim(); match reachability { - Reachable => collect_reachable_edges_and_locations( - system, - &mut location_tuples, - &mut edges, - &clocks, - dim, - ), + Reachable => { + collect_reachable_edges_and_locations(system, &mut location_tuples, &mut edges, &clocks) + } NoPruning => { - collect_all_edges_and_locations(system, &mut location_tuples, &mut edges, &clocks, dim) + collect_all_edges_and_locations(system, &mut location_tuples, &mut edges, &clocks) } }; @@ -39,10 +32,10 @@ pub fn combine_components( name: "".to_string(), declarations: Declarations { ints: HashMap::new(), - clocks: clocks, + clocks, }, - locations: locations, - edges: edges, + locations, + edges, input_edges: None, output_edges: None, }; @@ -51,14 +44,14 @@ pub fn combine_components( } fn get_locations_from_tuples( - location_tuples: &Vec, + location_tuples: &[LocationTuple], clock_map: &HashMap, ) -> Vec { location_tuples .iter() .cloned() .map(|loc_vec| { - let invariant: Option = loc_vec.get_invariants().map_or(None, |fed| { + let invariant: Option = loc_vec.get_invariants().and_then(|fed| { BoolExpression::from_disjunction(&fed.minimal_constraints(), clock_map) }); @@ -97,12 +90,11 @@ fn collect_all_edges_and_locations<'a>( locations: &mut Vec, edges: &mut Vec, clock_map: &HashMap, - dim: ClockIndex, ) { let l = representation.get_all_locations(); locations.extend(l); for location in locations { - collect_edges_from_location(location, representation, edges, clock_map, dim); + collect_edges_from_location(location, representation, edges, clock_map); } } @@ -111,7 +103,6 @@ fn collect_reachable_edges_and_locations<'a>( locations: &mut Vec, edges: &mut Vec, clock_map: &HashMap, - dim: ClockIndex, ) { let l = representation.get_initial_location(); @@ -125,7 +116,7 @@ fn collect_reachable_edges_and_locations<'a>( collect_reachable_locations(&l, representation, locations); for loc in locations { - collect_edges_from_location(&loc, representation, edges, clock_map, dim); + collect_edges_from_location(loc, representation, edges, clock_map); } } @@ -160,10 +151,9 @@ fn collect_edges_from_location( representation: &TransitionSystemPtr, edges: &mut Vec, clock_map: &HashMap, - dim: ClockIndex, ) { - collect_specific_edges_from_location(location, representation, edges, true, clock_map, dim); - collect_specific_edges_from_location(location, representation, edges, false, clock_map, dim); + collect_specific_edges_from_location(location, representation, edges, true, clock_map); + collect_specific_edges_from_location(location, representation, edges, false, clock_map); } fn collect_specific_edges_from_location( @@ -172,7 +162,6 @@ fn collect_specific_edges_from_location( edges: &mut Vec, input: bool, clock_map: &HashMap, - dim: ClockIndex, ) { for sync in if input { representation.get_input_actions() diff --git a/src/TransitionSystems/compiled_component.rs b/src/TransitionSystems/compiled_component.rs index 2f57dc4e..ff935dc1 100644 --- a/src/TransitionSystems/compiled_component.rs +++ b/src/TransitionSystems/compiled_component.rs @@ -1,6 +1,5 @@ -use crate::EdgeEval::constraint_applyer; use crate::ModelObjects::component::{ - Component, DeclarationProvider, Declarations, LocationType, State, SyncType, Transition, + Component, DeclarationProvider, Declarations, State, Transition, }; use edbm::util::bounds::Bounds; use edbm::util::constraints::ClockIndex; @@ -16,7 +15,7 @@ type Action = String; #[derive(Clone)] struct ComponentInfo { - name: String, + //name: String, declarations: Declarations, max_bounds: Bounds, } @@ -75,7 +74,7 @@ impl CompiledComponent { initial_location, dim, comp_info: ComponentInfo { - name: component.name, + //name: component.name, declarations: component.declarations, max_bounds, }, diff --git a/src/TransitionSystems/composition.rs b/src/TransitionSystems/composition.rs index 7263bcee..7b5d466d 100644 --- a/src/TransitionSystems/composition.rs +++ b/src/TransitionSystems/composition.rs @@ -23,6 +23,7 @@ pub struct Composition { } impl Composition { + #[allow(clippy::new_ret_no_self)] pub fn new( left: TransitionSystemPtr, right: TransitionSystemPtr, @@ -79,24 +80,24 @@ impl TransitionSystem for Composition { let loc_right = location.get_right(); if self.common_actions.contains(action) { - let left = self.left.next_transitions(&loc_left, action); - let right = self.right.next_transitions(&loc_right, action); + let left = self.left.next_transitions(loc_left, action); + let right = self.right.next_transitions(loc_right, action); return Transition::combinations(&left, &right, CompositionType::Composition); } if self.left_unique_actions.contains(action) { - let left = self.left.next_transitions(&loc_left, action); + let left = self.left.next_transitions(loc_left, action); return Transition::combinations( &left, - &mut vec![Transition::new(loc_right, self.dim)], + &vec![Transition::new(loc_right, self.dim)], CompositionType::Composition, ); } if self.right_unique_actions.contains(action) { - let right = self.right.next_transitions(&loc_right, action); + let right = self.right.next_transitions(loc_right, action); return Transition::combinations( - &mut vec![Transition::new(loc_left, self.dim)], + &vec![Transition::new(loc_left, self.dim)], &right, CompositionType::Composition, ); @@ -117,8 +118,8 @@ impl TransitionSystem for Composition { for loc1 in &left { for loc2 in &right { location_tuples.push(LocationTuple::compose( - &loc1, - &loc2, + loc1, + loc2, self.get_composition_type(), )); } diff --git a/src/TransitionSystems/conjunction.rs b/src/TransitionSystems/conjunction.rs index f0b782f3..46522022 100644 --- a/src/TransitionSystems/conjunction.rs +++ b/src/TransitionSystems/conjunction.rs @@ -19,6 +19,7 @@ pub struct Conjunction { } impl Conjunction { + #[allow(clippy::new_ret_no_self)] pub fn new( left: TransitionSystemPtr, right: TransitionSystemPtr, @@ -68,8 +69,8 @@ impl TransitionSystem for Conjunction { let loc_left = location.get_left(); let loc_right = location.get_right(); - let left = self.left.next_transitions(&loc_left, action); - let right = self.right.next_transitions(&loc_right, action); + let left = self.left.next_transitions(loc_left, action); + let right = self.right.next_transitions(loc_right, action); Transition::combinations(&left, &right, CompositionType::Conjunction) } @@ -85,8 +86,8 @@ impl TransitionSystem for Conjunction { for loc1 in &left { for loc2 in &right { location_tuples.push(LocationTuple::compose( - &loc1, - &loc2, + loc1, + loc2, self.get_composition_type(), )); } diff --git a/src/TransitionSystems/location_tuple.rs b/src/TransitionSystems/location_tuple.rs index 1e2636bc..a4f675a4 100644 --- a/src/TransitionSystems/location_tuple.rs +++ b/src/TransitionSystems/location_tuple.rs @@ -33,7 +33,7 @@ impl LocationTuple { pub fn simple(location: &Location, decls: &Declarations, dim: ClockIndex) -> Self { let invariant = if let Some(inv) = location.get_invariant() { let mut fed = OwnedFederation::universe(dim); - fed = apply_constraints_to_state(&inv, decls, fed); + fed = apply_constraints_to_state(inv, decls, fed); Some(fed) } else { None @@ -122,21 +122,21 @@ impl LocationTuple { pub fn apply_invariants(&self, mut fed: OwnedFederation) -> OwnedFederation { if let Some(inv) = &self.invariant { - fed = fed.intersection(&inv); + fed = fed.intersection(inv); } fed } pub fn get_left(&self) -> &LocationTuple { if self.is_universal() || self.is_inconsistent() { - return &self; + return self; } self.left.as_ref().unwrap() } pub fn get_right(&self) -> &LocationTuple { if self.is_universal() || self.is_inconsistent() { - return &self; + return self; } self.right.as_ref().unwrap() } diff --git a/src/TransitionSystems/quotient.rs b/src/TransitionSystems/quotient.rs index 241afe0b..a3e536ba 100644 --- a/src/TransitionSystems/quotient.rs +++ b/src/TransitionSystems/quotient.rs @@ -31,6 +31,7 @@ pub struct Quotient { static INCONSISTENT_LOC_NAME: &str = "Inconsistent"; static UNIVERSAL_LOC_NAME: &str = "Universal"; impl Quotient { + #[allow(clippy::new_ret_no_self)] pub fn new( T: TransitionSystemPtr, S: TransitionSystemPtr, @@ -166,7 +167,7 @@ impl TransitionSystem for Quotient { return transitions; } else if location.is_universal() { // Rule 9 - let mut transition = Transition::new(location, self.dim); + let transition = Transition::new(location, self.dim); transitions.push(transition); return transitions; } @@ -188,8 +189,8 @@ impl TransitionSystem for Quotient { for s_transition in &s { // In the following comments we use ϕ to symbolize the guard of the transition // ϕ_T ∧ Inv(l2_t)[r |-> 0] ∧ Inv(l1_t) ∧ ϕ_S ∧ Inv(l2_s)[r |-> 0] ∧ Inv(l1_s) - let mut guard_zone = get_allowed_fed(&loc_t, t_transition) - .intersection(&get_allowed_fed(&loc_s, s_transition)); + let guard_zone = get_allowed_fed(loc_t, t_transition) + .intersection(&get_allowed_fed(loc_s, s_transition)); let target_locations = merge( &t_transition.target_locations, @@ -213,9 +214,9 @@ impl TransitionSystem for Quotient { if self.S.actions_contain(action) && !self.T.actions_contain(action) { //Independent S for s_transition in &s { - let guard_zone = get_allowed_fed(&loc_s, s_transition); + let guard_zone = get_allowed_fed(loc_s, s_transition); - let target_locations = merge(&loc_t, &s_transition.target_locations); + let target_locations = merge(loc_t, &s_transition.target_locations); let updates = s_transition.updates.clone(); transitions.push(Transition { guard_zone, @@ -230,25 +231,25 @@ impl TransitionSystem for Quotient { let mut g_s = OwnedFederation::empty(self.dim); for s_transition in &s { - let allowed_fed = get_allowed_fed(&loc_s, s_transition); + let allowed_fed = get_allowed_fed(loc_s, s_transition); g_s += allowed_fed; } // Rule 5 when Rule 3 applies - let mut inv_l_s = loc_s.apply_invariants(OwnedFederation::universe(self.dim)); + let inv_l_s = loc_s.apply_invariants(OwnedFederation::universe(self.dim)); transitions.push(Transition { guard_zone: (!inv_l_s) + (!g_s), - target_locations: universal_location.clone(), + target_locations: universal_location, updates: vec![], }); } else { // Rule 5 when Rule 3 does not apply - let mut inv_l_s = loc_s.apply_invariants(OwnedFederation::universe(self.dim)); + let inv_l_s = loc_s.apply_invariants(OwnedFederation::universe(self.dim)); transitions.push(Transition { guard_zone: !inv_l_s, - target_locations: universal_location.clone(), + target_locations: universal_location, updates: vec![], }); } @@ -260,15 +261,14 @@ impl TransitionSystem for Quotient { //Calculate inverse G_T let mut g_t = OwnedFederation::empty(self.dim); for t_transition in &t { - g_t = g_t.union(&get_allowed_fed(&loc_t, t_transition)); + g_t = g_t.union(&get_allowed_fed(loc_t, t_transition)); } let inverse_g_t = g_t.inverse(); for s_transition in &s { // In the following comments we use ϕ to symbolize the guard of the transition // ϕ_S ∧ Inv(l2_s)[r |-> 0] ∧ Inv(l1_s) ∧ ¬G_T - let mut guard_zone = - get_allowed_fed(&loc_s, s_transition).intersection(&inverse_g_t); + let guard_zone = get_allowed_fed(loc_s, s_transition).intersection(&inverse_g_t); let updates = vec![CompiledUpdate { clock_index: self.new_clock_index, @@ -296,18 +296,18 @@ impl TransitionSystem for Quotient { transitions.push(Transition { guard_zone, - target_locations: inconsistent_location.clone(), + target_locations: inconsistent_location, updates, }) } //Rule 8 if self.T.actions_contain(action) && !self.S.actions_contain(action) { for t_transition in &t { - let mut guard_zone = get_allowed_fed(&loc_t, t_transition); + let mut guard_zone = get_allowed_fed(loc_t, t_transition); guard_zone = loc_s.apply_invariants(guard_zone); - let target_locations = merge(&t_transition.target_locations, &loc_s); + let target_locations = merge(&t_transition.target_locations, loc_s); let updates = t_transition.updates.clone(); transitions.push(Transition { @@ -329,16 +329,16 @@ impl TransitionSystem for Quotient { let left = self.T.get_all_locations(); let right = self.S.get_all_locations(); - for loc_t in left { + for loc_t in &left { for loc_s in &right { - let mut location = merge(&loc_t, &loc_s); + let location = merge(loc_t, loc_s); location_tuples.push(location); } } - let mut inconsistent = + let inconsistent = LocationTuple::simple(&self.inconsistent_location, &self.decls, self.dim); - let mut universal = LocationTuple::simple(&self.universal_location, &self.decls, self.dim); + let universal = LocationTuple::simple(&self.universal_location, &self.decls, self.dim); location_tuples.push(inconsistent); location_tuples.push(universal); @@ -392,7 +392,7 @@ impl TransitionSystem for Quotient { } fn get_initial_state(&self) -> Option { - let mut init_loc = self.get_initial_location()?; + let init_loc = self.get_initial_location()?; let zone = OwnedFederation::init(self.dim); Some(State::create(init_loc, zone)) } diff --git a/src/tests/ModelObjects/arith_expression.rs b/src/tests/ModelObjects/arith_expression.rs index 21b40545..26fb9c79 100644 --- a/src/tests/ModelObjects/arith_expression.rs +++ b/src/tests/ModelObjects/arith_expression.rs @@ -1,26 +1,26 @@ #[cfg(test)] -mod arith_expression { - use crate::ModelObjects::representations::{ArithExpression as AE, ArithExpression}; +mod test { + use crate::ModelObjects::representations::ArithExpression as AE; use AE::*; #[test] fn simplify_test1() { - let mut expr = AE::ADif(Int(10), Int(5)); //10 - 5 + let expr = AE::ADif(Int(10), Int(5)); //10 - 5 assert_eq!(Ok(Int(5)), expr.simplify()); - let mut expr = AE::AAdd(Int(10), Int(5)); //10 + 5 + let expr = AE::AAdd(Int(10), Int(5)); //10 + 5 assert_eq!(Ok(Int(15)), expr.simplify()); } #[test] fn simplify_test2() { - let mut expr = Multiplication( + let expr = Multiplication( //(10 - 5) * (5 + 3) Box::new(AE::ADif(Int(10), Int(5))), Box::new(AE::AAdd(Int(5), Int(3))), ); assert_eq!(Ok(Int(40)), expr.simplify()); - let mut expr = Multiplication( + let expr = Multiplication( //(10 + 5) * (5 - 3) Box::new(AE::AAdd(Int(10), Int(5))), Box::new(AE::ADif(Int(5), Int(3))), @@ -29,13 +29,13 @@ mod arith_expression { } #[test] fn simplify_test3() { - let mut expr = AE::ADif( + let expr = AE::ADif( Clock(1), AE::ADif(Int(5), AE::ADif(Int(4), AE::ADif(Int(3), Int(2)))), //5-(4-(3-2)) ); assert_eq!(Ok(AE::ADif(Clock(1), Int(2))), expr.simplify()); - let mut expr = AE::AAdd( + let expr = AE::AAdd( Clock(1), AE::AAdd(Int(5), AE::AAdd(Int(4), AE::AAdd(Int(3), Int(2)))), ); @@ -44,13 +44,13 @@ mod arith_expression { #[test] fn simplify_test4() { //((5-4)-3)-2 - let mut expr = AE::ADif( + let expr = AE::ADif( Clock(1), AE::ADif(AE::ADif(AE::ADif(Int(5), Int(4)), Int(3)), Int(2)), ); assert_eq!(Ok(AE::ADif(Clock(1), Int(-4))), expr.simplify()); - let mut expr = AE::AAdd( + let expr = AE::AAdd( Clock(1), AE::AAdd(AE::AAdd(AE::AAdd(Int(5), Int(4)), Int(3)), Int(2)), ); @@ -60,33 +60,33 @@ mod arith_expression { #[test] fn simplify_test5() { //((5-4)-3)-2 - let mut expr = AE::ADif(AE::ADif(AE::ADif(Int(5), Clock(4)), Int(3)), Int(2)); + let expr = AE::ADif(AE::ADif(AE::ADif(Int(5), Clock(4)), Int(3)), Int(2)); assert_eq!(Ok(AE::ADif(Int(0), Clock(4))), expr.simplify()); - let mut expr = AE::AAdd(AE::AAdd(AE::AAdd(Int(5), Clock(4)), Int(3)), Int(2)); + let expr = AE::AAdd(AE::AAdd(AE::AAdd(Int(5), Clock(4)), Int(3)), Int(2)); assert_eq!(Ok(AE::AAdd(Int(10), Clock(4))), expr.simplify()); } #[test] fn simplify_test6() { //5-(4-(3-2)) - let mut expr = AE::ADif(Int(5), AE::ADif(Int(4), AE::ADif(Int(3), Clock(2)))); + let expr = AE::ADif(Int(5), AE::ADif(Int(4), AE::ADif(Int(3), Clock(2)))); assert_eq!(Ok(AE::ADif(Int(4), Clock(2))), expr.simplify()); - let mut expr = AE::AAdd(Int(5), AE::AAdd(Int(4), AE::AAdd(Int(3), Clock(2)))); + let expr = AE::AAdd(Int(5), AE::AAdd(Int(4), AE::AAdd(Int(3), Clock(2)))); assert_eq!(Ok(AE::AAdd(Int(12), Clock(2))), expr.simplify()); } #[test] fn simplify_test7() { //5-(4-(3-2)) - let mut expr = AE::ADif( + let expr = AE::ADif( Int(5), AE::ADif(Clock(4), AE::ADif(Int(3), AE::ADif(Int(2), Int(1)))), ); assert_eq!(Ok(AE::ADif(Clock(4), Int(3))), expr.simplify()); - let mut expr = AE::AAdd( + let expr = AE::AAdd( Int(5), AE::AAdd(Clock(4), AE::AAdd(Int(3), AE::AAdd(Int(2), Int(1)))), ); @@ -95,34 +95,34 @@ mod arith_expression { #[test] fn simplify_test_highoperators_ints() { - let mut expr = AE::AMul(Int(10), Int(5)); + let expr = AE::AMul(Int(10), Int(5)); assert_eq!(Ok(Int(50)), expr.simplify()); - let mut expr = AE::ADiv(Int(10), Int(5)); + let expr = AE::ADiv(Int(10), Int(5)); assert_eq!(Ok(Int(2)), expr.simplify()); - let mut expr = AE::AMod(Int(10), Int(5)); + let expr = AE::AMod(Int(10), Int(5)); assert_eq!(Ok(Int(0)), expr.simplify()); } #[test] fn simplify_test_highoperators_clocks() { - let mut expr = AE::AMul(Clock(10), Int(5)); + let expr = AE::AMul(Clock(10), Int(5)); assert_eq!(expr.simplify().ok(), None); - let mut expr = AE::AMul(Int(10), Clock(5)); + let expr = AE::AMul(Int(10), Clock(5)); assert_eq!(expr.simplify().ok(), None); - let mut expr = AE::ADiv(Clock(10), Int(5)); + let expr = AE::ADiv(Clock(10), Int(5)); assert_eq!(expr.simplify().ok(), None); - let mut expr = AE::ADiv(Int(10), Clock(5)); + let expr = AE::ADiv(Int(10), Clock(5)); assert_eq!(expr.simplify().ok(), None); - let mut expr = AE::AMod(Clock(10), Int(5)); + let expr = AE::AMod(Clock(10), Int(5)); assert_eq!(expr.simplify().ok(), None); - let mut expr = AE::AMod(Int(10), Clock(5)); + let expr = AE::AMod(Int(10), Clock(5)); assert_eq!(expr.simplify().ok(), None); } } diff --git a/src/tests/ModelObjects/bool_expression.rs b/src/tests/ModelObjects/bool_expression.rs index d6a5cc06..8b11e89d 100644 --- a/src/tests/ModelObjects/bool_expression.rs +++ b/src/tests/ModelObjects/bool_expression.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod bool_expression { +mod test { use crate::ModelObjects::representations::ArithExpression as AE; use crate::ModelObjects::representations::BoolExpression as BE; use AE::Int; diff --git a/src/tests/grpc/send_query.rs b/src/tests/grpc/send_query.rs index 25d9ea2c..34b7a263 100644 --- a/src/tests/grpc/send_query.rs +++ b/src/tests/grpc/send_query.rs @@ -7,7 +7,7 @@ mod refinements { use crate::ProtobufServer::ConcreteEcdarBackend; use tonic::Request; - static CONJUN: &str = "samples/xml/conjun.xml"; + //static CONJUN: &str = "samples/xml/conjun.xml"; static ECDAR_UNI: &str = "samples/json/EcdarUniversity"; #[tokio::test] @@ -80,10 +80,10 @@ mod refinements { if let Some(result) = query_result.result { match result { query_response::Result::Refinement(refine) => assert!(refine.success), - _ => assert!(false), + _ => panic!(), } } else { - assert!(false); + panic!(); } } @@ -117,10 +117,10 @@ mod refinements { if let Some(result) = query_result.result { match result { query_response::Result::Consistency(consistent) => assert!(consistent.success), - _ => assert!(false), + _ => panic!(), } } else { - assert!(false); + panic!(); } } @@ -154,10 +154,10 @@ mod refinements { if let Some(result) = query_result.result { match result { query_response::Result::Determinism(determinsm) => assert!(determinsm.success), - _ => assert!(false), + _ => panic!(), } } else { - assert!(false); + panic!(); } } } diff --git a/src/tests/grpc/update_components.rs b/src/tests/grpc/update_components.rs index 2cbd9d7b..30a40b1b 100644 --- a/src/tests/grpc/update_components.rs +++ b/src/tests/grpc/update_components.rs @@ -2,8 +2,8 @@ mod refinements { use crate::ProtobufServer::services::component::Rep; use crate::ProtobufServer::services::ecdar_backend_server::EcdarBackend; - use crate::ProtobufServer::services::query_response; - use crate::ProtobufServer::services::{Component, ComponentsUpdateRequest, Query}; + + use crate::ProtobufServer::services::{Component, ComponentsUpdateRequest}; use crate::ProtobufServer::ConcreteEcdarBackend; use tonic::Request; diff --git a/src/tests/refinement/AG_Tests.rs b/src/tests/refinement/AG_Tests.rs index 4c7c94bd..63a6869e 100644 --- a/src/tests/refinement/AG_Tests.rs +++ b/src/tests/refinement/AG_Tests.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod AG_Tests { +mod test { use crate::tests::refinement::Helper::json_refinement_check; static PATH: &str = "samples/json/AG"; diff --git a/src/tests/refinement/Big_Refinement.rs b/src/tests/refinement/Big_Refinement.rs index e22f3342..218d3ad3 100644 --- a/src/tests/refinement/Big_Refinement.rs +++ b/src/tests/refinement/Big_Refinement.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod Big_refinement { +mod test { use crate::tests::refinement::Helper::json_refinement_check; static PATH: &str = "samples/json/BigRefinement"; diff --git a/src/tests/refinement/Conjunction_refinement.rs b/src/tests/refinement/Conjunction_refinement.rs index f6c06c36..7985fd43 100644 --- a/src/tests/refinement/Conjunction_refinement.rs +++ b/src/tests/refinement/Conjunction_refinement.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod Conjunction_refinement { +mod test { use crate::tests::refinement::Helper::json_refinement_check; static PATH: &str = "samples/json/Conjunction"; diff --git a/src/tests/refinement/Helper.rs b/src/tests/refinement/Helper.rs index 42554a8c..b2d69390 100644 --- a/src/tests/refinement/Helper.rs +++ b/src/tests/refinement/Helper.rs @@ -7,7 +7,7 @@ use crate::System::extract_system_rep::create_executable_query; pub fn xml_refinement_check(PATH: &str, QUERY: &str) -> bool { match xml_run_query(PATH, QUERY) { QueryResult::Refinement(result) => result, - QueryResult::Error(err) => panic!(err), + QueryResult::Error(err) => panic!("{}", err), _ => panic!("Not a refinement check"), } } @@ -15,7 +15,7 @@ pub fn xml_refinement_check(PATH: &str, QUERY: &str) -> bool { pub fn json_refinement_check(PATH: &str, QUERY: &str) -> bool { match json_run_query(PATH, QUERY) { QueryResult::Refinement(result) => result, - QueryResult::Error(err) => panic!(err), + QueryResult::Error(err) => panic!("{}", err), _ => panic!("Not a refinement check"), } } diff --git a/src/tests/refinement/Refinement_delay_add.rs b/src/tests/refinement/Refinement_delay_add.rs index 66a41883..d26ef6a3 100644 --- a/src/tests/refinement/Refinement_delay_add.rs +++ b/src/tests/refinement/Refinement_delay_add.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod Refinement_delay_add { +mod test { use crate::tests::refinement::Helper::json_refinement_check; static PATH: &str = "samples/json/DelayAdd"; diff --git a/src/tests/refinement/Refinement_university.rs b/src/tests/refinement/Refinement_university.rs index 9a5a8cfc..f326b5b3 100644 --- a/src/tests/refinement/Refinement_university.rs +++ b/src/tests/refinement/Refinement_university.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod Refinement_university { +mod test { use crate::tests::refinement::Helper::json_refinement_check; static PATH: &str = "samples/json/EcdarUniversity"; diff --git a/src/tests/refinement/Refinement_unspec.rs b/src/tests/refinement/Refinement_unspec.rs index 254e32b3..6dead22a 100644 --- a/src/tests/refinement/Refinement_unspec.rs +++ b/src/tests/refinement/Refinement_unspec.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod Refinement_unspec { +mod test { use crate::tests::refinement::Helper::json_refinement_check; static PATH: &str = "samples/json/Unspec"; diff --git a/src/tests/refinement/xml/conjunction_tests.rs b/src/tests/refinement/xml/conjunction_tests.rs index 953f8d7b..461b4d2b 100644 --- a/src/tests/refinement/xml/conjunction_tests.rs +++ b/src/tests/refinement/xml/conjunction_tests.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod conjunction_tests { +mod test { use crate::tests::refinement::Helper::xml_refinement_check; static PATH: &str = "samples/xml/conjun.xml"; diff --git a/src/tests/refinement/xml/consistency_tests.rs b/src/tests/refinement/xml/consistency_tests.rs index a48a0d69..8d8d1964 100644 --- a/src/tests/refinement/xml/consistency_tests.rs +++ b/src/tests/refinement/xml/consistency_tests.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod consistency_tests { +mod test { use crate::tests::refinement::Helper::xml_run_query; use crate::System::executable_query::QueryResult; diff --git a/src/tests/refinement/xml/delay_refinement.rs b/src/tests/refinement/xml/delay_refinement.rs index 3ba85fc5..c86a4aa3 100644 --- a/src/tests/refinement/xml/delay_refinement.rs +++ b/src/tests/refinement/xml/delay_refinement.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod delay_refinement { +mod test { use crate::tests::refinement::Helper::xml_refinement_check; static PATH: &str = "samples/xml/delayRefinement.xml"; diff --git a/src/tests/refinement/xml/determinism_tests.rs b/src/tests/refinement/xml/determinism_tests.rs index 180ad7b7..a6920d86 100644 --- a/src/tests/refinement/xml/determinism_tests.rs +++ b/src/tests/refinement/xml/determinism_tests.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod determinism_tests { +mod test { use crate::tests::refinement::Helper::xml_run_query; use crate::System::executable_query::QueryResult; diff --git a/src/tests/refinement/xml/extrapolation_tests.rs b/src/tests/refinement/xml/extrapolation_tests.rs index 134ce822..dfa6b908 100644 --- a/src/tests/refinement/xml/extrapolation_tests.rs +++ b/src/tests/refinement/xml/extrapolation_tests.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod extrapolation_tests { +mod test { use crate::tests::refinement::Helper::xml_refinement_check; static PATH: &str = "samples/xml/extrapolation_test.xml"; @@ -7,9 +7,6 @@ mod extrapolation_tests { // Self Refinements #[test] fn InfRefinesInf() { - assert!(xml_refinement_check( - PATH, - "refinement: Inf <= Inf" - )); + assert!(xml_refinement_check(PATH, "refinement: Inf <= Inf")); } -} \ No newline at end of file +} diff --git a/src/tests/refinement/xml/misc_tests.rs b/src/tests/refinement/xml/misc_tests.rs index 6d7106c8..ab6d1738 100644 --- a/src/tests/refinement/xml/misc_tests.rs +++ b/src/tests/refinement/xml/misc_tests.rs @@ -1,5 +1,5 @@ #[cfg(test)] -mod misc_tests { +mod test { use crate::tests::refinement::Helper::xml_refinement_check; static PATH: &str = "samples/xml/misc_test.xml"; diff --git a/src/tests/save_component/composition_tests.rs b/src/tests/save_component/composition_tests.rs index 60e8be23..a18080bd 100644 --- a/src/tests/save_component/composition_tests.rs +++ b/src/tests/save_component/composition_tests.rs @@ -1,8 +1,8 @@ #[cfg(test)] -mod composition_tests { - use crate::tests::save_component::save_comp_helper::save_comp_helper::json_reconstructed_component_refines_base_self; +mod test { + use crate::tests::save_component::save_comp_helper::util::json_reconstructed_component_refines_base_self; - static PATH: &str = "samples/json/Conjunction"; + //static PATH: &str = "samples/json/Conjunction"; static ECDAR_UNI: &str = "samples/json/EcdarUniversity"; #[test] diff --git a/src/tests/save_component/conjunction_tests.rs b/src/tests/save_component/conjunction_tests.rs index 81cebcb9..7f1f5d54 100644 --- a/src/tests/save_component/conjunction_tests.rs +++ b/src/tests/save_component/conjunction_tests.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod Conjunction_tests { - use crate::tests::save_component::save_comp_helper::save_comp_helper::json_reconstructed_component_refines_base_self; + use crate::tests::save_component::save_comp_helper::util::json_reconstructed_component_refines_base_self; static PATH: &str = "samples/json/Conjunction"; static ECDAR_UNI: &str = "samples/json/EcdarUniversity"; diff --git a/src/tests/save_component/no_operation_tests.rs b/src/tests/save_component/no_operation_tests.rs index b599177f..57253c19 100644 --- a/src/tests/save_component/no_operation_tests.rs +++ b/src/tests/save_component/no_operation_tests.rs @@ -1,6 +1,6 @@ #[cfg(test)] -mod no_operation_tests { - use crate::tests::save_component::save_comp_helper::save_comp_helper::json_reconstructed_component_refines_base_self; +mod test { + use crate::tests::save_component::save_comp_helper::util::json_reconstructed_component_refines_base_self; static PATH: &str = "samples/json/Conjunction"; static ECDAR_UNI: &str = "samples/json/EcdarUniversity"; diff --git a/src/tests/save_component/save_comp_helper.rs b/src/tests/save_component/save_comp_helper.rs index 99b2ba1e..883fd402 100644 --- a/src/tests/save_component/save_comp_helper.rs +++ b/src/tests/save_component/save_comp_helper.rs @@ -1,22 +1,17 @@ #[cfg(test)] -pub mod save_comp_helper { +pub mod util { use crate::DataReader::component_loader::JsonProjectLoader; use crate::DataReader::parse_queries; - use crate::ModelObjects::component::DeclarationProvider; use crate::ModelObjects::representations::QueryExpression; use crate::System::extract_system_rep; use crate::System::extract_system_rep::SystemRecipe; - use crate::System::input_enabler; use crate::System::refine; use crate::System::save_component::combine_components; use crate::System::save_component::PruningStrategy; - use crate::TransitionSystems::CompiledComponent; - use crate::TransitionSystems::TransitionSystem; use edbm::util::constraints::ClockIndex; pub fn json_reconstructed_component_refines_base_self(input_path: &str, system: &str) { let project_loader = JsonProjectLoader::new(String::from(input_path)); - let mut decl = project_loader.get_declarations().clone(); //This query is not executed but simply used to extract an UncachedSystem so the tests can just give system expressions let str_query = format!("get-component: {} save-as test", system); @@ -35,7 +30,7 @@ pub mod save_comp_helper { let new_comp = new_system.compile(dim); - if let Err(_) = new_comp { + if new_comp.is_err() { return; } let new_comp = combine_components(&new_comp.unwrap(), PruningStrategy::NoPruning); From ba75b04ea97c18609a76ca7c284cc1a273bd903c Mon Sep 17 00:00:00 2001 From: Sebastian Lund Date: Thu, 1 Sep 2022 20:49:09 +0200 Subject: [PATCH 4/8] Temporarily use GitHub version of edbm until we are on crates.io --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a5d92c0a..98fc85e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,8 +32,7 @@ simple-error = "0.2.3" force_graph = "0.3.2" rand = "0.8.5" futures = "0.3.21" -# edbm = {git = "https://github.com/Ecdar/EDBM"} -edbm = {path = "../EDBM"} +edbm = {git = "https://github.com/Ecdar/EDBM"} # Enable optimizations for EDBM in debug mode, but not for our code: From 5b89ce55e30573a335882e807ff1c794b72649ef Mon Sep 17 00:00:00 2001 From: Sebastian Lund Date: Thu, 1 Sep 2022 21:09:17 +0200 Subject: [PATCH 5/8] Attempt to fix CI (UDBM no longer exists) --- .github/workflows/build_artifacts.yaml | 22 ++++------------------ .github/workflows/ci.yaml | 12 ++---------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build_artifacts.yaml b/.github/workflows/build_artifacts.yaml index 76e9aa7e..3f8629db 100644 --- a/.github/workflows/build_artifacts.yaml +++ b/.github/workflows/build_artifacts.yaml @@ -14,15 +14,8 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'true' - - name: Install compiler tools - run: | - sudo apt-get update - sudo apt-get install llvm automake libxml2-dev gperf build-essential libboost-all-dev cmake make protobuf-compiler - - name: Compile UDBM wrapper - run: | - cd dbm - cmake -B build/ - cmake --build build/ + - name: Install llvm-config + run: sudo apt-get install llvm protobuf-compiler - uses: actions-rs/toolchain@v1 with: profile: minimal @@ -45,15 +38,8 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'true' - - name: Install compiler tools - run: | - sudo apt-get update - sudo apt-get install llvm automake libxml2-dev gperf build-essential libboost-all-dev cmake make protobuf-compiler mingw-w64 - - name: Compile UDBM wrapper - run: | - cd dbm - cmake -B build/ -D CMAKE_TOOLCHAIN_FILE=toolchain-x86_64-w64-mingw32.cmake - cmake --build build/ + - name: Install llvm-config + run: sudo apt-get install llvm protobuf-compiler - uses: actions-rs/toolchain@v1 with: profile: minimal diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index adbd2230..60019ec5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,15 +11,8 @@ jobs: - uses: actions/checkout@v2 with: submodules: 'true' - - name: Install compiler tools - run: | - sudo apt-get update - sudo apt-get install llvm automake libxml2-dev gperf build-essential libboost-all-dev cmake make protobuf-compiler - - name: Compile UDBM wrapper - run: | - cd dbm - cmake -B build/ - cmake --build build/ + - name: Install llvm-config + run: sudo apt-get install llvm protobuf-compiler - uses: actions-rs/toolchain@v1 with: profile: minimal @@ -28,7 +21,6 @@ jobs: - uses: actions-rs/cargo@v1 with: command: test - args: -- --skip "DBMLib::lib_dbm::UDBM::bindgen_test_layout_dbm_idbm_t" fmt: name: Check code is formatted runs-on: ubuntu-latest From 962ca58920ee8f3eb42e9563fae671717040eec0 Mon Sep 17 00:00:00 2001 From: Sebastian Lund Date: Thu, 1 Sep 2022 21:15:12 +0200 Subject: [PATCH 6/8] Add back mingw to CI windows build dependencies --- .github/workflows/build_artifacts.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_artifacts.yaml b/.github/workflows/build_artifacts.yaml index 3f8629db..0f868976 100644 --- a/.github/workflows/build_artifacts.yaml +++ b/.github/workflows/build_artifacts.yaml @@ -39,7 +39,7 @@ jobs: with: submodules: 'true' - name: Install llvm-config - run: sudo apt-get install llvm protobuf-compiler + run: sudo apt-get install llvm protobuf-compiler mingw-w64 - uses: actions-rs/toolchain@v1 with: profile: minimal From d444f655b8a1a40120625c2701dfaaeda99228cf Mon Sep 17 00:00:00 2001 From: Sebastian Lund Date: Mon, 5 Sep 2022 15:32:02 +0200 Subject: [PATCH 7/8] Have quotients share the same clock and ensure that the (upper) bound is set for that clock to 0 (the bound must be set otherwise the logic is wrong) --- src/System/extract_system_rep.rs | 47 +++++++++++++------- src/TransitionSystems/quotient.rs | 17 ++++--- src/tests/save_component/save_comp_helper.rs | 14 +++++- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/System/extract_system_rep.rs b/src/System/extract_system_rep.rs index b1b2a459..74860e9c 100644 --- a/src/System/extract_system_rep.rs +++ b/src/System/extract_system_rep.rs @@ -28,8 +28,9 @@ pub fn create_executable_query<'a>( if let Some(query) = full_query.get_query() { match query { QueryExpression::Refinement(left_side, right_side) => { - let left = get_system_recipe(left_side, component_loader, &mut dim); - let right =get_system_recipe(right_side, component_loader, &mut dim); + let mut quotient_index = None; + let left = get_system_recipe(left_side, component_loader, &mut dim, &mut quotient_index); + let right =get_system_recipe(right_side, component_loader, &mut dim, &mut quotient_index); Ok(Box::new(RefinementExecutor { sys1: left.compile(dim)?, sys2: right.compile(dim)?, @@ -39,6 +40,7 @@ pub fn create_executable_query<'a>( query_expression, component_loader, &mut dim, + &mut None ), dim })), @@ -47,13 +49,14 @@ pub fn create_executable_query<'a>( query_expression, component_loader, &mut dim, + &mut None ).compile(dim)?, })), QueryExpression::GetComponent(save_as_expression) => { if let QueryExpression::SaveAs(query_expression, comp_name) = save_as_expression.as_ref() { Ok(Box::new( GetComponentExecutor { - system: get_system_recipe(query_expression, component_loader, &mut dim).compile(dim)?, + system: get_system_recipe(query_expression, component_loader, &mut dim, &mut None).compile(dim)?, comp_name: comp_name.clone(), component_loader, } @@ -67,7 +70,7 @@ pub fn create_executable_query<'a>( if let QueryExpression::SaveAs(query_expression, comp_name) = save_as_expression.as_ref() { Ok(Box::new( GetComponentExecutor { - system: pruning::prune_system(get_system_recipe(query_expression, component_loader, &mut dim).compile(dim)?, dim), + system: pruning::prune_system(get_system_recipe(query_expression, component_loader, &mut dim, &mut None).compile(dim)?, dim), comp_name: comp_name.clone(), component_loader } @@ -120,26 +123,36 @@ pub fn get_system_recipe( side: &QueryExpression, component_loader: &mut dyn ComponentLoader, clock_index: &mut ClockIndex, + quotient_index: &mut Option, ) -> Box { match side { QueryExpression::Parentheses(expression) => { - get_system_recipe(expression, component_loader, clock_index) + get_system_recipe(expression, component_loader, clock_index, quotient_index) } QueryExpression::Composition(left, right) => Box::new(SystemRecipe::Composition( - get_system_recipe(left, component_loader, clock_index), - get_system_recipe(right, component_loader, clock_index), + get_system_recipe(left, component_loader, clock_index, quotient_index), + get_system_recipe(right, component_loader, clock_index, quotient_index), )), QueryExpression::Conjunction(left, right) => Box::new(SystemRecipe::Conjunction( - get_system_recipe(left, component_loader, clock_index), - get_system_recipe(right, component_loader, clock_index), + get_system_recipe(left, component_loader, clock_index, quotient_index), + get_system_recipe(right, component_loader, clock_index, quotient_index), )), QueryExpression::Quotient(left, right) => { - let left = get_system_recipe(left, component_loader, clock_index); - let right = get_system_recipe(right, component_loader, clock_index); - *clock_index += 1; - let quotient = Box::new(SystemRecipe::Quotient(left, right, *clock_index)); - println!("Quotient clock index: {}", *clock_index); - quotient + let left = get_system_recipe(left, component_loader, clock_index, quotient_index); + let right = get_system_recipe(right, component_loader, clock_index, quotient_index); + + let q_index = match quotient_index { + Some(q_i) => *q_i, + None => { + *clock_index += 1; + println!("Quotient clock index: {}", *clock_index); + + quotient_index.replace(*clock_index); + quotient_index.unwrap() + } + }; + + Box::new(SystemRecipe::Quotient(left, right, q_index)) } QueryExpression::VarName(name) => { let mut component = component_loader.get_component(name).clone(); @@ -148,7 +161,9 @@ pub fn get_system_recipe( Box::new(SystemRecipe::Component(Box::new(component))) } - QueryExpression::SaveAs(comp, _) => get_system_recipe(comp, component_loader, clock_index), + QueryExpression::SaveAs(comp, _) => { + get_system_recipe(comp, component_loader, clock_index, &mut None) + } _ => panic!("Got unexpected query side: {:?}", side), } } diff --git a/src/TransitionSystems/quotient.rs b/src/TransitionSystems/quotient.rs index a3e536ba..ad666c77 100644 --- a/src/TransitionSystems/quotient.rs +++ b/src/TransitionSystems/quotient.rs @@ -22,7 +22,7 @@ pub struct Quotient { universal_location: Location, inconsistent_location: Location, decls: Declarations, - new_clock_index: ClockIndex, + quotient_clock_index: ClockIndex, new_input_name: String, dim: ClockIndex, @@ -126,7 +126,7 @@ impl Quotient { universal_location, inconsistent_location, decls, - new_clock_index, + quotient_clock_index: new_clock_index, new_input_name, dim, }); @@ -137,7 +137,9 @@ impl Quotient { impl TransitionSystem for Quotient { fn get_local_max_bounds(&self, loc: &LocationTuple) -> Bounds { if loc.is_universal() || loc.is_inconsistent() { - Bounds::new(self.get_dim()) + let mut b = Bounds::new(self.get_dim()); + b.add_upper(self.quotient_clock_index, 0); + b } else { let (left, right) = self.get_children(); let loc_l = loc.get_left(); @@ -145,6 +147,7 @@ impl TransitionSystem for Quotient { let mut bounds_l = left.get_local_max_bounds(loc_l); let bounds_r = right.get_local_max_bounds(loc_r); bounds_l.add_bounds(&bounds_r); + bounds_l.add_upper(self.quotient_clock_index, 0); bounds_l } } @@ -161,7 +164,9 @@ impl TransitionSystem for Quotient { //Rule 10 if is_input { let mut transition = Transition::new(location, self.dim); - transition.guard_zone = transition.guard_zone.constrain_eq(self.new_clock_index, 0); + transition.guard_zone = transition + .guard_zone + .constrain_eq(self.quotient_clock_index, 0); transitions.push(transition); } return transitions; @@ -271,7 +276,7 @@ impl TransitionSystem for Quotient { let guard_zone = get_allowed_fed(loc_s, s_transition).intersection(&inverse_g_t); let updates = vec![CompiledUpdate { - clock_index: self.new_clock_index, + clock_index: self.quotient_clock_index, value: 0, }]; @@ -290,7 +295,7 @@ impl TransitionSystem for Quotient { let guard_zone = inverse_t_invariant.intersection(&s_invariant); let updates = vec![CompiledUpdate { - clock_index: self.new_clock_index, + clock_index: self.quotient_clock_index, value: 0, }]; diff --git a/src/tests/save_component/save_comp_helper.rs b/src/tests/save_component/save_comp_helper.rs index 883fd402..edc0174b 100644 --- a/src/tests/save_component/save_comp_helper.rs +++ b/src/tests/save_component/save_comp_helper.rs @@ -21,8 +21,18 @@ pub mod util { let (base_system, new_system) = if let QueryExpression::GetComponent(expr) = &query { let mut comp_loader = project_loader.to_comp_loader(); ( - extract_system_rep::get_system_recipe(expr.as_ref(), &mut *comp_loader, &mut dim), - extract_system_rep::get_system_recipe(expr.as_ref(), &mut *comp_loader, &mut dim), + extract_system_rep::get_system_recipe( + expr.as_ref(), + &mut *comp_loader, + &mut dim, + &mut None, + ), + extract_system_rep::get_system_recipe( + expr.as_ref(), + &mut *comp_loader, + &mut dim, + &mut None, + ), ) } else { panic!("Failed to create system") From 4fb177558f5a84e9f0d81cde5126e5d3b919f3cc Mon Sep 17 00:00:00 2001 From: Sebastian Lund Date: Mon, 5 Sep 2022 15:48:21 +0200 Subject: [PATCH 8/8] Fix build_state_pair bug from changing code to EDBM that caused some not-refines checks to fail in test framwork --- src/System/refine.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/System/refine.rs b/src/System/refine.rs index f2f0a995..9ef35601 100644 --- a/src/System/refine.rs +++ b/src/System/refine.rs @@ -384,17 +384,19 @@ fn build_state_pair( new_sp_zone = left_loc.apply_invariants(new_sp_zone); - // Apply right side invariants on a copy of the zone - let s_invariant = right_loc.apply_invariants(new_sp_zone.clone()); - // Maybe apply inv_t, then up, then inv_s? + // Clone the zone before applying right side invariants + let s_invariant = new_sp_zone.clone(); + + // Apply right side invariants on the zone + new_sp_zone = right_loc.apply_invariants(new_sp_zone); // Continue to the next transition pair if the newly built zones are empty if new_sp_zone.is_empty() || s_invariant.is_empty() { return BuildResult::Success; } - let t_invariant = new_sp_zone.clone().down(); // inv_s = x<10, inv_t = x>2 -> t cuts solutions but not delays, so it is fine and we can call down: + let t_invariant = new_sp_zone.clone().down(); // Check if the invariant of T (right) cuts delay solutions from S (left) and if so, report failure if !(s_invariant.subset_eq(&t_invariant)) {