diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78376445..262dde8e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,17 +18,17 @@ jobs: - os: macos-latest artifact: macos name: MacOSX - inklecate_url: https://github.com/inkle/ink/releases/download/0.9.0/inklecate_mac.zip + inklecate_url: https://github.com/inkle/ink/releases/download/v1.1.1/inklecate_mac.zip proof: false - os: windows-latest artifact: win64 name: Windows x64 - inklecate_url: https://github.com/inkle/ink/releases/download/v1.0.0/inklecate_windows.zip + inklecate_url: https://github.com/inkle/ink/releases/download/v1.1.1/inklecate_windows.zip proof: false - os: "ubuntu-20.04" artifact: linux name: Linux x64 - inklecate_url: https://github.com/inkle/ink/releases/download/v1.0.0/inklecate_linux.zip + inklecate_url: https://github.com/inkle/ink/releases/download/v1.1.1/inklecate_linux.zip proof: true steps: diff --git a/CMakeLists.txt b/CMakeLists.txt index 59541441..6740f81b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ enable_testing() # Project setup project(inkcpp VERSION 0.1) -SET(CMAKE_CXX_STANDARD 17) +SET(CMAKE_CXX_STANDARD 20) SET(CMAKE_CXX_STANDARD_REQUIRED ON) SET(CMAKE_INSTALL_LIBRARY_DIR lib) SET(CMAKE_INSTALL_INCLUDE_DIR include) @@ -18,7 +18,6 @@ add_subdirectory(inkcpp_test) add_subdirectory(unreal) -get_target_property(TEE inkcpp PUBLIC_HEADER) install(TARGETS inkcpp inkcpp_compiler inkcpp_shared EXPORT inkcppTarget ARCHIVE DESTINATION "lib/ink" @@ -57,3 +56,11 @@ set(CPACK_GENERATOR "ZIP") set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) set(CPACK_COMPONENTS_GROUPING IGNORE) include(CPack) + +find_package(Doxygen) +if (DOXYGEN_FOUND) + set(DOXYGEN_PROJECT_NAME ${PROJECT_NAME}) + doxygen_add_docs(doc ${PROJECT_SOURCE_DIR} COMMENT "Generate docs") +else(DOXYGEN_FOUND) + message("Doxygen needed to generate documntation!") +endif(DOXYGEN_FOUND) diff --git a/README.md b/README.md index 35195eaa..ad56a22d 100644 --- a/README.md +++ b/README.md @@ -49,25 +49,16 @@ thread->choose(0); ``` ## Current Status -Run `inkcpp_cl.exe -p myfile.json` to execute a compiled Ink JSON file in play mode. It can also operate on `.ink` files but `inklecate.exe` must me in the same folder or in the PATH. + +Run `inkcpp_cl.exe -p myfile.json` to execute a compiled Ink JSON file in play mode. It can also operate on `.ink` files but `inklecate.exe` must be in the same folder or in the PATH. +`inklecate` can be downloaded from the official [release page](https://github.com/inkle/ink/releases) and will be downloaded from CMake at configure time (located at `build/unreal/inkcpp/Resources/inklecate`). Without the `-p` flag, it'll just compile the JSON/Ink file into InkCPP's binary format (see the Wiki on GitHub). -Many, but not all features of the Ink language are supported (see Glaring Omissions below), but be warned, this runtime is still highly unstable. I am currently working on getting it to pass all the unit tests on [ink-proof](https://github.com/chromy/ink-proof). - -* Temporary and global variables -* Int, String, or Divert values -* Eval stack (`ev`, `/ev`), String stack (`str`, `/str`) -* Choices (support for both `*` and `+` and conditional choices) -* Diverts (variable and fixed, conditional and normal) -* All mathematical operators (`+`, `<=`, etc.). String equality not supported. -* Glue -* Visit and read counts (`visits` and `CNT?` commands). -* `seq` command and all sequence types (stopping, cycle, shuffle) -* Global store that can be shared between runners -* External function binding (no fallback support yet) -* Tunnels and internal functions -* Ink threads (probably incredibly unstable though) +All features of ink 1.1 are supported, and checked with [ink-proof](https://github.com/chromy/ink-proof). + +Big features missing compared to the `C#` implementation are: +* stable Ink Thread support ## Configuring and Building (CMake) @@ -79,6 +70,8 @@ To configure the project... CMake will then generate the necessary build files for your environment. By default, it generates Visual Studio projects and solutions on Windows and Makefiles on Mac and Linux. You can change this using CMake's command line options (see `cmake --help`). It supports pretty much anything. +The documentation can be build iff Doxygen is installed with `cmake --build . --target doc`. The documentation can then be found in at `html/index.html`. + To build, either run the generated buildfiles OR you can use `cmake --build . --config ` from the build folder to automatically execute the relevant toolchain. For a more in depth installation description please checkout the (wiki)[https://github.com/brwarner/inkcpp/wiki/building]. @@ -130,15 +123,6 @@ Code for the Unreal plugin is located in the `unreal` directory. In order to ins I am currently working toward a 1.0 release. You can track my progress here: https://github.com/brwarner/inkcpp/projects/1 -### Glaring Omissions - -The big things we're missing right now are: - -* Fallback functions for externals. -* Variable observers -* Lists and whatever cool, crazy stuff Ink has been adding recently. -* Robust tests using ink-proof. - ## Dependencies The compiler depends on Nlohmann's JSON library and the C++ STL. diff --git a/inkcpp/CMakeLists.txt b/inkcpp/CMakeLists.txt index 876b6b18..d8d0b883 100644 --- a/inkcpp/CMakeLists.txt +++ b/inkcpp/CMakeLists.txt @@ -1,8 +1,6 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) list(APPEND SOURCES - collections/restorable.h - collections/restorable.cpp array.h choice.cpp functional.cpp @@ -13,19 +11,33 @@ list(APPEND SOURCES runner_impl.h runner_impl.cpp simple_restorable_stack.h stack.h stack.cpp story_impl.h story_impl.cpp + snapshot_impl.h snapshot_impl.cpp snapshot_interface.h story_ptr.cpp system.cpp value.h value.cpp + tuple.hpp string_table.h string_table.cpp avl_array.h list_table.h list_table.cpp + list_impl.h list_impl.cpp + operations.h operation_bases.h list_operations.h list_operations.cpp container_operations.h container_operations.cpp + numeric_operations.h numeric_operations.cpp + string_operations.h string_operations.cpp string_operations.cpp numeric_operations.cpp + casting.h + executioner.h + string_utils.h header.cpp + random.h +) +list(APPEND COLLECTION_SOURCES + collections/restorable.h + collections/restorable.cpp ) source_group(Collections REGULAR_EXPRESSION collections/.*) -add_library(inkcpp ${SOURCES}) +add_library(inkcpp ${SOURCES} ${COLLECTION_SOURCES}) target_include_directories(inkcpp PUBLIC $ $ @@ -42,3 +54,4 @@ target_compile_features(inkcpp PUBLIC cxx_std_17) # Unreal installation install(DIRECTORY "include/" DESTINATION "inkcpp/Source/inkcpp/Public/ink/" COMPONENT unreal EXCLUDE_FROM_ALL) install(FILES ${SOURCES} DESTINATION "inkcpp/Source/inkcpp/Private/ink/" COMPONENT unreal EXCLUDE_FROM_ALL) +install(FILES ${COLLECTION_SOURCES} DESTINATION "inkcpp/Source/inkcpp/Private/ink/collections/" COMPONENT unreal EXCLUDE_FROM_ALL) diff --git a/inkcpp/array.h b/inkcpp/array.h index 9ad97afb..bc436c75 100644 --- a/inkcpp/array.h +++ b/inkcpp/array.h @@ -1,13 +1,15 @@ #pragma once #include "system.h" +#include "traits.h" +#include "snapshot_interface.h" namespace ink::runtime::internal { template - class managed_array { + class managed_array : snapshot_interface { public: - managed_array() : _capacity{initialCapacity}, _size{0}{ + managed_array() : _static_data{}, _capacity{ initialCapacity }, _size{ 0 }{ if constexpr (dynamic) { _dynamic_data = new T[initialCapacity]; } @@ -42,17 +44,50 @@ namespace ink::runtime::internal if constexpr (dynamic) { if (_size == _capacity) { extend(); } } else { - ink_assert(_size <= _capacity, "Stack Overflow!"); + inkAssert(_size <= _capacity, "Stack Overflow!"); + /// FIXME silent fail!! } return data()[_size++]; } void clear() { _size = 0; } void resize(size_t size) { - ink_assert(size <= _size, "Only allow to reduce size"); + if constexpr (dynamic) { + if (size > _capacity) { + extend(size); + } + } else { + inkAssert(size <= _size, "Only allow to reduce size"); + } _size = size; } - void extend(); + void extend(size_t capacity = 0); + + size_t snap(unsigned char* data, const snapper&) const override + { + inkAssert(!is_pointer{}(), "here is a special case oversight"); + unsigned char* ptr = data; + bool should_write = data != nullptr; + ptr = snap_write(ptr, _size, should_write ); + for(const T& e : *this) { + ptr = snap_write(ptr, e, should_write ); + } + return ptr - data; + } + const unsigned char* snap_load(const unsigned char* ptr, const loader&) override +{ + decltype(_size) size; + ptr = snap_read(ptr, size); + if constexpr (dynamic) { + resize(size); + } else { + inkAssert(size <= initialCapacity, "capacity of non dynamic array is to small vor snapshot!"); + } + for (T& e : *this) { + ptr = snap_read(ptr, e); + } + return ptr; + } private: if_t _static_data[dynamic ? 1 : initialCapacity]; @@ -62,10 +97,12 @@ namespace ink::runtime::internal }; template - void managed_array::extend() + void managed_array::extend(size_t capacity) { static_assert(dynamic, "Can only extend if array is dynamic!"); - size_t new_capacity = 1.5f * _capacity; + size_t new_capacity = capacity > _capacity + ? capacity + : 1.5f * _capacity; if (new_capacity < 5) { new_capacity = 5; } T* new_data = new T[new_capacity]; @@ -79,7 +116,7 @@ namespace ink::runtime::internal } template - class basic_restorable_array + class basic_restorable_array : public snapshot_interface { public: basic_restorable_array(T* array, size_t capacity, T nullValue) @@ -116,6 +153,10 @@ namespace ink::runtime::internal // Resets all values and clears any save points void clear(const T& value); + // snapshot interface + virtual size_t snap(unsigned char* data, const snapper&) const override; + virtual const unsigned char* snap_load(const unsigned char* data, const loader&) override; + protected: inline T* buffer() { return _array; } void set_new_buffer(T* buffer, size_t capacity) { @@ -144,6 +185,37 @@ namespace ink::runtime::internal const T _null; }; + template + inline size_t basic_restorable_array::snap(unsigned char* data, const snapper& snapper) const + { + unsigned char* ptr = data; + bool should_write = data != nullptr; + ptr = snap_write(ptr, _saved, should_write ); + ptr = snap_write(ptr, _capacity, should_write ); + ptr = snap_write(ptr, _null, should_write ); + for(size_t i = 0; i < _capacity; ++i) { + ptr = snap_write(ptr, _array[i], should_write ); + ptr = snap_write(ptr, _temp[i], should_write ); + } + return ptr - data; + } + + template + inline const unsigned char* basic_restorable_array::snap_load(const unsigned char* data, const loader& loader) + { + auto ptr = data; + ptr = snap_read(ptr, _saved); + ptr = snap_read(ptr, _capacity); + T null; + ptr = snap_read(ptr, null); + inkAssert(null == _null, "null value is different to snapshot!"); + for(size_t i = 0; i < _capacity; ++i) { + ptr = snap_read(ptr, _array[i]); + ptr = snap_read(ptr, _temp[i]); + } + return ptr; + } + template inline void basic_restorable_array::set(size_t index, const T& value) { @@ -238,7 +310,7 @@ namespace ink::runtime::internal }; template - class allocated_restorable_array : public basic_restorable_array + class allocated_restorable_array final : public basic_restorable_array { using base = basic_restorable_array; public: @@ -275,7 +347,7 @@ namespace ink::runtime::internal this->set_new_buffer(_buffer, new_capacity); } - ~allocated_restorable_array() + virtual ~allocated_restorable_array() { if(_buffer) { delete[] _buffer; diff --git a/inkcpp/avl_array.h b/inkcpp/avl_array.h index 9690149a..e4fb3a24 100644 --- a/inkcpp/avl_array.h +++ b/inkcpp/avl_array.h @@ -41,6 +41,8 @@ #ifndef _AVL_ARRAY_H_ #define _AVL_ARRAY_H_ +#include "system.h" + #include @@ -73,20 +75,31 @@ class avl_array static const size_type INVALID_IDX = Size; // iterator class - typedef class tag_avl_array_iterator + template + class tag_avl_array_iterator { - avl_array* instance_; // array instance + template + using if_t = ink::runtime::internal::if_t; + if_t + instance_; // array instance size_type idx_; // actual node friend avl_array; // avl_array may access index pointer public: + // ctor - tag_avl_array_iterator(avl_array* instance = nullptr, size_type idx = 0U) + tag_avl_array_iterator(if_t instance = nullptr, size_type idx = 0U) : instance_(instance) , idx_(idx) { } + template> + tag_avl_array_iterator(const tag_avl_array_iterator& itr) + : instance_(itr.instance_) + , idx_(itr.idx_) + {} + inline tag_avl_array_iterator& operator=(const tag_avl_array_iterator& other) { instance_ = other.instance_; @@ -101,17 +114,22 @@ class avl_array { return !(*this == rhs); } // dereference - access value - inline T& operator*() const + inline if_t operator*() const { return val(); } // access value - inline T& val() const + inline if_t val() const { return instance_->val_[idx_]; } // access key - inline Key& key() const + inline const Key& key() const { return instance_->key_[idx_]; } + // returns unique number for each entry + // the numbers are unique as long no operation are executed + // on the avl + inline size_t temp_identifier() const { return instance_->size() - idx_ - 1; } + // preincrement tag_avl_array_iterator& operator++() { @@ -152,7 +170,7 @@ class avl_array ++(*this); return _copy; } - } avl_array_iterator; + }; public: @@ -163,7 +181,8 @@ class avl_array typedef T& reference; typedef const T& const_reference; typedef Key key_type; - typedef avl_array_iterator iterator; + typedef tag_avl_array_iterator iterator; + typedef tag_avl_array_iterator const_iterator; // ctor @@ -184,9 +203,19 @@ class avl_array return iterator(this, i); } + inline const_iterator begin() const + { + return const_iterator(const_cast(*this).begin()); + } + inline iterator end() { return iterator(this, INVALID_IDX); } + inline const_iterator end() const + { + return const_iterator(this, INVALID_IDX); + } + // capacity inline size_type size() const @@ -319,6 +348,11 @@ class avl_array return end(); } + inline const_iterator find(const key_type& key) const + { + return const_iterator(const_cast(*this).find(key)); + } + /** * Count elements with a specific key @@ -481,10 +515,10 @@ class avl_array /** - * Integrity (self) check + * Integrity (self) test * \return True if the tree intergity is correct, false if error (should not happen normally) */ - bool check() const + bool test() const { // check root if (empty() && (root_ != INVALID_IDX)) { diff --git a/inkcpp/choice.cpp b/inkcpp/choice.cpp index 735b0c3d..005bb166 100644 --- a/inkcpp/choice.cpp +++ b/inkcpp/choice.cpp @@ -1,45 +1,48 @@ #include "choice.h" + #include "output.h" -#include "string_utils.h" #include "string_table.h" +#include "string_utils.h" -namespace ink -{ - namespace runtime +namespace ink { +namespace runtime { + choice& choice::setup( internal::basic_stream& in, internal::string_table& strings, internal::list_table& lists, int index, uint32_t path, thread_t thread, const char* const* tags ) { - choice& choice::setup(internal::basic_stream& in, internal::string_table& strings, internal::list_table& lists, int index, uint32_t path, thread_t thread) + char* text = nullptr; + // if we only have one item in our output stream + if ( in.queued() == 2 ) { - char* text = nullptr; - // if we only have one item in our output stream - if (in.queued() == 2) - { - // If it's a string, just grab it. Otherwise, use allocation - const internal::value& data = in.peek(); - switch (data.type()) - { - case internal::value_type::string: - text = strings.duplicate(data.get()); - in.discard(2); - break; - default: - text = in.get_alloc(strings, lists); - } - } - else + // If it's a string, just grab it. Otherwise, use allocation + const internal::value& data = in.peek(); + switch ( data.type() ) { - // Non-string. Must allocate - text = in.get_alloc(strings, lists); + case internal::value_type::string: + text = strings.duplicate( data.get() ); + in.discard( 2 ); + break; + default: + text = in.get_alloc( strings, lists ); } - char* end = text; - while(*end) { ++end; } - end = ink::runtime::internal::clean_string(text, end); - *end = 0; - _text = text; - // Index/path - _index = index; - _path = path; - _thread = thread; - return *this; } + else + { + // Non-string. Must allocate + text = in.get_alloc( strings, lists ); + } + char* end = text; + while ( *end ) + { + ++end; + } + end = ink::runtime::internal::clean_string( text, end ); + *end = 0; + _text = text; + // Index/path + _index = index; + _path = path; + _thread = thread; + _tags = tags; + return *this; } } +} // namespace ink::runtime diff --git a/inkcpp/collections/restorable.cpp b/inkcpp/collections/restorable.cpp index e69de29b..b7bf8230 100644 --- a/inkcpp/collections/restorable.cpp +++ b/inkcpp/collections/restorable.cpp @@ -0,0 +1,96 @@ +#include "restorable.h" +#include "../stack.h" + +namespace ink::runtime::internal { + unsigned char* snap_base(unsigned char* ptr, bool write, size_t pos, size_t jump, size_t save, size_t& max) + { + ptr = snapshot_interface::snap_write(ptr, pos, write); + ptr = snapshot_interface::snap_write(ptr, jump, write); + ptr = snapshot_interface::snap_write(ptr, save, write); + max = pos; + if (jump > max) { max = jump; } + if (save > max) { max = save; } + return ptr; + } + const unsigned char* snap_load_base(const unsigned char* ptr, size_t& pos, size_t& jump, size_t& save, size_t& max) + { + ptr = snapshot_interface::snap_read(ptr, pos); + ptr = snapshot_interface::snap_read(ptr, jump); + ptr = snapshot_interface::snap_read(ptr, save); + max = pos; + if (jump > max) { max = jump; } + if (save > max) { max = save; } + return ptr; + } + + template<> + size_t restorable::snap(unsigned char* data, const snapper& snapper) const + { + unsigned char* ptr = data; + size_t max; + ptr = snap_base(ptr, data != nullptr, _pos, _jump, _save, max); + for(size_t i = 0; i < max; ++i) { + ptr = snap_write(ptr, _buffer[i].name, data != nullptr); + ptr += _buffer[i].data.snap(data ? ptr : nullptr, snapper); + } + return ptr - data; + } + template<> + size_t restorable::snap(unsigned char* data, const snapper& snapper) const + { + unsigned char* ptr = data; + size_t max; + ptr = snap_base(ptr, data != nullptr, _pos, _jump, _save, max); + for(size_t i = 0; i < max; ++i) { + ptr += _buffer[i].snap(data ? ptr : nullptr, snapper); + } + return ptr - data; + } + template<> + size_t restorable::snap(unsigned char* data, const snapper&) const + { + unsigned char* ptr = data; + size_t max; + ptr = snap_base(ptr, data != nullptr, _pos, _jump, _save, max); + for(size_t i = 0; i < max; ++i) { + ptr = snap_write(ptr, _buffer[i], data != nullptr); + } + return ptr - data; + } + + template<> + const unsigned char* restorable::snap_load(const unsigned char* ptr, const loader& loader) + { + size_t max; + ptr = snap_load_base(ptr, _pos, _jump, _save, max); + while(_size < max) { overflow(_buffer, _size); } + for(size_t i = 0; i < max; ++i) { + ptr = snap_read(ptr, _buffer[i].name); + ptr = _buffer[i].data.snap_load(ptr, loader); + } + return ptr; + } + template<> + const unsigned char* restorable::snap_load(const unsigned char* ptr, const loader& loader) + { + size_t max; + ptr = snap_load_base(ptr, _pos, _jump, _save, max); + while(_size < max) { overflow(_buffer, _size); } + for(size_t i = 0; i < max; ++i) { + ptr = _buffer[i].snap_load(ptr, loader); + } + return ptr; + } + template<> + const unsigned char* restorable::snap_load(const unsigned char* ptr, const loader& loader) + { + size_t max; + ptr = snap_load_base(ptr, _pos, _jump, _save, max); + while(_size < max) { overflow(_buffer, _size); } + for(size_t i = 0; i < max; ++i) { + ptr = snap_read(ptr, _buffer[i]); + } + return ptr; + } + +} diff --git a/inkcpp/collections/restorable.h b/inkcpp/collections/restorable.h index ad64175e..63997d1f 100644 --- a/inkcpp/collections/restorable.h +++ b/inkcpp/collections/restorable.h @@ -1,7 +1,13 @@ +#pragma once + +#include "../snapshot_impl.h" + #include +#include namespace ink::runtime::internal { + struct entry; template constexpr auto EmptyNullPredicate = [](const ElementType&) { return false; }; @@ -68,11 +74,11 @@ namespace ink::runtime::internal * from this class gain this functionality. */ template - class restorable + class restorable : public snapshot_interface { public: restorable(ElementType* buffer, size_t size) - : _buffer(buffer), _size(size), _pos(0), _save(~0), _jump(~0) + : _buffer(buffer), _size(size), _pos(0), _jump(~0), _save(~0) { } // Checks if we have a save state @@ -326,10 +332,14 @@ namespace ink::runtime::internal return count; } + // snapshot interface + virtual size_t snap(unsigned char* data, const snapper&) const override; + const unsigned char* snap_load(const unsigned char* data, const loader&) override; + protected: // Called when we run out of space in buffer. virtual void overflow(ElementType*& buffer, size_t& size) { - throw ink_exception("Restorable run out of memory!"); + inkFail("Restorable run out of memory!"); } private: @@ -374,4 +384,17 @@ namespace ink::runtime::internal size_t _jump; size_t _save; }; + template<> + size_t restorable::snap(unsigned char* data, const snapper& snapper) const; + template<> + size_t restorable::snap(unsigned char* data, const snapper& snapper) const; + template<> + size_t restorable::snap(unsigned char* data, const snapper&) const; + + template<> + const unsigned char* restorable::snap_load(const unsigned char* data, const loader&); + template<> + const unsigned char* restorable::snap_load(const unsigned char* data, const loader&); + template<> + const unsigned char* restorable::snap_load(const unsigned char* data, const loader&); } diff --git a/inkcpp/container_operations.cpp b/inkcpp/container_operations.cpp index c34b681c..79de3f93 100644 --- a/inkcpp/container_operations.cpp +++ b/inkcpp/container_operations.cpp @@ -13,9 +13,10 @@ namespace ink::runtime::internal { basic_eval_stack& stack, value* vals) { container_t id; - inkAssert(_story.get_container_id( - _story.instructions() + vals[0].get(), - id), "failed to find container to read visit count!"); + bool success = _story.get_container_id( + _story.instructions() + vals[0].get(), + id); + inkAssert(success, "failed to find container to read visit count!"); stack.push(value{}.set( static_cast(_visit_counts.visits( id ) ))); @@ -25,9 +26,10 @@ namespace ink::runtime::internal { basic_eval_stack& stack, value* vals) { container_t id; - inkAssert(_story.get_container_id( - _story.instructions() + vals[0].get(), - id), "failed to find container to read turn count!"); + bool success = _story.get_container_id( + _story.instructions() + vals[0].get(), + id); + inkAssert(success, "failed to find container to read turn count!"); stack.push(value{}.set( static_cast(_visit_counts.turns(id) ))); diff --git a/inkcpp/executioner.h b/inkcpp/executioner.h index 532b3b28..78703aa5 100644 --- a/inkcpp/executioner.h +++ b/inkcpp/executioner.h @@ -79,7 +79,7 @@ namespace ink::runtime::internal { typed_executer(const T& t) {} void operator()(value_type, basic_eval_stack&, value*) { - throw ink_exception("Operation for value not supported!"); + inkFail("Operation for value not supported!"); } }; @@ -140,7 +140,7 @@ namespace ink::runtime::internal { template executer_imp(const T& t) {} void operator()(Command, basic_eval_stack&) { - throw ink_exception("requested command was not found!"); + inkFail("requested command was not found!"); } }; diff --git a/inkcpp/functional.cpp b/inkcpp/functional.cpp index 9c0cad62..b4849651 100644 --- a/inkcpp/functional.cpp +++ b/inkcpp/functional.cpp @@ -11,7 +11,7 @@ namespace ink::runtime::internal { template<> - int32_t function_base::pop(basic_eval_stack* stack) + int32_t function_base::pop(basic_eval_stack* stack, list_table& lists) { value val = stack->pop(); inkAssert(val.type() == value_type::int32, "Type missmatch!"); @@ -19,7 +19,7 @@ namespace ink::runtime::internal } template<> - const char* function_base::pop(basic_eval_stack* stack) + const char* function_base::pop(basic_eval_stack* stack, list_table& lists) { value val = stack->pop(); inkAssert(val.type() == value_type::string, "Type missmatch!"); @@ -32,6 +32,12 @@ namespace ink::runtime::internal stack->push(value{}.set(v)); } + void function_base::push_void(basic_eval_stack* stack) + { + stack->push(values::null); + } + + void function_base::push_string(basic_eval_stack* stack, const char* dynamic_string) { stack->push(value{}.set(dynamic_string, true)); @@ -46,54 +52,25 @@ namespace ink::runtime::internal #ifdef INK_ENABLE_STL template<> - std::string function_base::pop(basic_eval_stack* stack) { - return std::string(pop(stack)); + std::string function_base::pop(basic_eval_stack* stack, list_table& lists) { + return std::string(pop(stack, lists)); } #endif #ifdef INK_ENABLE_UNREAL - SUPPORT_TYPE_PARAMETER_ONLY(FString); - template<> - FInkVar function_base::pop(basic_eval_stack* stack) + FInkVar function_base::pop(basic_eval_stack* stack, list_table& lists) { - value v = stack->pop(); - switch (v.type()) - { - case value_type::null: - case value_type::divert: - inkFail("Trying to pass null or divert as ink parameter to external function"); - break; - case value_type::integer: - return FInkVar(v.get()); - case value_type::decimal: - return FInkVar(v.get()); - case value_type::string: - return FInkVar(v.get()); - } - - return FInkVar(); + return FInkVar(stack->pop().to_interface_value(lists)); } template<> - void function_base::push(basic_eval_stack* stack, const FInkVar& value) + void function_base::push(basic_eval_stack* stack, const ink::runtime::value& value) { - switch (value.type) - { - case EInkVarType::None: - { - internal::value v; - stack->push(v); - } - break; - case EInkVarType::Int: - stack->push(value.intVar); - break; - case EInkVarType::Float: - stack->push(value.floatVar); - break; - case EInkVarType::String: - inkFail("NOT IMPLEMENTED"); // TODO: String support - return; + internal::value val{}; + if(val.set(value)) { + stack->push(val); + } else { + inkFail("unable to set variable?"); } } #endif diff --git a/inkcpp/functions.cpp b/inkcpp/functions.cpp index 3c76479b..0c923183 100644 --- a/inkcpp/functions.cpp +++ b/inkcpp/functions.cpp @@ -39,7 +39,7 @@ namespace ink::runtime::internal } } - bool functions::call(hash_t name, basic_eval_stack* stack, size_t num_arguments, string_table& strings) + bool functions::call(hash_t name, basic_eval_stack* stack, size_t num_arguments, string_table& strings, list_table& lists) { // find entry entry* iter = _list; @@ -51,7 +51,7 @@ namespace ink::runtime::internal return false; // call - iter->value->call(stack, num_arguments, strings); + iter->value->call(stack, num_arguments, strings, lists); return true; } } \ No newline at end of file diff --git a/inkcpp/functions.h b/inkcpp/functions.h index 7a47884c..8e45e21f 100644 --- a/inkcpp/functions.h +++ b/inkcpp/functions.h @@ -18,7 +18,7 @@ namespace ink::runtime::internal void add(hash_t name, function_base* func); // Calls a function (if available) - bool call(hash_t name, basic_eval_stack* stack, size_t num_arguments, string_table& strings); + bool call(hash_t name, basic_eval_stack* stack, size_t num_arguments, string_table& strings, list_table& lists); private: struct entry diff --git a/inkcpp/globals_impl.cpp b/inkcpp/globals_impl.cpp index 1749366e..47037d27 100644 --- a/inkcpp/globals_impl.cpp +++ b/inkcpp/globals_impl.cpp @@ -1,17 +1,23 @@ #include "globals_impl.h" #include "story_impl.h" #include "runner_impl.h" +#include "snapshot_impl.h" +#include "system.h" +#include "types.h" + +#include namespace ink::runtime::internal { globals_impl::globals_impl(const story_impl* story) : _num_containers(story->num_containers()) - , _visit_counts(_num_containers) + , _visit_counts() , _owner(story) , _runners_start(nullptr) , _lists(story->list_meta(), story->get_header()) , _globals_initialized(false) { + _visit_counts.resize(_num_containers); if (_lists) { // initelize static lists const list_flag* flags = story->lists(); @@ -98,7 +104,23 @@ namespace ink::runtime::internal void globals_impl::set_variable(hash_t name, const value& val) { + ink::optional old_var = ink::nullopt; + value* p_old_var = get_variable(name); + if (p_old_var != nullptr) { + old_var = *p_old_var; + } + _variables.set(name, val); + + for(auto& callback : _callbacks) { + if (callback.name == name) { + if (old_var.has_value()) { + callback.operation->call(val.to_interface_value(lists()), {old_var->to_interface_value(lists())}); + } else { + callback.operation->call(val.to_interface_value(lists()), ink::nullopt); + } + } + } } const value* globals_impl::get_variable(hash_t name) const @@ -110,63 +132,52 @@ namespace ink::runtime::internal return _variables.get(name); } - template - optional fetch_variable(const value* val) { - if (val && val->type() == ty) { - return optional(val->get()); - } - return {nullopt}; - } - - template - bool try_set_value(value* val, T x) { - if (val && val->type() == ty) { - val->set(x); - return true; - } - return false; - } - - optional globals_impl::get_int(hash_t name) const { - return fetch_variable(get_variable(name)); - } - bool globals_impl::set_int(hash_t name, int32_t i) { - return try_set_value(get_variable(name), i); - } - optional globals_impl::get_uint(hash_t name) const { - return fetch_variable(get_variable(name)); - } - bool globals_impl::set_uint(hash_t name, uint32_t i) { - return try_set_value(get_variable(name), i); - } - optional globals_impl::get_float(hash_t name) const { - return fetch_variable(get_variable(name)); - } - bool globals_impl::set_float(hash_t name, float i) { - return try_set_value(get_variable(name), i); + optional globals_impl::get_var(hash_t name) const { + auto* var = get_variable(name); + if (!var) { return nullopt; } + return {var->to_interface_value(_lists)}; } + + bool globals_impl::set_var(hash_t name, const ink::runtime::value& val) { + auto* var = get_variable(name); + if (!var) { return false; } + ink::runtime::value old_val = var->to_interface_value(lists()); - optional globals_impl::get_str(hash_t name) const { - return fetch_variable(get_variable(name)); - } - bool globals_impl::set_str(hash_t name, const char* val) { - value* v = get_variable(name); - if (v->type() == value_type::string) - { + bool ret = false; + if ( val.type == ink::runtime::value::Type::String) { + if (!(var->type() == value_type::none || var->type() == value_type::string)) { return false; } size_t size = 0; char* ptr; - for(const char*i = val; *i; ++i) { ++size; } - char* new_string = strings().create(size + 1); - strings().mark_used(new_string); + for ( const char* i = val.v_string; *i; ++i ) { ++size; } + char* new_string = strings().create( size + 1 ); + strings().mark_used( new_string ); ptr = new_string; - for(const char* i = val; *i; ++i) { + for ( const char* i = val.v_string; *i; ++i ) { *ptr++ = *i; } *ptr = 0; - *v = value{}.set(static_cast(new_string), true); - return true; + *var = value{}.set( static_cast( new_string ), true ); + ret = true; + } else { + ret = var->set(val); + } + + for (auto& callback : _callbacks) { + if (callback.name == name) { + callback.operation->call(val, {old_val}); + } + } + + return ret; + } + + void globals_impl::internal_observe(hash_t name, callback_base* callback) { + _callbacks.push() = Callback { .name = name, .operation = callback }; + if (_globals_initialized) { + value* p_var = _variables.get(name); + inkAssert(p_var != nullptr, "Global variable to observe does not exists after initiliazation. This variable will therofe not get any value."); + callback->call(p_var->to_interface_value(lists()), ink::nullopt); } - return false; } void globals_impl::initialize_globals(runner_impl* run) @@ -174,32 +185,34 @@ namespace ink::runtime::internal // If no way to move there, then there are no globals. if (!run->move_to(hash_string("global decl"))) { - _globals_initialized = true; return; } // execute one line to startup the globals run->getline_silent(); + _globals_initialized = true; } void globals_impl::gc() { // Mark all strings as unused _strings.clear_usage(); + _lists.clear_usage(); // Iterate runners and mark their strings auto iter = _runners_start; while (iter != nullptr) { - iter->object->mark_strings(_strings); + iter->object->mark_used(_strings, _lists); iter = iter->next; } // Mark our own strings - _variables.mark_strings(_strings); + _variables.mark_used(_strings, _lists); // run garbage collection _strings.gc(); + _lists.gc(); } void globals_impl::save() @@ -216,4 +229,32 @@ namespace ink::runtime::internal { _variables.forget(); } + + snapshot* globals_impl::create_snapshot() const + { + return new snapshot_impl(*this); + } + + size_t globals_impl::snap(unsigned char* data, const snapper& snapper) const + { + unsigned char* ptr = data; + inkAssert(_num_containers == _visit_counts.size(), "Should be equal!"); + inkAssert(_globals_initialized, "Only support snapshot of globals with runner! or you don't need a snapshot for this state"); + ptr += _visit_counts.snap( data ? ptr : nullptr, snapper ); + ptr += _strings.snap( data ? ptr : nullptr, snapper ); + ptr += _lists.snap( data ? ptr : nullptr, snapper ); + ptr += _variables.snap(data ? ptr : nullptr, snapper ); + return ptr - data; + } + + const unsigned char* globals_impl::snap_load(const unsigned char* ptr, const loader& loader) + { + _globals_initialized = true; + ptr = _visit_counts.snap_load(ptr, loader); + inkAssert(_num_containers == _visit_counts.size(), "errer when loading visit counts, story file dont match snapshot!"); + ptr = _strings.snap_load(ptr, loader); + ptr = _lists.snap_load(ptr, loader); + ptr = _variables.snap_load(ptr, loader); + return ptr; + } } diff --git a/inkcpp/globals_impl.h b/inkcpp/globals_impl.h index a2d9704b..d6d4fc1c 100644 --- a/inkcpp/globals_impl.h +++ b/inkcpp/globals_impl.h @@ -1,37 +1,39 @@ #pragma once +#include "config.h" #include "system.h" #include "array.h" #include "globals.h" #include "string_table.h" #include "list_table.h" +#include "list_impl.h" #include "stack.h" +#include "snapshot_impl.h" +#include "functional.h" namespace ink::runtime::internal { class story_impl; class runner_impl; + class snapshot_impl; // Implementation of the global store - class globals_impl : public globals_interface + class globals_impl final : public globals_interface, public snapshot_interface { + friend snapshot_impl; public: + size_t snap(unsigned char* data, const snapper&) const override; + const unsigned char* snap_load(const unsigned char* data, const loader&) override; // Initializes a new global store from the given story globals_impl(const story_impl*); virtual ~globals_impl() { } - protected: - optional get_uint(hash_t name) const override; - bool set_uint(hash_t name, uint32_t value) override; - - optional get_int(hash_t name) const override; - bool set_int(hash_t name, int32_t value) override; - - optional get_float(hash_t name) const override; - bool set_float(hash_t name, float value) override; + snapshot* create_snapshot() const override; - optional get_str(hash_t name) const override; - bool set_str(hash_t name, const char* value) override; + protected: + optional get_var(hash_t name) const override; + bool set_var(hash_t name, const ink::runtime::value& val) override; + void internal_observe(hash_t name, internal::callback_base* callback) override; public: // Records a visit to a container @@ -66,6 +68,7 @@ namespace ink::runtime::internal // gets the allocated string table inline string_table& strings() { return _strings; } + inline const string_table& strings() const { return _strings; } // gets list entries list_table& lists() { return _lists; } @@ -93,16 +96,7 @@ namespace ink::runtime::internal return !(*this == vc); } }; - class visit_counts{ - visit_count* _data; - size_t _len; - public: - visit_counts(size_t len) - : _data{new visit_count[len]}, _len{len} {} - size_t size() const { return _len; } - visit_count& operator[](size_t i) { return _data[i]; } - const visit_count& operator[](size_t i) const { return _data[i]; } - } _visit_counts; + managed_array _visit_counts; // Pointer back to owner story. const story_impl* const _owner; @@ -124,6 +118,11 @@ namespace ink::runtime::internal // Implemented as a stack (slow lookup) because it has save/restore functionality. // If I could create an avl tree with save/restore, that'd be great but seems super complex. internal::stack _variables; + struct Callback { + hash_t name; + callback_base* operation; + }; + managed_array _callbacks; bool _globals_initialized; }; } diff --git a/inkcpp/header.cpp b/inkcpp/header.cpp index e80b2858..57faf733 100644 --- a/inkcpp/header.cpp +++ b/inkcpp/header.cpp @@ -27,11 +27,11 @@ namespace ink::internal { res.ink_bin_version_number = swap_bytes(*reinterpret_cast(ptr)); } else { - throw ink_exception("Failed to parse endian encoding!"); + inkFail("Failed to parse endian encoding!"); } if (res.ink_bin_version_number != InkBinVersion) { - throw ink_exception("InkCpp-version mismatch: file was compiled with different InkCpp-version!"); + inkFail("InkCpp-version mismatch: file was compiled with different InkCpp-version!"); } return res; } diff --git a/inkcpp/include/choice.h b/inkcpp/include/choice.h index 9441e6d6..3d9ccf83 100644 --- a/inkcpp/include/choice.h +++ b/inkcpp/include/choice.h @@ -43,12 +43,32 @@ namespace ink * @returns choice text as a string */ const char* text() const { return _text; } + + choice() : choice(0) {} + choice(int) : _tags{nullptr}, _text{nullptr}, _index{~0}, _path{~0u}, _thread{~0u} {} + + bool has_tags() const { return _tags != nullptr; } + size_t num_tags() const + { + size_t i = 0; + if (has_tags()) while ( _tags[i] != nullptr ) + { + ++i; + }; + return i; + } + const char* get_tag(size_t index) const { + return _tags[index]; + } + private: friend class internal::runner_impl; uint32_t path() const { return _path; } - choice& setup(internal::basic_stream&, internal::string_table& strings, internal::list_table& lists, int index, uint32_t path, thread_t thread); + choice& setup( internal::basic_stream&, internal::string_table& strings, internal::list_table& lists, int index, uint32_t path, thread_t thread, const char* const* tags ); + private: + const char* const* _tags; const char* _text; int _index; uint32_t _path; diff --git a/inkcpp/include/functional.h b/inkcpp/include/functional.h index a5461b9b..94b49c0a 100644 --- a/inkcpp/include/functional.h +++ b/inkcpp/include/functional.h @@ -1,12 +1,103 @@ #pragma once +#include "list.h" #include "traits.h" #include "system.h" +#include "types.h" + +#ifdef INK_ENABLE_UNREAL +#include "../InkVar.h" +#endif namespace ink::runtime::internal { class basic_eval_stack; class string_table; + class list_table; + + class callback_base { + public: + virtual void call(ink::runtime::value, ink::optional) = 0; + }; + + template + class callback final : public callback_base + { + using traits = function_traits; + static_assert(traits::arity < 3); + + template + void call_functor(ink::runtime::value new_val, ink::optional old_val) { + if constexpr(traits::arity == 2) { + if (old_val.has_value()) { + functor(new_val.get(), typename traits::template argument<1>::type{old_val.value().get()}); + } else { + functor(new_val.get(), ink::nullopt); + } + } else { + functor(new_val.get()); + } + } + + public: + callback( const callback& ) = delete; + callback( callback&& ) = delete; + callback& operator=( const callback& ) = delete; + callback& operator=( callback&& ) = delete; + callback( F functor ) + : functor( functor ) {} + + virtual void call(ink::runtime::value new_val, + ink::optional old_val) { + using value = ink::runtime::value; + auto check_type = [&new_val, &old_val](value::Type type){ + inkAssert(new_val.type == type, + "Missmatch type for variable observer: expected %i, got %i", + static_cast(type), + static_cast(new_val.type)); + if constexpr (traits::arity == 2) { + // inkAssert(!old_val.has_value() || old_val.value().type == type, + // "Missmatch type for variable observers old value: expected optional<%i> got optional<%i>", + // static_cast(type), + // static_cast(old_val.value().type)); + } + }; + if constexpr (traits::arity > 0) { + using arg_t = typename remove_cvref::type>::type; + if constexpr (is_same::value) { + if constexpr (traits::arity == 2) { + functor(new_val, old_val); + } else { + functor(new_val); + } + } else if constexpr (is_same::value) { + check_type(value::Type::Bool); + call_functor(new_val, old_val); + } else if constexpr (is_same::value) { + check_type(value::Type::Uint32); + call_functor(new_val, old_val); + } else if constexpr (is_same::value) { + check_type(value::Type::Int32); + call_functor(new_val, old_val); + } else if constexpr (is_same::value) { + check_type(value::Type::String); + call_functor(new_val, old_val); + } else if constexpr (is_same::value) { + check_type(value::Type::Float); + call_functor(new_val, old_val); + } else if constexpr (is_same::value){ + check_type(value::Type::List); + call_functor(new_val, old_val); + } else { + static_assert(always_false::value, "Unsupported value for variable observer callback!"); + } + } else { + functor(); + } + } + private: + F functor; + }; // base function container with virtual callback methods class function_base @@ -15,17 +106,23 @@ namespace ink::runtime::internal virtual ~function_base() { } // calls the underlying function object taking parameters from a stack - virtual void call(basic_eval_stack* stack, ink::size_t length, string_table& strings) = 0; +#ifdef INK_ENABLE_UNREAL + virtual void call(basic_eval_stack* stack, size_t length, string_table& strings, list_table& lists) = 0; +#else + virtual void call(basic_eval_stack* stack, size_t length, string_table& strings, list_table& lists) = 0; +#endif protected: // used to hide basic_eval_stack and value definitions template - static T pop(basic_eval_stack* stack); + static T pop(basic_eval_stack* stack, list_table& lists); // used to hide basic_eval_stack and value definitions template static void push(basic_eval_stack* stack, const T& value); + static void push_void(basic_eval_stack* stack); + // string special push static void push_string(basic_eval_stack* stack, const char* dynamic_string); @@ -41,9 +138,9 @@ namespace ink::runtime::internal function(F functor) : functor(functor) { } // calls the underlying function using arguments on the stack - virtual void call(basic_eval_stack* stack, size_t length, string_table& strings) override + virtual void call(basic_eval_stack* stack, size_t length, string_table& strings, list_table& lists) override { - call(stack, length, strings, GenSeq()); + call(stack, length, strings, lists, GenSeq()); } private: @@ -59,15 +156,15 @@ namespace ink::runtime::internal // pops an argument from the stack using the function-type template - arg_type pop_arg(basic_eval_stack* stack) + arg_type pop_arg(basic_eval_stack* stack, list_table& lists) { // todo - type assert? - return pop>(stack); + return pop>(stack, lists); } template - void call(basic_eval_stack* stack, size_t length, string_table& strings, seq) + void call(basic_eval_stack* stack, size_t length, string_table& strings, list_table& lists, seq) { // Make sure the argument counts match inkAssert(sizeof...(Is) == length, "Attempting to call functor with too few/many arguments"); @@ -77,31 +174,25 @@ namespace ink::runtime::internal if constexpr (is_same::value) { // Just evaluevaluatelate - functor(pop_arg(stack)...); + functor(pop_arg(stack, lists)...); // Ink expects us to push something // TODO -- Should be a special "void" value - push(stack, 0); + push_void(stack); } else if constexpr (is_string::value) { // SPECIAL: The result of the functor is a string type // in order to store it in the inkcpp interpreter we // need to store it in our allocated string table - auto string_result = functor(pop_arg(stack)...); + auto string_result = functor(pop_arg(stack, lists)...); // Get string length size_t len = string_handler::length(string_result); // Get source and allocate buffer - const char* src = string_handler::src(string_result); char* buffer = allocate(strings, len + 1); - - // Copy - char* ptr = buffer; - while (*src != '\0') - *(ptr++) = *(src++); - *ptr = 0; + string_handler::src_copy(string_result, buffer); // push string result push_string(stack, buffer); @@ -109,7 +200,7 @@ namespace ink::runtime::internal else { // Evaluate and push the result onto the stack - push(stack, functor(pop_arg(stack)...)); + push(stack, functor(pop_arg(stack, lists)...)); } } }; @@ -122,19 +213,37 @@ namespace ink::runtime::internal function_array_delegate(const D& del) : invocableDelegate(del) { } // calls the underlying delegate using arguments on the stack - virtual void call(basic_eval_stack* stack, size_t length) override + virtual void call(basic_eval_stack* stack, size_t length, string_table& strings, list_table& lists) override { + constexpr bool RET_VOID = + is_same::return_type, + void>::value; // Create variable array TArray variables; for (size_t i = 0; i < length; i++) { - variables.Add(pop(stack)); + variables.Add(pop(stack, lists)); + } + if constexpr (RET_VOID) + { + invocableDelegate.Execute(variables); + push(stack, 0); + } else { + + auto ret = invocableDelegate.Execute(variables); + ink::runtime::value result = ret.to_value(); + if(result.type == ink::runtime::value::Type::String) { + const char* src = result.v_string; + size_t len = string_handler::length(src); + char* buffer = allocate(strings, len + 1); + char* ptr = buffer; + while(*src != '\0') + *(ptr++) = *(src++); + *ptr = 0; + result.v_string = buffer; + } + push(stack, result); } - - FInkVar result; - invocableDelegate.ExecuteIfBound(variables, result); - - push(stack, result); } private: D invocableDelegate; diff --git a/inkcpp/include/globals.h b/inkcpp/include/globals.h index ae6b1a97..ac18c284 100644 --- a/inkcpp/include/globals.h +++ b/inkcpp/include/globals.h @@ -1,11 +1,11 @@ #pragma once -#include "system.h" +#include "types.h" +#include "functional.h" namespace ink::runtime { - class globals_interface; - namespace internal { class globals_impl;} + class snapshot; /** * Represents a global store to be shared amongst ink runners. @@ -42,52 +42,117 @@ namespace ink::runtime return false; } + /** + * @brief Observers global variable. + * + * Calls callback with `value` or with casted value if it is one of + * values variants. The callback will also be called with the current value + * when the observe is bind. + * @param callback functor with: + * * 0 arguments + * * 1 argument: `new_value` + * * 2 arguments: `new_value`, `ink::optional`: first time call will not contain a old_value + */ + template + void observe(const char* name, F callback) { + internal_observe(hash_string(name), new internal::callback(callback)); + } + + virtual snapshot* create_snapshot() const = 0; + virtual ~globals_interface() = default; protected: - virtual optional get_uint(hash_t name) const = 0; - virtual bool set_uint(hash_t name, uint32_t val) = 0; - virtual optional get_int(hash_t name) const = 0; - virtual bool set_int(hash_t name, int32_t val) = 0; - virtual optional get_float(hash_t name) const = 0; - virtual bool set_float(hash_t name, float val) = 0; - virtual optional get_str(hash_t name) const = 0; - virtual bool set_str(hash_t name, const char* val) = 0; + virtual optional get_var(hash_t name) const = 0; + virtual bool set_var(hash_t name, const value& val) = 0; + virtual void internal_observe(hash_t name, internal::callback_base* callback) = 0; }; + + template<> + inline optional globals_interface::get(const char* name) const { + return get_var(hash_string(name)); + } + template<> + inline bool globals_interface::set(const char* name, const value& val) { + return set_var(hash_string(name), val); + } + + template<> + inline optional globals_interface::get(const char* name) const { + auto var = get_var(hash_string(name)); + if ( var && var->type == value::Type::Bool) { + return {var->v_bool}; + } + return nullopt; + } + template<> + inline bool globals_interface::set(const char* name, const bool& val) { + return set_var(hash_string(name), value(val)); + } template<> inline optional globals_interface::get(const char* name) const { - return get_uint(hash_string(name)); + auto var = get_var(hash_string(name)); + if (var && var->type == value::Type::Uint32) { + return {var->v_uint32}; + } + return nullopt; } template<> inline bool globals_interface::set(const char* name, const uint32_t& val) { - return set_uint(hash_string(name), val); + return set_var(hash_string(name), value(val)); } template<> inline optional globals_interface::get(const char* name) const { - return get_int(hash_string(name)); + auto var = get_var(hash_string(name)); + if (var && var->type == value::Type::Int32) { + return {var->v_int32}; + } + return nullopt; } template<> inline bool globals_interface::set(const char* name, const int32_t& val) { - return set_int(hash_string(name), val); + return set_var(hash_string(name), value(val)); } - + + template<> inline optional globals_interface::get(const char* name) const { - return get_float(hash_string(name)); + auto var = get_var(hash_string(name)); + if ( var && var->type == value::Type::Float) { + return {var->v_float}; + } + return nullopt; } template<> inline bool globals_interface::set(const char* name, const float& val) { - return set_float(hash_string(name), val); + return set_var(hash_string(name), value(val)); + } + + template<> + inline optional globals_interface::get(const char* name) const { + auto var = get_var(hash_string(name)); + if ( var && var->type == value::Type::String ) { + return {var->v_string}; + } + return nullopt; + } + template<> + inline bool globals_interface::set(const char* name, const char* const& val) { + return set_var(hash_string(name), value(val)); } template<> - inline optionalglobals_interface::get(const char* name) const { - return get_str(hash_string(name)); + inline optional globals_interface::get(const char* name) const { + auto var = get_var(hash_string(name)); + if (var && var->type == value::Type::List) { + return {var->v_list}; + } + return nullopt; } template<> - inline bool globals_interface::set(const char* name, const char * const & val) { - return set_str(hash_string(name), val); + inline bool globals_interface::set(const char* name, const list& val) { + return set_var(hash_string(name), value(val)); } } diff --git a/inkcpp/include/list.h b/inkcpp/include/list.h new file mode 100644 index 00000000..06c062d1 --- /dev/null +++ b/inkcpp/include/list.h @@ -0,0 +1,94 @@ +#pragma once + +#include "system.h" + +#ifdef INK_ENABLE_STL +#include +#endif + +namespace ink::runtime { + namespace internal { + class list_table; + } + class list_interface { + public: + list_interface() : _list_table{nullptr}, _list{-1} {} + + class iterator { + const char* _flag_name; + const char* _list_name; + const list_interface& _list; + int _i; + bool _one_list_iterator; //< iterates only though values of one list + friend list_interface; + protected: + iterator(const char* flag_name, const list_interface& list, size_t i, bool one_list_only = false) + : _flag_name(flag_name), _list(list), _i(i), _one_list_iterator(one_list_only) {} + public: + struct Flag { + const char* flag_name; + const char* list_name; +#ifdef INK_ENABLE_STL + friend std::ostream& operator<<(std::ostream& os, const Flag& flag) { + os << flag.list_name << "(" << flag.flag_name << ")"; + return os; + } +#endif + }; + Flag operator*() const { return Flag{ .flag_name = _flag_name, .list_name = _list_name }; }; + iterator& operator++() + { + _list.next( _flag_name, _list_name, _i ); + return *this; + } + bool operator!=(const iterator& itr) const { return itr._i != _i; } + bool operator==(const iterator& itr) const { + return itr._i == _i; + } + }; + + /** checks if a flag is contained in the list */ + virtual bool contains(const char* flag) const { + inkAssert(false, "Not implemented function from interfaces is called!"); return false; + }; + + /** add a flag to list */ + virtual void add(const char* flag) { + inkAssert(false, "Not implemented function from interface is called!"); + }; + + /** removes a flag from list */ + virtual void remove(const char* flag) { + inkAssert(false, "Not implemented function from interface is called!"); + }; + + /** begin iterator for contained flags in list */ + virtual iterator begin() const { + inkAssert(false, "Not implemented function from interface is called!"); + return new_iterator(nullptr, -1); + }; + + /** returns a iterator over elements of the given list */ + virtual iterator begin(const char* list_name) const { + inkAssert(false, "Not implemented function from interface is called!"); + return new_iterator(nullptr, -1); + } + /** end iterator for contained flags in list */ + virtual iterator end() const { + inkAssert(false, "Not implemented function from interface is called!"); + return new_iterator(nullptr, -1); }; + + private: + friend iterator; + virtual void next(const char*& flag_name, const char*& list_name, int& i) const { + inkAssert(false, "Not implemented funciton from interface is called!"); + }; + protected: + iterator new_iterator(const char* flag_name, int i, bool one_list_only = false) const { + return iterator(flag_name, *this, i, one_list_only); + } + list_interface(internal::list_table& table, int list) : _list_table {&table}, _list{list} {} + internal::list_table* _list_table; + int _list; + }; +} diff --git a/inkcpp/include/runner.h b/inkcpp/include/runner.h index 737553de..5863e8ec 100644 --- a/inkcpp/include/runner.h +++ b/inkcpp/include/runner.h @@ -3,6 +3,7 @@ #include "config.h" #include "system.h" #include "functional.h" +#include "types.h" #ifdef INK_ENABLE_UNREAL #include "Containers/UnrealString.h" @@ -32,6 +33,12 @@ namespace ink::runtime virtual ~runner_interface(){}; #pragma region Interface Methods + /** + * Sets seed for PRNG used in runner. + * Else runner is started with the current time as seed. + * @param seed seed to use for PRNG + */ + virtual void set_rng_seed(uint32_t seed) = 0; /** * Moves the runner to the specified path @@ -56,6 +63,7 @@ namespace ink::runtime */ virtual bool can_continue() const = 0; +#ifdef INK_ENABLE_CSTD /** * Continue execution until the next newline, then allocate a c-style * string with the output. This allocated string is now the callers @@ -64,6 +72,13 @@ namespace ink::runtime * @return allocated c-style string with the output of a single line of execution */ virtual char* getline_alloc() = 0; +#endif + + /** + * @brief creates a snapshot containing the runner, globals and all other runners connected to the globals. + * @sa story::new_runner_from_snapshot, story::new_globals_from_snapshot + */ + virtual snapshot* create_snapshot() const = 0; #ifdef INK_ENABLE_STL /** @@ -147,7 +162,10 @@ namespace ink::runtime */ virtual void choose(size_t index) = 0; + /** check if since last choice selection tags have been added */ virtual bool has_tags() const = 0; + /** return the number of tags accumulated since last choice + * order of tags wont change, and new are added at the end */ virtual size_t num_tags() const = 0; virtual const char* get_tag(size_t index) const = 0; diff --git a/inkcpp/include/snapshot.h b/inkcpp/include/snapshot.h new file mode 100644 index 00000000..987a7564 --- /dev/null +++ b/inkcpp/include/snapshot.h @@ -0,0 +1,22 @@ +#pragma once + +#include "types.h" + +namespace ink::runtime +{ + class snapshot { + public: + virtual ~snapshot() {}; + + static snapshot* from_binary(const unsigned char* data, size_t length, bool freeOnDestroy = true); + + virtual const unsigned char* get_data() const = 0; + virtual size_t get_data_len() const = 0; + virtual size_t num_runners() const = 0; + +#ifdef INK_ENABLE_STL + static snapshot* from_file(const char* filename); + void write_to_file(const char* filename) const; +#endif + }; +} diff --git a/inkcpp/include/story.h b/inkcpp/include/story.h index 0e4bfbd4..c62cbbdd 100644 --- a/inkcpp/include/story.h +++ b/inkcpp/include/story.h @@ -19,6 +19,7 @@ namespace ink::runtime class story { public: + virtual ~story(){}; #pragma region Interface Methods /** * Creates a new global store @@ -30,6 +31,7 @@ namespace ink::runtime * @return managed pointer to a new global store */ virtual globals new_globals() = 0; + virtual globals new_globals_from_snapshot(const snapshot&) = 0; /** * Creates a new runner @@ -41,6 +43,17 @@ namespace ink::runtime * @return managed pointer to a new runner */ virtual runner new_runner(globals store = nullptr) = 0; + /** + * @brief reconstruct runner from a snapshot + * @attention runner must be snap_shotted from the same story + * @attention if globals is explicit set, + * make sure the globals are from the same snapshot as + * @attention if you snap_shotted a multiple runner with shared global + * please reconstruct it in the same fashion + * @param store can be set if explicit access to globals is required or multiple runner with a shared global are used + * @param idx if the snapshot was of a multiple runner one global situation load first the global, and then each runner with global set and increasing idx + */ + virtual runner new_runner_from_snapshot(const snapshot&, globals store = nullptr, unsigned idx = 0) = 0; #pragma endregion #pragma region Factory Methods @@ -71,4 +84,4 @@ namespace ink::runtime static story* from_binary(unsigned char* data, size_t length, bool freeOnDestroy = true); #pragma endregion }; -} \ No newline at end of file +} diff --git a/inkcpp/include/traits.h b/inkcpp/include/traits.h index 86ade898..c46ebd26 100644 --- a/inkcpp/include/traits.h +++ b/inkcpp/include/traits.h @@ -9,6 +9,13 @@ namespace ink::runtime::internal { + template + constexpr size_t sizeof_largest_type() + { + size_t ret = 0; + return ( (ret = sizeof(Ts) > ret ? sizeof(Ts) : ret), ... ); + } + template struct get_ith_type : get_ith_type {}; @@ -37,6 +44,21 @@ namespace ink::runtime::internal template struct is_same : true_type {}; + template + struct is_pointer : false_type {}; + + template + struct is_pointer : true_type {}; + + template struct remove_cv { typedef T type; }; + template struct remove_cv { typedef T type; }; + template struct remove_cv { typedef T type; }; + template struct remove_cv { typedef T type; }; + template + struct remove_cvref + { typedef std::remove_cv_t> type; }; + + // == string testing (from me) == template @@ -66,8 +88,13 @@ namespace ink::runtime::internal #define MARK_AS_STRING(TYPE, LEN, SRC) template<> struct is_string : constant { }; \ template<> struct string_handler { \ static size_t length(const TYPE& x) { return LEN; } \ - static const char* src(const TYPE& x) { return SRC; } \ - }; + static void src_copy(const TYPE& x, char* output) { \ + [&output](const char* src){\ + while(*src != '\0') *(output++) = *(src++); \ + *output = 0; \ + }(SRC);\ + } \ + } inline size_t c_str_len(const char* c) { const char* i = c; diff --git a/inkcpp/include/types.h b/inkcpp/include/types.h index 406078d8..208d2d08 100644 --- a/inkcpp/include/types.h +++ b/inkcpp/include/types.h @@ -1,17 +1,77 @@ #pragma once +#include "list.h" #include "story_ptr.h" - -namespace ink -{ - -} +#include "system.h" namespace ink::runtime { class globals_interface; class runner_interface; + class snapshot; - typedef story_ptr globals; - typedef story_ptr runner; -} \ No newline at end of file + using globals = story_ptr; + using runner = story_ptr; + using list = list_interface*; + + struct value { + union { + bool v_bool; + uint32_t v_uint32; + int32_t v_int32; + const char* v_string; + float v_float; + list v_list; + }; + enum class Type { + Bool, Uint32, Int32, String, Float, List + } type; + value() : v_int32{0}, type{Type::Int32} {} + value(bool v) : v_bool{v}, type{Type::Bool} {} + value(uint32_t v) : v_uint32{v}, type{Type::Uint32} {} + value(int32_t v) : v_int32{v}, type{Type::Int32} {} + value(const char* v) : v_string{v}, type{Type::String} {} + value(float v) : v_float{v}, type{Type::Float} {} + value(list_interface* list) : v_list{list}, type{Type::List} {} + value(const value& v) : type{v.type} { + switch(type) { + case Type::Bool: v_bool = v.v_bool; break; + case Type::Uint32: v_uint32 = v.v_uint32; break; + case Type::Int32: v_int32 = v.v_int32; break; + case Type::String: v_string = v.v_string; break; + case Type::Float: v_float = v.v_float; break; + case Type::List: v_list = v.v_list; break; + } + } + + template + const auto& get() const { + static_assert(Ty != Ty, "No value getter for the selected type"); + } + }; + + template<> + inline const auto& value::get() const { + return v_bool; + } + template<> + inline const auto& value::get() const { + return v_uint32; + } + template<> + inline const auto& value::get() const { + return v_int32; + } + template<> + inline const auto& value::get() const { + return v_string; + } + template<> + inline const auto& value::get() const { + return v_float; + } + template<> + inline const auto& value::get() const { + return v_list; + } +} diff --git a/inkcpp/list_impl.cpp b/inkcpp/list_impl.cpp new file mode 100644 index 00000000..f4551d5b --- /dev/null +++ b/inkcpp/list_impl.cpp @@ -0,0 +1,58 @@ +#include "list_impl.h" +#include "list.h" +#include "list_table.h" + +namespace ink::runtime::internal { + bool list_impl::contains(const char* flag_name) const { + auto flag = _list_table->toFlag(flag_name); + inkAssert(flag.has_value(), "No flag with name found! '%s'", flag_name); + return _list_table->has(list_table::list{_list}, *flag); + } + + void list_impl::add(const char* flag_name) { + auto flag = _list_table->toFlag(flag_name); + inkAssert(flag.has_value(), "No flag with name found to add! '%s'", flag_name); + _list = _list_table->add(list_table::list{_list}, *flag).lid; + } + + void list_impl::remove(const char* flag_name) { + auto flag = _list_table->toFlag(flag_name); + inkAssert(flag.has_value(), "No flag with name found to remove! '%s'", flag_name); + _list = _list_table->sub(list_table::list{_list}, *flag).lid; + } + + void list_impl::next(const char*& flag_name, const char*& list_name, int& i) const { + if (i == -1) { return; } + + list_flag flag{.list_id = static_cast(i >> 16), .flag = static_cast(i & 0xFF)}; + if(flag_name != nullptr) { + ++flag.flag; + } + if (flag.flag >= _list_table->_list_end[flag.list_id]) { + next_list: + flag.flag = 0; + do { + ++flag.list_id; + if(static_cast(flag.list_id) >= _list_table->_list_end.size()) { + i = -1; + return; + } + } while(!_list_table->hasList(_list_table->getPtr(_list), flag.list_id)); + } + while(!_list_table->has(list_table::list{_list}, flag)) { + ++flag.flag; + if(flag.flag >= _list_table->_list_end[flag.list_id] - _list_table->listBegin(flag.list_id)) { + goto next_list; + } + } + flag_name = _list_table->_flag_names[_list_table->toFid(flag)]; + list_name = _list_table->_list_names[flag.list_id]; + + i = (flag.list_id << 16) | flag.flag; + } + + list_interface::iterator list_impl::begin(const char* list_name) const { + size_t list_id = _list_table->get_list_id(list_name).list_id; + return ++new_iterator(nullptr, list_id<<16); + } +} diff --git a/inkcpp/list_impl.h b/inkcpp/list_impl.h new file mode 100644 index 00000000..09b09694 --- /dev/null +++ b/inkcpp/list_impl.h @@ -0,0 +1,33 @@ +#pragma once + +#include "list.h" + +namespace ink::runtime::internal { + class list_table; + class value; + class list_impl final : public list_interface { + public: + list_impl(list_table& table, int lid) : list_interface(table, lid) {} + int get_lid() const { return _list; } + + bool contains(const char* flag_name) const override; + void add(const char* flag_name) override; + void remove(const char* flag_name) override; + + list_interface::iterator begin() const override { + return ++new_iterator(nullptr, 0); + } + + list_interface::iterator begin(const char* list_name) const override; + list_interface::iterator end() const override { + return new_iterator(nullptr, -1); + } + + private: + friend ink::runtime::internal::value; + + /// @todo wrong iteration order, first lists then flags + void next(const char*& flag_name, const char*& list_name, int& i) const override; + + }; +} diff --git a/inkcpp/list_operations.cpp b/inkcpp/list_operations.cpp index 252a7244..eac2bbb8 100644 --- a/inkcpp/list_operations.cpp +++ b/inkcpp/list_operations.cpp @@ -23,7 +23,7 @@ ) \ )); \ } else {\ - inkAssert(vals[1].type()==value_type::list_flag);\ + inkAssert(vals[1].type()==value_type::list_flag, "list operation was called but second argument is not a list or list_flag");\ stack.push(value{}.set( \ _list_table.FUN( \ vals[0].get(), \ @@ -32,7 +32,7 @@ )); \ } \ } else { \ - inkAssert(vals[0].type() == value_type::list); \ + inkAssert(vals[0].type() == value_type::list, "list operation was called but first argument is not a list or a list_flag!"); \ if(vals[1].type() == value_type::list) { \ stack.push(value{}.set( \ _list_table.FUN( \ @@ -41,7 +41,7 @@ ) \ )); \ } else {\ - inkAssert(vals[1].type()==value_type::list_flag);\ + inkAssert(vals[1].type()==value_type::list_flag, "list operation was called but second argument ist not a list or list_flag!");\ stack.push(value{}.set( \ _list_table.FUN( \ vals[0].get(), \ @@ -76,8 +76,8 @@ namespace ink::runtime::internal { { int i = vals[1].type() == value_type::int32 ? vals[1].get() - : vals[1].get(); - inkAssert(vals[0].type() == value_type::list); + : static_cast(vals[1].get()); + inkAssert(vals[0].type() == value_type::list, "try to use list add function but value is not of type list"); stack.push(value{}.set( _list_table.add(vals[0].get(), i) )); @@ -88,12 +88,13 @@ namespace ink::runtime::internal { void operation::operator()( basic_eval_stack& stack, value* vals) { - inkAssert(vals[0].type() == value_type::list_flag); + inkAssert(vals[0].type() == value_type::list_flag, "try to use add function with list_flag results but first argument is not a list_flag!"); inkAssert(vals[1].type() == value_type::int32 - || vals[1].type() == value_type::uint32); + || vals[1].type() == value_type::uint32, + "try modify a list flag with a non intiger type!"); int i = vals[1].type() == value_type::int32 ? vals[1].get() - : vals[1].get(); + : static_cast(vals[1].get()); stack.push(value{}.set( _list_table.add(vals[0].get(), i) )); @@ -108,7 +109,7 @@ namespace ink::runtime::internal { int i = vals[1].type() == value_type::int32 ? vals[1].get() : vals[1].get(); - inkAssert(vals[0].type() == value_type::list); + inkAssert(vals[0].type() == value_type::list, "A in list resulting subtraction needs at leas one list as argument!"); stack.push(value{}.set( _list_table.sub(vals[0].get(), i) )); @@ -119,9 +120,10 @@ namespace ink::runtime::internal { void operation::operator()( basic_eval_stack& stack, value* vals) { - inkAssert(vals[0].type() == value_type::list_flag); + inkAssert(vals[0].type() == value_type::list_flag, "subtraction resulting in list_flag needs a list_flag as first arguments!"); inkAssert(vals[1].type() == value_type::int32 - || vals[1].type() == value_type::uint32); + || vals[1].type() == value_type::uint32, + "Try to subtract non integer value from list_flag."); int i = vals[1].type() == value_type::int32 ? vals[1].get() : vals[1].get(); @@ -170,8 +172,8 @@ namespace ink::runtime::internal { void operation::operator()( basic_eval_stack& stack, value* vals) { - inkAssert(vals[0].type() == value_type::string); - inkAssert(vals[1].type() == value_type::int32); + inkAssert(vals[0].type() == value_type::string, "list_flag construction needs the list name as string as first argument!"); + inkAssert(vals[1].type() == value_type::int32, "list_flag construction needs the flag numeric value as second argument!"); list_flag entry = _list_table.get_list_id(vals[0].get()); entry.flag = vals[1].get() - 1; stack.push(value{}.set(entry)); @@ -181,14 +183,14 @@ namespace ink::runtime::internal { if(val.type() == value_type::int32) { return val.get() - 1; } else { - inkAssert(val.type() == value_type::list_flag); + inkAssert(val.type() == value_type::list_flag, "flag value must be a integer or a list_flag"); return val.get().flag; } } void operation::operator()( basic_eval_stack& stack, value* vals) { - inkAssert(vals[0].type() == value_type::list); + inkAssert(vals[0].type() == value_type::list, "Can't get range of non list type!"); stack.push(value{}.set(_list_table.range( vals[0].get(), get_limit(vals[1]), diff --git a/inkcpp/list_table.cpp b/inkcpp/list_table.cpp index 06b57aa8..a988ab0a 100644 --- a/inkcpp/list_table.cpp +++ b/inkcpp/list_table.cpp @@ -3,6 +3,7 @@ #include "header.h" #include "random.h" #include "string_utils.h" +#include "list_impl.h" #ifdef INK_ENABLE_STL #include @@ -52,7 +53,7 @@ namespace ink::runtime::internal list_table::list list_table::create() { - for(int i = 0; i < _entry_state.size(); ++i) { + for(size_t i = 0; i < _entry_state.size(); ++i) { if (_entry_state[i] == state::empty) { _entry_state[i] = state::used; return list(i); @@ -78,11 +79,13 @@ namespace ink::runtime::internal } void list_table::mark_used(list l) { - _entry_state[l.lid] = state::used; + if (_entry_state[l.lid] == state::unused) { + _entry_state[l.lid] = state::used; + } } void list_table::gc() { - for(int i = 0; i < _entry_state.size(); ++i) { + for(size_t i = 0; i < _entry_state.size(); ++i) { if (_entry_state[i] == state::unused) { _entry_state[i] = state::empty; data_t* entry = getPtr(i); @@ -91,6 +94,7 @@ namespace ink::runtime::internal } } } + _list_handouts.clear(); } int list_table::toFid(list_flag e) const { @@ -299,10 +303,10 @@ namespace ink::runtime::internal } - list_table::list list_table::add(list arg, int i) { + list_table::list list_table::add(list arg, int n) { // TODO: handle i == 0 (for performance only) - if (i < 0) { - return sub(arg, -i); + if (n < 0) { + return sub(arg, -n); } list res = create(); data_t* l = getPtr(arg.lid); @@ -314,7 +318,7 @@ namespace ink::runtime::internal for(int j = listBegin(i); j < _list_end[i] - i;++j) { if(hasFlag(l, j)) { - setFlag(o,j+i); + setFlag(o,j+n); has_flag = true; } } @@ -339,10 +343,10 @@ namespace ink::runtime::internal return arg; } - list_table::list list_table::sub(list arg, int i) { + list_table::list list_table::sub(list arg, int n) { // TODO: handle i == 0 (for perofrgmance only) - if(i < 0) { - return add(arg, -i); + if(n < 0) { + return add(arg, -n); } list res = create(); data_t* l = getPtr(arg.lid); @@ -354,7 +358,7 @@ namespace ink::runtime::internal for(int j = listBegin(i) + i; j < _list_end[i]; ++j) { if(hasFlag(l,j)) { - setFlag(o,j-i); + setFlag(o,j-n); has_flag = true; } } @@ -399,7 +403,7 @@ namespace ink::runtime::internal const data_t* data = getPtr(l.lid); for(int i = 0; i < numLists(); ++i) { if(hasList(data, i)) { - for(int j = listBegin(i); j < _list_end[j]; ++j) { + for(int j = listBegin(i); j < _list_end[i]; ++j) { if(hasFlag(data, j)) { int value = j - listBegin(i); if(res.flag < 0 || value < res.flag) { @@ -554,14 +558,14 @@ namespace ink::runtime::internal list_flag list_table::lrnd(list lh, prng& rng) const { const data_t* l = getPtr(lh.lid); - int i = count(lh); - rng.rand(i); + int n = count(lh); + n = rng.rand(n); int count = 0; for(int i = 0; i < numLists(); ++i) { if(hasList(l, i)) { for(int j = listBegin(i); j < _list_end[i]; ++j) { if(hasFlag(l,j)) { - if(count++ == i) { + if(count++ == n) { return list_flag{ static_cast(i), static_cast( j - listBegin(i) ) @@ -620,6 +624,13 @@ namespace ink::runtime::internal return res; } + list_interface* list_table::handout_list(list l) { + static_assert(sizeof(list_interface) == sizeof(list_impl)); + auto& res = _list_handouts.push(); + new(&res) list_impl(*this, l.lid); + return &res; + } + #ifdef INK_ENABLE_STL std::ostream& list_table::write(std::ostream& os, list l) const { bool first = true; @@ -650,5 +661,20 @@ namespace ink::runtime::internal } #endif + size_t list_table::snap(unsigned char* data, const snapper& snapper) const + { + unsigned char* ptr = data; + ptr += _data.snap(data ? ptr : nullptr, snapper); + ptr += _entry_state.snap(data ? ptr : nullptr, snapper); + return ptr - data; + } + + const unsigned char* list_table::snap_load(const unsigned char* ptr, const loader& loader) + { + ptr = _data.snap_load(ptr, loader); + ptr = _entry_state.snap_load(ptr, loader); + return ptr; + } + } diff --git a/inkcpp/list_table.h b/inkcpp/list_table.h index 3ebd5497..ec95538e 100644 --- a/inkcpp/list_table.h +++ b/inkcpp/list_table.h @@ -2,13 +2,14 @@ #include "system.h" #include "array.h" +#include "snapshot_impl.h" #ifdef INK_ENABLE_STL #include #endif namespace ink::internal { - class header; + struct header; } namespace ink::runtime::internal { @@ -24,7 +25,7 @@ namespace ink::runtime::internal } /// managed all list entries and list metadata - class list_table + class list_table : public snapshot_interface { using data_t = int; enum class state : char { @@ -63,7 +64,7 @@ namespace ink::runtime::internal // parse binary list meta data list_table(const char* data, const ink::internal::header&); - explicit list_table() : _valid{false} {} + explicit list_table() : _entrySize{0}, _valid{ false } {} size_t stringLen(const list_flag& e) const; const char* toString(const list_flag& e) const; @@ -73,10 +74,39 @@ namespace ink::runtime::internal /** converts list to string representation * @param out char array with minimu size of stringLen(l) * @param l list to stringify - * @return pointer to end of insierted string + * @return pointer to end of inserted string */ char* toString(char* out, const list& l) const; + /** Finds flag id to flag name + * currently used a simple O(n) serach, for the expected number of flags should this be no problem + * @param flag_name null terminated string contaning the flag name + * @return list_flag with corresponding name + * @retval nullopt if no flag was found + */ + optional toFlag(const char* flag_name) const { + for(auto flag_itr = _flag_names.begin(); flag_itr != _flag_names.end(); ++flag_itr) { + if (strcmp(*flag_itr, flag_name) == 0) { + int fid = flag_itr - _flag_names.begin(); + int lid = 0; + int begin = 0; + for(auto list_itr = _list_end.begin(); list_itr != _list_end.end(); ++list_itr) { + if(*list_itr > fid) { + lid = list_itr - _list_end.begin(); + break; + } + begin = *list_itr; + } + return {list_flag{.list_id = static_cast(lid), .flag = static_cast(fid - begin)}}; + } + } + return nullopt; + } + + // snapshot interface implementation + size_t snap(unsigned char* data, const snapper&) const override; + const unsigned char* snap_load(const unsigned char* data, const loader&) override; + /** special traitment when a list get assignet again * when a list get assigned and would have no origin, it gets the origin of the base with origin * eg. I072 @@ -146,6 +176,7 @@ namespace ink::runtime::internal } list range(list l, int min, int max); + list_interface* handout_list(list); private: void copy_lists(const data_t* src, data_t* dst); static constexpr int bits_per_data = sizeof(data_t) * 8; @@ -153,10 +184,10 @@ namespace ink::runtime::internal return lid == 0 ? 0 : _list_end[lid-1]; } const data_t* getPtr(int eid) const { - return _data.begin() + _entrySize * eid; + return _data.begin() + static_cast(_entrySize) * static_cast(eid); } data_t* getPtr(int eid) { - return _data.begin() + _entrySize * eid; + return _data.begin() + static_cast(_entrySize) * static_cast(eid); } int numFlags() const { return _flag_names.size(); @@ -215,7 +246,7 @@ namespace ink::runtime::internal abs(config::maxListTypes) + abs(config::maxFlags), sizeof(data_t) - ) * abs(config::maxLists); + ) * static_cast(abs(config::maxLists)); int _entrySize; ///< entry size in data_t // entries (created lists) @@ -226,10 +257,13 @@ namespace ink::runtime::internal managed_array _list_end; managed_array _flag_names; managed_array _list_names; + /// keep track over lists accessed with get_var, and clear then at gc time + managed_array _list_handouts; bool _valid; public: friend class name_flag_itr; + friend class list_impl; class named_flag_itr { const list_table& _list; const data_t* _data; @@ -300,6 +334,7 @@ namespace ink::runtime::internal named_flag_itr(*this, f)}; return res; } + #ifdef INK_ENABLE_STL std::ostream& write(std::ostream&,list) const; #endif diff --git a/inkcpp/numeric_operations.cpp b/inkcpp/numeric_operations.cpp index 16f67ae0..6d17c57c 100644 --- a/inkcpp/numeric_operations.cpp +++ b/inkcpp/numeric_operations.cpp @@ -19,7 +19,7 @@ namespace ink::runtime::internal { void operation::operator()( basic_eval_stack& stack, value* vals) { - inkAssert(vals[0].type() == value_type::float32); + inkAssert(vals[0].type() == value_type::float32, "Expected floating point number to floor."); stack.push(value{}.set( floor(vals->get()))); } @@ -27,7 +27,7 @@ namespace ink::runtime::internal { void operation::operator()( basic_eval_stack& stack, value* vals) { - inkAssert(vals[0].type() == value_type::float32); + inkAssert(vals[0].type() == value_type::float32, "Expected floating point number to ceil."); stack.push(value{}.set( ceil(vals->get()))); } diff --git a/inkcpp/numeric_operations.h b/inkcpp/numeric_operations.h index 50c5f05a..3a1068a1 100644 --- a/inkcpp/numeric_operations.h +++ b/inkcpp/numeric_operations.h @@ -1,4 +1,5 @@ #pragma once +#include "value.h" /// Define operation for numeric types. /// use generalized types numeric and integral to keep redundancy minimal. @@ -14,6 +15,11 @@ namespace ink::runtime::internal { || ty == value_type::int32 || ty == value_type::uint32 || ty == value_type::float32, void>::type; + + template + using is_signed_numeric_t = typename enable_if< + ty == value_type::int32 + || ty == value_type::float32, void>::type; /// list of internal value types /// produces a SFINAE error if type is not part of list @@ -47,7 +53,8 @@ namespace ink::runtime::internal { inline typename value::ret::type numeric_cast(const value& v) { if (to == v.type()) { return v.get(); } else { - throw ink_exception("invalid numeric_cast!"); + inkFail("invalid numeric_cast! from %i to %i", v.type(), to); + return 0; } } @@ -61,7 +68,8 @@ namespace ink::runtime::internal { case value_type::boolean: return static_cast(v.get()); default: - throw ink_exception("invalid cast to uint!"); + inkFail("invalid cast to uint!"); + return 0; } } @@ -73,7 +81,8 @@ namespace ink::runtime::internal { case value_type::boolean: return static_cast(v.get()); default: - throw ink_exception("invalid cast to int!"); + inkFail("invalid cast to int!"); + return 0; } } @@ -87,7 +96,26 @@ namespace ink::runtime::internal { case value_type::int32: return static_cast(v.get()); default: - throw ink_exception("invalid numeric_cast!"); + inkFail("invalid numeric_cast!"); + return 0; + } + } + + /// specialisation for boolean + template<> + inline bool numeric_cast(const value& v) { + switch(v.type()) { + case value_type::boolean: + return v.get(); + case value_type::int32: + return v.get() != 0; + case value_type::uint32: + return v.get() != 0; + case value_type::float32: + return v.get() != 0; + default: + inkFail("invalid numeric_cast to boolean from: %i", v.type()); + return false; } } } @@ -227,7 +255,9 @@ namespace ink::runtime::internal { public: using operation_base::operation_base; void operator()(basic_eval_stack& stack, value* vals) { - stack.push(value{}.set( vals[0].get() % vals[1].get() )); + stack.push(value{}.set( + casting::numeric_cast(vals[0]) + % casting::numeric_cast(vals[1]))); } }; @@ -320,7 +350,9 @@ namespace ink::runtime::internal { public: using operation_base::operation_base; void operator()(basic_eval_stack& stack, value* vals) { - stack.push(value{}.set( vals[0].get() && vals[1].get() )); + stack.push(value{}.set( + casting::numeric_cast(vals[0]) + && casting::numeric_cast(vals[1]))); } }; @@ -328,8 +360,11 @@ namespace ink::runtime::internal { class operation> : public operation_base { public: using operation_base::operation_base; - void operator()(basic_eval_stack& stack, value* vals) { - stack.push(value{}.set( vals[0].get() || vals[1].get() )); + void operator()( basic_eval_stack& stack, value* vals ) + { + stack.push(value{}.set( + casting::numeric_cast(vals[0]) + || casting::numeric_cast(vals[1]))); } }; @@ -369,7 +404,7 @@ namespace ink::runtime::internal { }; template - class operation> : public operation_base { + class operation> : public operation_base { public: using operation_base::operation_base; void operator()(basic_eval_stack& stack, value* vals) { @@ -393,7 +428,7 @@ namespace ink::runtime::internal { void operator()(basic_eval_stack& stack, value* vals) { int min = casting::numeric_cast(vals[0]); int max = casting::numeric_cast(vals[0]); - stack.push(value{}.set(_prng.rand(max - min + 1) + min)); + stack.push(value{}.set(static_cast(_prng.rand(max - min + 1) + min))); } }; } diff --git a/inkcpp/operations.h b/inkcpp/operations.h index 98339ffe..ac24ca2d 100644 --- a/inkcpp/operations.h +++ b/inkcpp/operations.h @@ -2,7 +2,9 @@ /// Define base constructs to specify by operation headers. -#include "../shared/private/command.h" +#include "command.h" +#include "stack.h" +#include "value.h" namespace ink::runtime::internal { @@ -54,7 +56,7 @@ namespace ink::runtime::internal { * @param vs array of values, first one = first argument etc */ void operator()(basic_eval_stack& stack, value* vs) { - throw ink_exception("operation not implemented!"); + inkFail("operation not implemented!"); } }; } diff --git a/inkcpp/output.cpp b/inkcpp/output.cpp index 559de9ff..7d9a17bc 100644 --- a/inkcpp/output.cpp +++ b/inkcpp/output.cpp @@ -8,500 +8,490 @@ #include #endif -namespace ink +namespace ink::runtime::internal { - namespace runtime + basic_stream::basic_stream(value* buffer, size_t len) + : _data(buffer), _max(len), _size(0), _save(~0) + {} + + void basic_stream::append(const value& in) { - namespace internal + // SPECIAL: Incoming newline + if (in.type() == value_type::newline && _size > 1) { - basic_stream::basic_stream(value* buffer, size_t len) - : _data(buffer), _max(len), _size(0), _save(~0) - {} + // If the end of the stream is a function start marker, we actually + // want to ignore this. Function start trimming. + if (_data[_size - 1].type() == value_type::func_start) + return; + } - void basic_stream::append(const value& in) - { - // SPECIAL: Incoming newline - if (in.type() == value_type::newline && _size > 1) - { - // If the end of the stream is a function start marker, we actually - // want to ignore this. Function start trimming. - if (_data[_size - 1].type() == value_type::func_start) - return; - } + // Ignore leading newlines + if (in.type() == value_type::newline && _size == 0) + return; - // Ignore leading newlines - if (in.type() == value_type::newline && _size == 0) - return; + // Add to data stream + inkAssert(_size < _max, "Output stream overflow"); + _data[_size++] = in; - // Add to data stream - inkAssert(_size < _max, "Output stream overflow"); - _data[_size++] = in; + // Special: Incoming glue. Trim whitespace/newlines prior + // This also applies when a function ends to trim trailing whitespace. + if ((in.type() == value_type::glue || in.type() == value_type::func_end) && _size > 1) + { + // Run backwards + size_t i = _size - 2; + while(true) + { + value& d = _data[i]; - // Special: Incoming glue. Trim whitespace/newlines prior - // This also applies when a function ends to trim trailing whitespace. - if ((in.type() == value_type::glue || in.type() == value_type::func_end) && _size > 1) - { - // Run backwards - size_t i = _size - 2; - while(true) - { - value& d = _data[i]; - - // Nullify newlines - if (d.type() == value_type::newline) { - d = value{}; - } - - // Nullify whitespace - else if ( d.type() == value_type::string - && is_whitespace(d.get())) - d = value{}; - - // If it's not a newline or whitespace, stop - else break; - - // If we've hit the end, break - if (i == 0) - break; - - // Move on to next element - i--; - } + // Nullify newlines + if (d.type() == value_type::newline) { + d = value{}; } - } - void basic_stream::append(const value* in, unsigned int length) - { - // TODO: Better way to bulk while still executing glue checks? - for (size_t i = 0; i < length; i++) - append(in[i]); - } + // Nullify whitespace + else if ( d.type() == value_type::string + && is_whitespace(d.get())) + d = value{}; - template - inline void write_char(OUT& output, char c) - { - static_assert(always_false::value, "Invalid output type"); - } + // If it's not a newline or whitespace, stop + else break; - template<> - inline void write_char(char*& output, char c) - { - (*output++) = c; - } + // If we've hit the end, break + if (i == 0) + break; - template<> - inline void write_char(std::stringstream& output, char c) - { - output.put(c); + // Move on to next element + i--; } + } + } - inline bool get_next(const value* list, size_t i, size_t size, const value** next) - { - while (i + 1 < size) - { - *next = &list[i + 1]; - value_type type = (*next)->type(); - if ((*next)->printable()) { return true; } - i++; - } + void basic_stream::append(const value* in, unsigned int length) + { + // TODO: Better way to bulk while still executing glue checks? + for (size_t i = 0; i < length; i++) + append(in[i]); + } - return false; - } + template + inline void write_char(T& output, char c) + { + static_assert(always_false::value, "Invalid output type"); + } - template - void basic_stream::copy_string(const char* str, size_t& dataIter, OUT& output) - { - while(*str != 0) { - write_char(output, *str++); - } - } + template<> + inline void write_char(char*& output, char c) + { + (*output++) = c; + } #ifdef INK_ENABLE_STL - std::string basic_stream::get() - { - size_t start = find_start(); - - // Move up from marker - bool hasGlue = false, lastNewline = false; - std::stringstream str; - for (size_t i = start; i < _size; i++) - { - if (should_skip(i, hasGlue, lastNewline)) - continue; - if (_data[i].printable()){ - _data[i].write(str, _lists_table); - } - - } - - // Reset stream size to where we last held the marker - _size = start; - - // Return processed string - // remove mulitple accourencies of ' ' - std::string result = str.str(); - auto end = clean_string(result.begin(), result.end()); - _last_char = *(end-1); - result.resize(end - result.begin() - (_last_char == ' ' ? 1 : 0)); - return result; - } + template<> + inline void write_char(std::stringstream& output, char c) + { + output.put(c); + } #endif -#ifdef INK_ENABLE_UNREAL - FString basic_stream::get() - { - size_t start = find_start(); - // TODO: Slow! FString concatonation. - // Is there really no equivilent of stringstream in Unreal? Some kind of String Builder? + inline bool get_next(const value* list, size_t i, size_t size, const value** next) + { + while (i + 1 < size) + { + *next = &list[i + 1]; + value_type type = (*next)->type(); + if ((*next)->printable()) { return true; } + i++; + } - // Move up from marker - bool hasGlue = false; - FString str; - for (size_t i = start; i < _size; i++) - { - if (should_skip(i, hasGlue)) - continue; + return false; + } - switch (_data[i].type) - { - case value_type::int32: - str += FString::Printf(TEXT("%d"), _data[i].integer_value); - break; - case value_type::float32: - // TODO: Whitespace cleaning - str += FString::Printf(TEXT("%f"), _data[i].float_value); - break; - case value_type::string: - str += _data[i].string_val; - break; - case data_type::newline: - str += "\n"; - break; - default: - break; - } - } + template + void basic_stream::copy_string(const char* str, size_t& dataIter, T& output) + { + while(*str != 0) { + write_char(output, *str++); + } + } - // Reset stream size to where we last held the marker - _size = start; +#ifdef INK_ENABLE_STL + std::string basic_stream::get() + { + size_t start = find_start(); - // Return processed string - return str; + // Move up from marker + bool hasGlue = false, lastNewline = false; + std::stringstream str; + for (size_t i = start; i < _size; i++) + { + if (should_skip(i, hasGlue, lastNewline)) + continue; + if (_data[i].printable()){ + _data[i].write(str, _lists_table); } -#endif - int basic_stream::queued() const - { - size_t start = find_start(); - return _size - start; - } + } - const value& basic_stream::peek() const - { - inkAssert(_size > 0, "Attempting to peek empty stream!"); - return _data[_size - 1]; - } + // Reset stream size to where we last held the marker + _size = start; - void basic_stream::discard(size_t length) - { - // discard elements - _size -= length; - if (_size < 0) - _size = 0; - } + // Return processed string + // remove mulitple accourencies of ' ' + std::string result = str.str(); + if ( !result.empty() ) { + auto end = clean_string( result.begin(), result.end() ); + _last_char = *( end - 1 ); + result.resize( end - result.begin() - ( _last_char == ' ' ? 1 : 0 ) ); + } + return result; + } +#endif +#ifdef INK_ENABLE_UNREAL + FString basic_stream::get() + { + UE_LOG( InkCpp, Warning, TEXT("Basic stream::get is not implemented correctly and should not be used implemented correctly!" ) ); + FString str; + return str; + } +#endif - void basic_stream::get(value* ptr, size_t length) - { - // Find start - size_t start = find_start(); + int basic_stream::queued() const + { + size_t start = find_start(); + return _size - start; + } - const value* end = ptr + length; - //inkAssert(_size - start < length, "Insufficient space in data array to store stream contents!"); + const value& basic_stream::peek() const + { + inkAssert(_size > 0, "Attempting to peek empty stream!"); + return _data[_size - 1]; + } - // Move up from marker - bool hasGlue = false, lastNewline = false; - for (size_t i = start; i < _size; i++) - { - if (should_skip(i, hasGlue, lastNewline)) - continue; + void basic_stream::discard(size_t length) + { + // discard elements + _size -= length; + if (_size < 0) + _size = 0; + } - // Make sure we can fit the next element - inkAssert(ptr < end, "Insufficient space in data array to store stream contents!"); + void basic_stream::get(value* ptr, size_t length) + { + // Find start + size_t start = find_start(); - // Copy any value elements - if (_data[i].printable()) { - *(ptr++) = _data[i]; - } - } + const value* end = ptr + length; + //inkAssert(_size - start < length, "Insufficient space in data array to store stream contents!"); - // Reset stream size to where we last held the marker - _size = start; - } + // Move up from marker + bool hasGlue = false, lastNewline = false; + for (size_t i = start; i < _size; i++) + { + if (should_skip(i, hasGlue, lastNewline)) + continue; - bool basic_stream::has_marker() const - { - // TODO: Cache? - for (size_t i = 0; i < _size; i++) - { - if (_data[i].type() == value_type::marker) - return true; - } + // Make sure we can fit the next element + inkAssert(ptr < end, "Insufficient space in data array to store stream contents!"); - return false; + // Copy any value elements + if (_data[i].printable()) { + *(ptr++) = _data[i]; } + } - bool basic_stream::ends_with(value_type type) const - { - if (_size == 0) - return false; + // Reset stream size to where we last held the marker + _size = start; + } - return _data[_size - 1].type() == type; - } + bool basic_stream::has_marker() const + { + // TODO: Cache? + for (size_t i = 0; i < _size; i++) + { + if (_data[i].type() == value_type::marker) + return true; + } - bool basic_stream::saved_ends_with(value_type type) const - { - inkAssert(_save != ~0, "Stream is not saved!"); + return false; + } - if (_save == 0) - return false; + bool basic_stream::ends_with(value_type type) const + { + if (_size == 0) + return false; - return _data[_save - 1].type() == type; - } + return _data[_size - 1].type() == type; + } - void basic_stream::save() - { - inkAssert(_save == ~0, "Can not save over existing save point!"); + bool basic_stream::saved_ends_with(value_type type) const + { + inkAssert(_save != ~0, "Stream is not saved!"); - // Save the current size - _save = _size; - } + if (_save == 0) + return false; - void basic_stream::restore() - { - inkAssert(_save != ~0, "No save point to restore!"); + return _data[_save - 1].type() == type; + } - // Restore size to saved position - _size = _save; - _save = ~0; - } + void basic_stream::save() + { + inkAssert(_save == ~0, "Can not save over existing save point!"); - void basic_stream::forget() - { - inkAssert(_save != ~0, "No save point to forget!"); + // Save the current size + _save = _size; + } - // Just null the save point and continue as normal - _save = ~0; - } - - template char* basic_stream::get_alloc(string_table& strings, list_table& lists); - template char* basic_stream::get_alloc(string_table& strings, list_table& lists); + void basic_stream::restore() + { + inkAssert(_save != ~0, "No save point to restore!"); - template - char* basic_stream::get_alloc(string_table& strings, list_table& lists) - { - size_t start = find_start(); + // Restore size to saved position + _size = _save; + _save = ~0; + } - // Two passes. First for length - size_t length = 0; - bool hasGlue = false, lastNewline = false; - for (size_t i = start; i < _size; i++) - { - if (should_skip(i, hasGlue, lastNewline)) - continue; - ++length; // potenzial space to sperate - if (_data[i].printable()) { - switch(_data[i].type()) { - case value_type::list: - length += lists.stringLen(_data[i].get()); - break; - case value_type::list_flag: - length += lists.stringLen(_data[i].get()); - default: length += value_length(_data[i]); - } - } - } + void basic_stream::forget() + { + inkAssert(_save != ~0, "No save point to forget!"); - // Allocate - char* buffer = strings.create(length + 1); - char* end = buffer + length + 1; - char* ptr = buffer; - hasGlue = false; lastNewline = false; - for (size_t i = start; i < _size; i++) - { - if (should_skip(i, hasGlue, lastNewline)) - continue; - if(!_data[i].printable()) { continue; } - switch (_data[i].type()) - { - case value_type::int32: - case value_type::float32: - case value_type::uint32: - // Convert to string and advance - toStr(ptr, end - ptr, _data[i]); - while (*ptr != 0) ptr++; + // Just null the save point and continue as normal + _save = ~0; + } + + template char* basic_stream::get_alloc(string_table& strings, list_table& lists); + template char* basic_stream::get_alloc(string_table& strings, list_table& lists); - break; - case value_type::string: - { - // Copy string and advance - const char* value = _data[i].get(); - copy_string(value, i, ptr); - } break; - case value_type::newline: - *ptr = '\n'; ptr++; - break; + template + char* basic_stream::get_alloc(string_table& strings, list_table& lists) + { + size_t start = find_start(); + + // Two passes. First for length + size_t length = 0; + bool hasGlue = false, lastNewline = false; + for (size_t i = start; i < _size; i++) + { + if (should_skip(i, hasGlue, lastNewline)) + continue; + ++length; // potenzial space to sperate + if (_data[i].printable()) { + switch(_data[i].type()) { case value_type::list: - ptr = lists.toString(ptr, _data[i].get()); + length += lists.stringLen(_data[i].get()); break; case value_type::list_flag: - ptr = lists.toString(ptr, _data[i].get()); + length += lists.stringLen(_data[i].get()); break; - default: throw ink_exception("cant convert expression to string!"); - } + default: length += value_length(_data[i]); } + } + } - // Make sure last character is a null - *ptr = 0; + // Allocate + char* buffer = strings.create(length + 1); + char* end = buffer + length + 1; + char* ptr = buffer; + hasGlue = false; lastNewline = false; + for (size_t i = start; i < _size; i++) + { + if (should_skip(i, hasGlue, lastNewline)) + continue; + if(!_data[i].printable()) { continue; } + switch (_data[i].type()) + { + case value_type::int32: + case value_type::float32: + case value_type::uint32: + // Convert to string and advance + toStr(ptr, end - ptr, _data[i]); + while (*ptr != 0) ptr++; + + break; + case value_type::string: + { + // Copy string and advance + const char* value = _data[i].get(); + copy_string(value, i, ptr); + } break; + case value_type::newline: + *ptr = '\n'; ptr++; + break; + case value_type::list: + ptr = lists.toString(ptr, _data[i].get()); + break; + case value_type::list_flag: + ptr = lists.toString(ptr, _data[i].get()); + break; + default: inkFail("cant convert expression to string!"); + } + } - // Reset stream size to where we last held the marker - _size = start; + // Make sure last character is a null + *ptr = 0; - // Return processed string - { - auto end = clean_string(buffer, buffer+length); - *end = 0; - _last_char = end[-1]; - if constexpr (RemoveTail) { - if (_last_char == ' ') { end[-1] = 0; } - } - } - return buffer; - } + // Reset stream size to where we last held the marker + _size = start; - size_t basic_stream::find_start() const - { - // Find marker (or start) - size_t start = _size; - while (start > 0) - { - start--; - if (_data[start].type() == value_type::marker) - break; - } + // Return processed string + end = clean_string(buffer, buffer + c_str_len(buffer)); + *end = 0; + _last_char = end[-1]; + if constexpr (RemoveTail) { + if (_last_char == ' ') { end[-1] = 0; } + } + + return buffer; + } - // Make sure we're not violating a save point - if (_save != ~0 && start < _save) { - // TODO: check if we don't reset save correct - // at some point we can modifiy the output even behind save (probally discard?) and push a new element -> invalid save point - // inkAssert(false, "Trying to access output stream prior to save point!"); - const_cast(*this).clear(); - } + size_t basic_stream::find_start() const + { + // Find marker (or start) + size_t start = _size; + while (start > 0) + { + start--; + if (_data[start].type() == value_type::marker) + break; + } - return start; - } + // Make sure we're not violating a save point + if (_save != ~0 && start < _save) { + // TODO: check if we don't reset save correct + // at some point we can modifiy the output even behind save (probally discard?) and push a new element -> invalid save point + // inkAssert(false, "Trying to access output stream prior to save point!"); + const_cast(*this).clear(); + } + + return start; + } - bool basic_stream::should_skip(size_t iter, bool& hasGlue, bool& lastNewline) const + bool basic_stream::should_skip(size_t iter, bool& hasGlue, bool& lastNewline) const + { + if (_data[iter].printable() + && _data[iter].type() != value_type::newline + && _data[iter].type() != value_type::string) { + lastNewline = false; + hasGlue = false; + } else { + switch (_data[iter].type()) + { + case value_type::newline: + if (lastNewline) + return true; + if (hasGlue) + return true; + lastNewline = true; + break; + case value_type::glue: + hasGlue = true; + break; + case value_type::string: { - if (_data[iter].printable() - && _data[iter].type() != value_type::newline - && _data[iter].type() != value_type::string) { - lastNewline = false; - hasGlue = false; - } else { - switch (_data[iter].type()) + lastNewline = false; + // an empty string don't count as glued I095 + for(const char* i=_data[iter].get(); + *i; ++i) { - case value_type::newline: - if (lastNewline) - return true; - if (hasGlue) - return true; - lastNewline = true; - break; - case value_type::glue: - hasGlue = true; - break; - case value_type::string: - { - lastNewline = false; - // an empty string don't count as glued I095 - for(const char* i=_data[iter].get(); - *i; ++i) - { - // isspace only supports characters in [0, UCHAR_MAX] - if (!isspace(static_cast(*i))) { - hasGlue = false; - break; - } - } - } break; - default: + // isspace only supports characters in [0, UCHAR_MAX] + if (!isspace(static_cast(*i))) { + hasGlue = false; break; } } - - return false; + } break; + default: + break; } + } - bool basic_stream::text_past_save() const - { - // Check if there is text past the save - for (size_t i = _save; i < _size; i++) - { - const value& d = _data[i]; - if (d.type() == value_type::string) - { - // TODO: Cache what counts as whitespace? - if (!is_whitespace(d.get(), false)) - return true; - } - } - - // No text - return false; - } + return false; + } - void basic_stream::clear() + bool basic_stream::text_past_save() const + { + // Check if there is text past the save + for (size_t i = _save; i < _size; i++) + { + const value& d = _data[i]; + if (d.type() == value_type::string) { - _save = ~0; - _size = 0; + // TODO: Cache what counts as whitespace? + if (!is_whitespace(d.get(), false)) + return true; } + } - void basic_stream::mark_strings(string_table& strings) const - { - // Find all allocated strings and mark them as used - for (int i = 0; i < _size; i++) - { - if (_data[i].type() == value_type::string) { - string_type str = _data[i].get(); - if (str.allocated) { - strings.mark_used(str.str); - } - } + // No text + return false; + } + + void basic_stream::clear() + { + _save = ~0; + _size = 0; + } + + void basic_stream::mark_used(string_table& strings, list_table& lists) const + { + // Find all allocated strings and mark them as used + for (size_t i = 0; i < _size; i++) + { + if (_data[i].type() == value_type::string) { + string_type str = _data[i].get(); + if (str.allocated) { + strings.mark_used(str.str); } + } else if (_data[i].type() == value_type::list) { + lists.mark_used(_data[i].get()); } + } + } #ifdef INK_ENABLE_STL - std::ostream& operator<<(std::ostream& out, basic_stream& in) - { - out << in.get(); - return out; - } + std::ostream& operator<<(std::ostream& out, basic_stream& in) + { + out << in.get(); + return out; + } - basic_stream& operator>>(basic_stream& in, std::string& out) - { - out = in.get(); - return in; - } + basic_stream& operator>>(basic_stream& in, std::string& out) + { + out = in.get(); + return in; + } #endif #ifdef INK_ENABLE_UNREAL - basic_stream& operator>>(basic_stream& in, FString& out) - { - out = in.get(); - return in; - } + basic_stream& operator>>(basic_stream& in, FString& out) + { + out = in.get(); + return in; + } #endif + size_t basic_stream::snap(unsigned char* data, const snapper& snapper) const + { + unsigned char* ptr = data; + ptr = snap_write(ptr, _last_char, data != nullptr); + ptr = snap_write(ptr, _size, data != nullptr); + ptr = snap_write(ptr, _save, data != nullptr); + for(auto itr = _data; itr != _data + _size; ++itr) + { + ptr += itr->snap(data ? ptr : nullptr, snapper); + } + return ptr - data; + } + const unsigned char* basic_stream::snap_load(const unsigned char* ptr, const loader& loader) + { + ptr = snap_read(ptr, _last_char); + ptr = snap_read(ptr, _size); + ptr = snap_read(ptr, _save); + inkAssert(_max >= _size, "output is to small to hold stored data"); + for(auto itr = _data; itr != _data + _size; ++itr) + { + ptr = itr->snap_load(ptr, loader); } + return ptr; } } + diff --git a/inkcpp/output.h b/inkcpp/output.h index 60663f8e..1cb48cb5 100644 --- a/inkcpp/output.h +++ b/inkcpp/output.h @@ -2,6 +2,7 @@ #include "value.h" #include "platform.h" +#include "snapshot_impl.h" namespace ink { @@ -11,7 +12,7 @@ namespace ink { class string_table; class list_table; - class basic_stream + class basic_stream : public snapshot_interface { protected: basic_stream(value*, size_t); @@ -53,12 +54,8 @@ namespace ink #ifdef INK_ENABLE_STL // Extract into a string std::string get(); -#else - // will conflict with stl definition -# ifdef INK_ENABLE_UNREAL - // Extract into a string +#elif defined(INK_ENABLE_UNREAL) FString get(); -# endif #endif // Check if the stream is empty @@ -80,8 +77,8 @@ namespace ink // Clears the whole stream void clear(); - // Marks strings that are in use - void mark_strings(string_table&) const; + // Marks strings and lists that are in use + void mark_used(string_table&, list_table&) const; // = Save/Restore void save(); @@ -99,12 +96,16 @@ namespace ink bool saved() const { return _save != ~0; } + // snapshot interface + size_t snap(unsigned char* data, const snapper&) const override; + const unsigned char* snap_load(const unsigned char* data, const loader&) override; + private: size_t find_start() const; bool should_skip(size_t iter, bool& hasGlue, bool& lastNewline) const; - template - void copy_string(const char* str, size_t& dataIter, OUT& output); + template + void copy_string(const char* str, size_t& dataIter, T& output); private: char _last_char; @@ -126,9 +127,7 @@ namespace ink std::ostream& operator <<(std::ostream&, basic_stream&); basic_stream& operator >>(basic_stream&, std::string&); #endif -#ifdef INK_ENABLE_UNREAL - basic_stream& operator >>(basic_stream&, FString&); -#endif + template class stream : public basic_stream diff --git a/inkcpp/random.h b/inkcpp/random.h index 995b7947..518e3e27 100644 --- a/inkcpp/random.h +++ b/inkcpp/random.h @@ -1,29 +1,32 @@ #pragma once -#include "../shared/public/system.h" +#include "system.h" namespace ink::runtime::internal { /** - * @brief pseudo random number generator based on Linear Congruential Generator. + * @brief pseudo random number generator based on Linear Congruential Generator (using glibc default values). */ class prng { - static constexpr uint32_t C = 12345; - static constexpr uint32_t A = 1103515245; - static constexpr uint32_t M = 1<<31; + static constexpr uint64_t C = 12345; + static constexpr uint64_t A = 1103515245; + static constexpr uint64_t M = 1ul<<31; public: - void srand(int32_t seed) { + void srand(uint32_t seed) { _x = seed; } uint32_t rand() { - _x = (A*_x+ C) % M; + _x = static_cast((A*_x+ C) % M); return _x; } - int32_t rand(int32_t max) { + uint32_t rand(uint32_t max) { uint64_t prod = rand(); prod *= max; return static_cast(prod / M); } + uint32_t get_state() const { return _x; } + prng(uint32_t seed) : _x{seed}{} + prng() : prng(1337) {} private: - uint32_t _x = 1337; + uint32_t _x; }; } diff --git a/inkcpp/runner_impl.cpp b/inkcpp/runner_impl.cpp index ee51511a..02e31147 100644 --- a/inkcpp/runner_impl.cpp +++ b/inkcpp/runner_impl.cpp @@ -5,6 +5,8 @@ #include "globals_impl.h" #include "header.h" #include "string_utils.h" +#include "snapshot_impl.h" +#include "value.h" namespace ink::runtime { @@ -163,6 +165,7 @@ namespace ink::runtime::internal void runner_impl::clear_tags() { _tags.clear(); + _choice_tags_begin = -1; } void runner_impl::jump(ip_t dest, bool record_visits) @@ -188,8 +191,8 @@ namespace ink::runtime::internal // Iterate until we find the container marker just before our own while (_story->iterate_containers(iter, container_id, offset, reverse)) { - if (!reverse && offset > _ptr - || reverse && offset < _ptr) { + if (( !reverse && offset > _ptr ) + || ( reverse && offset < _ptr )) { // Step back once in the iteration and break inBound = true; @@ -202,57 +205,57 @@ namespace ink::runtime::internal bool first = true; // Start moving forward (or backwards) - if(inBound && (offset == nullptr || !reverse&&offset<=dest || reverse&&offset>dest) ) - while (_story->iterate_containers(iter, container_id, offset, reverse)) - { - // Break when we've past the destination - if (!reverse && offset > dest || reverse && offset <= dest) { - // jump back to start of same container - if(first && reverse && offset == dest - && _container.top() == container_id) { - // check if it was start flag - auto con_id = container_id; - _story->iterate_containers(iter, container_id, offset, true); - if(offset == nullptr || con_id == container_id) - { - _globals->visit(container_id); + if(inBound && (offset == nullptr || (!reverse&&offset<=dest) || (reverse&&offset>dest)) ) + while (_story->iterate_containers(iter, container_id, offset, reverse)) + { + // Break when we've past the destination + if ((!reverse && offset > dest) || (reverse && offset <= dest)) { + // jump back to start of same container + if(first && reverse && offset == dest + && _container.top() == container_id) { + // check if it was start flag + auto con_id = container_id; + _story->iterate_containers(iter, container_id, offset, true); + if(offset == nullptr || con_id == container_id) + { + _globals->visit(container_id); + } } + break; } - break; - } - first = false; + first = false; - // Two cases: + // Two cases: - // (1) Container iterator has the same value as the top of the stack. - // This means that this is an end marker for the container we're in - if (!_container.empty() && _container.top() == container_id) - { - if (_container.size() == pos) - pos--; + // (1) Container iterator has the same value as the top of the stack. + // This means that this is an end marker for the container we're in + if (!_container.empty() && _container.top() == container_id) + { + if (_container.size() == pos) + pos--; - // Get out of that container - _container.pop(); - } + // Get out of that container + _container.pop(); + } - // (2) This must be the entrance marker for a new container. Enter it - else - { - // Push it - _container.push(container_id); + // (2) This must be the entrance marker for a new container. Enter it + else + { + // Push it + _container.push(container_id); + } } - } // Iterate over the container stack marking any _new_ entries as "visited" if (record_visits) { - const container_t* iter; + const container_t* con_iter; size_t num_new = _container.size() - pos; - while (_container.iter(iter)) + while (_container.iter(con_iter)) { if (num_new <= 0) break; - _globals->visit(*iter); + _globals->visit(*con_iter); --num_new; } } @@ -269,10 +272,10 @@ namespace ink::runtime::internal // Push next address onto the callstack { size_t address = _ptr - _story->instructions(); - _stack.push_frame(address, bEvaluationMode); - _ref_stack.push_frame(address, bEvaluationMode); + _stack.push_frame(address, _evaluation_mode); + _ref_stack.push_frame(address, _evaluation_mode); } - bEvaluationMode = false; // unset eval mode when enter function or tunnel + _evaluation_mode = false; // unset eval mode when enter function or tunnel // Do the jump inkAssert(_story->instructions() + target < _story->end(), "Diverting past end of story data!"); @@ -284,12 +287,12 @@ namespace ink::runtime::internal // Pop the callstack _ref_stack.fetch_values(_stack); frame_type type; - offset_t offset = _stack.pop_frame(&type,bEvaluationMode); + offset_t offset = _stack.pop_frame(&type,_evaluation_mode); _ref_stack.push_values(_stack); { frame_type t; bool eval; // TODO: write all refs to new frame offset_t o = _ref_stack.pop_frame(&t, eval); - inkAssert(o == offset && t == type && eval == bEvaluationMode, + inkAssert(o == offset && t == type && eval == _evaluation_mode, "_ref_stack and _stack should be in frame sync!"); } @@ -316,7 +319,7 @@ namespace ink::runtime::internal } runner_impl::runner_impl(const story_impl* data, globals global) - : _story(data), _globals(global.cast()), _container(~0), + : _story(data), _globals(global.cast()), _operations( global.cast()->strings(), global.cast()->lists(), @@ -324,10 +327,11 @@ namespace ink::runtime::internal *global.cast(), *data, static_cast(*this)), - _backup(nullptr), _done(nullptr), _choices() + _backup(nullptr), _done(nullptr), _choices(), _container(~0), _rng(time(NULL)) { _ptr = _story->instructions(); - bEvaluationMode = false; + _evaluation_mode = false; + _choice_tags_begin = -1; // register with globals _globals->add_runner(this); @@ -364,9 +368,7 @@ namespace ink::runtime::internal // Advance interpreter one line advance_line(); // Read line into std::string - std::string part; - _output >> part; - result += part; + result += _output.get(); fill = _output.last_char() == ' '; } while(_ptr != nullptr && _output.last_char() != '\n'); @@ -429,16 +431,26 @@ namespace ink::runtime::internal #ifdef INK_ENABLE_UNREAL FString runner_impl::getline() { - inkAssert(false, "Fix (see getline for std)"); - // Advance interpreter one line - advance_line(); + clear_tags(); + FString result{}; + bool fill = false; + do { + if ( fill ) { + result += " "; + } + // Advance interpreter one line + advance_line(); + // Read lin ve into std::string + const char* str = _output.get_alloc(_globals->strings(), _globals->lists()); + result.Append( str, c_str_len( str ) ); + fill = _output.last_char() == ' '; + } while ( _ptr != nullptr && _output.last_char() != '\n' ); - // Read line into std::string - FString result; - _output >> result; + // TODO: fallback choice = no choice + if ( !has_choices() && _fallback_choice ) { choose( ~0 ); } // Return result - inkAssert(_output.is_empty(), "Output should be empty after getline!"); + inkAssert( _output.is_empty(), "Output should be empty after getline!" ); return result; } #endif @@ -516,7 +528,7 @@ namespace ink::runtime::internal size_t runner_impl::num_tags() const { - return _tags.size(); + return _choice_tags_begin < 0 ? _tags.size() : _choice_tags_begin; } const char* runner_impl::get_tag(size_t index) const @@ -525,14 +537,118 @@ namespace ink::runtime::internal return _tags[index]; } + snapshot* runner_impl::create_snapshot() const + { + return _globals->create_snapshot(); + } + + size_t runner_impl::snap(unsigned char* data, const snapper& snapper) const + { + unsigned char* ptr = data; + bool should_write = data != nullptr; + ptr = snap_write(ptr, _ptr, should_write); + ptr = snap_write(ptr, _backup, should_write); + ptr = snap_write(ptr, _done, should_write); + ptr = snap_write(ptr, _rng.get_state(), should_write); + ptr = snap_write(ptr, _evaluation_mode, should_write); + ptr = snap_write(ptr, _string_mode, should_write); + ptr = snap_write(ptr, _saved_evaluation_mode, should_write); + ptr = snap_write(ptr, _saved, should_write); + ptr = snap_write(ptr, _is_falling, should_write); + ptr += _output.snap(data ? ptr : nullptr, snapper); + ptr += _stack.snap(data ? ptr : nullptr, snapper); + ptr += _ref_stack.snap(data ? ptr : nullptr, snapper); + ptr += _eval.snap(data ? ptr : nullptr, snapper); + ptr = snap_write(ptr, _choice_tags_begin, should_write); + ptr = snap_write(ptr, _tags.size(), should_write); + for (const auto& tag : _tags) { + std::uintptr_t offset = tag - snapper.story_string_table; + ptr = snap_write(ptr, offset, should_write); + } + ptr += _container.snap(data ? ptr : nullptr, snapper); + ptr += _threads.snap(data ? ptr : nullptr, snapper); + ptr = snap_write(ptr, _backup_choice_len, should_write); + ptr = snap_write(ptr, _fallback_choice.has_value(), should_write); + auto snap_choice = [&snapper, &should_write](unsigned char* data, const choice& c) -> size_t { + unsigned char* ptr = data; + ptr = snap_write(ptr, c._index, should_write ); + ptr = snap_write(ptr, c._path, should_write ); + ptr = snap_write(ptr, c._thread, should_write ); + ptr = snap_write(ptr, snapper.strings.get_id(c._text), should_write ); + return ptr - data; + }; + if (_fallback_choice) { + ptr += snap_choice(ptr, _fallback_choice.value()); + } + ptr = snap_write(ptr, _choices.size(), should_write); + for (const choice& c : _choices) { + ptr += snap_choice(ptr, c); + } + return ptr - data; + } + + const unsigned char* runner_impl::snap_load(const unsigned char* data, const loader& loader) + { + auto ptr = data; + ptr = snap_read(ptr, _ptr); + ptr = snap_read(ptr, _backup); + ptr = snap_read(ptr, _done); + int32_t seed; + ptr = snap_read(ptr, seed); + _rng.srand(seed); + ptr = snap_read(ptr, _evaluation_mode); + ptr = snap_read(ptr, _saved_evaluation_mode); + ptr = snap_read(ptr, _saved); + ptr = snap_read(ptr, _is_falling); + ptr = _output.snap_load(ptr, loader); + ptr = _stack.snap_load(ptr, loader); + ptr = _ref_stack.snap_load(ptr, loader); + ptr = _eval.snap_load(ptr, loader); + int choice_tags_begin; + ptr = snap_read(ptr, choice_tags_begin); + _choice_tags_begin = choice_tags_begin; + size_t num_tags; + ptr = snap_read(ptr, num_tags); + for(size_t i = 0; i < num_tags; ++i) { + std::uintptr_t offset; + ptr = snap_read(ptr, offset); + _tags.push() = offset + loader.story_string_table; + } + ptr = _container.snap_load(ptr, loader); + ptr = _threads.snap_load(ptr, loader); + ptr = snap_read(ptr, _backup_choice_len); + auto read_choice = [&ptr,&loader]() -> choice{ + choice c; + ptr = snap_read(ptr, c._index); + ptr = snap_read(ptr, c._path); + ptr = snap_read(ptr, c._thread); + size_t string_id; + ptr = snap_read(ptr, string_id); + c._text = loader.string_table[string_id]; + return c; + }; + bool has_fallback_choice; + ptr = snap_read(ptr, has_fallback_choice); + _fallback_choice = has_fallback_choice + ? optional{read_choice()} + : nullopt; + size_t num_choices; + ptr = snap_read(ptr, num_choices); + for (size_t i = 0; i < num_choices; ++i) { + _choices.push() = read_choice(); + } + + return ptr; + } + #ifdef INK_ENABLE_CSTD char* runner_impl::getline_alloc() - { - // TODO + { + /// TODO + inkFail("Not implemented yet!"); return nullptr; - -#endif } +#endif bool runner_impl::move_to(hash_t path) { @@ -579,6 +695,7 @@ namespace ink::runtime::internal return change_type::extended_past_newline; inkFail("Invalid change detction. Never should be here!"); + return change_type::no_change; } bool runner_impl::line_step() @@ -612,9 +729,6 @@ namespace ink::runtime::internal // If we're on a newline if (_output.ends_with(value_type::newline)) { - // TODO: REMOVE - // return true; - // Unless we are out of content, we are going to try // to continue a little further. This is to check for // glue (which means there is potentially more content @@ -641,7 +755,9 @@ namespace ink::runtime::internal void runner_impl::step() { +#ifndef INK_ENABLE_UNREAL try +#endif { inkAssert(_ptr != nullptr, "Can not step! Do not have a valid pointer"); @@ -665,7 +781,7 @@ namespace ink::runtime::internal case Command::STR: { const char* str = read(); - if (bEvaluationMode) + if (_evaluation_mode) _eval.push(value{}.set(str)); else _output << value{}.set(str); @@ -674,7 +790,7 @@ namespace ink::runtime::internal case Command::INT: { int val = read(); - if (bEvaluationMode) + if (_evaluation_mode) _eval.push(value{}.set(val)); // TEST-CASE B006 don't print integers } @@ -682,7 +798,7 @@ namespace ink::runtime::internal case Command::BOOL: { bool val = read() ? true : false; - if(bEvaluationMode) + if(_evaluation_mode) _eval.push(value{}.set(val)); else _output << value{}.set(val); @@ -691,24 +807,24 @@ namespace ink::runtime::internal case Command::FLOAT: { float val = read(); - if (bEvaluationMode) + if (_evaluation_mode) _eval.push(value{}.set(val)); // TEST-CASE B006 don't print floats } break; case Command::VALUE_POINTER: { hash_t val = read(); - if(bEvaluationMode) { + if(_evaluation_mode) { _eval.push(value{}.set(val, static_cast(flag) - 1)); } else { - throw ink_exception("never conciderd what should happend here! (value pointer print)"); + inkFail("never conciderd what should happend here! (value pointer print)"); } } break; case Command::LIST: { list_table::list list(read()); - if(bEvaluationMode) + if(_evaluation_mode) _eval.push(value{}.set(list)); else { char* str = _globals->strings().create(_globals->lists().stringLen( @@ -720,7 +836,7 @@ namespace ink::runtime::internal break; case Command::DIVERT_VAL: { - inkAssert(bEvaluationMode, "Can not push divert value into the output stream!"); + inkAssert(_evaluation_mode, "Can not push divert value into the output stream!"); // Push the divert target onto the stack uint32_t target = read(); @@ -729,7 +845,7 @@ namespace ink::runtime::internal break; case Command::NEWLINE: { - if (bEvaluationMode) + if (_evaluation_mode) _eval.push(values::newline); else _output << values::newline; @@ -737,7 +853,7 @@ namespace ink::runtime::internal break; case Command::GLUE: { - if (bEvaluationMode) + if (_evaluation_mode) _eval.push(values::glue); else _output << values::glue; @@ -745,7 +861,7 @@ namespace ink::runtime::internal break; case Command::VOID: { - if (bEvaluationMode) + if (_evaluation_mode) _eval.push(values::null); // TODO: void type? } break; @@ -830,7 +946,7 @@ namespace ink::runtime::internal if(flag & CommandFlag::TUNNEL_TO_VARIABLE) { hash_t var_name = read(); const value* val = get_var(var_name); - inkAssert(val != nullptr); + inkAssert(val != nullptr, "Variable containing tunnel target could not be found!"); target = val->get(); } else { target = read(); @@ -845,12 +961,21 @@ namespace ink::runtime::internal if(flag & CommandFlag::FUNCTION_TO_VARIABLE) { hash_t var_name = read(); const value* val = get_var(var_name); - inkAssert(val != nullptr); + inkAssert(val != nullptr, "Varibale containing function could not be found!"); target = val->get(); } else { target = read(); } - start_frame(target); + if (!(flag & CommandFlag::FALLBACK_FUNCTION)) { + start_frame(target); + } else { + inkAssert(!_eval.is_empty(), "fallback function but no function call before?"); + if(_eval.top_value().type() == value_type::ex_fn_not_found) { + _eval.pop(); + inkAssert(target != 0, "Exetrnal function was not binded, and no fallback function provided!"); + start_frame(target); + } + } } break; case Command::TUNNEL_RETURN: @@ -865,8 +990,8 @@ namespace ink::runtime::internal // Push a thread frame so we can return easily // TODO We push ahead of a single divert. Is that correct in all cases....????? auto returnTo = _ptr + CommandSize; - _stack.push_frame(returnTo - _story->instructions(), bEvaluationMode); - _ref_stack.push_frame(returnTo - _story->instructions(), bEvaluationMode); + _stack.push_frame(returnTo - _story->instructions(), _evaluation_mode); + _ref_stack.push_frame(returnTo - _story->instructions(), _evaluation_mode); // Fork a new thread on the callstack thread_t thread = _stack.fork_thread(); @@ -920,29 +1045,22 @@ namespace ink::runtime::internal int numArguments = (int)flag; // find and execute. will automatically push a valid if applicable - bool success = _functions.call(functionName, &_eval, numArguments, _globals->strings()); + bool success = _functions.call(functionName, &_eval, numArguments, _globals->strings(), _globals->lists()); - // If we failed, we need to at least pretend so our state doesn't get fucked + // If we failed, notify a potential fallback function if (!success) { - // pop arguments - for (int i = 0; i < numArguments; i++) - _eval.pop(); - - // push void - _eval.push(value()); + _eval.push(values::ex_fn_not_found); } - - // TODO: Verify something was found? } break; // == Evaluation stack case Command::START_EVAL: - bEvaluationMode = true; + _evaluation_mode = true; break; case Command::END_EVAL: - bEvaluationMode = false; + _evaluation_mode = false; // Assert stack is empty? Is that necessary? break; @@ -970,15 +1088,17 @@ namespace ink::runtime::internal } case Command::START_STR: { - inkAssert(bEvaluationMode, "Can not enter string mode while not in evaluation mode!"); - bEvaluationMode = false; + inkAssert(_evaluation_mode, "Can not enter string mode while not in evaluation mode!"); + _string_mode = true; + _evaluation_mode = false; _output << values::marker; } break; case Command::END_STR: { // TODO: Assert we really had a marker on there? - inkAssert(!bEvaluationMode, "Must be in evaluation mode"); - bEvaluationMode = true; + inkAssert(!_evaluation_mode, "Must be in evaluation mode"); + _string_mode = false; + _evaluation_mode = true; // Load value from output stream // Push onto stack @@ -987,6 +1107,20 @@ namespace ink::runtime::internal _globals->lists()))); } break; + case Command::START_TAG: + { + _output << values::marker; + } break; + + case Command::END_TAG: + { + auto tag = _output.get_alloc(_globals->strings(), _globals->lists()); + if(_string_mode && _choice_tags_begin < 0) { + _choice_tags_begin = _tags.size(); + } + _tags.push() = tag; + } break; + // == Choice commands case Command::CHOICE: { @@ -1030,12 +1164,19 @@ namespace ink::runtime::internal } for(;sc;--sc) { _output << stack[sc-1]; } + // fetch relevant tags + const char* const* tags = nullptr; + if (_choice_tags_begin >= 0 && _tags[_tags.size()-1] != nullptr) { + for(tags = _tags.end() - 1; *(tags-1) != nullptr && (tags - _tags.begin()) > _choice_tags_begin; --tags); + _tags.push() = nullptr; + } + // Create choice and record it if (flag & CommandFlag::CHOICE_IS_INVISIBLE_DEFAULT) { _fallback_choice - = choice{}.setup(_output, _globals->strings(), _globals->lists(), _choices.size(), path, current_thread()); + = choice{}.setup(_output, _globals->strings(), _globals->lists(), _choices.size(), path, current_thread(), tags); } else { - add_choice().setup(_output, _globals->strings(), _globals->lists(), _choices.size(), path, current_thread()); + add_choice().setup(_output, _globals->strings(), _globals->lists(), _choices.size(), path, current_thread(), tags); } // save stack at last choice if(_saved) { forget(); } @@ -1104,7 +1245,7 @@ namespace ink::runtime::internal int sequenceLength = _eval.pop().get(); int index = _eval.pop().get(); - _eval.push(value{}.set(_rng.rand(sequenceLength))); + _eval.push(value{}.set(static_cast(_rng.rand(sequenceLength)))); } break; case Command::SEED: { @@ -1130,13 +1271,16 @@ namespace ink::runtime::internal inkAssert(false, "Unrecognized command!"); break; } + } +#ifndef INK_ENABLE_UNREAL catch (...) { // Reset our whole state as it's probably corrupt reset(); throw; } +#endif } void runner_impl::on_done(bool setDone) @@ -1184,7 +1328,7 @@ namespace ink::runtime::internal _stack.clear(); _ref_stack.clear(); _threads.clear(); - bEvaluationMode = false; + _evaluation_mode = false; _saved = false; _choices.clear(); _ptr = nullptr; @@ -1192,16 +1336,20 @@ namespace ink::runtime::internal _container.clear(); } - void runner_impl::mark_strings(string_table& strings) const + void runner_impl::mark_used(string_table& strings, list_table& lists) const { // Find strings in output and stacks - _output.mark_strings(strings); - _stack.mark_strings(strings); - // ref_stack has no strings! - _eval.mark_strings(strings); - + _output.mark_used(strings, lists); + _stack.mark_used(strings, lists); + // ref_stack has no strings and lists! + _eval.mark_used(strings, lists); + + // Take into account tags + for (size_t i = 0; i < _tags.size(); ++i) { + strings.mark_used(_tags[i]); + } // Take into account choice text - for (int i = 0; i < _choices.size(); i++) + for (size_t i = 0; i < _choices.size(); i++) strings.mark_used(_choices[i]._text); } @@ -1219,7 +1367,7 @@ namespace ink::runtime::internal _eval.save(); _threads.save(); _backup_choice_len = _choices.size(); - bSavedEvaluationMode = bEvaluationMode; + _saved_evaluation_mode = _evaluation_mode; // Not doing this anymore. There can be lingering stack entries from function returns // inkAssert(_eval.is_empty(), "Can not save interpreter state while eval stack is not empty"); @@ -1238,7 +1386,7 @@ namespace ink::runtime::internal _eval.restore(); _threads.restore(); _choices.resize(_backup_choice_len); - bEvaluationMode = bSavedEvaluationMode; + _evaluation_mode = _saved_evaluation_mode; // Not doing this anymore. There can be lingering stack entries from function returns // inkAssert(_eval.is_empty(), "Can not save interpreter state while eval stack is not empty"); diff --git a/inkcpp/runner_impl.h b/inkcpp/runner_impl.h index 7f208036..590d4945 100644 --- a/inkcpp/runner_impl.h +++ b/inkcpp/runner_impl.h @@ -13,6 +13,7 @@ #include "list_table.h" #include "array.h" #include "random.h" +#include "snapshot_impl.h" #include "runner.h" #include "choice.h" @@ -23,8 +24,10 @@ namespace ink::runtime::internal { class story_impl; class globals_impl; + class snapshot_impl; - class runner_impl : public runner_interface + + class runner_impl : public runner_interface, public snapshot_interface { public: // Creates a new runner at the start of a loaded ink story @@ -32,9 +35,11 @@ namespace ink::runtime::internal virtual ~runner_impl(); // used by the globals object to do garbage collection - void mark_strings(string_table&) const; + void mark_used(string_table&, list_table&) const; #pragma region runner Implementation + // sets seed for prng in runner + virtual void set_rng_seed(uint32_t seed) override { _rng.srand(seed); } // Checks that the runner can continue virtual bool can_continue() const override; @@ -55,6 +60,11 @@ namespace ink::runtime::internal virtual size_t num_tags() const override; virtual const char* get_tag(size_t index) const override; + snapshot* create_snapshot() const override; + + size_t snap(unsigned char* data, const snapper&) const override; + const unsigned char* snap_load(const unsigned char* data, const loader&) override; + #ifdef INK_ENABLE_CSTD // c-style getline @@ -146,51 +156,24 @@ namespace ink::runtime::internal inline thread_t current_thread() const { return _threads.empty() ? ~0 : _threads.top(); } - private: - const story_impl* const _story; - story_ptr _globals; - executer _operations; - - // == State == - - // Instruction pointer - ip_t _ptr; - ip_t _backup; // backup pointer - ip_t _done; // when we last hit a done - - // Output stream - internal::stream _output; - - // Runtime stack. Used to store temporary variables and callstack - internal::stack _stack; - internal::stack _ref_stack; - - // Evaluation stack - bool bEvaluationMode = false; - internal::eval_stack _eval; - bool bSavedEvaluationMode = false; - - // Keeps track of what threads we're inside - class threads : public internal::simple_restorable_stack { - using base = internal::simple_restorable_stack; - static constexpr bool dynamic = config::limitThreadDepth < 0; - static constexpr size_t N = abs(config::limitThreadDepth); + public: + template + class threads : public internal::managed_restorable_stack { + using base = internal::managed_restorable_stack; public: template = true > threads() - : base(nullptr, 0, ~0), + : base(~0), _threadDone(nullptr, reinterpret_cast(~0)) { static_assert(sizeof...(D) == 0, "Don't use explicit template arguments!"); } template = true > threads() - : _stack{}, - base(_stack.data(), N, ~0), + : base(~0), _threadDone(nullptr, reinterpret_cast(~0)) { static_assert(sizeof...(D) == 0, "Don't use explicit template arguments"); _threadDone.clear(nullptr); } - void clear() { base::clear(); _threadDone.clear(nullptr); @@ -216,28 +199,59 @@ namespace ink::runtime::internal } const ip_t& operator[](size_t index) const { return get(index); } + // snapshot interface + size_t snap(unsigned char* data, const snapper&) const override; + const unsigned char* snap_load(const unsigned char* data, const loader&) override; + protected: virtual void overflow(thread_t*& buffer, size_t& size) override final; private: using array_type = if_t, internal::fixed_restorable_array>; - template - void resize(size_t size, int) { (_threadDone.*A)(size); } - void resize(size_t size, long) {} + + void resize(size_t size, int) { _threadDone.resize(size); } - managed_array _stack; array_type _threadDone; - } _threads; + }; + + private: + const story_impl* const _story; + story_ptr _globals; + executer _operations; + + // == State == + + // Instruction pointer + ip_t _ptr; + ip_t _backup; // backup pointer + ip_t _done; // when we last hit a done + + // Output stream + internal::stream _output; + + // Runtime stack. Used to store temporary variables and callstack + internal::stack _stack; + internal::stack _ref_stack; + + // Evaluation stack + bool _evaluation_mode = false; + bool _string_mode = false; + internal::eval_stack _eval; + bool _saved_evaluation_mode = false; + + // Keeps track of what threads we're inside + threads _threads; // Choice list managed_array _choices; optional _fallback_choice; - size_t _backup_choice_len; + size_t _backup_choice_len = 0; // Tag list managed_array _tags; + int _choice_tags_begin; // TODO: Move to story? Both? functions _functions; @@ -248,22 +262,32 @@ namespace ink::runtime::internal bool _saved = false; - prng _rng{}; + prng _rng; }; - inline void runner_impl::threads::overflow(thread_t*& buffer, size_t& size) { + template + void runner_impl::threads::overflow(thread_t*& buffer, size_t& size) { + base::overflow(buffer, size); if constexpr (dynamic) { - if(buffer) { - _stack.extend(); - } - buffer = _stack.data(); - size = _stack.capacity(); resize(size, 0); - } else { - base::overflow(buffer, size); } } + template + size_t runner_impl::threads::snap( unsigned char* data, const snapper& snapper ) const { + unsigned char* ptr = data; + ptr += base::snap( data ? ptr : nullptr, snapper ); + ptr += _threadDone.snap( data ? ptr : nullptr, snapper ); + return ptr - data; + } + + template + const unsigned char* runner_impl::threads::snap_load( const unsigned char* ptr, const loader& loader ) { + ptr = base::snap_load( ptr, loader ); + ptr = _threadDone.snap_load( ptr, loader ); + return ptr; + } + template<> inline const char* runner_impl::read(); diff --git a/inkcpp/simple_restorable_stack.h b/inkcpp/simple_restorable_stack.h index bf09d633..cacb8806 100644 --- a/inkcpp/simple_restorable_stack.h +++ b/inkcpp/simple_restorable_stack.h @@ -2,15 +2,18 @@ #include "system.h" #include "array.h" +#include "snapshot_impl.h" namespace ink::runtime::internal { template - class simple_restorable_stack + class simple_restorable_stack : public snapshot_interface { public: simple_restorable_stack(T* buffer, size_t size, const T& null) : _buffer(buffer), _size(size), _null(null) { } + virtual ~simple_restorable_stack() = default; + void push(const T& value); T pop(); @@ -27,9 +30,12 @@ namespace ink::runtime::internal void restore(); void forget(); + virtual size_t snap(unsigned char* data, const snapper&) const override; + virtual const unsigned char* snap_load(const unsigned char* data, const loader&) override; + protected: virtual void overflow(T*& buffer, size_t& size) { - throw ink_exception("Stack overflow!"); + inkFail("Stack overflow!"); } void initialize_data(T* buffer, size_t size) { @@ -60,7 +66,7 @@ namespace ink::runtime::internal managed_restorable_stack(const T& null) : simple_restorable_stack(nullptr, 0, null), _stack{} { base::initialize_data(_stack.data(), N); } - virtual void overflow(T*& buffer, size_t& size) override final { + virtual void overflow(T*& buffer, size_t& size) override { if constexpr (dynamic) { if (buffer) { _stack.extend(); @@ -144,7 +150,6 @@ namespace ink::runtime::internal inline void simple_restorable_stack::clear() { // Reset to start - // TODO: Support save! _save = _jump = InvalidIndex; _pos = 0; } @@ -208,18 +213,58 @@ namespace ink::runtime::internal { inkAssert(_save != InvalidIndex, "Can not forget when the stack has never been saved!"); - /*// If we have moven to a point earlier than the save point but we have a jump point - if (_pos < _save && _pos > _jump) - {*/ - // If we're at the save point, move us instead - if (_pos == _save) - _pos = _jump; - // Everything between the jump point and the save point needs to be nullified - else for (size_t i = _jump; i < _save; i++) - _buffer[i] = _null; - /*}*/ + inkAssert(_pos >= _save || _pos < _jump, "Pos is in backup areal! (should be impossible)"); + // if we are below the backup areal, no changes are needed + // if we above the backup areal, we need to collpse it + if (_pos >= _save) { + size_t delta = _save - _jump; + for(size_t i = _save; i < _pos; ++i) { + _buffer[i - delta] = _buffer[i]; + } + _pos -= delta; + } // Just reset save position - _save = InvalidIndex; + _save = _jump = InvalidIndex; + } + template + size_t simple_restorable_stack::snap(unsigned char* data, const snapper&) const + { + static_assert(is_same{}() || is_same{}() || is_same{}()); + unsigned char* ptr = data; + bool should_write = data != nullptr; + ptr = snap_write(ptr, _null, should_write); + ptr = snap_write(ptr, _pos, should_write ); + ptr = snap_write(ptr, _save, should_write ); + ptr = snap_write(ptr, _jump, should_write ); + size_t max = _pos; + if (_save > max) { max = _save; } + if (_jump > max) { max = _jump; } + for(size_t i = 0; i < max; ++i) + { + ptr = snap_write(ptr, _buffer[i], should_write ); + } + return ptr - data; + } + + template + const unsigned char* simple_restorable_stack::snap_load(const unsigned char* ptr, const loader& loader) + { + static_assert(is_same{}() || is_same{}() || is_same{}()); + T null; + ptr = snap_read(ptr, null); + inkAssert(null == _null, "different null value compared to snapshot!"); + ptr = snap_read(ptr, _pos); + ptr = snap_read(ptr, _save); + ptr = snap_read(ptr, _jump); + size_t max = _pos; + if(_save > max) { max = _save; } + if(_jump > max) { max = _jump; } + while(_size < max) { overflow(_buffer, _size); } + for(size_t i = 0; i < max; ++i) + { + ptr = snap_read(ptr, _buffer[i]); + } + return ptr; } } diff --git a/inkcpp/snapshot_impl.cpp b/inkcpp/snapshot_impl.cpp new file mode 100644 index 00000000..c819929b --- /dev/null +++ b/inkcpp/snapshot_impl.cpp @@ -0,0 +1,112 @@ +#include "snapshot_impl.h" + +#include "story_impl.h" +#include "globals_impl.h" +#include "runner_impl.h" + +#include +#ifdef INK_ENABLE_STL +#include +#endif + +namespace ink::runtime +{ + snapshot* snapshot::from_binary(const unsigned char* data, size_t length, bool freeOnDestroy) + { + return new internal::snapshot_impl(data, length, freeOnDestroy); + } + +#ifdef INK_ENABLE_STL + snapshot* snapshot::from_file(const char* filename) { + std::ifstream ifs(filename, std::ios::binary | std::ios::ate); + if(!ifs.is_open()) { + throw ink_exception("Failed to open snapshot file: " + std::string(filename)); + } + + size_t length = static_cast(ifs.tellg()); + unsigned char* data = new unsigned char[length]; + ifs.seekg(0, std::ios::beg); + ifs.read(reinterpret_cast(data), length); + ifs.close(); + + return from_binary(data, length); + } + + void snapshot::write_to_file(const char* filename) const + { + std::ofstream ofs(filename, std::ios::binary); + if(!ofs.is_open()) { + throw ink_exception("Failed to open file to write snapshot: " + + std::string(filename)); + } + ofs.write(reinterpret_cast(get_data()), get_data_len()); + } +#endif +} + +namespace ink::runtime::internal +{ + size_t snapshot_impl::file_size(size_t serialization_length, size_t runner_cnt) { + return serialization_length + sizeof(header) + (runner_cnt + 1) * sizeof(size_t); + } + + const unsigned char* snapshot_impl::get_data() const { + return _file; + } + size_t snapshot_impl::get_data_len() const { + return _length; + } + + snapshot_impl::snapshot_impl(const globals_impl& globals) + : _managed{true} + { + snapshot_interface::snapper snapper{ + globals.strings(), + globals._owner->string(0) + }; + _length = globals.snap(nullptr, snapper); + size_t runner_cnt = 0; + for(auto node = globals._runners_start; node; node = node->next) + { + _length += node->object->snap(nullptr, snapper); + ++runner_cnt; + } + + _length = file_size(_length, runner_cnt); + _header.length = _length; + _header.num_runners = runner_cnt; + unsigned char* data = new unsigned char[_length]; + _file = data; + unsigned char* ptr = data; + // write header + memcpy(ptr, &_header, sizeof(_header)); + // write lookup table + ptr += sizeof(header); + { + size_t offset = (ptr - data) + (_header.num_runners + 1) * sizeof(size_t); + memcpy(ptr, &offset, sizeof(offset)); + ptr += sizeof(offset); + offset += globals.snap(nullptr, snapper); + for(auto node = globals._runners_start; node; node = node->next) + { + memcpy(ptr, &offset, sizeof(offset)); + ptr += sizeof(offset); + offset += node->object->snap(nullptr, snapper); + } + } + + ptr += globals.snap(ptr, snapper); + for (auto node = globals._runners_start; node; node = node->next) + { + ptr += node->object->snap(ptr, snapper); + } + } + + snapshot_impl::snapshot_impl(const unsigned char* data, size_t length, bool managed) + : _file{data}, _length{length}, _managed{managed} + { + const unsigned char* ptr = data; + memcpy(&_header, ptr, sizeof(_header)); + inkAssert(_header.length == _length, "Corrupted file length"); + } +} diff --git a/inkcpp/snapshot_impl.h b/inkcpp/snapshot_impl.h new file mode 100644 index 00000000..7eb7ebd2 --- /dev/null +++ b/inkcpp/snapshot_impl.h @@ -0,0 +1,61 @@ +#pragma once + +#include "snapshot.h" +#include "snapshot_interface.h" +#include "array.h" + + +namespace ink::runtime::internal +{ + + class snapshot_impl : public snapshot + { + public: + ~snapshot_impl() override { + if (_managed) { delete[] _file; } + }; + + managed_array& strings() const { + return string_table; + } + const unsigned char* get_data() const override; + size_t get_data_len() const override; + + snapshot_impl(const globals_impl&); + // write down all allocated strings + // replace pointer with idx + // reconsrtuct static strings index + // list_table _data & _entry_state + snapshot_impl(const unsigned char* data, size_t length, bool managed); + + const unsigned char* get_globals_snap() const { + return _file + get_offset(0); + } + + const unsigned char* get_runner_snap(size_t idx) const { + return _file + get_offset(idx + 1); + } + + size_t num_runners() const override { return _header.num_runners; } + + private: + // file information + // only populated when loading snapshots + mutable managed_array string_table; + const unsigned char* _file; + size_t _length; + bool _managed; + static size_t file_size(size_t, size_t); + struct header { + size_t num_runners; + size_t length; + + } _header; + + size_t get_offset(size_t idx) const { + inkAssert(idx <= _header.num_runners, "Out of Bound access for runner in snapshot."); + return reinterpret_cast(_file + sizeof(header))[idx]; + } + + }; +} diff --git a/inkcpp/snapshot_interface.h b/inkcpp/snapshot_interface.h new file mode 100644 index 00000000..1408124b --- /dev/null +++ b/inkcpp/snapshot_interface.h @@ -0,0 +1,49 @@ +#pragma once + +#include "snapshot.h" +#include + +namespace ink::runtime::internal +{ + class globals_impl; + class value; + class string_table; + template + class managed_array; + + class snapshot_interface { + public: + constexpr snapshot_interface(){}; + static unsigned char* snap_write(unsigned char* ptr, const void* data, size_t length, bool write) + { + if (write) { memcpy(ptr, data, length); } + return ptr + length; + } + template + static unsigned char* snap_write(unsigned char* ptr, const T& data, bool write) + { + return snap_write(ptr, &data, sizeof(data), write); + } + static const unsigned char* snap_read(const unsigned char* ptr, void* data, size_t length) + { + memcpy(data, ptr, length); + return ptr + length; + } + template + static const unsigned char* snap_read(const unsigned char* ptr, T& data) + { + return snap_read(ptr, &data, sizeof(data)); + } + + struct snapper { + const string_table& strings; + const char* story_string_table; + }; + struct loader { + managed_array& string_table; + const char* story_string_table; + }; + virtual size_t snap(unsigned char* data, const snapper&) const = 0; + virtual const unsigned char* snap_load(const unsigned char* data, const loader&) = 0; + }; +} diff --git a/inkcpp/stack.cpp b/inkcpp/stack.cpp index 40c73127..ef5bcde2 100644 --- a/inkcpp/stack.cpp +++ b/inkcpp/stack.cpp @@ -76,7 +76,7 @@ namespace ink::runtime::internal }; class reverse_find_from_frame_predicat_operator { public: - reverse_find_from_frame_predicat_operator(int ci, hash_t name) : _name{name}, _ci{ci} { + reverse_find_from_frame_predicat_operator(int ci, hash_t name) : _ci{ci}, _name{name} { inkAssert(ci == -1 || ci == 0, "only support ci == -1, for now!"); } bool operator()(entry& e) { @@ -208,7 +208,7 @@ namespace ink::runtime::internal } else if (vt == value_type::thread_start) { start.set(jump); } else { - throw ink_exception("unknown jump type"); + inkFail("unknown jump type"); } return threadIter.get(); } @@ -368,13 +368,15 @@ namespace ink::runtime::internal base::clear(); } - void basic_stack::mark_strings(string_table& strings) const + void basic_stack::mark_used(string_table& strings, list_table& lists) const { // Mark all strings base::for_each_all( - [&strings](const entry& elem) { + [&strings, &lists](const entry& elem) { if (elem.data.type() == value_type::string) { strings.mark_used(elem.data.get()); + } else if (elem.data.type() == value_type::list) { + lists.mark_used(elem.data.get()); } }); } @@ -532,15 +534,17 @@ namespace ink::runtime::internal base::clear(); } - void basic_eval_stack::mark_strings(string_table& strings) const + void basic_eval_stack::mark_used(string_table& strings, list_table& lists) const { // Iterate everything (including what we have saved) and mark strings - base::for_each_all([&strings](const value& elem) { + base::for_each_all([&strings,&lists](const value& elem) { if (elem.type() == value_type::string) { string_type str = elem.get(); if (str.allocated) { strings.mark_used(str.str); } + } else if (elem.type() == value_type::list) { + lists.mark_used(elem.get()); } }); } @@ -587,4 +591,22 @@ namespace ink::runtime::internal stack.set(itr.get()->name, itr.get()->data); } } + + size_t basic_stack::snap(unsigned char* data, const snapper& snapper) const + { + unsigned char* ptr = data; + bool should_write = data != nullptr; + ptr = snap_write(ptr, _next_thread, should_write ); + ptr = snap_write(ptr, _backup_next_thread, should_write ); + ptr += base::snap(data ? ptr : nullptr, snapper); + return ptr - data; + } + + const unsigned char* basic_stack::snap_load(const unsigned char* ptr, const loader& loader) + { + ptr = snap_read(ptr, _next_thread); + ptr = snap_read(ptr, _backup_next_thread); + ptr = base::snap_load(ptr, loader); + return ptr; + } } diff --git a/inkcpp/stack.h b/inkcpp/stack.h index 147e4c54..f7f418f4 100644 --- a/inkcpp/stack.h +++ b/inkcpp/stack.h @@ -3,6 +3,7 @@ #include "value.h" #include "collections/restorable.h" #include "array.h" +#include "snapshot_impl.h" namespace ink { @@ -13,7 +14,7 @@ namespace ink class string_table; struct entry { - hash_t name; + hash_t name = 0; value data; }; @@ -24,7 +25,7 @@ namespace ink thread }; - class basic_stack : protected restorable + class basic_stack : protected restorable { protected: basic_stack(entry* data, size_t size); @@ -56,7 +57,7 @@ namespace ink void clear(); // Garbage collection - void mark_strings(string_table&) const; + void mark_used(string_table&, list_table&) const; // == Threading == @@ -79,6 +80,10 @@ namespace ink // push all values to other _stack void push_values(basic_stack& _stack); + // snapshot interface + size_t snap(unsigned char* data, const snapper&) const override; + const unsigned char* snap_load(const unsigned char* data, const loader&) override; + private: entry& add(hash_t name, const value& val); const entry* pop(); @@ -91,6 +96,10 @@ namespace ink static const hash_t NulledHashId = ~0; }; + + template<> void basic_stack::push_frame(offset_t return_to, bool eval); + template<> void basic_stack::push_frame(offset_t return_to, bool eval); + template<> void basic_stack::push_frame(offset_t return_to, bool eval); /** * @brief stack for call history and temporary variables @@ -135,6 +144,7 @@ namespace ink using base = restorable; public: + // Push value onto the stack void push(const value&); @@ -153,13 +163,19 @@ namespace ink // Clear stack void clear(); - // Garbage collection - void mark_strings(string_table&) const; + /** Mark used strings and lists for garbage collection */ + void mark_used(string_table&, list_table&) const; // == Save/Restore == void save(); void restore(); void forget(); + + // snapshot interface + size_t snap(unsigned char* data, const snapper& snapper) const override + { return base::snap(data, snapper); } + const unsigned char* snap_load(const unsigned char* data, const loader& loader) override + { return base::snap_load(data, loader); } }; template diff --git a/inkcpp/story_impl.cpp b/inkcpp/story_impl.cpp index f83a7e57..c7a1a6a6 100644 --- a/inkcpp/story_impl.cpp +++ b/inkcpp/story_impl.cpp @@ -2,6 +2,8 @@ #include "platform.h" #include "runner_impl.h" #include "globals_impl.h" +#include "snapshot.h" +#include "snapshot_impl.h" #include "version.h" #ifdef INK_ENABLE_STL @@ -175,6 +177,18 @@ namespace ink::runtime::internal return globals(new globals_impl(this), _block); } + globals story_impl::new_globals_from_snapshot(const snapshot& data) + { + const snapshot_impl& snapshot = reinterpret_cast(data); + auto* globs = new globals_impl(this); + auto end = globs->snap_load(snapshot.get_globals_snap(), snapshot_interface::loader{ + snapshot.strings(), + _string_table, + }); + inkAssert(end == snapshot.get_runner_snap(0), "not all data were used for global reconstruction"); + return globals(globs, _block); + } + runner story_impl::new_runner(globals store) { if (store == nullptr) @@ -182,6 +196,24 @@ namespace ink::runtime::internal return runner(new runner_impl(this, store), _block); } + runner story_impl::new_runner_from_snapshot(const snapshot& data, globals store, unsigned idx) + { + const snapshot_impl& snapshot = reinterpret_cast(data); + if (store == nullptr) + store = new_globals_from_snapshot(snapshot); + auto* run = new runner_impl(this, store); + auto end = run->snap_load(snapshot.get_runner_snap(idx), + snapshot_interface::loader{ + snapshot.strings(), + _string_table, + }); + inkAssert( + (idx + 1 < snapshot.num_runners() && end == snapshot.get_runner_snap(idx + 1)) + || end == snapshot.get_data() + snapshot.get_data_len(), "not all data were used for runner reconstruction" + ); + return runner(run, _block); + } + void story_impl::setup_pointers() { using header = ink::internal::header; @@ -236,6 +268,9 @@ namespace ink::runtime::internal _list_meta = nullptr; _lists = nullptr; } + inkAssert(_header.ink_bin_version_number == ink::InkBinVersion, "invalid InkBinVerison! currently: %i you used %i", ink::InkBinVersion, _header.ink_bin_version_number); + inkAssert(_header.endien == header::endian_types::same, + "different endien support not yet implemented"); diff --git a/inkcpp/story_impl.h b/inkcpp/story_impl.h index bf6dea04..2bfa322e 100644 --- a/inkcpp/story_impl.h +++ b/inkcpp/story_impl.h @@ -40,8 +40,9 @@ namespace ink::runtime::internal // Creates a new global store for use with runners executing this story virtual globals new_globals() override; + virtual globals new_globals_from_snapshot(const snapshot&) override; virtual runner new_runner(globals store = nullptr) override; - + virtual runner new_runner_from_snapshot(const snapshot&, globals store = nullptr, unsigned idx = 0) override; const ink::internal::header& get_header() const { return _header; } private: diff --git a/inkcpp/string_table.cpp b/inkcpp/string_table.cpp index aa8cda88..467a6e1a 100644 --- a/inkcpp/string_table.cpp +++ b/inkcpp/string_table.cpp @@ -94,4 +94,43 @@ namespace ink::runtime::internal iter++; } } + + size_t string_table::snap(unsigned char* data, const snapper&) const + { + unsigned char* ptr = data; + bool should_write = data != nullptr; + for (size_t i = 0; i < _table.size(); ++i) { + for(auto itr = _table.begin(); itr != _table.end(); ++itr) { + if (itr.temp_identifier() == i) { + ptr = snap_write(ptr, itr.key(), strlen(itr.key()) + 1, should_write ); + break; + } + } + } + ptr = snap_write(ptr, "\0", 1, should_write ); + return ptr - data; + } + + const unsigned char* string_table::snap_load(const unsigned char* data, const loader& loader) + { + auto* ptr = data; + int i = 0; + while(*ptr) { + size_t len = 0; + for(;ptr[len];++len); + ++len; + auto str = create(len); + loader.string_table.push() = str; + ptr = snap_read(ptr, str, len); + mark_used(str); + } + return ptr + 1; + } + + size_t string_table::get_id(const char* string) const + { + auto iter = _table.find(string); + inkAssert(iter != _table.end(), "Try to fetch not contained string!"); + return iter.temp_identifier(); + } } diff --git a/inkcpp/string_table.h b/inkcpp/string_table.h index e2eb6049..6b7ea5a6 100644 --- a/inkcpp/string_table.h +++ b/inkcpp/string_table.h @@ -2,14 +2,15 @@ #include "avl_array.h" #include "system.h" +#include "snapshot_impl.h" namespace ink::runtime::internal { // hash tree sorted by string pointers - class string_table + class string_table final : public snapshot_interface { public: - ~string_table(); + virtual ~string_table(); // Create a dynmaic string of a particular length char* create(size_t length); @@ -21,6 +22,15 @@ namespace ink::runtime::internal // mark a string as used void mark_used(const char* string); + + // snapshot interface implementation + size_t snap(unsigned char* data, const snapper&) const override; + const unsigned char* snap_load(const unsigned char* data, const loader&) override; + + // get position of string when iterate through data + // used to enable storing a string table references + size_t get_id(const char* string) const; + // deletes all unused strings void gc(); diff --git a/inkcpp/string_utils.h b/inkcpp/string_utils.h index 55d9fac4..3f8b97b5 100644 --- a/inkcpp/string_utils.h +++ b/inkcpp/string_utils.h @@ -74,7 +74,8 @@ namespace ink::runtime::internal { case value_type::newline: return toStr(buffer, size, "\n"); default: - throw ink_exception("only support toStr for numeric types"); + inkFail("only support toStr for numeric types"); + return -1; } } @@ -108,7 +109,8 @@ namespace ink::runtime::internal { case value_type::newline: return 1; default: - throw ink_exception("Can't determine length of this value type"); + inkFail("Can't determine length of this value type"); + return -1; } } @@ -126,7 +128,7 @@ namespace ink::runtime::internal { inline constexpr ITR clean_string(ITR begin, ITR end) { auto dst = begin; for(auto src = begin; src != end; ++src){ - if (src == begin) { + if (dst == begin) { if (LEADING_SPACES && (src[0] == ' ' || src[0] == '\n')) { continue; } } else if(src[-1] == '\n' && (src[0] == ' ' || src[0] == '\n')) { continue;} diff --git a/inkcpp/system.cpp b/inkcpp/system.cpp index a2adda4b..b3580a09 100644 --- a/inkcpp/system.cpp +++ b/inkcpp/system.cpp @@ -25,13 +25,6 @@ namespace ink for (size_t i = 0; i < length; i++) *(buf++) = 0; } - - void ink_assert(bool condition, const char* msg /*= nullptr*/) - { - if (!condition) - throw ink_exception(msg); - } - } #endif \ No newline at end of file diff --git a/inkcpp/tuple.hpp b/inkcpp/tuple.hpp index 528c8d47..eb4f99a5 100644 --- a/inkcpp/tuple.hpp +++ b/inkcpp/tuple.hpp @@ -2,7 +2,7 @@ /// very basic flat tuple implementation, only use for trivial data types. -#include "./include/traits.h" +#include "traits.h" namespace ink::runtime::internal { namespace tuple_internal { diff --git a/inkcpp/value.cpp b/inkcpp/value.cpp index b0ff301d..3a8b9af5 100644 --- a/inkcpp/value.cpp +++ b/inkcpp/value.cpp @@ -1,7 +1,10 @@ #include "value.h" + +#include "list_impl.h" #include "output.h" #include "list_table.h" #include "string_utils.h" +#include "string_table.h" namespace ink::runtime::internal { @@ -69,4 +72,90 @@ namespace ink::runtime::internal os.append(val); return os; } + + value::value(const ink::runtime::value& val) : value() { + using types = ink::runtime::value::Type; + switch (val.type) { + case types::Bool: + set(val.v_bool); + break; + case types::Uint32: + set(val.v_uint32); + break; + case types::Int32: + set(val.v_int32); + break; + case types::String: + set(val.v_string); + break; + case types::Float: + set(val.v_float); + break; + case types::List: + set(list_table::list{static_cast(val.v_list)->get_lid()}); + } + } + + bool value::set( const ink::runtime::value& val ) { + auto var = value( val ); + if ( type() == value_type::none || var.type() == type() ) { + *this = var; + return true; + } + return false; + } + + ink::runtime::value value::to_interface_value(list_table& table) const { + using val = ink::runtime::value; + if(type() == value_type::boolean) { return val(get()); } + else if(type() == value_type::uint32) { return val(get()); } + else if(type() == value_type::int32) { return val(get()); } + else if(type() == value_type::string) { return val(get().str); } + else if(type() == value_type::float32) { return val(get()); } + else if(type() == value_type::list_flag) { + auto v = table.create(); + v = table.add(v, get()); + return val(table.handout_list(v)); + } else if(type() == value_type::list) { + return val(table.handout_list(get())); + } + inkFail("No valid type to convert to interface value!"); + return val(); + } + + size_t value::snap(unsigned char* data, const snapper& snapper) const + { + unsigned char* ptr = data; + bool should_write = data != nullptr; + ptr = snap_write(ptr, _type, should_write ); + if (_type == value_type::string) { + unsigned char buf[max_value_size]; + string_type* res = reinterpret_cast(buf); + auto str = get(); + res->allocated = str.allocated; + if (str.allocated) { + res->str = reinterpret_cast(static_cast(snapper.strings.get_id(str.str))); + } else { + res->str = reinterpret_cast(static_cast(str.str - snapper.story_string_table)); + } + ptr = snap_write(ptr, buf, should_write ); + } else { + // TODO more space efficent? + ptr = snap_write(ptr, &bool_value, max_value_size, should_write ); + } + return ptr - data; + } + const unsigned char* value::snap_load(const unsigned char* ptr, const loader& loader) + { + ptr = snap_read(ptr, _type); + ptr = snap_read(ptr, &bool_value, max_value_size); + if(_type == value_type::string) { + if(string_value.allocated) { + string_value.str = loader.string_table[(std::uintptr_t)(string_value.str)]; + } else { + string_value.str = loader.story_string_table +(std::uintptr_t)(string_value.str); + } + } + return ptr; + } } diff --git a/inkcpp/value.h b/inkcpp/value.h index 88382f5a..2e215296 100644 --- a/inkcpp/value.h +++ b/inkcpp/value.h @@ -6,9 +6,11 @@ /// define different value_types, and the mapping between type and data. #include "system.h" -#include "../shared/private/command.h" +#include "command.h" #include "list_table.h" +#include "snapshot_impl.h" #include "tuple.hpp" +#include "types.h" #ifdef INK_ENABLE_STL #include @@ -41,6 +43,7 @@ namespace ink::runtime::internal { func_start, // start of function marker func_end, // end of function marker null, // void value, for function returns + ex_fn_not_found, // value for failed external function calls tunnel_frame, // return from tunnel function_frame, // return from function thread_frame, // return from thread @@ -82,12 +85,21 @@ namespace ink::runtime::internal { /** * @brief class to wrap stack value to common type. */ - class value { + class value : public snapshot_interface { public: + // snapshot interface + size_t snap(unsigned char* data, const snapper&) const override; + const unsigned char* snap_load(const unsigned char* data, const loader&) override; + /// help struct to determine cpp type which represent the value_type template struct ret { using type = void; }; - constexpr value() : _type{value_type::none}, uint32_value{0}{} + constexpr value() : snapshot_interface(), bool_value{ 0 }, _type{ value_type::none } {} + constexpr explicit value( value_type type ) : bool_value{ 0 }, _type{ type } {} + + explicit value(const ink::runtime::value& val); + bool set( const ink::runtime::value& val ); + ink::runtime::value to_interface_value(list_table&) const; /// get value of the type (if possible) template @@ -122,7 +134,7 @@ namespace ink::runtime::internal { /// this new type template value redefine(const value& oth, T& ... env) const { - inkAssert(type() == oth.type()); + inkAssert(type() == oth.type(), "try to redefine value of other type"); return redefine(oth, {&env...}); } @@ -130,7 +142,8 @@ namespace ink::runtime::internal { template value redefine(const value& oth, const tuple& env) const { if constexpr ( ty == value_type::OP_END) { - throw ink_exception("Can't redefine value with this type! (It is not an variable type!)"); + inkFail("Can't redefine value with this type! (It is not an variable type!)"); + return value{}; } else if (ty != type()) { return redefine(oth, env); } else { @@ -160,6 +173,19 @@ namespace ink::runtime::internal { char ci; } pointer; }; + static constexpr size_t max_value_size = + sizeof_largest_type< + decltype(bool_value), + decltype(int32_value), + decltype(string_value), + decltype(uint32_value), + decltype(float_value), + decltype(jump), + decltype(list_value), + decltype(list_flag_value), + decltype(frame_value), + decltype(pointer) + >(); value_type _type; }; @@ -351,6 +377,11 @@ namespace ink::runtime::internal { return *this; } template<> + inline constexpr value& value::set() { + _type = value_type::ex_fn_not_found; + return *this; + } + template<> inline constexpr value& value::set() { _type = value_type::newline; return *this; @@ -416,11 +447,12 @@ namespace ink::runtime::internal { // static constexpr instantiations of flag values namespace values { - static constexpr value marker = value{}.set(); - static constexpr value glue = value{}.set(); - static constexpr value newline = value{}.set(); - static constexpr value func_start = value{}.set(); - static constexpr value func_end = value{}.set(); - static constexpr value null = value{}.set(); + static constexpr value marker = value( value_type::marker ); + static constexpr value glue = value( value_type::glue ); + static constexpr value newline = value( value_type::newline ); + static constexpr value func_start = value( value_type::func_start ); + static constexpr value func_end = value( value_type::func_end ); + static constexpr value null = value( value_type::null ); + static constexpr value ex_fn_not_found = value(value_type::ex_fn_not_found); } } diff --git a/inkcpp_cl/inkcpp_cl.cpp b/inkcpp_cl/inkcpp_cl.cpp index 53a08209..acdb1c64 100644 --- a/inkcpp_cl/inkcpp_cl.cpp +++ b/inkcpp_cl/inkcpp_cl.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "test.h" @@ -19,7 +20,7 @@ void usage() cout << "Usage: inkcpp_cl \n" << "\t-o :\tOutput file name\n" - << "\t-p:\tPlay mode\n" + << "\t-p []:\tPlay mode\n\toptional snapshot file to load\n\tto create a snapshot file enter '-1' as choice\n" << endl; } @@ -35,6 +36,7 @@ int main(int argc, const char** argv) // Parse options std::string outputFilename; bool playMode = false, testMode = false, testDirectory = false; + std::string snapshotFile; for (int i = 1; i < argc - 1; i++) { std::string option = argv[i]; @@ -43,8 +45,13 @@ int main(int argc, const char** argv) outputFilename = argv[i + 1]; i += 1; } - else if (option == "-p") + else if (option == "-p") { playMode = true; + if (i + 1 < argc - 1 && argv[i+1][0] != '-') { + ++i; + snapshotFile = argv[i]; + } + } else if (option == "-t") testMode = true; else if (option == "-td") @@ -81,6 +88,7 @@ int main(int argc, const char** argv) // If input filename is an .ink file int val = inputFilename.find(".ink"); + bool json_file_is_tmp_file = false; if (val == inputFilename.length() - 4) { // Create temporary filename @@ -98,6 +106,7 @@ int main(int argc, const char** argv) } // New input is the json file + json_file_is_tmp_file = true; inputFilename = jsonFile; } @@ -108,6 +117,7 @@ int main(int argc, const char** argv) std::ofstream fout(outputFilename, std::ios::binary | std::ios::out); ink::compiler::run(inputFilename.c_str(), fout, &results); fout.close(); + if(json_file_is_tmp_file) { remove(inputFilename.c_str()); } // Report errors for (auto& warn : results.warnings) @@ -123,6 +133,7 @@ int main(int argc, const char** argv) } catch (std::exception& e) { + if(json_file_is_tmp_file) { remove(inputFilename.c_str()); } std::cerr << "Unhandled InkBin compiler exception: " << e.what() << std::endl; return 1; } @@ -139,13 +150,19 @@ int main(int argc, const char** argv) story* myInk = story::from_file(outputFilename.c_str()); // Start runner - runner thread = myInk->new_runner(); + runner thread; + if (snapshotFile.size()) { + auto snap_ptr = snapshot::from_file( snapshotFile.c_str() ); + thread = myInk->new_runner_from_snapshot(*snap_ptr); + delete snap_ptr; + } else { + thread = myInk->new_runner(); + } while (true) { while (thread->can_continue()) std::cout << thread->getline(); - if (thread->has_tags()){ std::cout << "# tags: "; for (int i = 0; i < thread->num_tags(); ++i) { @@ -162,15 +179,27 @@ int main(int argc, const char** argv) int index = 1; for (const ink::runtime::choice& c : *thread) { - std::cout << index++ << ": " << c.text() << std::endl; + std::cout << index++ << ": " << c.text(); + if(c.has_tags()) { + std::cout << "\n\t"; + for(size_t i = 0; i < c.num_tags(); ++i) { + std::cout << "# " << c.get_tag(i) << " "; + } + } + std::cout << std::endl; } int c = 0; std::cin >> c; + if (c == -1) { + snapshot* snap = thread->create_snapshot(); + snap->write_to_file(std::regex_replace(inputFilename, std::regex("\\.[^\\.]+$"), ".snap").c_str()); + delete snap; + break; + } thread->choose(c - 1); std::cout << "?> "; continue; - continue; } // out of content diff --git a/inkcpp_compiler/binary_emitter.cpp b/inkcpp_compiler/binary_emitter.cpp index dd163e63..05c86371 100644 --- a/inkcpp_compiler/binary_emitter.cpp +++ b/inkcpp_compiler/binary_emitter.cpp @@ -17,7 +17,6 @@ namespace ink::compiler::internal using std::vector; using std::map; using std::string; - using std::tuple; char* strtok_s(char * s, const char * sep, char** context) { #if defined(_WIN32) || defined(_WIN64) @@ -26,7 +25,7 @@ namespace ink::compiler::internal if ( context == nullptr || sep == nullptr || - s == nullptr && *context == nullptr ) + (s == nullptr && *context == nullptr) ) { errno = EINVAL; return nullptr; @@ -67,9 +66,9 @@ namespace ink::compiler::internal // Clear lists children.clear(); - named_children.clear(); - indexed_children.clear(); - noop_offsets.clear(); + //named_children.clear(); + //indexed_children.clear(); + //noop_offsets.clear(); parent = nullptr; } }; @@ -107,8 +106,9 @@ namespace ink::compiler::internal _current->children.push_back(container); _current->indexed_children.insert({ index_in_parent, container }); - if (!name.empty()) + if (!name.empty()) { _current->named_children.insert({ name, container }); + } } // Set this as the current pointer @@ -127,6 +127,23 @@ namespace ink::compiler::internal return _containers.pos(); } + int binary_emitter::function_container_arguments(const std::string& name) + { + if(_root == nullptr) { return -1; } + auto fn = _root->named_children.find(name); + if (fn == _root->named_children.end()) { return -1; } + + size_t offset = fn->second->offset; + byte_t cmd = _containers.get(offset); + int arity = 0; + while(static_cast(cmd) == Command::DEFINE_TEMP) { + offset += 6; // command(1) + flag(1) + variable_name_hash(4) + cmd = _containers.get(offset); + ++arity; + } + return arity; + } + void binary_emitter::write_raw(Command command, CommandFlag flag, const char* payload, ink::size_t payload_size) { _containers.write(command); @@ -142,7 +159,8 @@ namespace ink::compiler::internal // Note the position of this later so we can resolve the paths at the end size_t param_position = _containers.pos() - sizeof(uint32_t); - _paths.push_back(std::make_tuple(param_position, path, _current, useCountIndex)); + bool op = flag & CommandFlag::FALLBACK_FUNCTION; + _paths.push_back(std::make_tuple(param_position, path, op, _current, useCountIndex)); } void binary_emitter::write_variable(Command command, CommandFlag flag, const std::string& name) @@ -171,8 +189,8 @@ namespace ink::compiler::internal void binary_emitter::write_list(Command command, CommandFlag flag, const std::vector& entries) { uint32_t id = _list_count++; - for(const list_flag& flag : entries) { - _lists.write(flag); + for(const list_flag& entry : entries) { + _lists.write(entry); } _lists.write(null_flag); write(command, id, flag); @@ -274,8 +292,9 @@ namespace ink::compiler::internal using std::get; size_t position = get<0>(pair); const std::string& path = get<1>(pair); - container_data* context = get<2>(pair); - bool useCountIndex = get<3>(pair); + bool optional = get<2>(pair); + container_data* context = get<3>(pair); + bool useCountIndex = get<4>(pair); // Start at the root container_data* container = _root; @@ -325,7 +344,10 @@ namespace ink::compiler::internal // Named child else { - container = container->named_children[token]; + auto itr = container->named_children.find(token); + container = itr == container->named_children.end() + ? nullptr + : itr->second; } firstParent = false; @@ -350,7 +372,12 @@ namespace ink::compiler::internal else { // Otherwise, write container address - _containers.set(position, container->offset); + if (container == nullptr) { + _containers.set(position, 0); + inkAssert(optional, "Was not able to resolve a not optional path! '%s'", path.c_str()); + } else { + _containers.set(position, container->offset); + } } } } diff --git a/inkcpp_compiler/binary_emitter.h b/inkcpp_compiler/binary_emitter.h index 1cf73c69..7033c909 100644 --- a/inkcpp_compiler/binary_emitter.h +++ b/inkcpp_compiler/binary_emitter.h @@ -18,6 +18,7 @@ namespace ink::compiler::internal // Begin emitter virtual uint32_t start_container(int index_in_parent, const std::string& name) override; virtual uint32_t end_container() override; + virtual int function_container_arguments(const std::string& name) override; virtual void write_raw(Command command, CommandFlag flag = CommandFlag::NO_FLAGS, const char* payload = nullptr, ink::size_t payload_size = 0) override; virtual void write_path(Command command, CommandFlag flag, const std::string& path, bool useCountIndex = false) override; virtual void write_variable(Command command, CommandFlag flag, const std::string& name) override; @@ -53,6 +54,11 @@ namespace ink::compiler::internal binary_stream _lists; binary_stream _containers; - std::vector> _paths; + // positon to write address + // path as string + // if path may not exists (used for function fallbackes) + // container data + // use count index? + std::vector> _paths; }; } diff --git a/inkcpp_compiler/binary_stream.cpp b/inkcpp_compiler/binary_stream.cpp index 6f44f59e..6c57064d 100644 --- a/inkcpp_compiler/binary_stream.cpp +++ b/inkcpp_compiler/binary_stream.cpp @@ -124,6 +124,23 @@ namespace ink memcpy(ptr, data, len); } + byte_t binary_stream::get(size_t offset) const + { + // Find slab for offset + unsigned int slab_index = offset / DATA_SIZE; + size_t pos = offset % DATA_SIZE; + + // Get slab and ptr + byte_t* slab = nullptr; + if (slab_index < _slabs.size()) + slab = _slabs[slab_index]; + else if (slab_index == _slabs.size()) + slab = _currentSlab; + + inkAssert(slab != nullptr, "try to access invalid slab in binary stream"); + return slab[pos]; + } + void binary_stream::reset() { // Delete all slabs diff --git a/inkcpp_compiler/binary_stream.h b/inkcpp_compiler/binary_stream.h index 6d4efe25..d5228727 100644 --- a/inkcpp_compiler/binary_stream.h +++ b/inkcpp_compiler/binary_stream.h @@ -48,6 +48,9 @@ namespace ink // reset to 0 void reset(); + // read a byte from stream + byte_t get(size_t offset) const; + private: // Size of a data slab. Whenever // a slab runs out of data, diff --git a/inkcpp_compiler/command.cpp b/inkcpp_compiler/command.cpp index 496734da..47a2b114 100644 --- a/inkcpp_compiler/command.cpp +++ b/inkcpp_compiler/command.cpp @@ -14,7 +14,7 @@ namespace ink "\n", "<>", "void", - "#", + "inkcpp_TAG", "inkcpp_DIVERT", "inkcpp_DIVERT_TO_VARIABLE", "inkcpp_TUNNEL", @@ -40,6 +40,8 @@ namespace ink "str", "/str", + "#", + "/#", "inkcpp_CHOICE", "thread", diff --git a/inkcpp_compiler/emitter.h b/inkcpp_compiler/emitter.h index 75a99bc9..cee87890 100644 --- a/inkcpp_compiler/emitter.h +++ b/inkcpp_compiler/emitter.h @@ -28,6 +28,12 @@ namespace ink::compiler::internal // ends a container virtual uint32_t end_container() = 0; + // checks if _root contains a container named name to check + // if name is in valid internal function name + // @return number of arguments functions takes (arity) + // @retval -1 if the function was not found + virtual int function_container_arguments(const std::string& name) = 0; + // Writes a command with an optional payload virtual void write_raw(Command command, CommandFlag flag = CommandFlag::NO_FLAGS, const char* payload = nullptr, ink::size_t payload_size = 0) = 0; diff --git a/inkcpp_compiler/json.hpp b/inkcpp_compiler/json.hpp index 2a32a829..4d1a37ad 100644 --- a/inkcpp_compiler/json.hpp +++ b/inkcpp_compiler/json.hpp @@ -1,46 +1,30 @@ -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.7.0 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License . -SPDX-License-Identifier: MIT -Copyright (c) 2013-2019 Niels Lohmann . - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +/****************************************************************************\ + * Note on documentation: The source files contain links to the online * + * documentation of the public API at https://json.nlohmann.me. This URL * + * contains the most recent documentation and should also be applicable to * + * previous versions; documentation for deprecated functions is not * + * removed, but marked deprecated. See "Generate documentation" section in * + * file docs/README.md. * +\****************************************************************************/ #ifndef INCLUDE_NLOHMANN_JSON_HPP_ #define INCLUDE_NLOHMANN_JSON_HPP_ -#define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 7 -#define NLOHMANN_JSON_VERSION_PATCH 0 - #include // all_of, find, for_each -#include // assert -#include // and, not, or #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list -#include // istream, ostream +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO #include // random_access_iterator_tag #include // unique_ptr #include // accumulate @@ -49,16 +33,133 @@ SOFTWARE. #include // vector // #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + #include +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif + // #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + #include // transform #include // array -#include // and, not #include // forward_list #include // inserter, front_inserter, end #include // map @@ -70,63 +171,169 @@ SOFTWARE. #include // valarray // #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include // nullptr_t #include // exception #include // runtime_error #include // to_string +#include // vector -// #include +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#include // array #include // size_t +#include // uint8_t +#include // string + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // declval, pair +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + -namespace nlohmann +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template struct make_void { + using type = void; +}; +template using void_t = typename make_void::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { -/// struct to capture the start position of the current token -struct position_t + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch { - /// the total number of characters read - std::size_t chars_read_total = 0; - /// the number of characters read in the current line - std::size_t chars_read_current_line = 0; - /// the number of lines read - std::size_t lines_read = 0; + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; - /// conversion to size_t to preserve SAX interface - constexpr operator size_t() const - { - return chars_read_total; - } +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; }; -} // namespace detail -} // namespace nlohmann +template class Op, class... Args> +using is_detected = typename detector::value_t; -// #include +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END -#include // pair // #include + + +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson +// SPDX-License-Identifier: MIT + /* Hedley - https://nemequ.github.io/hedley * Created by Evan Nemerson - * - * To the extent possible under law, the author(s) have dedicated all - * copyright and related and neighboring rights to this software to - * the public domain worldwide. This software is distributed without - * any warranty. - * - * For details, see . - * SPDX-License-Identifier: CC0-1.0 */ -#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 9) +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) #if defined(JSON_HEDLEY_VERSION) #undef JSON_HEDLEY_VERSION #endif -#define JSON_HEDLEY_VERSION 9 +#define JSON_HEDLEY_VERSION 15 #if defined(JSON_HEDLEY_STRINGIFY_EX) #undef JSON_HEDLEY_STRINGIFY_EX @@ -148,6 +355,16 @@ struct position_t #endif #define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + #if defined(JSON_HEDLEY_VERSION_ENCODE) #undef JSON_HEDLEY_VERSION_ENCODE #endif @@ -189,18 +406,18 @@ struct position_t #if defined(JSON_HEDLEY_MSVC_VERSION) #undef JSON_HEDLEY_MSVC_VERSION #endif -#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) -#elif defined(_MSC_FULL_VER) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && !defined(__ICL) #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) #endif #if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) #undef JSON_HEDLEY_MSVC_VERSION_CHECK #endif -#if !defined(_MSC_VER) +#if !defined(JSON_HEDLEY_MSVC_VERSION) #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) #elif defined(_MSC_VER) && (_MSC_VER >= 1400) #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) @@ -213,9 +430,9 @@ struct position_t #if defined(JSON_HEDLEY_INTEL_VERSION) #undef JSON_HEDLEY_INTEL_VERSION #endif -#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) -#elif defined(__INTEL_COMPILER) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) #endif @@ -228,6 +445,22 @@ struct position_t #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) #endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#endif + #if defined(JSON_HEDLEY_PGI_VERSION) #undef JSON_HEDLEY_PGI_VERSION #endif @@ -323,9 +556,17 @@ struct position_t #if defined(JSON_HEDLEY_TI_VERSION) #undef JSON_HEDLEY_TI_VERSION #endif -#if defined(__TI_COMPILER_VERSION__) +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) #endif +#endif #if defined(JSON_HEDLEY_TI_VERSION_CHECK) #undef JSON_HEDLEY_TI_VERSION_CHECK @@ -336,6 +577,102 @@ struct position_t #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) #endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + #if defined(JSON_HEDLEY_CRAY_VERSION) #undef JSON_HEDLEY_CRAY_VERSION #endif @@ -363,7 +700,7 @@ struct position_t #if __VER__ > 1000 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) #else - #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) #endif #endif @@ -440,6 +777,22 @@ struct position_t #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) #endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) + #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#endif + #if defined(JSON_HEDLEY_GCC_VERSION) #undef JSON_HEDLEY_GCC_VERSION #endif @@ -449,8 +802,16 @@ struct position_t !defined(JSON_HEDLEY_INTEL_VERSION) && \ !defined(JSON_HEDLEY_PGI_VERSION) && \ !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && \ !defined(JSON_HEDLEY_TI_VERSION) && \ - !defined(__COMPCERT__) + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION #endif @@ -466,17 +827,21 @@ struct position_t #if defined(JSON_HEDLEY_HAS_ATTRIBUTE) #undef JSON_HEDLEY_HAS_ATTRIBUTE #endif -#if defined(__has_attribute) - #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#if \ + defined(__has_attribute) && \ + ( \ + (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + ) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) #else - #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) - #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) #else #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) #endif @@ -485,7 +850,7 @@ struct position_t #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) - #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) #else #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) #endif @@ -493,12 +858,30 @@ struct position_t #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE #endif -#if defined(__has_cpp_attribute) && defined(__cplusplus) +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) #else #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) #endif +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + #if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE #endif @@ -660,7 +1043,13 @@ struct position_t JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ @@ -687,13 +1076,21 @@ struct position_t #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) #elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,1,0) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) @@ -704,54 +1101,209 @@ struct position_t #define JSON_HEDLEY_DIAGNOSTIC_POP #endif -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ #endif -#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x #endif -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST #endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") #else #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif @@ -765,40 +1317,74 @@ struct position_t #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + #if defined(JSON_HEDLEY_DEPRECATED) #undef JSON_HEDLEY_DEPRECATED #endif #if defined(JSON_HEDLEY_DEPRECATED_FOR) #undef JSON_HEDLEY_DEPRECATED_FOR #endif -#if defined(__cplusplus) && (__cplusplus >= 201402L) - #define JSON_HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]] - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]] +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) #elif \ - JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ + (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,3,0) + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) - #define JSON_HEDLEY_DEPRECATED(since) _declspec(deprecated) + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") @@ -814,7 +1400,8 @@ struct position_t #if \ JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) #else #define JSON_HEDLEY_UNAVAILABLE(available_since) @@ -823,21 +1410,41 @@ struct position_t #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) #undef JSON_HEDLEY_WARN_UNUSED_RESULT #endif -#if defined(__cplusplus) && (__cplusplus >= 201703L) - #define JSON_HEDLEY_WARN_UNUSED_RESULT [[nodiscard]] -#elif \ +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if \ JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) #elif defined(_Check_return_) /* SAL */ #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ #else #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) #endif #if defined(JSON_HEDLEY_SENTINEL) @@ -847,7 +1454,8 @@ struct position_t JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) #else #define JSON_HEDLEY_SENTINEL(position) @@ -858,24 +1466,40 @@ struct position_t #endif #if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_NO_RETURN __noreturn -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +#elif \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define JSON_HEDLEY_NO_RETURN _Noreturn #elif defined(__cplusplus) && (__cplusplus >= 201103L) - #define JSON_HEDLEY_NO_RETURN [[noreturn]] + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) #elif \ JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) @@ -885,67 +1509,82 @@ struct position_t #define JSON_HEDLEY_NO_RETURN #endif +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + #if defined(JSON_HEDLEY_UNREACHABLE) #undef JSON_HEDLEY_UNREACHABLE #endif #if defined(JSON_HEDLEY_UNREACHABLE_RETURN) #undef JSON_HEDLEY_UNREACHABLE_RETURN #endif -#if \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) - #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) - #define JSON_HEDLEY_UNREACHABLE() __assume(0) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) - #if defined(__cplusplus) - #define JSON_HEDLEY_UNREACHABLE() std::_nassert(0) - #else - #define JSON_HEDLEY_UNREACHABLE() _nassert(0) - #endif - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value -#elif defined(EXIT_FAILURE) - #define JSON_HEDLEY_UNREACHABLE() abort() -#else - #define JSON_HEDLEY_UNREACHABLE() - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value -#endif -#if !defined(JSON_HEDLEY_UNREACHABLE_RETURN) - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() -#endif - #if defined(JSON_HEDLEY_ASSUME) #undef JSON_HEDLEY_ASSUME #endif #if \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_ASSUME(expr) __assume(expr) #elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) #if defined(__cplusplus) #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) #else #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) #endif -#elif \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(JSON_HEDLEY_ARM_VERSION)) || \ +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) - #define JSON_HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif #else - #define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) #endif - JSON_HEDLEY_DIAGNOSTIC_PUSH -#if \ - JSON_HEDLEY_HAS_WARNING("-Wvariadic-macros") || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) #if defined(__clang__) #pragma clang diagnostic ignored "-Wvariadic-macros" #elif defined(JSON_HEDLEY_GCC_VERSION) @@ -979,8 +1618,18 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) #elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) @@ -993,7 +1642,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif #if defined(__cplusplus) #if __cplusplus >= 201103L - #define JSON_HEDLEY_CONSTEXPR constexpr + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) #endif #endif #if !defined(JSON_HEDLEY_CONSTEXPR) @@ -1013,44 +1662,50 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_UNPREDICTABLE #endif #if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) - #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) #endif #if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) -# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) -#if !defined(JSON_HEDLEY_BUILTIN_UNPREDICTABLE) - #define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) -#endif + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) #elif \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) # define JSON_HEDLEY_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ (__extension__ ({ \ - JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + double hedley_probability_ = (probability); \ ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ })) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ (__extension__ ({ \ - JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + double hedley_probability_ = (probability); \ ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ })) # define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #else -# define JSON_HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr)) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) # define JSON_HEDLEY_LIKELY(expr) (!!(expr)) @@ -1070,10 +1725,24 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_MALLOC __declspec(restrict) #else #define JSON_HEDLEY_MALLOC @@ -1083,20 +1752,37 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_PURE #endif #if \ - JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_PURE __attribute__((__pure__)) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") #else - #define JSON_HEDLEY_PURE +# define JSON_HEDLEY_PURE #endif #if defined(JSON_HEDLEY_CONST) @@ -1109,10 +1795,23 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") #else #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE #endif @@ -1126,13 +1825,18 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - defined(__clang__) + defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_RESTRICT __restrict #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) #define JSON_HEDLEY_RESTRICT _Restrict @@ -1153,8 +1857,15 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_HEDLEY_INLINE __inline__ #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_INLINE __inline #else #define JSON_HEDLEY_INLINE @@ -1164,23 +1875,44 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_ALWAYS_INLINE #endif #if \ - JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) - #define JSON_HEDLEY_ALWAYS_INLINE __forceinline -#elif JSON_HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") #else - #define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE #endif #if defined(JSON_HEDLEY_NEVER_INLINE) @@ -1193,14 +1925,27 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) #elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") @@ -1222,26 +1967,32 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_IMPORT #endif #if defined(_WIN32) || defined(__CYGWIN__) - #define JSON_HEDLEY_PRIVATE - #define JSON_HEDLEY_PUBLIC __declspec(dllexport) - #define JSON_HEDLEY_IMPORT __declspec(dllimport) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) #else - #if \ - JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) - #define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) - #else - #define JSON_HEDLEY_PRIVATE - #define JSON_HEDLEY_PUBLIC - #endif - #define JSON_HEDLEY_IMPORT extern +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern #endif #if defined(JSON_HEDLEY_NO_THROW) @@ -1250,10 +2001,12 @@ JSON_HEDLEY_DIAGNOSTIC_POP #if \ JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) #elif \ JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) #define JSON_HEDLEY_NO_THROW __declspec(nothrow) #else @@ -1264,27 +2017,18 @@ JSON_HEDLEY_DIAGNOSTIC_POP #undef JSON_HEDLEY_FALL_THROUGH #endif #if \ - defined(__cplusplus) && \ - (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ - !defined(JSON_HEDLEY_PGI_VERSION) - #if \ - (__cplusplus >= 201703L) || \ - ((__cplusplus >= 201103L) && JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)) - #define JSON_HEDLEY_FALL_THROUGH [[fallthrough]] - #elif (__cplusplus >= 201103L) && JSON_HEDLEY_HAS_CPP_ATTRIBUTE(clang::fallthrough) - #define JSON_HEDLEY_FALL_THROUGH [[clang::fallthrough]] - #elif (__cplusplus >= 201103L) && JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) - #define JSON_HEDLEY_FALL_THROUGH [[gnu::fallthrough]] - #endif -#endif -#if !defined(JSON_HEDLEY_FALL_THROUGH) - #if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) - #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) - #elif defined(__fallthrough) /* SAL */ - #define JSON_HEDLEY_FALL_THROUGH __fallthrough - #else - #define JSON_HEDLEY_FALL_THROUGH - #endif + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH #endif #if defined(JSON_HEDLEY_RETURNS_NON_NULL) @@ -1292,7 +2036,8 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif #if \ JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) #elif defined(_Ret_notnull_) /* SAL */ #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ @@ -1320,12 +2065,11 @@ JSON_HEDLEY_DIAGNOSTIC_POP #if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) #undef JSON_HEDLEY_REQUIRE_CONSTEXPR #endif -/* Note the double-underscore. For internal use only; no API - * guarantees! */ -#if defined(JSON_HEDLEY__IS_CONSTEXPR) - #undef JSON_HEDLEY__IS_CONSTEXPR +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ #endif - #if \ JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ @@ -1333,9 +2077,10 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) #endif #if !defined(__cplusplus) @@ -1348,31 +2093,40 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) #if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) #else #include - #define JSON_HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) #endif # elif \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ - JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) #if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) #else #include - #define JSON_HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) #endif # elif \ defined(JSON_HEDLEY_GCC_VERSION) || \ defined(JSON_HEDLEY_INTEL_VERSION) || \ defined(JSON_HEDLEY_TINYC_VERSION) || \ - defined(JSON_HEDLEY_TI_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ defined(__clang__) -# define JSON_HEDLEY__IS_CONSTEXPR(expr) ( \ +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ sizeof(void) != \ sizeof(*( \ 1 ? \ @@ -1383,11 +2137,11 @@ JSON_HEDLEY_DIAGNOSTIC_POP ) # endif #endif -#if defined(JSON_HEDLEY__IS_CONSTEXPR) +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) #if !defined(JSON_HEDLEY_IS_CONSTANT) - #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY__IS_CONSTEXPR(expr) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) #endif - #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY__IS_CONSTEXPR(expr) ? (expr) : (-1)) + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) #else #if !defined(JSON_HEDLEY_IS_CONSTANT) #define JSON_HEDLEY_IS_CONSTANT(expr) (0) @@ -1420,67 +2174,36 @@ JSON_HEDLEY_DIAGNOSTIC_POP #if \ !defined(__cplusplus) && ( \ (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ - JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ defined(_Static_assert) \ ) # define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) #elif \ - (defined(__cplusplus) && (__cplusplus >= 201703L)) || \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ - (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr, message) -#elif defined(__cplusplus) && (__cplusplus >= 201103L) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr) + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) #else # define JSON_HEDLEY_STATIC_ASSERT(expr, message) #endif -#if defined(JSON_HEDLEY_CONST_CAST) - #undef JSON_HEDLEY_CONST_CAST -#endif -#if defined(__cplusplus) -# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) -#elif \ - JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) -#else -# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_REINTERPRET_CAST) - #undef JSON_HEDLEY_REINTERPRET_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) -#else - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr))) -#endif - -#if defined(JSON_HEDLEY_STATIC_CAST) - #undef JSON_HEDLEY_STATIC_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) -#else - #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_CPP_CAST) - #undef JSON_HEDLEY_CPP_CAST +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL #endif #if defined(__cplusplus) - #define JSON_HEDLEY_CPP_CAST(T, expr) static_cast(expr) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL #else - #define JSON_HEDLEY_CPP_CAST(T, expr) (expr) + #define JSON_HEDLEY_NULL ((void*) 0) #endif #if defined(JSON_HEDLEY_MESSAGE) @@ -1517,41 +2240,51 @@ JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_DIAGNOSTIC_POP #elif \ JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) #else # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) #endif +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif #if defined(JSON_HEDLEY_REQUIRE_MSG) #undef JSON_HEDLEY_REQUIRE_MSG #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) # if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") -# define JSON_HEDLEY_REQUIRE_MSG(expr, msg) \ +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ JSON_HEDLEY_DIAGNOSTIC_PUSH \ _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((__diagnose_if__(!(expr), msg, "error"))) \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ JSON_HEDLEY_DIAGNOSTIC_POP # else -# define JSON_HEDLEY_REQUIRE_MSG(expr, msg) __attribute__((__diagnose_if__(!(expr), msg, "error"))) +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) # endif #else -# define JSON_HEDLEY_REQUIRE_MSG(expr, msg) -#endif - -#if defined(JSON_HEDLEY_REQUIRE) - #undef JSON_HEDLEY_REQUIRE +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) #endif -#define JSON_HEDLEY_REQUIRE(expr) JSON_HEDLEY_REQUIRE_MSG(expr, #expr) #if defined(JSON_HEDLEY_FLAGS) #undef JSON_HEDLEY_FLAGS #endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else + #define JSON_HEDLEY_FLAGS #endif #if defined(JSON_HEDLEY_FLAGS_CAST) @@ -1568,6 +2301,17 @@ JSON_HEDLEY_DIAGNOSTIC_POP # define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) #endif +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if \ + (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + /* Remaining macros are deprecated. */ #if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) @@ -1617,10 +2361,13 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ -// This file contains all internal macro definitions +// This file contains all internal macro definitions (except those affecting ABI) // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them -// exclude unsupported compilers +// #include + + +// exclude unsupported compilers #if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) #if defined(__clang__) #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 @@ -1634,26 +2381,128 @@ JSON_HEDLEY_DIAGNOSTIC_POP #endif // C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE #endif -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS #endif // disable documentation warnings on clang #if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" #endif -// allow to disable exceptions +// allow disabling exceptions #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try @@ -1687,35 +2536,48 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #endif +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + /*! @brief macro to briefly define a mapping between an enum and JSON @def NLOHMANN_JSON_SERIALIZE_ENUM @since version 3.4.0 */ -#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ - template \ - inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [e](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.first == e; \ - }); \ - j = ((it != std::end(m)) ? it : std::begin(m))->second; \ - } \ - template \ - inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [j](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.second == j; \ - }); \ - e = ((it != std::end(m)) ? it : std::begin(m))->first; \ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ } // Ugly macros to avoid uglier copy-paste when specializing basic_json. They @@ -1727,413 +2589,603 @@ JSON_HEDLEY_DIAGNOSTIC_POP class StringType, class BooleanType, class NumberIntegerType, \ class NumberUnsignedType, class NumberFloatType, \ template class AllocatorType, \ - template class JSONSerializer> + template class JSONSerializer, \ + class BinaryType> #define NLOHMANN_BASIC_JSON_TPL \ basic_json + AllocatorType, JSONSerializer, BinaryType> + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } -namespace nlohmann -{ -namespace detail -{ -//////////////// -// exceptions // -//////////////// +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } /*! -@brief general exception of the @ref basic_json class +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } -This class is an extension of `std::exception` objects with a member @a id for -exception ids. It is used as the base class for all exceptions thrown by the -@ref basic_json class. This class can hence be used as "wildcard" to catch -exceptions. +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } -Subclasses: -- @ref parse_error for exceptions indicating a parse error -- @ref invalid_iterator for exceptions indicating errors with iterators -- @ref type_error for exceptions indicating executing a member function with - a wrong type -- @ref out_of_range for exceptions indicating access out of the defined range -- @ref other_error for exceptions indicating other library errors -@internal -@note To have nothrow-copy-constructible exceptions, we internally use - `std::runtime_error` which can cope with arbitrary-length error messages. - Intermediate strings are built with static functions and then passed to - the actual constructor. -@endinternal +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif -@liveexample{The following code shows how arbitrary library exceptions can be -caught.,exception} +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif -@since version 3.0.0 -*/ -class exception : public std::exception +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + #include // partial_ordering +#endif + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail { - public: - /// returns the explanatory string - JSON_HEDLEY_RETURNS_NON_NULL - const char* what() const noexcept override - { - return m.what(); - } - /// the id of the exception - const int id; +/////////////////////////// +// JSON type enumeration // +/////////////////////////// - protected: - JSON_HEDLEY_NON_NULL(3) - exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} +/*! +@brief the JSON type enumeration - static std::string name(const std::string& ename, int id_) - { - return "[json.exception." + ename + "." + std::to_string(id_) + "] "; - } +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. - private: - /// an exception object as storage for error messages - std::runtime_error m; +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function }; /*! -@brief exception indicating a parse error - -This exception is thrown by the library when a parse error occurs. Parse errors -can occur during the deserialization of JSON text, CBOR, MessagePack, as well -as when using JSON Patch. - -Member @a byte holds the byte index of the last read character in the input -file. - -Exceptions have ids 1xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. -json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. -json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. -json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. -json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. -json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). - -@note For an input with n bytes, 1 is the index of the first character and n+1 - is the index of the terminating null byte or the end of file. This also - holds true when reading a byte vector (CBOR or MessagePack). - -@liveexample{The following code shows how a `parse_error` exception can be -caught.,parse_error} - -@sa - @ref exception for the base class of the library exceptions -@sa - @ref invalid_iterator for exceptions indicating errors with iterators -@sa - @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa - @ref out_of_range for exceptions indicating access out of the defined range -@sa - @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 */ -class parse_error : public exception +#if JSON_HAS_THREE_WAY_COMPARISON + inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* +#else + inline bool operator<(const value_t lhs, const value_t rhs) noexcept +#endif { - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] pos the position where the error occurred (or with - chars_read_total=0 if the position cannot be - determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - static parse_error create(int id_, const position_t& pos, const std::string& what_arg) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - position_string(pos) + ": " + what_arg; - return parse_error(id_, pos.chars_read_total, w.c_str()); - } + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); +#if JSON_HAS_THREE_WAY_COMPARISON + if (l_index < order.size() && r_index < order.size()) { - std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + - ": " + what_arg; - return parse_error(id_, byte_, w.c_str()); + return order[l_index] <=> order[r_index]; // *NOPAD* } + return std::partial_ordering::unordered; +#else + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +#endif +} - /*! - @brief byte index of the parse error +// GCC selects the built-in operator< over an operator rewritten from +// a user-defined spaceship operator +// Clang, MSVC, and ICC select the rewritten candidate +// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) +#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + return std::is_lt(lhs <=> rhs); // *NOPAD* +} +#endif - The byte index of the last read character in the input file. +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END - @note For an input with n bytes, 1 is the index of the first character and - n+1 is the index of the terminating null byte or the end of file. - This also holds true when reading a byte vector (CBOR or MessagePack). - */ - const std::size_t byte; +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT - private: - parse_error(int id_, std::size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) {} - static std::string position_string(const position_t& pos) - { - return " at line " + std::to_string(pos.lines_read + 1) + - ", column " + std::to_string(pos.chars_read_current_line); - } -}; -/*! -@brief exception indicating errors with iterators - -This exception is thrown if iterators passed to a library function do not match -the expected semantics. - -Exceptions have ids 2xx. - -name / id | example message | description ------------------------------------ | --------------- | ------------------------- -json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. -json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. -json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). - -@liveexample{The following code shows how an `invalid_iterator` exception can be -caught.,invalid_iterator} - -@sa - @ref exception for the base class of the library exceptions -@sa - @ref parse_error for exceptions indicating a parse error -@sa - @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa - @ref out_of_range for exceptions indicating access out of the defined range -@sa - @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class invalid_iterator : public exception -{ - public: - static invalid_iterator create(int id_, const std::string& what_arg) - { - std::string w = exception::name("invalid_iterator", id_) + what_arg; - return invalid_iterator(id_, w.c_str()); - } +// #include - private: - JSON_HEDLEY_NON_NULL(3) - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) {} -}; + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ /*! -@brief exception indicating executing a member function with a wrong type - -This exception is thrown in case of a type error; that is, a library function is -executed on a JSON value whose type does not match the expected semantics. - -Exceptions have ids 3xx. - -name / id | example message | description ------------------------------ | --------------- | ------------------------- -json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. -json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. -json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. -json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. -json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. -json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | -json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | - -@liveexample{The following code shows how a `type_error` exception can be -caught.,type_error} - -@sa - @ref exception for the base class of the library exceptions -@sa - @ref parse_error for exceptions indicating a parse error -@sa - @ref invalid_iterator for exceptions indicating errors with iterators -@sa - @ref out_of_range for exceptions indicating access out of the defined range -@sa - @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 */ -class type_error : public exception +template +inline void replace_substring(StringType& s, const StringType& f, + const StringType& t) { - public: - static type_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("type_error", id_) + what_arg; - return type_error(id_, w.c_str()); - } + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != StringType::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} - private: - JSON_HEDLEY_NON_NULL(3) - type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +template +inline StringType escape(StringType s) +{ + replace_substring(s, StringType{"~"}, StringType{"~0"}); + replace_substring(s, StringType{"/"}, StringType{"~1"}); + return s; +} /*! -@brief exception indicating access out of the defined range - -This exception is thrown in case a library function is called on an input -parameter that exceeds the expected range, for instance in case of array -indices or nonexisting object keys. - -Exceptions have ids 4xx. - -name / id | example message | description -------------------------------- | --------------- | ------------------------- -json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. -json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. -json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. -json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. -json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. -json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. -json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | -json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | -json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | - -@liveexample{The following code shows how an `out_of_range` exception can be -caught.,out_of_range} - -@sa - @ref exception for the base class of the library exceptions -@sa - @ref parse_error for exceptions indicating a parse error -@sa - @ref invalid_iterator for exceptions indicating errors with iterators -@sa - @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa - @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class out_of_range : public exception + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +template +static void unescape(StringType& s) { - public: - static out_of_range create(int id_, const std::string& what_arg) - { - std::string w = exception::name("out_of_range", id_) + what_arg; - return out_of_range(id_, w.c_str()); - } + replace_substring(s, StringType{"~1"}, StringType{"/"}); + replace_substring(s, StringType{"~0"}, StringType{"~"}); +} - private: - JSON_HEDLEY_NON_NULL(3) - out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END -/*! -@brief exception indicating other library errors +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT -This exception is thrown in case of errors that cannot be classified with the -other exception types. -Exceptions have ids 5xx. -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. +#include // size_t -@sa - @ref exception for the base class of the library exceptions -@sa - @ref parse_error for exceptions indicating a parse error -@sa - @ref invalid_iterator for exceptions indicating errors with iterators -@sa - @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa - @ref out_of_range for exceptions indicating access out of the defined range +// #include -@liveexample{The following code shows how an `other_error` exception can be -caught.,other_error} -@since version 3.0.0 -*/ -class other_error : public exception +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail { - public: - static other_error create(int id_, const std::string& what_arg) + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const { - std::string w = exception::name("other_error", id_) + what_arg; - return other_error(id_, w.c_str()); + return chars_read_total; } - - private: - JSON_HEDLEY_NON_NULL(3) - other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} }; + } // namespace detail -} // namespace nlohmann +NLOHMANN_JSON_NAMESPACE_END // #include // #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT -#include // not + +#include // array #include // size_t #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for -namespace nlohmann -{ +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; template using uncvref_t = typename std::remove_cv::type>::type; -// implementation of C++14 index_sequence and affiliates -// source: https://stackoverflow.com/a/32223343 -template -struct index_sequence -{ - using type = index_sequence; - using value_type = std::size_t; +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; static constexpr std::size_t size() noexcept { return sizeof...(Ints); } }; -template -struct merge_and_renumber; +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal -template -struct merge_and_renumber, index_sequence> - : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; +// Compile-time sequences of integers -template -struct make_index_sequence - : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > {}; +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; -template<> struct make_index_sequence<0> : index_sequence<> {}; -template<> struct make_index_sequence<1> : index_sequence<0> {}; +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; -template +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template using index_sequence_for = make_index_sequence; +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + // dispatch utility (taken from ranges-v3) template struct priority_tag : priority_tag < N - 1 > {}; template<> struct priority_tag<0> {}; @@ -2142,53 +3194,67 @@ template<> struct priority_tag<0> {}; template struct static_const { - static constexpr T value{}; + static JSON_INLINE_VARIABLE constexpr T value{}; }; -template -constexpr T static_const::value; +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +inline constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + } // namespace detail -} // namespace nlohmann +NLOHMANN_JSON_NAMESPACE_END // #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + -#include // not #include // numeric_limits #include // false_type, is_constructible, is_integral, is_same, true_type #include // declval +#include // tuple // #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT -#include // random_access_iterator_tag -// #include +#include // random_access_iterator_tag +// #include -namespace nlohmann -{ -namespace detail -{ -template struct make_void -{ - using type = void; -}; -template using void_t = typename make_void::type; -} // namespace detail -} // namespace nlohmann +// #include // #include -namespace nlohmann -{ +NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { -template + +template struct iterator_types {}; -template +template struct iterator_types < It, void_t +template struct iterator_traits { }; -template +template struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> : iterator_types { }; -template +template struct iterator_traits::value>> { using iterator_category = std::random_access_iterator_tag; @@ -2223,143 +3289,135 @@ struct iterator_traits::value>> using pointer = T*; using reference = T&; }; -} // namespace detail -} // namespace nlohmann + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END // #include -// #include +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT -// #include -#include +// #include -// #include +NLOHMANN_JSON_NAMESPACE_BEGIN -// http://en.cppreference.com/w/cpp/experimental/is_detected -namespace nlohmann -{ -namespace detail -{ -struct nonesuch -{ - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - nonesuch(nonesuch const&&) = delete; - void operator=(nonesuch const&) = delete; - void operator=(nonesuch&&) = delete; -}; +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); -template class Op, - class... Args> -struct detector -{ - using value_t = std::false_type; - using type = Default; -}; +NLOHMANN_JSON_NAMESPACE_END -template class Op, class... Args> -struct detector>, Op, Args...> -{ - using value_t = std::true_type; - using type = Op; -}; +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT -template