diff --git a/.clang-format-ignore b/.clang-format-ignore new file mode 100644 index 00000000..faac041c --- /dev/null +++ b/.clang-format-ignore @@ -0,0 +1 @@ +inkcpp_compiler/json.hpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c7b7cae..f5a695b7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -117,12 +117,20 @@ jobs: working-directory: ${{github.workspace}}/build shell: bash run: | + cmake $GITHUB_WORKSPACE -DINKCPP_UNREAL_TARGET_VERSION="5.7" -DINKCPP_UNREAL=ON + cmake --install . --config $BUILD_TYPE --prefix comp_unreal_5_7 --component unreal cmake $GITHUB_WORKSPACE -DINKCPP_UNREAL_TARGET_VERSION="5.6" -DINKCPP_UNREAL=ON cmake --install . --config $BUILD_TYPE --prefix comp_unreal_5_6 --component unreal cmake $GITHUB_WORKSPACE -DINKCPP_UNREAL_TARGET_VERSION="5.5" -DINKCPP_UNREAL=ON cmake --install . --config $BUILD_TYPE --prefix comp_unreal_5_5 --component unreal cmake $GITHUB_WORKSPACE -DINKCPP_UNREAL_TARGET_VERSION="5.4" -DINKCPP_UNREAL=ON cmake --install . --config $BUILD_TYPE --prefix comp_unreal_5_4 --component unreal + - name: Upload UE 5.7 + if: ${{ matrix.unreal }} + uses: actions/upload-artifact@v4 + with: + name: unreal_5_7 + path: build/comp_unreal_5_7/ - name: Upload UE 5.6 if: ${{ matrix.unreal }} uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 63696585..8c82eed1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,12 +26,12 @@ jobs: run: | mkdir artifacts ID=$(gh run list -b master --limit 1 --json databaseId | jq '.[0].databaseId') - gh run download $ID -D artifacts -n linux-cl -n linux-lib -n linux-clib -n unreal_5_6 -n unreal_5_5 -n unreal_5_4 -n macos-cl -n macos-lib -n macos-clib -n macos-arm-cl -n macos-arm-lib -n macos-arm-clib -n win64-cl -n win64-lib -n win64-clib -n python-package-distribution + gh run download $ID -D artifacts -n linux-cl -n linux-lib -n linux-clib -n unreal_5_7 -n unreal_5_6 -n unreal_5_5 -n unreal_5_4 -n macos-cl -n macos-lib -n macos-clib -n macos-arm-cl -n macos-arm-lib -n macos-arm-clib -n win64-cl -n win64-lib -n win64-clib -n python-package-distribution mv artifacts/python-package-distribution dist - name: Zip working-directory: ${{github.workspace}}/artifacts run: | - for f in linux-cl linux-lib linux-clib unreal_5_6 unreal_5_5 unreal_5_4 macos-cl macos-lib macos-clib macos-arm-cl macos-arm-lib macos-arm-clib win64-cl win64-lib win64-clib; do zip -r ../$f.zip $f; done + for f in linux-cl linux-lib linux-clib unreal_5_7 unreal_5_6 unreal_5_5 unreal_5_4 macos-cl macos-lib macos-clib macos-arm-cl macos-arm-lib macos-arm-clib win64-cl win64-lib win64-clib; do zip -r ../$f.zip $f; done - name: List run: tree - name: Publish to PyPI @@ -45,5 +45,5 @@ jobs: --repo="$GITHUB_REPOSITORY" \ --title="${GITHUB_REPOSITORY#*/} ${tag#v}" \ --generate-notes \ - "$tag" "linux-cl.zip" "linux-lib.zip" "linux-clib.zip" "unreal_5_6.zip" "unreal_5_5.zip" "unreal_5_4.zip" "macos-cl.zip" "macos-lib.zip" "macos-clib.zip" "win64-cl.zip" "macos-arm-cl.zip" "macos-arm-lib.zip" "macos-arm-clib.zip" "win64-lib.zip" "win64-clib.zip" + "$tag" "linux-cl.zip" "linux-lib.zip" "linux-clib.zip" "unreal_5_7.zip" "unreal_5_6.zip" "unreal_5_5.zip" "unreal_5_4.zip" "macos-cl.zip" "macos-lib.zip" "macos-clib.zip" "win64-cl.zip" "macos-arm-cl.zip" "macos-arm-lib.zip" "macos-arm-clib.zip" "win64-lib.zip" "win64-clib.zip" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 38ab6a8d..cb068f80 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,10 @@ repos: - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v18.1.0 + rev: v18.1.8 hooks: - id: clang-format types_or: [c++, c, cuda] + exclude: inkcpp_compiler/json.hpp - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 490af3e7..23dc4632 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,14 @@ SET(CMAKE_CXX_STANDARD 17) SET(CMAKE_CXX_STANDARD_REQUIRED ON) SET(CMAKE_INSTALL_LIBRARY_DIR lib) SET(CMAKE_INSTALL_INCLUDE_DIR include) - +if (MSVC) + # disable: + # aligment problems + # non explicit switch case + add_compile_options(/W4 /wd4820 /wd4061) +else() + add_compile_options(-Wall -Wextra -Wpedantic) +endif() # Add subdirectories include(CMakeDependentOption) option(INKCPP_PY "Build python bindings" OFF) diff --git a/Documentation/cmake_example/main.cpp b/Documentation/cmake_example/main.cpp index bf661cbf..4ab30388 100644 --- a/Documentation/cmake_example/main.cpp +++ b/Documentation/cmake_example/main.cpp @@ -4,6 +4,7 @@ #include #include +#include #include using namespace ink::runtime; @@ -14,7 +15,7 @@ int main() { ink::compiler::run("test.ink.json", "test.bin"); // Load ink binary story, generated from the inkCPP compiler - story* myInk = story::from_file("test.bin"); + std::unique_ptr myInk{story::from_file("test.bin")}; // Create a new thread runner thread = myInk->new_runner(); diff --git a/Documentation/unreal/InkCPP_DEMO.zip b/Documentation/unreal/InkCPP_DEMO.zip index fa200976..6ae55b55 100644 Binary files a/Documentation/unreal/InkCPP_DEMO.zip and b/Documentation/unreal/InkCPP_DEMO.zip differ diff --git a/README.md b/README.md index fa9a2602..64478826 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Alternativly is the latest version of the UE plugin can be downloaded from the [ Place the content of this file at your plugin folder of your UE project and at the next start up it will be intigrated. -A example project can be found [here](https://jbenda.github.io/inkcpp/unreal/InkCPP_DEMO.zip). And here the [Documentation](https://jbenda.github.io/inkcpp/html/group__unreal.html). +A example project can be found [here](https://jbenda.github.io/inkcpp/unreal/InkCPP_DEMO.zip). And here the [Documentation](https://jbenda.github.io/inkcpp/html/group__unreal.html). Code for the Unreal plugin is located in the `unreal` directory. In order to install it, run ```sh @@ -104,6 +104,7 @@ Instructions: #include #include #include +#include using namespace ink::runtime; @@ -112,7 +113,7 @@ int MyInkFunction(int a, int b) { return a + b; } ... // Load ink binary story, generated from the inkCPP compiler -story* myInk = story::from_file("test.bin"); +std::unique_ptr myInk{story::from_file("test.bin")}; // Create a new thread runner thread = myInk->new_runner(); @@ -208,6 +209,6 @@ The python bindnigs are defined in `inkcpp_python` subfolder. ## Dependencies The compiler depends on Nlohmann's JSON library and the C++ STL. -The runtime does not depend on either. If `INK_ENABLE_STL` is defined then STL extensions are added such as stream operators and `std::string` support. If `INK_ENABLE_UNREAL`, then FStrings, Delegates and other Unreal classes will be supported. +The runtime does not depend on either. If `INK_ENABLE_STL` is defined then STL extensions are added such as stream operators and `std::string` support. If `INK_ENABLE_UNREAL`, then FStrings, Delegates and other Unreal classes will be supported. NOTE: There is still some lingering C standard library calls in the runtime. I will be guarding them with an `INK_ENABLE_CSTD` or something soon. diff --git a/inkcpp/array.h b/inkcpp/array.h index a28a8b83..eb009f54 100644 --- a/inkcpp/array.h +++ b/inkcpp/array.h @@ -15,17 +15,29 @@ namespace ink::runtime::internal { -template +/** Managed array of objects. + * + * @tparam simple if the object has a trivial destructor, so delete[](char*) can be used instead of + * calling the constructor. + * @tparam dynamic if the memory should be allocated on the heap and grow if needed + * @tparam initialCapacitiy number of elements to allocate at construction, if !dynamic, this is + * allocated in place and can not be changed. + */ +template class managed_array : public snapshot_interface { public: managed_array() - : _static_data{} - , _capacity{initialCapacity} + : _capacity{initialCapacity} , _size{0} + , _static_data{} { if constexpr (dynamic) { - _dynamic_data = new T[initialCapacity]; + if constexpr (simple) { + _dynamic_data = reinterpret_cast(new char[sizeof(T) * initialCapacity]); + } else { + _dynamic_data = new T[initialCapacity]; + } } } @@ -37,13 +49,25 @@ class managed_array : public snapshot_interface virtual ~managed_array() { if constexpr (dynamic) { - delete[] _dynamic_data; + if constexpr (simple) { + delete[] reinterpret_cast(_dynamic_data); + } else { + delete[] _dynamic_data; + } } } - const T& operator[](size_t i) const { return data()[i]; } + const T& operator[](size_t i) const + { + inkAssert(i < _size, "Access array out of bounds, index %u in array of size %u", i, _size); + return data()[i]; + } - T& operator[](size_t i) { return data()[i]; } + T& operator[](size_t i) + { + inkAssert(i < _size, "Access array out of bounds, index %u in array of size %u", i, _size); + return data()[i]; + } const T* data() const { @@ -75,9 +99,9 @@ class managed_array : public snapshot_interface T& back() { return end()[-1]; } - const size_t size() const { return _size; } + size_t size() const { return _size; } - const size_t capacity() const { return _capacity; } + size_t capacity() const { return _capacity; } T& push() { @@ -146,7 +170,7 @@ class managed_array : public snapshot_interface ptr = snap_write(ptr, e, should_write); } } - return ptr - data; + return static_cast(ptr - data); } const unsigned char* snap_load(const unsigned char* ptr, const loader& loader) @@ -170,10 +194,10 @@ class managed_array : public snapshot_interface } private: - if_t _static_data[dynamic ? 1 : initialCapacity]; T* _dynamic_data = nullptr; size_t _capacity; size_t _size; + if_t _static_data[dynamic ? 1 : initialCapacity]; }; template @@ -219,7 +243,7 @@ class managed_restorable_array : public managed_array(ptr - data); } const unsigned char* snap_load(const unsigned char* ptr, const snapshot_interface::loader& loader) @@ -233,21 +257,30 @@ class managed_restorable_array : public managed_array -void managed_array::extend(size_t capacity) +template +void managed_array::extend(size_t capacity) { static_assert(dynamic, "Can only extend if array is dynamic!"); - size_t new_capacity = capacity > _capacity ? capacity : 1.5f * _capacity; + size_t new_capacity = capacity > _capacity ? capacity : _capacity + _capacity / 2U; if (new_capacity < 5) { new_capacity = 5; } - T* new_data = new T[new_capacity]; + T* new_data = nullptr; + if constexpr (simple) { + new_data = reinterpret_cast(new char[sizeof(T) * new_capacity]); + } else { + new_data = new T[new_capacity]; + } for (size_t i = 0; i < _capacity; ++i) { new_data[i] = _dynamic_data[i]; } - delete[] _dynamic_data; + if constexpr (simple) { + delete[] reinterpret_cast(_dynamic_data); + } else { + delete[] _dynamic_data; + } _dynamic_data = new_data; _capacity = new_capacity; } @@ -459,15 +492,15 @@ class allocated_restorable_array final : public basic_restorable_array T* new_buffer = new T[new_capacity]; if (_buffer) { for (size_t i = 0; i < base::capacity(); ++i) { - new_buffer[i] = _buffer[i]; + new_buffer[i] = _buffer[i]; // copy temp - new_buffer[i + base::capacity()] = _buffer[i + base::capacity()]; + new_buffer[i + n] = _buffer[i + base::capacity()]; } delete[] _buffer; } - for (size_t i = base::capacity(); i < new_capacity / 2; ++i) { - new_buffer[i] = _initialValue; - new_buffer[i + base::capacity()] = _nullValue; + for (size_t i = base::capacity(); i < n; ++i) { + new_buffer[i] = _initialValue; + new_buffer[i + n] = _nullValue; } _buffer = new_buffer; @@ -489,7 +522,7 @@ class allocated_restorable_array final : public basic_restorable_array }; template -inline size_t basic_restorable_array::snap(unsigned char* data, const snapper& snapper) const +inline size_t basic_restorable_array::snap(unsigned char* data, const snapper&) const { unsigned char* ptr = data; bool should_write = data != nullptr; @@ -500,12 +533,12 @@ inline size_t basic_restorable_array::snap(unsigned char* data, const snapper ptr = snap_write(ptr, _array[i], should_write); ptr = snap_write(ptr, _temp[i], should_write); } - return ptr - data; + return static_cast(ptr - data); } template inline const unsigned char* - basic_restorable_array::snap_load(const unsigned char* data, const loader& loader) + basic_restorable_array::snap_load(const unsigned char* data, const loader&) { auto ptr = data; ptr = snap_read(ptr, _saved); diff --git a/inkcpp/avl_array.h b/inkcpp/avl_array.h index 30cd36fd..d3847a51 100644 --- a/inkcpp/avl_array.h +++ b/inkcpp/avl_array.h @@ -44,8 +44,6 @@ #include "system.h" -#include - /** * \param Key The key type. The type (class) must provide a 'less than' and 'equal to' operator * \param T The Data type @@ -72,7 +70,7 @@ class avl_array ink::runtime::internal::if_t balance_; ink::runtime::internal::if_t child_; size_type size_; // actual size - size_t _capacity; + size_type _capacity; size_type root_; // root node ink::runtime::internal::if_t parent_; @@ -114,6 +112,12 @@ class avl_array return *this; } + tag_avl_array_iterator(const tag_avl_array_iterator& other) + : instance_{other.instance_} + , idx_{other.idx_} + { + } + inline bool operator==(const tag_avl_array_iterator& rhs) const { return idx_ == rhs.idx_; } inline bool operator!=(const tag_avl_array_iterator& rhs) const { return ! (*this == rhs); } @@ -130,7 +134,7 @@ class avl_array // 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; } + inline size_type temp_identifier() const { return instance_->size() - idx_ - 1; } // preincrement tag_avl_array_iterator& operator++() @@ -208,6 +212,9 @@ class avl_array delete[] val_; delete[] balance_; delete[] child_; + if (parent_) { + delete[] parent_; + } } } @@ -257,7 +264,7 @@ class avl_array void extend() { - size_t new_size = _capacity * 1.5; + size_type new_size = _capacity + _capacity / 2; if (new_size < 5) { new_size = 5; } diff --git a/inkcpp/choice.cpp b/inkcpp/choice.cpp index b1ffbc7c..97e4b1dd 100644 --- a/inkcpp/choice.cpp +++ b/inkcpp/choice.cpp @@ -16,7 +16,10 @@ namespace ink namespace runtime { - size_t choice::num_tags() const { return std::distance(_tags_start, _tags_end); } + size_t choice::num_tags() const + { + return static_cast(std::distance(_tags_start, _tags_end)); + } const char* choice::get_tag(size_t index) const { diff --git a/inkcpp/collections/restorable.cpp b/inkcpp/collections/restorable.cpp index b2b0abc8..643d390a 100644 --- a/inkcpp/collections/restorable.cpp +++ b/inkcpp/collections/restorable.cpp @@ -16,10 +16,10 @@ unsigned char* ptr = snapshot_interface::snap_write(ptr, jump, write); ptr = snapshot_interface::snap_write(ptr, save, write); max = pos; - if (jump != ~0 && jump > max) { + if (jump != ~0U && jump > max) { max = jump; } - if (save != ~0 && save > max) { + if (save != ~0U && save > max) { max = save; } return ptr; @@ -32,10 +32,10 @@ const unsigned char* ptr = snapshot_interface::snap_read(ptr, jump); ptr = snapshot_interface::snap_read(ptr, save); max = pos; - if (jump != ~0 && jump > max) { + if (jump != ~0U && jump > max) { max = jump; } - if (save != ~0 && save > max) { + if (save != ~0U && save > max) { max = save; } return ptr; @@ -51,7 +51,7 @@ size_t restorable::snap(unsigned char* data, const snapper& snapper) cons ptr = snap_write(ptr, _buffer[i].name, data != nullptr); ptr += _buffer[i].data.snap(data ? ptr : nullptr, snapper); } - return ptr - data; + return static_cast(ptr - data); } template<> @@ -63,7 +63,7 @@ size_t restorable::snap(unsigned char* data, const snapper& snapper) cons for (size_t i = 0; i < max; ++i) { ptr += _buffer[i].snap(data ? ptr : nullptr, snapper); } - return ptr - data; + return static_cast(ptr - data); } template<> @@ -75,7 +75,7 @@ size_t restorable::snap(unsigned char* data, const snapper&) const for (size_t i = 0; i < max; ++i) { ptr = snap_write(ptr, _buffer[i], data != nullptr); } - return ptr - data; + return static_cast(ptr - data); } template<> @@ -108,7 +108,7 @@ const unsigned char* restorable::snap_load(const unsigned char* ptr, cons } template<> -const unsigned char* restorable::snap_load(const unsigned char* ptr, const loader& loader) +const unsigned char* restorable::snap_load(const unsigned char* ptr, const loader&) { size_t max; ptr = snap_load_base(ptr, _pos, _jump, _save, max); diff --git a/inkcpp/collections/restorable.h b/inkcpp/collections/restorable.h index 4d7f38d1..7f8b9b7a 100644 --- a/inkcpp/collections/restorable.h +++ b/inkcpp/collections/restorable.h @@ -6,7 +6,7 @@ */ #pragma once -#include "../snapshot_impl.h" +#include "../snapshot_interface.h" #include #include @@ -91,8 +91,8 @@ class restorable : public snapshot_interface : _buffer(buffer) , _size(size) , _pos(0) - , _jump(~0) - , _save(~0) + , _jump(~0U) + , _save(~0U) { } @@ -102,15 +102,15 @@ class restorable : public snapshot_interface } // Checks if we have a save state - bool is_saved() const { return _save != ~0; } + bool is_saved() const { return _save != ~0U; } // Creates a save point which can later be restored to or forgotten void save() { inkAssert( - _save == ~0, "Collection is already saved. You should never call save twice. Ignoring." + _save == ~0U, "Collection is already saved. You should never call save twice. Ignoring." ); - if (_save != ~0) { + if (_save != ~0U) { return; } @@ -121,8 +121,8 @@ class restorable : public snapshot_interface // Restore to the last save point void restore() { - inkAssert(_save != ~0, "Collection can't be restored because it's not saved. Ignoring."); - if (_save == ~0) { + inkAssert(_save != ~0U, "Collection can't be restored because it's not saved. Ignoring."); + if (_save == ~0U) { return; } @@ -130,15 +130,15 @@ class restorable : public snapshot_interface _pos = _save; // Clear save point - _save = _jump = ~0; + _save = _jump = ~0U; } // Forget the save point and continue with the current data template void forget(NullifyMethod nullify) { - inkAssert(_save != ~0, "Can't forget save point because there is none. Ignoring."); - if (_save == ~0) { + inkAssert(_save != ~0U, "Can't forget save point because there is none. Ignoring."); + if (_save == ~0U) { return; } @@ -150,7 +150,7 @@ class restorable : public snapshot_interface } // Reset save position - _save = _jump = ~0; + _save = _jump = ~0U; } using iterator = restorable_iter; @@ -170,7 +170,7 @@ class restorable : public snapshot_interface ElementType& push(const ElementType& elem) { // Don't destroy saved data. Jump over it - if (_pos < _save && _save != ~0) { + if (_pos < _save && _save != ~0U) { _jump = _pos; _pos = _save; } @@ -223,7 +223,7 @@ class restorable : public snapshot_interface void clear() { _pos = 0; - _save = _jump = ~0; + _save = _jump = ~0U; } // Forward iterate @@ -279,7 +279,7 @@ class restorable : public snapshot_interface void for_each_all(CallbackMethod callback) const { // no matter if we're saved or not, we iterate everything - int len = (_save == ~0 || _pos > _save) ? _pos : _save; + int len = (_save == ~0U || _pos > _save) ? _pos : _save; // Iterate for (int i = 0; i < len; i++) @@ -358,10 +358,7 @@ class restorable : public snapshot_interface protected: // Called when we run out of space in buffer. - virtual void overflow(ElementType*& buffer, size_t& size) - { - inkFail("Restorable run out of memory!"); - } + virtual void overflow(ElementType*&, size_t&) { inkFail("Restorable run out of memory!"); } private: template diff --git a/inkcpp/container_operations.cpp b/inkcpp/container_operations.cpp index 64575b1d..a724baa2 100644 --- a/inkcpp/container_operations.cpp +++ b/inkcpp/container_operations.cpp @@ -13,40 +13,35 @@ #include -namespace ink::runtime::internal { +namespace ink::runtime::internal +{ - void operation::operator()( - basic_eval_stack& stack, value* vals) - { - container_t id; - 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 ) - ))); - } - - void operation::operator()( - basic_eval_stack& stack, value* vals) - { - container_t id; - 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) - ))); - } +void operation::operator()( + basic_eval_stack& stack, value* vals +) +{ + container_t id; + 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)))); +} - void operation::operator() - (basic_eval_stack& stack, value* vals) - { - stack.push(value{}.set(static_cast( - _runner.num_choices() - ))); - } +void operation::operator()( + basic_eval_stack& stack, value* vals +) +{ + container_t id; + 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)))); +} +void operation< + Command::CHOICE_COUNT, value_type::none, void>::operator()(basic_eval_stack& stack, value*) +{ + stack.push(value{}.set(static_cast(_runner.num_choices()))); } + +} // namespace ink::runtime::internal diff --git a/inkcpp/executioner.h b/inkcpp/executioner.h index 154d2d70..fdcdec62 100644 --- a/inkcpp/executioner.h +++ b/inkcpp/executioner.h @@ -31,149 +31,179 @@ #include "stack.h" #include "operations.h" +namespace ink::runtime::internal +{ + +/** + * @brief iterates through value_types until it found a matching operator. + * Matching means a operator which implements the command for the type. + * @tparam cmd Command to search operation for. + * @tparam t value type to start search + * @tparam Offset t + Offset is real start, used because trouble with mscv + * @return value_type::OP_END, if no "next operation" found + * @return type which is greater t + Offset and implement the command + */ +template +constexpr value_type next_operatable_type() +{ + constexpr value_type ty = t + Offset; + if constexpr (operation::enabled) { + return ty; + } else if constexpr (ty >= value_type::OP_END) { + return value_type::OP_END; + } else { + return next_operatable_type(); + } +} +/** + * @brief Iterates through all existing operations for this Command. + */ +template()> +class typed_executer +{ +public: + static constexpr bool enabled = true; + + template + typed_executer(const T& t) + : _typed_exe{t} + , _op{t} + { + } -namespace ink::runtime::internal { - - /** - * @brief iterates through value_types until it found a matching operator. - * Matching means a operator which implements the command for the type. - * @tparam cmd Command to search operation for. - * @tparam t value type to start search - * @tparam Offset t + Offset is real start, used because trouble with mscv - * @return value_type::OP_END, if no "next operation" found - * @return type which is greater t + Offset and implement the command - */ - template - constexpr value_type next_operatable_type() { - constexpr value_type ty = t + Offset; - if constexpr (operation::enabled) { - return ty; - } else if constexpr (ty >= value_type::OP_END){ - return value_type::OP_END; + void operator()(value_type t, basic_eval_stack& s, value* v) + { + if (t == ty) { + _op(s, v); } else { - return next_operatable_type(); + _typed_exe(t, s, v); } } - /** - * @brief Iterates through all existing operations for this Command. - */ - template()> - class typed_executer { - public: - static constexpr bool enabled = true; - template - typed_executer(const T& t) : _typed_exe{t}, _op{t} {} - - void operator()(value_type t, basic_eval_stack& s, value* v) { - if (t == ty) { _op(s, v); } - else { _typed_exe(t, s, v); } - } - private: - // skip command for not implemented types - typed_executer(ty),1>()> _typed_exe; - operation _op; - }; - - // end of recursion (has no operation attached to it) - template - class typed_executer { - public: - static constexpr bool enabled = false; - template - typed_executer(const T& t) {} - - void operator()(value_type, basic_eval_stack&, value*) { - inkFail("Operation for value not supported!"); - } - }; +private: + // skip command for not implemented types + typed_executer(ty), 1>()> _typed_exe; + operation _op; +}; + +// end of recursion (has no operation attached to it) +template +class typed_executer +{ +public: + static constexpr bool enabled = false; + + template + typed_executer(const T&) + { + } - /** - * @brief Find next command which is at least for one type implemented. - * @tparam c command to start search - * @tparam Offset offset to start search, used because of trouble with mscv - * @return Command::OP_END if no next operation is found - * @return next command witch at least of implementation. - */ - template - constexpr Command next_operatable_command() { - constexpr Command cmd = c + Offset; - if constexpr (typed_executer::enabled) { - return cmd; - } else if constexpr (cmd >= Command::OP_END){ - return Command::OP_END; + void operator()(value_type, basic_eval_stack&, value*) + { + inkFail("Operation for value not supported!"); + } +}; + +/** + * @brief Find next command which is at least for one type implemented. + * @tparam c command to start search + * @tparam Offset offset to start search, used because of trouble with mscv + * @return Command::OP_END if no next operation is found + * @return next command witch at least of implementation. + */ +template +constexpr Command next_operatable_command() +{ + constexpr Command cmd = c + Offset; + if constexpr (typed_executer::enabled) { + return cmd; + } else if constexpr (cmd >= Command::OP_END) { + return Command::OP_END; + } else { + return next_operatable_command(); + } +} + +/** + * @brief Iterate through all commands to find correct command. + * Also instantiates all typed_executer and with them the operations. + */ +template()> +class executer_imp +{ +public: + template + executer_imp(const T& t) + : _exe{t} + , _typed_exe{t} + { + } + + void operator()(Command c, basic_eval_stack& s) + { + if (c == cmd) { + static constexpr size_t N = command_num_args(cmd); + if constexpr (N == 0) { + value_type ty = casting::common_base<0>(nullptr); + _typed_exe(ty, s, nullptr); + } else { + value args[N]; + for (int i = command_num_args(cmd) - 1; i >= 0; --i) { + args[i] = s.pop(); + } + value_type ty = casting::common_base(args); + _typed_exe(ty, s, args); + } } else { - return next_operatable_command(); + _exe(c, s); } } +private: + executer_imp()> _exe; + typed_executer _typed_exe; +}; + +/// end of recursion +template<> +class executer_imp +{ +public: + template + executer_imp(const T&) + { + } + + void operator()(Command, basic_eval_stack&) { inkFail("requested command was not found!"); } +}; + +/** + * @brief Class which instantiates all operations and give access to them. + */ +class executer +{ +public: /** - * @brief Iterate through all commands to find correct command. - * Also instantiates all typed_executer and with them the operations. + * @brief pass all arguments to operations who need them. + * @attention each type need to be unique for the look up later! + * @tparam Args argument types + * @param args arguments */ - template()> - class executer_imp { - public: - template - executer_imp(const T& t) : _exe{t}, _typed_exe{t}{} - - void operator()(Command c, basic_eval_stack& s) { - if (c == cmd) { - static constexpr size_t N = command_num_args(cmd); - if constexpr (N == 0) { - value_type ty = casting::common_base<0>(nullptr); - _typed_exe(ty, s, nullptr); - } else { - value args[N]; - for (int i = command_num_args(cmd)-1; i >= 0 ; --i) { - args[i] = s.pop(); - } - value_type ty = casting::common_base(args); - _typed_exe(ty, s, args); - } - } else { _exe(c, s); } - } - private: - executer_imp()> _exe; - typed_executer _typed_exe; - }; - - /// end of recursion - template<> - class executer_imp { - public: - template - executer_imp(const T& t) {} - void operator()(Command, basic_eval_stack&) { - inkFail("requested command was not found!"); - } - }; + template + executer(Args&... args) + : _executer{tuple(&args...)} + { + } /** - * @brief Class which instantiates all operations and give access to them. + * @brief execute command on stack. + * @param cmd command to execute + * @param stack stack to operate on */ - class executer { - public: - /** - * @brief pass all arguments to operations who need them. - * @attention each type need to be unique for the look up later! - * @tparam Args argument types - * @param args arguments - */ - template - executer(Args& ... args) : _executer{tuple(&args...)} {} - - /** - * @brief execute command on stack. - * @param cmd command to execute - * @param stack stack to operate on - */ - void operator()(Command cmd, basic_eval_stack& stack) { - _executer(cmd, stack); - } - private: - executer_imp _executer; - }; -} + void operator()(Command cmd, basic_eval_stack& stack) { _executer(cmd, stack); } +private: + executer_imp _executer; +}; +} // namespace ink::runtime::internal diff --git a/inkcpp/functional.cpp b/inkcpp/functional.cpp index 81289436..f10dd1b2 100644 --- a/inkcpp/functional.cpp +++ b/inkcpp/functional.cpp @@ -25,7 +25,7 @@ ink::runtime::value } template<> -int32_t function_base::pop(basic_eval_stack* stack, list_table& lists) +int32_t function_base::pop(basic_eval_stack* stack, list_table&) { value val = stack->pop(); inkAssert(val.type() == value_type::int32, "Type mismatch!"); @@ -33,7 +33,7 @@ int32_t function_base::pop(basic_eval_stack* stack, list_table& lists) } template<> -const char* function_base::pop(basic_eval_stack* stack, list_table& lists) +const char* function_base::pop(basic_eval_stack* stack, list_table&) { value val = stack->pop(); inkAssert(val.type() == value_type::string, "Type mismatch!"); diff --git a/inkcpp/globals_impl.cpp b/inkcpp/globals_impl.cpp index 6daed149..6003b107 100644 --- a/inkcpp/globals_impl.cpp +++ b/inkcpp/globals_impl.cpp @@ -10,6 +10,7 @@ #include "snapshot_impl.h" #include "system.h" #include "types.h" +#include "value.h" namespace ink::runtime::internal { @@ -204,6 +205,7 @@ void globals_impl::initialize_globals(runner_impl* run) { // If no way to move there, then there are no globals. if (! run->move_to(hash_string("global decl"))) { + _globals_initialized = true; return; } @@ -267,7 +269,7 @@ size_t globals_impl::snap(unsigned char* data, const snapper& snapper) const ptr += _strings.snap(data ? ptr : nullptr, snapper); ptr += _lists.snap(data ? ptr : nullptr, snapper); ptr += _variables.snap(data ? ptr : nullptr, snapper); - return ptr - data; + return static_cast(ptr - data); } const unsigned char* globals_impl::snap_load(const unsigned char* ptr, const loader& loader) diff --git a/inkcpp/include/choice.h b/inkcpp/include/choice.h index 60b9c700..489ac305 100644 --- a/inkcpp/include/choice.h +++ b/inkcpp/include/choice.h @@ -74,12 +74,13 @@ namespace runtime ); protected: - int _index = -1; ///< @private const char* _text = nullptr; ///< @private - uint32_t _path = ~0; ///< @private - thread_t _thread = ~0; ///< @private const internal::snap_tag* _tags_start = nullptr; ///< @private const internal::snap_tag* _tags_end = nullptr; ///< @private + uint32_t _path = ~0U; ///< @private + thread_t _thread = ~0U; ///< @private + int _index = -1; ///< @private }; + } // namespace runtime } // namespace ink diff --git a/inkcpp/include/list.h b/inkcpp/include/list.h index 1b2cdd93..72dc1f9a 100644 --- a/inkcpp/include/list.h +++ b/inkcpp/include/list.h @@ -48,6 +48,10 @@ class list_interface { } + virtual list_interface& operator=(const list_interface&) = default; + + virtual ~list_interface() {} + /** iterater for flags in a list * @todo implement `operator->` */ @@ -67,9 +71,7 @@ class list_interface protected: /** @private */ - iterator( - const char* flag_name, const list_interface& list, size_t i, bool one_list_only = false - ) + iterator(const char* flag_name, const list_interface& list, int i, bool one_list_only = false) : _flag_name(flag_name) , _list_name(nullptr) , _list(list) @@ -97,7 +99,7 @@ class list_interface }; /** access value the iterator is pointing to */ - Flag operator*() const { return Flag{ _flag_name, _list_name }; }; + Flag operator*() const { return Flag{_flag_name, _list_name}; }; /** continue iterator to next value */ iterator& operator++() @@ -115,8 +117,21 @@ class list_interface * @param itr other iterator */ bool operator==(const iterator& itr) const { return itr._i == _i; } + + iterator& operator=(const iterator&) = delete; }; + +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +#else +# pragma warning(push) +# pragma warning( \ + disable : 4100, justification : "non functional prototypes do not need the argument." \ + ) +#endif + /** checks if a flag is contained in the list */ virtual bool contains(const char* flag) const { @@ -166,6 +181,12 @@ class list_interface inkAssert(false, "Not implemented funciton from interface is called!"); }; +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#else +# pragma warning(pop) +#endif + protected: /** @private */ iterator new_iterator(const char* flag_name, int i, bool one_list_only = false) const @@ -182,7 +203,7 @@ class list_interface /** @private */ internal::list_table* _list_table; - /** @private */ int _list; }; + } // namespace ink::runtime diff --git a/inkcpp/include/story_ptr.h b/inkcpp/include/story_ptr.h index ad4b4290..0c33c46a 100644 --- a/inkcpp/include/story_ptr.h +++ b/inkcpp/include/story_ptr.h @@ -20,10 +20,10 @@ namespace internal { } + static void remove_reference(ref_block*&); + size_t references; bool valid; - - static void remove_reference(ref_block*&); }; /** @private */ diff --git a/inkcpp/include/traits.h b/inkcpp/include/traits.h index e119a640..242e9cb2 100644 --- a/inkcpp/include/traits.h +++ b/inkcpp/include/traits.h @@ -162,7 +162,7 @@ inline size_t c_str_len(const char* c) const char* i = c; while (*i != 0) i++; - return i - c; + return static_cast(i - c); } MARK_AS_STRING(char*, c_str_len(x), x); diff --git a/inkcpp/list_impl.cpp b/inkcpp/list_impl.cpp index a9d2bccd..030c4684 100644 --- a/inkcpp/list_impl.cpp +++ b/inkcpp/list_impl.cpp @@ -44,7 +44,7 @@ void list_impl::next(const char*& flag_name, const char*& list_name, int& i, boo if (flag_name != nullptr) { ++flag.flag; } - if (flag.flag >= _list_table->_list_end[flag.list_id]) { + if (static_cast(flag.flag) >= _list_table->_list_end[flag.list_id]) { next_list: if (one_list_only) { i = -1; @@ -61,7 +61,8 @@ void list_impl::next(const char*& flag_name, const char*& list_name, int& i, boo } 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)) { + if (static_cast(flag.flag) + >= _list_table->_list_end[flag.list_id] - _list_table->listBegin(flag.list_id)) { goto next_list; } } diff --git a/inkcpp/list_impl.h b/inkcpp/list_impl.h index ea7b1dd6..1aefb2be 100644 --- a/inkcpp/list_impl.h +++ b/inkcpp/list_impl.h @@ -8,32 +8,40 @@ #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, bool one_list_only) - const override; - }; -} +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) + { + } + + list_impl& operator=(const list_impl&) = default; + + ~list_impl() override {} + + 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, bool one_list_only) + const override; +}; +} // namespace ink::runtime::internal diff --git a/inkcpp/list_operations.cpp b/inkcpp/list_operations.cpp index 45023bfc..091d2ed5 100644 --- a/inkcpp/list_operations.cpp +++ b/inkcpp/list_operations.cpp @@ -199,7 +199,7 @@ void operation::operator()( "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(); + entry.flag = static_cast(vals[1].get()); entry = _list_table.external_fvalue_to_internal(entry); stack.push(value{}.set(entry)); } diff --git a/inkcpp/list_table.cpp b/inkcpp/list_table.cpp index 85a756ea..703de027 100644 --- a/inkcpp/list_table.cpp +++ b/inkcpp/list_table.cpp @@ -43,7 +43,7 @@ list_table::list_table(const char* data, const ink::internal::header& header) int start = 0; while ((flag = header.read_list_flag(ptr)) != null_flag) { // start of new list - if (_list_end.size() == flag.list_id) { + if (static_cast(_list_end.size()) == flag.list_id) { start = _list_end.size() == 0 ? 0 : _list_end.back(); _list_end.push() = start; _list_names.push() = ptr; @@ -112,7 +112,7 @@ void list_table::gc() _list_handouts.clear(); } -int list_table::toFid(list_flag e) const { return listBegin(e.list_id) + e.flag; } +size_t list_table::toFid(list_flag e) const { return listBegin(e.list_id) + e.flag; } size_t list_table::stringLen(const list_flag& e) const { return c_str_len(toString(e)); } @@ -130,9 +130,9 @@ size_t list_table::stringLen(const list& l) const size_t len = 0; const data_t* entry = getPtr(l.lid); bool first = true; - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(entry, i)) { - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(entry, j) && _flag_names[j]) { if (! first) { len += 2; // ', ' @@ -163,14 +163,18 @@ char* list_table::toString(char* out, const list& l) const while (1) { bool change = false; - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(entry, i)) { - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (! hasFlag(entry, j)) { continue; } int value = _flag_values[j]; - if (first || value > last_value || (value == last_value && i > last_list)) { + // the cast is ok, since if we are in the + // first round, `first` is true and we do not evaluate + // second round, `last_list` is >= 0 + if (first || value > last_value + || (value == last_value && i > static_cast(last_list))) { if (min_id == -1 || value < min_value) { change = true; min_list = i; @@ -206,10 +210,10 @@ list_table::list list_table::range(list_table::list l, int min, int max) data_t* in = getPtr(l.lid); data_t* out = getPtr(res.lid); bool has_any_list = false; - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(in, i)) { bool has_flag = false; - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { int value = _flag_values[j]; if (value < min) { continue; @@ -301,10 +305,10 @@ list_table::list list_table::sub(list lh, list rh) o[i] = (l[i] & r[i]) ^ l[i]; } - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(r, i)) { if (hasList(l, i)) { - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(o, j)) { setList(o, i); active_flag = true; @@ -317,7 +321,7 @@ list_table::list list_table::sub(list lh, list rh) if (active_flag) { return res; } - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(o, i)) { return res; } @@ -335,13 +339,13 @@ list_table::list list_table::sub(list lh, list_flag rh) o[i] = l[i]; } setFlag(o, toFid(rh), false); - for (int i = listBegin(rh.list_id); i < _list_end[rh.list_id]; ++i) { + for (size_t i = listBegin(rh.list_id); i < _list_end[rh.list_id]; ++i) { if (hasFlag(o, i)) { return res; } } setList(l, rh.list_id, false); - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(o, i)) { return res; } @@ -371,13 +375,13 @@ list_table::list list_table::add(list arg, int n) data_t* o = getPtr(res.lid); bool active_flag = false; ; - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(l, i)) { bool has_flag = false; - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(l, j)) { int value = _flag_values[j] + n; - for (int k = j + 1; k < _list_end[i]; ++k) { + for (size_t k = j + 1; k < _list_end[i]; ++k) { if (value == _flag_values[k]) { setFlag(o, k); has_flag = true; @@ -404,9 +408,9 @@ list_flag list_table::add(list_flag arg, int n) return arg; } int value = _flag_values[arg.flag] + n; - for (int i = listBegin(arg.list_id); i < _list_end[arg.list_id]; ++i) { + for (size_t i = listBegin(arg.list_id); i < _list_end[arg.list_id]; ++i) { if (_flag_values[i] == value) { - arg.flag = i; + arg.flag = static_cast(i); return arg; } } @@ -425,13 +429,13 @@ list_table::list list_table::sub(list arg, int n) data_t* l = getPtr(arg.lid); data_t* o = getPtr(res.lid); bool active_flag = false; - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(l, i)) { bool has_flag = false; - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(l, j)) { int value = _flag_values[j] - n; - for (int k = j - 1; k >= listBegin(i); --k) { + for (size_t k = j - 1; k != ~0U && k >= listBegin(i) && k != ~0U; --k) { if (_flag_values[k] == value) { setFlag(o, k); has_flag = true; @@ -469,9 +473,9 @@ int32_t list_table::count(list l) const { int count = 0; const data_t* data = getPtr(l.lid); - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(data, i)) { - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (_flag_names[j] != nullptr && hasFlag(data, j)) { ++count; } @@ -485,14 +489,14 @@ list_flag list_table::min(list l) const { list_flag res{-1, -1}; const data_t* data = getPtr(l.lid); - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(data, i)) { - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(data, j)) { int value = _flag_values[j]; if (res.flag < 0 || value < res.flag) { - res.flag = value; - res.list_id = i; + res.flag = static_cast(value); + res.list_id = static_cast(i); } break; } @@ -506,14 +510,14 @@ list_flag list_table::max(list l) const { list_flag res{-1, -1}; const data_t* data = getPtr(l.lid); - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(data, i)) { - for (int j = _list_end[i] - 1; j >= listBegin(i); --j) { + for (size_t j = _list_end[i] - 1; j != ~0U && j >= listBegin(i); --j) { if (hasFlag(data, j)) { int value = _flag_values[j]; if (value > res.flag) { - res.flag = value; - res.list_id = i; + res.flag = static_cast(value); + res.list_id = static_cast(i); } break; } @@ -527,12 +531,12 @@ bool list_table::equal(list lh, list rh) const { const data_t* l = getPtr(lh.lid); const data_t* r = getPtr(rh.lid); - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(l, i) != hasList(r, i)) { return false; } if (hasList(l, i)) { - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(l, j) != hasFlag(r, j)) { return false; } @@ -545,13 +549,13 @@ bool list_table::equal(list lh, list rh) const bool list_table::equal(list lh, list_flag rh) const { const data_t* l = getPtr(lh.lid); - for (int i = 0; i < numLists(); ++i) { - if (hasList(l, i) != (rh.list_id == i)) { + for (size_t i = 0; i < numLists(); ++i) { + if (hasList(l, i) != (rh.list_id == static_cast(i))) { return false; } } - for (int i = listBegin(rh.list_id); i < _list_end[rh.list_id]; ++i) { - if (hasFlag(l, i) != (rh.flag == i - listBegin(rh.list_id))) { + for (size_t i = listBegin(rh.list_id); i < _list_end[rh.list_id]; ++i) { + if (hasFlag(l, i) != (rh.flag == static_cast(i - listBegin(rh.list_id)))) { return false; } } @@ -563,10 +567,10 @@ list_table::list list_table::all(list arg) list res = create(); data_t* l = getPtr(arg.lid); data_t* o = getPtr(res.lid); - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(l, i)) { setList(o, i); - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { setFlag(o, j); } } @@ -580,7 +584,7 @@ list_table::list list_table::all(list_flag arg) if (arg != null_flag) { data_t* o = getPtr(res.lid); setList(o, arg.list_id); - for (int i = listBegin(arg.list_id); i < _list_end[arg.list_id]; ++i) { + for (size_t i = listBegin(arg.list_id); i < _list_end[arg.list_id]; ++i) { setFlag(o, i); } } @@ -593,10 +597,10 @@ list_table::list list_table::invert(list arg) list res = create(); data_t* l = getPtr(arg.lid); data_t* o = getPtr(res.lid); - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(l, i)) { bool hasList = false; - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { bool have = hasFlag(l, j); if (! have) { hasList = true; @@ -616,8 +620,8 @@ list_table::list list_table::invert(list_flag arg) list res = create(); if (arg != null_flag) { data_t* o = getPtr(res.lid); - for (int i = listBegin(arg.list_id); i < _list_end[arg.list_id]; ++i) { - setFlag(o, i, i - listBegin(arg.list_id) != arg.flag); + for (size_t i = listBegin(arg.list_id); i < _list_end[arg.list_id]; ++i) { + setFlag(o, i, arg.flag != static_cast(i - listBegin(arg.list_id))); } } return res; @@ -656,9 +660,9 @@ list_flag list_table::lrnd(list lh, prng& rng) const int n = count(lh); n = rng.rand(n); int count = 0; - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(l, i)) { - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(l, j)) { if (count++ == n) { return list_flag{ @@ -677,12 +681,12 @@ bool list_table::has(list lh, list rh) const { const data_t* r = getPtr(rh.lid); const data_t* l = getPtr(lh.lid); - for (int i = 0; i < numLists(); ++i) { + for (size_t i = 0; i < numLists(); ++i) { if (hasList(r, i)) { if (! hasList(l, i)) { return false; } - for (int j = listBegin(i); j < _list_end[i]; ++j) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(r, j) && ! hasFlag(l, j)) { return false; } @@ -700,7 +704,7 @@ optional list_table::toFlag(const char* flag_name) const list_flag list = get_list_id(flag_name); // since flag_name is `list_name.flag_name` flag_name = periode + 1; int list_begin = list.list_id == 0 ? 0 : _list_end[list.list_id - 1]; - for (int i = list_begin; i != _list_end[list.list_id]; ++i) { + for (size_t i = list_begin; i != _list_end[list.list_id]; ++i) { if (str_equal(flag_name, _flag_names[i])) { return { list_flag{list.list_id, static_cast(i - list_begin)} @@ -710,12 +714,12 @@ optional list_table::toFlag(const char* flag_name) const } else { for (auto flag_itr = _flag_names.begin(); flag_itr != _flag_names.end(); ++flag_itr) { if (str_equal(*flag_itr, flag_name)) { - 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) { + size_t fid = static_cast(flag_itr - _flag_names.begin()); + size_t 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(); + lid = static_cast(list_itr - _list_end.begin()); break; } begin = *list_itr; @@ -733,7 +737,7 @@ list_flag list_table::get_list_id(const char* list_name) const { using int_t = decltype(list_flag::list_id); const char* period = str_find(list_name, '.'); - size_t len = period ? period - list_name : c_str_len(list_name); + size_t len = period ? static_cast(period - list_name) : c_str_len(list_name); for (int_t i = 0; i < static_cast(_list_names.size()); ++i) { if (str_equal_len(list_name, _list_names[i], len)) { return list_flag{i, -1}; @@ -752,8 +756,8 @@ list_table::list list_table::redefine(list lh, list rh) // if the new list has no origin: give it the origin of the old value bool has_origin = false; - for (int i = 0; i < numLists(); ++i) { - if (hasList(r, i)) { + for (size_t i = 0; i < numLists(); ++i) { + if (hasList(r, static_cast(i))) { has_origin = true; break; } @@ -790,14 +794,18 @@ std::ostream& list_table::write(std::ostream& os, list l) const while (1) { bool change = false; - for (int i = 0; i < numLists(); ++i) { - if (hasList(entry, i)) { - for (int j = listBegin(i); j < _list_end[i]; ++j) { - if (! hasFlag(entry, j)) { + for (size_t i = 0; i < numLists(); ++i) { + if (hasList(entry, static_cast(i))) { + for (size_t j = listBegin(i); j < _list_end[i]; ++j) { + if (! hasFlag(entry, static_cast(j))) { continue; } int value = _flag_values[j]; - if (first || value > last_value || (value == last_value && i > last_list)) { + // the cast is ok, since if we are in the + // first round, `first` is true and we do not evaluate + // second round, `last_list` is >= 0 + if (first || value > last_value + || (value == last_value && i > static_cast(last_list))) { if (min_id == -1 || value < min_value) { min_value = value; min_id = j; @@ -830,7 +838,7 @@ 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; + return static_cast(ptr - data); } const unsigned char* list_table::snap_load(const unsigned char* ptr, const loader& loader) diff --git a/inkcpp/list_table.h b/inkcpp/list_table.h index 9139f6a6..b0d12ab1 100644 --- a/inkcpp/list_table.h +++ b/inkcpp/list_table.h @@ -28,16 +28,16 @@ class prng; // memory segments // @param bits size in bits // @param size segment size in bytes -constexpr int segmentsFromBits(int bits, int size) +constexpr size_t segmentsFromBits(size_t bits, size_t size) { - size *= 8; - return bits / size + (bits % size ? 1 : 0); + size *= 8U; + return bits / size + (bits % size ? 1U : 0); } /// managed all list entries and list metadata class list_table : public snapshot_interface { - using data_t = int; + using data_t = unsigned; enum class state : char { unused, used, @@ -77,9 +77,11 @@ class list_table : public snapshot_interface flag.flag = -1; return flag; } - for (int i = listBegin(flag.list_id); i < _list_end[flag.list_id]; ++i) { + inkAssert(flag.list_id >= 0); + for (size_t i = listBegin(static_cast(flag.list_id)); + i < _list_end[static_cast(flag.list_id)]; ++i) { if (_flag_values[i] == flag.flag) { - flag.flag = i - listBegin(flag.list_id); + flag.flag = static_cast(i - listBegin(static_cast(flag.list_id))); return flag; } } @@ -89,7 +91,9 @@ class list_table : public snapshot_interface int get_flag_value(list_flag flag) const { - return _flag_values[listBegin(flag.list_id) + flag.flag]; + inkAssert(flag.list_id >= 0 && flag.flag >= 0); + return _flag_values + [listBegin(static_cast(flag.list_id)) + static_cast(flag.flag)]; } /// zeros all usage values @@ -256,10 +260,13 @@ class list_table : public snapshot_interface 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; + void copy_lists(const data_t* src, data_t* dst); + static constexpr size_t bits_per_data = sizeof(data_t) * 8U; - int listBegin(int lid) const { return lid == 0 ? 0 : _list_end[lid - 1]; } + size_t listBegin(size_t lid) const + { + return lid == 0 ? 0 : _list_end[static_cast(lid - 1)]; + } const data_t* getPtr(int eid) const { @@ -273,22 +280,22 @@ class list_table : public snapshot_interface + static_cast(_entrySize) * static_cast(eid); } - int numFlags() const + size_t numFlags() const { return _flag_names.size(); // return _list_end.end()[-1]; TODO: } - int numLists() const { return _list_end.size(); } + size_t numLists() const { return _list_end.size(); } - bool getBit(const data_t* data, int id) const + bool getBit(const data_t* data, size_t id) const { return data[id / bits_per_data] & (0x01 << (bits_per_data - 1 - (id % bits_per_data))); } - void setBit(data_t* data, int id, bool value = true) + void setBit(data_t* data, size_t id, bool value = true) { - data_t mask = 0x01 << (bits_per_data - 1 - (id % bits_per_data)); + data_t mask = 0x01U << (bits_per_data - 1U - (id % bits_per_data)); if (value) { data[id / bits_per_data] |= mask; } else { @@ -296,44 +303,58 @@ class list_table : public snapshot_interface } } - bool hasList(const data_t* data, int lid) const { return getBit(data, lid); } + bool hasList(const data_t* data, int lid) const + { + if (lid < 0) { + return false; + } + return getBit(data, static_cast(lid)); + } void setList(data_t* data, int lid, bool value = true) { if (lid >= 0) { - setBit(data, lid, value); + setBit(data, static_cast(lid), value); } } - bool hasFlag(const data_t* data, int fid) const { return getBit(data, fid + numLists()); } + bool hasFlag(const data_t* data, int fid) const + { + if (fid < 0) { + return false; + } + return getBit(data, static_cast(fid) + numLists()); + } void setFlag(data_t* data, int fid, bool value = true) { if (fid >= 0) { - setBit(data, fid + numLists(), value); + setBit(data, static_cast(fid) + numLists(), value); } } - int toFid(list_flag e) const; + size_t toFid(list_flag e) const; auto flagStartMask() const { struct { - int segment; + size_t segment; data_t mask; } res{numLists() / bits_per_data, ~static_cast(0) >> (numLists() % bits_per_data)}; return res; } - template + template using managed_array = managed_array < T, - config<0, abs(config)>; + config<0, abs(config), simple>; - static constexpr int maxMemorySize + static constexpr long maxMemorySize = (config::maxListTypes < 0 || config::maxFlags < 0 || config::maxLists < 0 ? -1 : 1) - * segmentsFromBits(abs(config::maxListTypes) + abs(config::maxFlags), sizeof(data_t)) - * static_cast(abs(config::maxLists)); + * static_cast( + segmentsFromBits(abs(config::maxListTypes) + abs(config::maxFlags), sizeof(data_t)) + * static_cast(abs(config::maxLists)) + ); int _entrySize; ///< entry size in data_t // entries (created lists) @@ -341,17 +362,17 @@ class list_table : public snapshot_interface managed_array _entry_state; // defined list (meta data) - managed_array _list_end; - managed_array _flag_names; - managed_array _flag_values; - managed_array _list_names; + managed_array _list_end; + managed_array _flag_names; + managed_array _flag_values; + managed_array _list_names; /// keep track over lists accessed with get_var, and clear then at gc time - managed_array _list_handouts; + managed_array _list_handouts; bool _valid; public: - friend class name_flag_itr; + friend class named_flag_itr; friend class list_impl; class named_flag_itr @@ -364,14 +385,22 @@ class list_table : public snapshot_interface const char* name; } _pos; + /** carry list change. + * if the iterator incremented to the next flag, also increment the list if necessary + * @pre _pos.flag.list_id >= 0 + */ void carry() { - if (_pos.flag.flag - == _list._list_end[_pos.flag.list_id] - _list.listBegin(_pos.flag.list_id)) { + if (_pos.flag.flag < 0 || _pos.flag.list_id < 0) { + return; + } + if (static_cast(_pos.flag.flag) + == _list._list_end[static_cast(_pos.flag.list_id)] + - _list.listBegin(static_cast(_pos.flag.list_id))) { _pos.flag.flag = 0; ++_pos.flag.list_id; } - if (_pos.flag.list_id == _list.numLists()) { + if (static_cast(_pos.flag.list_id) == _list.numLists()) { _pos.flag = null_flag; } else { _pos.name = _list._flag_names[_list.toFid(_pos.flag)]; @@ -382,8 +411,8 @@ class list_table : public snapshot_interface { bool valid; do { - valid = true; - int fid = _list.toFid(_pos.flag); + valid = true; + size_t fid = _list.toFid(_pos.flag); if (_data == nullptr) { if (_list._flag_names[fid] == nullptr) { valid = false; @@ -392,7 +421,8 @@ class list_table : public snapshot_interface } else if (! _list.hasList(_data, _pos.flag.list_id)) { valid = false; ++_pos.flag.list_id; - } else if (! _list.hasFlag(_data, fid) || _list._flag_names[fid] == nullptr) { + } else if (! _list.hasFlag(_data, static_cast(fid)) + || _list._flag_names[fid] == nullptr) { valid = false; ++_pos.flag.flag; } @@ -401,6 +431,15 @@ class list_table : public snapshot_interface } public: + named_flag_itr(const named_flag_itr& o) + : _list{o._list} + , _data{o._data} + , _pos{o._pos} + { + } + + named_flag_itr& operator=(const named_flag_itr&) = delete; + bool operator!=(const named_flag_itr& o) const { return _pos.flag != o._pos.flag; } named_flag_itr(const list_table& list, const data_t* filter) diff --git a/inkcpp/output.cpp b/inkcpp/output.cpp index 6162db2c..6cb7eee6 100644 --- a/inkcpp/output.cpp +++ b/inkcpp/output.cpp @@ -33,10 +33,7 @@ void basic_stream::initelize_data(value* buffer, size_t size) _max = size; } -void basic_stream::overflow(value*& buffer, size_t& size, size_t target) -{ - inkFail("Stack overflow!"); -} +void basic_stream::overflow(value*&, size_t&, size_t) { inkFail("Stack overflow!"); } void basic_stream::append(const value& in) { @@ -145,8 +142,7 @@ inline void write_char(std::stringstream& output, char c) 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(); + *next = &list[i + 1]; if ((*next)->printable()) { return true; } @@ -157,7 +153,7 @@ inline bool get_next(const value* list, size_t i, size_t size, const value** nex } template -void basic_stream::copy_string(const char* str, size_t& dataIter, T& output) +void basic_stream::copy_string(const char* str, size_t&, T& output) { while (*str != 0) { write_char(output, *str++); @@ -274,7 +270,7 @@ size_t basic_stream::find_first_of(value_type type, size_t offset /*= 0*/) const size_t basic_stream::find_last_of(value_type type, size_t offset /*= 0*/) const { if (_size == 0) - return -1; + return ~0U; // Special case to make the reverse loop easier if (_size == 1 && offset == 0) @@ -363,7 +359,7 @@ char* basic_stream::get_alloc(string_table& strings, list_table& lists) case value_type::float32: case value_type::uint32: // Convert to string and advance - toStr(ptr, end - ptr, _data[i]); + toStr(ptr, static_cast(end - ptr), _data[i]); while (*ptr != 0) ptr++; @@ -529,7 +525,7 @@ size_t basic_stream::snap(unsigned char* data, const snapper& snapper) const for (auto itr = _data; itr != _data + _size; ++itr) { ptr += itr->snap(data ? ptr : nullptr, snapper); } - return ptr - data; + return static_cast(ptr - data); } const unsigned char* basic_stream::snap_load(const unsigned char* ptr, const loader& loader) diff --git a/inkcpp/output.h b/inkcpp/output.h index 493bdcfe..eb9b2e8e 100644 --- a/inkcpp/output.h +++ b/inkcpp/output.h @@ -30,7 +30,7 @@ namespace runtime public: // Constant to identify an invalid position in the stream - static constexpr size_t npos = ~0; + static constexpr size_t npos = ~0U; // Append data to stream void append(const value&); diff --git a/inkcpp/runner_impl.cpp b/inkcpp/runner_impl.cpp index 05ab406b..9fad54e7 100644 --- a/inkcpp/runner_impl.cpp +++ b/inkcpp/runner_impl.cpp @@ -34,7 +34,7 @@ const choice* runner_interface::get_choice(size_t index) const return begin() + index; } -size_t runner_interface::num_choices() const { return end() - begin(); } +size_t runner_interface::num_choices() const { return static_cast(end() - begin()); } } // namespace ink::runtime namespace ink::runtime::internal @@ -42,7 +42,7 @@ namespace ink::runtime::internal hash_t runner_impl::get_current_knot() const { - return _current_knot_id == ~0 ? 0 : _story->container_hash(_current_knot_id); + return _current_knot_id == ~0U ? 0 : _story->container_hash(_current_knot_id); } template<> @@ -409,7 +409,7 @@ void runner_impl::start_frame(uint32_t target) } // Push next address onto the callstack { - size_t address = _ptr - _story->instructions(); + offset_t address = static_cast(_ptr - _story->instructions()); _stack.push_frame(address, _evaluation_mode); _ref_stack.push_frame(address, _evaluation_mode); } @@ -477,7 +477,7 @@ runner_impl::runner_impl(const story_impl* data, globals global) , _choices() , _tags_begin(0, ~0) , _container(ContainerData{}) - , _rng(time(NULL)) + , _rng(static_cast(time(NULL))) { @@ -520,7 +520,7 @@ runner_impl::line_type runner_impl::getline() // Fall through the fallback choice, if available if (! has_choices() && _fallback_choice) { - choose(~0); + choose(~0U); } inkAssert(_output.is_empty(), "Output should be empty after getline!"); @@ -599,7 +599,7 @@ void runner_impl::choose(size_t index) // Figure out where our previous pointer was for that thread ip_t prev = nullptr; - if (choiceThread == ~0) { + if (choiceThread == ~0U) { prev = _done; } else { prev = _threads.get(choiceThread); @@ -655,10 +655,11 @@ size_t runner_impl::snap(unsigned char* data, snapper& snapper) const ptr += _eval.snap(data ? ptr : nullptr, snapper); ptr += _tags_begin.snap(data ? ptr : nullptr, snapper); ptr += _tags.snap(data ? ptr : nullptr, snapper); - ptr = snap_write(ptr, _entered_global, should_write); - ptr = snap_write(ptr, _entered_knot, should_write); - ptr = snap_write(ptr, _current_knot_id, should_write); - ptr = snap_write(ptr, _current_knot_id_backup, should_write); + snapper.runner_tags = _tags.data(); + ptr = snap_write(ptr, _entered_global, should_write); + ptr = snap_write(ptr, _entered_knot, should_write); + ptr = snap_write(ptr, _current_knot_id, should_write); + ptr = snap_write(ptr, _current_knot_id_backup, should_write); ptr += _container.snap(data ? ptr : nullptr, snapper); ptr += _threads.snap(data ? ptr : nullptr, snapper); ptr = snap_write(ptr, _fallback_choice.has_value(), should_write); @@ -666,7 +667,7 @@ size_t runner_impl::snap(unsigned char* data, snapper& snapper) const ptr += _fallback_choice.value().snap(data ? ptr : nullptr, snapper); } ptr += _choices.snap(data ? ptr : nullptr, snapper); - return ptr - data; + return static_cast(ptr - data); } const unsigned char* runner_impl::snap_load(const unsigned char* data, loader& loader) @@ -682,23 +683,24 @@ const unsigned char* runner_impl::snap_load(const unsigned char* data, loader& l int32_t seed; ptr = snap_read(ptr, seed); _rng.srand(seed); - ptr = snap_read(ptr, _evaluation_mode); - ptr = snap_read(ptr, _string_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); - ptr = _tags_begin.snap_load(ptr, loader); - ptr = _tags.snap_load(ptr, loader); - ptr = snap_read(ptr, _entered_global); - ptr = snap_read(ptr, _entered_knot); - ptr = snap_read(ptr, _current_knot_id); - ptr = snap_read(ptr, _current_knot_id_backup); - ptr = _container.snap_load(ptr, loader); - ptr = _threads.snap_load(ptr, loader); + ptr = snap_read(ptr, _evaluation_mode); + ptr = snap_read(ptr, _string_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); + ptr = _tags_begin.snap_load(ptr, loader); + ptr = _tags.snap_load(ptr, loader); + loader.runner_tags = _tags.data(); + ptr = snap_read(ptr, _entered_global); + ptr = snap_read(ptr, _entered_knot); + ptr = snap_read(ptr, _current_knot_id); + ptr = snap_read(ptr, _current_knot_id_backup); + ptr = _container.snap_load(ptr, loader); + ptr = _threads.snap_load(ptr, loader); bool has_fallback_choice; ptr = snap_read(ptr, has_fallback_choice); _fallback_choice = nullopt; @@ -716,7 +718,7 @@ const char* runner_impl::getline_alloc() advance_line(); const char* res = _output.get_alloc(_globals->strings(), _globals->lists()); if (! has_choices() && _fallback_choice) { - choose(~0); + choose(~0U); } inkAssert(_output.is_empty(), "Output should be empty after getline!"); return res; @@ -779,7 +781,7 @@ bool runner_impl::line_step() // Step the interpreter until we've parsed all tags for the line _entered_global = true; - _current_knot_id = ~0; + _current_knot_id = ~0U; _entered_knot = false; } // Step the interpreter @@ -1159,10 +1161,10 @@ void runner_impl::step() // TODO We push ahead of a single divert. Is that correct in all cases....????? auto returnTo = _ptr + CommandSize; _stack.push_frame( - returnTo - _story->instructions(), _evaluation_mode + static_cast(returnTo - _story->instructions()), _evaluation_mode ); _ref_stack.push_frame( - returnTo - _story->instructions(), _evaluation_mode + static_cast(returnTo - _story->instructions()), _evaluation_mode ); // Fork a new thread on the callstack @@ -1330,7 +1332,7 @@ void runner_impl::step() // been visited if (flag & CommandFlag::CHOICE_IS_ONCE_ONLY) { // Need to convert offset to container index - container_t destination = -1; + container_t destination = ~0U; if (_story->get_container_id(_story->instructions() + path, destination)) { // Ignore the choice if we've visited the destination before if (_globals->visits(destination) > 0) { @@ -1457,7 +1459,9 @@ void runner_impl::step() // iteration loop. I don't feel like replicating that right now. // So, let's just return a random number and *shrug* int sequenceLength = _eval.pop().get(); - int index = _eval.pop().get(); + /* shuffel index */ + _eval.pop(); + _eval.push(value{}.set(static_cast(_rng.rand(sequenceLength))) ); @@ -1539,7 +1543,7 @@ void runner_impl::on_done(bool setDone) void runner_impl::set_done_ptr(ip_t ptr) { thread_t curr = current_thread(); - if (curr == ~0) { + if (curr == ~0U) { _done = ptr; } else { _threads.set(curr, ptr); @@ -1621,7 +1625,7 @@ void runner_impl::restore() _tags_begin.restore(); _evaluation_mode = _saved_evaluation_mode; _current_knot_id = _current_knot_id_backup; - _current_knot_id_backup = ~0; + _current_knot_id_backup = ~0U; // 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"); @@ -1645,7 +1649,7 @@ void runner_impl::forget() _choices.forgett(); _tags.forgett(); _tags_begin.forget(); - _current_knot_id_backup = ~0; + _current_knot_id_backup = ~0U; // Nothing to do for eval stack. It should just stay as it is _saved = false; diff --git a/inkcpp/runner_impl.h b/inkcpp/runner_impl.h index 26f4e44a..f4089a29 100644 --- a/inkcpp/runner_impl.h +++ b/inkcpp/runner_impl.h @@ -211,8 +211,8 @@ class runner_impl // Special code for jumping from the current IP to another void jump(ip_t, bool record_visits, bool track_knot_visit); - uint32_t _current_knot_id = ~0; // id to detect knot changes from the outside - uint32_t _current_knot_id_backup = ~0; + uint32_t _current_knot_id = ~0U; // id to detect knot changes from the outside + uint32_t _current_knot_id_backup = ~0U; uint32_t _entered_knot = false; // if we are in the first action after a jump to an snitch/knot bool _entered_global = false; // if we are in the first action after a jump to an snitch/knot @@ -234,7 +234,7 @@ class runner_impl public: template = true> threads() - : base(~0) + : base(~0U) , _threadDone(nullptr, reinterpret_cast(~0)) { static_assert(sizeof...(D) == 0, "Don't use explicit template arguments!"); @@ -376,7 +376,7 @@ size_t runner_impl::threads::snap(unsigned char* data, const snapper unsigned char* ptr = data; ptr += base::snap(data ? ptr : nullptr, snapper); ptr += _threadDone.snap(data ? ptr : nullptr, snapper); - return ptr - data; + return static_cast(ptr - data); } template diff --git a/inkcpp/simple_restorable_stack.h b/inkcpp/simple_restorable_stack.h index db20ef93..12ce3d40 100644 --- a/inkcpp/simple_restorable_stack.h +++ b/inkcpp/simple_restorable_stack.h @@ -53,7 +53,7 @@ class simple_restorable_stack : public snapshot_interface virtual const unsigned char* snap_load(const unsigned char* data, const loader&); protected: - virtual void overflow(T*& buffer, size_t& size) { inkFail("Stack overflow!"); } + virtual void overflow(T*&, size_t&) { inkFail("Stack overflow!"); } void initialize_data(T* buffer, size_t size) { @@ -71,7 +71,7 @@ class simple_restorable_stack : public snapshot_interface size_t _size; const T _null; - const static size_t InvalidIndex = ~0; + const static size_t InvalidIndex = ~0U; size_t _pos = 0; size_t _save = InvalidIndex, _jump = InvalidIndex; @@ -309,12 +309,11 @@ size_t simple_restorable_stack::snap(unsigned char* data, const snapper&) con for (size_t i = 0; i < max; ++i) { ptr = snap_write(ptr, _buffer[i], should_write); } - return ptr - data; + return static_cast(ptr - data); } template -const unsigned char* - simple_restorable_stack::snap_load(const unsigned char* ptr, const loader& loader) +const unsigned char* simple_restorable_stack::snap_load(const unsigned char* ptr, const loader&) { T null; ptr = snap_read(ptr, null); diff --git a/inkcpp/snapshot_impl.cpp b/inkcpp/snapshot_impl.cpp index f18bc9c5..12d55f6a 100644 --- a/inkcpp/snapshot_impl.cpp +++ b/inkcpp/snapshot_impl.cpp @@ -83,7 +83,7 @@ snapshot_impl::snapshot_impl(const globals_impl& globals) // write lookup table ptr += sizeof(header); { - size_t offset = (ptr - data) + (_header.num_runners + 1) * sizeof(size_t); + size_t offset = static_cast((ptr - data) + (_header.num_runners + 1) * sizeof(size_t)); memcpy(ptr, &offset, sizeof(offset)); ptr += sizeof(offset); offset += globals.snap(nullptr, snapper); @@ -122,13 +122,13 @@ size_t snap_choice::snap(unsigned char* data, const snapper& snapper) const ptr = snap_write(ptr, false, should_write); } else { ptr = snap_write(ptr, true, should_write); - std::uintptr_t offset_start = _tags_start != nullptr ? _tags_start - snapper.runner_tags : 0; + std::uintptr_t offset_start = _tags_start - snapper.runner_tags; ptr = snap_write(ptr, offset_start, should_write); - std::uintptr_t offset_end = _tags_end != nullptr ? _tags_end - snapper.runner_tags : 0; + std::uintptr_t offset_end = _tags_end - snapper.runner_tags; ptr = snap_write(ptr, offset_end, should_write); } ptr = snap_write(ptr, snapper.strings.get_id(_text), should_write); - return ptr - data; + return static_cast(ptr - data); } const unsigned char* snap_choice::snap_load(const unsigned char* data, const loader& loader) @@ -167,7 +167,7 @@ size_t snap_tag::snap(unsigned char* data, const snapper& snapper) const ptr = snap_write(ptr, true, should_write); ptr = snap_write(ptr, id, should_write); } - return ptr - data; + return static_cast(ptr - data); } const unsigned char* snap_tag::snap_load(const unsigned char* data, const loader& loader) diff --git a/inkcpp/snapshot_interface.h b/inkcpp/snapshot_interface.h index 88c103a8..42c4eb50 100644 --- a/inkcpp/snapshot_interface.h +++ b/inkcpp/snapshot_interface.h @@ -6,13 +6,14 @@ */ #pragma once -#include "snapshot.h" +#include "system.h" + #include namespace ink::runtime::internal { class globals_impl; -template +template class managed_array; class snap_tag; class string_table; @@ -52,15 +53,29 @@ class snapshot_interface struct snapper { const string_table& strings; const char* story_string_table; - const snap_tag* runner_tags = nullptr; + const snap_tag* runner_tags = nullptr; + snapper() = delete; + snapper& operator=(const snapper&) = delete; }; struct loader { managed_array& string_table; /// FIXME: make configurable const char* story_string_table; const snap_tag* runner_tags = nullptr; + loader() = delete; + loader& operator=(const loader&) = delete; }; +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +#else +# pragma warning(push) +# pragma warning( \ + disable : 4100, justification : "non functional prototypes do not need the argument." \ + ) +#endif + size_t snap(unsigned char* data, snapper&) const { inkFail("Snap function not implemented"); @@ -72,5 +87,11 @@ class snapshot_interface inkFail("Snap function not implemented"); return nullptr; }; + +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#else +# pragma warning(pop) +#endif }; } // namespace ink::runtime::internal diff --git a/inkcpp/stack.cpp b/inkcpp/stack.cpp index 58783e2e..dd9c562f 100644 --- a/inkcpp/stack.cpp +++ b/inkcpp/stack.cpp @@ -9,610 +9,620 @@ namespace ink::runtime::internal { - basic_stack::basic_stack(entry* data, size_t size) - : base(data, size) - { +basic_stack::basic_stack(entry* data, size_t size) + : base(data, size) +{ +} + +void basic_stack::set(hash_t name, const value& val) +{ + // If we have a save point, always add no matter what + if (base::is_saved()) { + add(name, val); + return; + } + + // Either set an existing variable or add it to the stack + value* existing = const_cast(get(name)); + if (existing == nullptr) + add(name, val); + else + *existing = val; +} + +bool reverse_find_predicat(hash_t name, thread_t& skip, uint32_t& jumping, entry& e) +{ + // Jumping + if (jumping > 0) { + jumping--; + return false; } - void basic_stack::set(hash_t name, const value& val) - { - // If we have a save point, always add no matter what - if (base::is_saved()) - { - add(name, val); - return; + // If this is an end thread marker, skip over it + if (skip == ~0U && e.data.type() == value_type::thread_end) { + skip = e.data.get(); + } + + // If we're skipping + if (skip != ~0U) { + // Stop if we get to the start of the thread block + if (e.data.type() == value_type::thread_start + && skip == e.data.get().jump) { + skip = ~0U; } - // Either set an existing variable or add it to the stack - value* existing = const_cast(get(name)); - if (existing == nullptr) - add(name, val); - else - *existing = val; + // Don't return anything in the hidden thread block + return false; } - bool reverse_find_predicat(hash_t name, thread_t& skip, uint32_t& jumping, entry& e) { - // Jumping - if (jumping > 0) { - jumping--; - return false; - } + // Is it a thread start or a jump marker + if (e.name == InvalidHash + && (e.data.type() == value_type::thread_start || e.data.type() == value_type::jump_marker)) { + // If this thread start has a jump value + uint32_t jump = e.data.get().thread_id; - // If this is an end thread marker, skip over it - if (skip == ~0 && e.data.type() == value_type::thread_end) { - skip = e.data.get(); - } + // Then we need to do some jumping. Skip + if (jump > 0) { + jumping = jump; + return false; + } + } - // If we're skipping - if (skip != ~0) { - // Stop if we get to the start of the thread block - if (e.data.type() == value_type::thread_start && skip == e.data.get().jump) { - skip = ~0; - } + return e.name == name || e.name == InvalidHash; +} - // Don't return anything in the hidden thread block - return false; - } +class reverse_find_predicat_operator +{ +public: + explicit reverse_find_predicat_operator(hash_t name) + : _name{name} + { + } - // Is it a thread start or a jump marker - if (e.name == InvalidHash && (e.data.type() == value_type::thread_start || e.data.type() == value_type::jump_marker)) - { - // If this thread start has a jump value - uint32_t jump = e.data.get().thread_id; - - // Then we need to do some jumping. Skip - if (jump > 0) { - jumping = jump; - return false; - } - } + bool operator()(entry& e) { return reverse_find_predicat(_name, _skip, _jumping, e); } - return e.name == name || e.name == InvalidHash; +private: + hash_t _name; + thread_t _skip = ~0U; + uint32_t _jumping = 0; +}; + +class reverse_find_from_frame_predicat_operator +{ +public: + 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!"); } - class reverse_find_predicat_operator { - public: - explicit reverse_find_predicat_operator(hash_t name) : _name{name} {} - bool operator()(entry& e) { - return reverse_find_predicat(_name, _skip, _jumping, e); - } - private: - hash_t _name; - thread_t _skip = ~0; - uint32_t _jumping = 0; - }; - class reverse_find_from_frame_predicat_operator { - public: - 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) { - if(reverse_find_predicat(_name, _skip, _jumping, e)) { - if(_ci == _current_frame) { return true; } - _current_frame -= 1; + + bool operator()(entry& e) + { + if (reverse_find_predicat(_name, _skip, _jumping, e)) { + if (_ci == _current_frame) { + return true; } - return false; + _current_frame -= 1; } - private: - int _ci; - int _current_frame = 0; - hash_t _name; - thread_t _skip = ~0; - uint32_t _jumping = 0; - }; - - const value* basic_stack::get(hash_t name) const { - // Find whatever comes first: a matching entry or a stack frame entry - const entry* found = base::reverse_find(reverse_find_predicat_operator(name)); + return false; + } - // If nothing found, no value - if (found == nullptr) - return nullptr; +private: + int _ci; + int _current_frame = 0; + hash_t _name; + thread_t _skip = ~0U; + uint32_t _jumping = 0; +}; - // If we found something of that name, return the value - if (found->name == name) - return &found->data; +const value* basic_stack::get(hash_t name) const +{ + // Find whatever comes first: a matching entry or a stack frame entry + const entry* found = base::reverse_find(reverse_find_predicat_operator(name)); - // Otherwise, nothing in this stack frame + // If nothing found, no value + if (found == nullptr) return nullptr; - } - value* basic_stack::get(hash_t name) { - // Find whatever comes first: a matching entry or a stack frame entry - entry* found = base::reverse_find(reverse_find_predicat_operator(name)); - // If nothing found, no value - if (found == nullptr) - return nullptr; + // If we found something of that name, return the value + if (found->name == name) + return &found->data; - // If we found something of that name, return the value - if (found->name == name) - return &found->data; + // Otherwise, nothing in this stack frame + return nullptr; +} - // Otherwise, nothing in this stack frame +value* basic_stack::get(hash_t name) +{ + // Find whatever comes first: a matching entry or a stack frame entry + entry* found = base::reverse_find(reverse_find_predicat_operator(name)); + + // If nothing found, no value + if (found == nullptr) return nullptr; + + // If we found something of that name, return the value + if (found->name == name) + return &found->data; + + // Otherwise, nothing in this stack frame + return nullptr; +} + +value* basic_stack::get_from_frame(int ci, hash_t name) +{ + entry* found = base::reverse_find(reverse_find_from_frame_predicat_operator(ci, name)); + if (found == nullptr && ci == -1) { + found = base::reverse_find(reverse_find_from_frame_predicat_operator(0, name)); } - - value* basic_stack::get_from_frame(int ci, hash_t name) { - entry* found = base::reverse_find(reverse_find_from_frame_predicat_operator(ci, name)); - if(found == nullptr && ci == -1) { - found = base::reverse_find(reverse_find_from_frame_predicat_operator(0, name)); - } - if(found == nullptr) { return nullptr; } - if(found->name == name) { return &found->data; } + if (found == nullptr) { return nullptr; } - - template<> - void basic_stack::push_frame(offset_t return_to, bool eval) - { - add(InvalidHash, value{}.set(return_to, eval)); - } - template<> - void basic_stack::push_frame(offset_t return_to, bool eval) - { - add(InvalidHash, value{}.set(return_to, eval)); - } - template<> - void basic_stack::push_frame(offset_t return_to, bool eval) - { - add(InvalidHash, value{}.set(return_to, eval)); + if (found->name == name) { + return &found->data; } + return nullptr; +} - const entry* basic_stack::pop() - { - return &base::pop([](const entry& elem) { return elem.name == ~0; }); - } +template<> +void basic_stack::push_frame(offset_t return_to, bool eval) +{ + add(InvalidHash, value{}.set(return_to, eval)); +} - entry* basic_stack::do_thread_jump_pop(const basic_stack::iterator& jumpStart) - { - // Start an iterator right after the jumping marker (might be a thread_start or a jump_marker) - iterator threadIter = jumpStart; +template<> +void basic_stack::push_frame(offset_t return_to, bool eval) +{ + add(InvalidHash, value{}.set(return_to, eval)); +} - // Get a reference to its jump count - value& start = threadIter.get()->data; - value_type vt = start.type(); - auto jump = start.get(); +template<> +void basic_stack::push_frame(offset_t return_to, bool eval) +{ + add(InvalidHash, value{}.set(return_to, eval)); +} - // Move over it +const entry* basic_stack::pop() +{ + return &base::pop([](const entry& elem) { return elem.name == ~0U; }); +} + +entry* basic_stack::do_thread_jump_pop(const basic_stack::iterator& jumpStart) +{ + // Start an iterator right after the jumping marker (might be a thread_start or a jump_marker) + iterator threadIter = jumpStart; + + // Get a reference to its jump count + value& start = threadIter.get()->data; + value_type vt = start.type(); + auto jump = start.get(); + + // Move over it + threadIter.next(); + + // Move back over the current jump value + for (uint32_t i = 0; i < jump.thread_id; i++) threadIter.next(); - // Move back over the current jump value - for (uint32_t i = 0; i < jump.thread_id; i++) - threadIter.next(); - - // Now keep iterating back until we get to a frame marker - // FIXME: meta types or subtypes? - while (!threadIter.done() && (threadIter.get()->name != InvalidHash - || threadIter.get()->data.type() == value_type::thread_start - || threadIter.get()->data.type() == value_type::thread_end)) - { - // If we've hit an end of thread marker - auto e = threadIter.get(); - if (e->data.type() == value_type::thread_end) - { - // We basically want to skip until we get to the start of this thread (leave the block alone) - thread_t tid = e->data.get(); - while (threadIter.get()->data.type() != value_type::thread_start - || threadIter.get()->data.get().jump != tid) - { - jump.thread_id++; - threadIter.next(); - } - - // Now let us skip over the thread start + // Now keep iterating back until we get to a frame marker + // FIXME: meta types or subtypes? + while (! threadIter.done() + && (threadIter.get()->name != InvalidHash + || threadIter.get()->data.type() == value_type::thread_start + || threadIter.get()->data.type() == value_type::thread_end)) { + // If we've hit an end of thread marker + auto e = threadIter.get(); + if (e->data.type() == value_type::thread_end) { + // We basically want to skip until we get to the start of this thread (leave the block alone) + thread_t tid = e->data.get(); + while (threadIter.get()->data.type() != value_type::thread_start + || threadIter.get()->data.get().jump != tid) { + jump.thread_id++; + threadIter.next(); } - threadIter.next(); - jump.thread_id++; + // Now let us skip over the thread start } - // Move us over the frame marker + threadIter.next(); jump.thread_id++; + } - // Now that thread marker is set to the correct jump value. - if (vt == value_type::jump_marker) { - start.set(jump); - } else if (vt == value_type::thread_start) { - start.set(jump); - } else { - inkFail("unknown jump type"); - } - return threadIter.get(); + // Move us over the frame marker + jump.thread_id++; + + // Now that thread marker is set to the correct jump value. + if (vt == value_type::jump_marker) { + start.set(jump); + } else if (vt == value_type::thread_start) { + start.set(jump); + } else { + inkFail("unknown jump type"); } + return threadIter.get(); +} - frame_type get_frame_type(value_type type) - { - switch (type) - { - case value_type::tunnel_frame: - return frame_type::tunnel; - case value_type::function_frame: - return frame_type::function; - case value_type::thread_frame: - return frame_type::thread; - default: - inkAssert(false, "Unknown frame type detected"); - return (frame_type)-1; - } +frame_type get_frame_type(value_type type) +{ + switch (type) { + case value_type::tunnel_frame: return frame_type::tunnel; + case value_type::function_frame: return frame_type::function; + case value_type::thread_frame: return frame_type::thread; + default: inkAssert(false, "Unknown frame type detected"); return ( frame_type ) -1; } +} - offset_t basic_stack::pop_frame(frame_type* type, bool& eval) - { - inkAssert(!base::is_empty(), "Can not pop frame from empty callstack."); - - const entry* returnedFrame = nullptr; - auto isNull = [](const entry& e) { return e.name == ~0; }; - - // Start iterating backwards - iterator iter = base::begin(); - if(isNull(*iter.get())) { iter.next(isNull); } - while (!iter.done()) - { - // Keep popping if it's not a frame marker or thread marker of some kind - entry* frame = iter.get(); - if (frame->name != InvalidHash) - { - pop(); - iter = base::begin(); - if(isNull(*iter.get())) { iter.next(isNull); } - continue; +offset_t basic_stack::pop_frame(frame_type* type, bool& eval) +{ + inkAssert(! base::is_empty(), "Can not pop frame from empty callstack."); + + const entry* returnedFrame = nullptr; + auto isNull = [](const entry& e) { + return e.name == ~0U; + }; + + // Start iterating backwards + iterator iter = base::begin(); + if (isNull(*iter.get())) { + iter.next(isNull); + } + while (! iter.done()) { + // Keep popping if it's not a frame marker or thread marker of some kind + entry* frame = iter.get(); + if (frame->name != InvalidHash) { + pop(); + iter = base::begin(); + if (isNull(*iter.get())) { + iter.next(isNull); } + continue; + } - // We now have a frame marker. Check if it's a thread - // Thread handling - if ( + // We now have a frame marker. Check if it's a thread + // Thread handling + if ( // FIXME: is_tghead_marker, is_jump_marker frame->data.type() == value_type::thread_start || frame->data.type() == value_type::thread_end || frame->data.type() == value_type::jump_marker ) { - // End of thread marker, we need to create a jump marker - if (frame->data.type() == value_type::thread_end) - { - // Push a new jump marker after the thread end - entry& jump = push({ InvalidHash, value{}.set(0u,0u) }); - - // Do a pop back - returnedFrame = do_thread_jump_pop(base::begin()); - break; - } - - // If this is a jump marker, we actually want to extend it to the next frame - if (frame->data.type() == value_type::jump_marker) - { - // Use the thread jump pop method using this jump marker - returnedFrame = do_thread_jump_pop(iter); - break; - } - - // Popping past thread start - if (frame->data.type() == value_type::thread_start) - { - returnedFrame = do_thread_jump_pop(iter); - break; - } - } - - // Otherwise, pop the frame marker off and return it - returnedFrame = pop(); - break; - } - - // If we didn't find a frame entry, we never had a frame to return from - inkAssert(returnedFrame, "Attempting to pop_frame when no frames exist! Stack reset."); - - // Make sure we're not somehow trying to "return" from a thread - inkAssert(returnedFrame->data.type() != value_type::thread_start - && returnedFrame->data.type() != value_type::thread_end, - "Can not return from a thread! How did this happen?"); - - // Store frame type - if (type != nullptr) - { - *type = get_frame_type(returnedFrame->data.type()); - } - - // Return the offset stored in the frame record - // FIXME: correct type? - const auto& frame = returnedFrame->data.get(); - eval = frame.eval; - return frame.addr; - } - - bool basic_stack::has_frame(frame_type* returnType) const - { - // Empty case - if (base::is_empty()) - return false; - - uint32_t jumping = 0; - uint32_t thread = ~0; - // Search in reverse for a stack frame - const entry* frame = base::reverse_find([&jumping, &thread](const entry& elem) { - // If we're jumping over data, just keep returning false until we're done - if (jumping > 0) { - jumping--; - return false; - } - - // We only care about elements with InvalidHash - if (elem.name != InvalidHash) - return false; - - // If we're skipping over a thread, wait until we hit its start before checking - if (thread != ~0) { - if (elem.data.type() == value_type::thread_start && elem.data.get().jump == thread) - thread = ~0; - - return false; + // End of thread marker, we need to create a jump marker + if (frame->data.type() == value_type::thread_end) { + // Push a new jump marker after the thread end + push({InvalidHash, value{}.set(0u, 0u)}); + + // Do a pop back + returnedFrame = do_thread_jump_pop(base::begin()); + break; } - // If it's a jump marker or a thread start - if (elem.data.type() == value_type::jump_marker || elem.data.type() == value_type::thread_start) { - jumping = elem.data.get().thread_id; - return false; + // If this is a jump marker, we actually want to extend it to the next frame + if (frame->data.type() == value_type::jump_marker) { + // Use the thread jump pop method using this jump marker + returnedFrame = do_thread_jump_pop(iter); + break; } - // If it's a thread end, we need to skip to the matching thread start - if (elem.data.type() == value_type::thread_end) { - thread = elem.data.get(); - return false; + // Popping past thread start + if (frame->data.type() == value_type::thread_start) { + returnedFrame = do_thread_jump_pop(iter); + break; } + } - return elem.name == InvalidHash; - }); - - if (frame != nullptr && returnType != nullptr) - *returnType = get_frame_type(frame->data.type()); - - // Return true if a frame was found - return frame != nullptr; + // Otherwise, pop the frame marker off and return it + returnedFrame = pop(); + break; } - void basic_stack::clear() - { - base::clear(); - } + // If we didn't find a frame entry, we never had a frame to return from + inkAssert(returnedFrame, "Attempting to pop_frame when no frames exist! Stack reset."); - void basic_stack::mark_used(string_table& strings, list_table& lists) const - { - // Mark all strings - base::for_each_all( - [&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()); - } - }); - } - - thread_t basic_stack::fork_thread() - { - // TODO create unique thread ID - thread_t new_thread = _next_thread++; + // Make sure we're not somehow trying to "return" from a thread + inkAssert( + returnedFrame->data.type() != value_type::thread_start + && returnedFrame->data.type() != value_type::thread_end, + "Can not return from a thread! How did this happen?" + ); - // Push a thread start marker here - entry& thread_entry = add(InvalidHash, value{}.set(new_thread, 0u)); + // Store frame type + if (type != nullptr) { + *type = get_frame_type(returnedFrame->data.type()); + } - // Set stack jump counter for thread to 0. This number is used if the thread ever - // tries to pop past its origin. It keeps track of how much of the preceeding stack it's popped back + // Return the offset stored in the frame record + // FIXME: correct type? + const auto& frame = returnedFrame->data.get(); + eval = frame.eval; + return frame.addr; +} - return new_thread; - } +bool basic_stack::has_frame(frame_type* returnType) const +{ + // Empty case + if (base::is_empty()) + return false; + + uint32_t jumping = 0; + uint32_t thread = ~0U; + // Search in reverse for a stack frame + const entry* frame = base::reverse_find([&jumping, &thread](const entry& elem) { + // If we're jumping over data, just keep returning false until we're done + if (jumping > 0) { + jumping--; + return false; + } + + // We only care about elements with InvalidHash + if (elem.name != InvalidHash) + return false; + + // If we're skipping over a thread, wait until we hit its start before checking + if (thread != ~0U) { + if (elem.data.type() == value_type::thread_start + && elem.data.get().jump == thread) + thread = ~0U; + + return false; + } + + // If it's a jump marker or a thread start + if (elem.data.type() == value_type::jump_marker + || elem.data.type() == value_type::thread_start) { + jumping = elem.data.get().thread_id; + return false; + } + + // If it's a thread end, we need to skip to the matching thread start + if (elem.data.type() == value_type::thread_end) { + thread = elem.data.get(); + return false; + } + + return elem.name == InvalidHash; + }); + + if (frame != nullptr && returnType != nullptr) + *returnType = get_frame_type(frame->data.type()); + + // Return true if a frame was found + return frame != nullptr; +} - void basic_stack::complete_thread(thread_t thread) - { - // Add a thread complete marker - add(InvalidHash, value{}.set(thread)); - } +void basic_stack::clear() { base::clear(); } - void basic_stack::collapse_to_thread(thread_t thread) - { - // Reset thread counter - _next_thread = 0; - - // If we're restoring a specific thread (and not the main thread) - if (thread != ~0) - { - // Keep popping until we find the requested thread's end marker - const entry* top = pop(); - while (!( - top->data.type() == value_type::thread_end && - top->data.get() == thread)) - { - inkAssert(!is_empty(), "Ran out of stack while searching for end of thread marker. Did you call complete_thread?"); - top = pop(); - } +void basic_stack::mark_used(string_table& strings, list_table& lists) const +{ + // Mark all strings + base::for_each_all([&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()); } + }); +} - // Now, start iterating backwards - thread_t nulling = ~0; - uint32_t jumping = 0; - base::reverse_for_each([&nulling, &jumping](entry& elem) { - if (jumping > 0) { - // delete data - elem.name = NulledHashId; - - // Move on - jumping--; - return; - } +thread_t basic_stack::fork_thread() +{ + // TODO create unique thread ID + thread_t new_thread = _next_thread++; - // Thread end. We just need to delete this whole block - if (nulling == ~0 && elem.data.type() == value_type::thread_end && elem.name == InvalidHash) { - nulling = elem.data.get(); - } + // Push a thread start marker here + add(InvalidHash, value{}.set(new_thread, 0u)); - // If we're deleting a useless thread block - if (nulling != ~0) { - // If this is the start of the block, stop deleting - if (elem.name == InvalidHash && elem.data.type() == value_type::thread_start && elem.data.get().jump == nulling) { - nulling = ~0; - } + // Set stack jump counter for thread to 0. This number is used if the thread ever + // tries to pop past its origin. It keeps track of how much of the preceeding stack it's popped + // back - // delete data - elem.name = NulledHashId; - } - else - { - // Clear thread start markers. We don't need or want them anymore - if (elem.name == InvalidHash && - (elem.data.type() == value_type::thread_start || elem.data.type() == value_type::jump_marker)) { - // Clear it out - elem.name = NulledHashId; - - // Check if this is a jump, if so we need to ignore even more data - jumping = elem.data.get().thread_id; - } - - // Clear thread frame markers. We can't use them anymore - if (elem.name == InvalidHash && elem.data.type() == value_type::thread_frame) { - elem.name = NulledHashId; - } - } + return new_thread; +} - }, [](entry& elem) { return elem.name == NulledHashId; }); +void basic_stack::complete_thread(thread_t thread) +{ + // Add a thread complete marker + add(InvalidHash, value{}.set(thread)); +} - // No more threads. Clear next thread counter - _next_thread = 0; +void basic_stack::collapse_to_thread(thread_t thread) +{ + // Reset thread counter + _next_thread = 0; + + // If we're restoring a specific thread (and not the main thread) + if (thread != ~0U) { + // Keep popping until we find the requested thread's end marker + const entry* top = pop(); + while ( + ! (top->data.type() == value_type::thread_end + && top->data.get() == thread) + ) { + inkAssert( + ! is_empty(), + "Ran out of stack while searching for end of thread marker. Did you call complete_thread?" + ); + top = pop(); + } } - void basic_stack::save() - { - base::save(); + // Now, start iterating backwards + thread_t nulling = ~0U; + uint32_t jumping = 0; + base::reverse_for_each( + [&nulling, &jumping](entry& elem) { + if (jumping > 0) { + // delete data + elem.name = NulledHashId; + + // Move on + jumping--; + return; + } + + // Thread end. We just need to delete this whole block + if (nulling == ~0U && elem.data.type() == value_type::thread_end + && elem.name == InvalidHash) { + nulling = elem.data.get(); + } + + // If we're deleting a useless thread block + if (nulling != ~0U) { + // If this is the start of the block, stop deleting + if (elem.name == InvalidHash && elem.data.type() == value_type::thread_start + && elem.data.get().jump == nulling) { + nulling = ~0U; + } + + // delete data + elem.name = NulledHashId; + } else { + // Clear thread start markers. We don't need or want them anymore + if (elem.name == InvalidHash + && (elem.data.type() == value_type::thread_start + || elem.data.type() == value_type::jump_marker)) { + // Clear it out + elem.name = NulledHashId; + + // Check if this is a jump, if so we need to ignore even more data + jumping = elem.data.get().thread_id; + } + + // Clear thread frame markers. We can't use them anymore + if (elem.name == InvalidHash && elem.data.type() == value_type::thread_frame) { + elem.name = NulledHashId; + } + } + }, + [](entry& elem) { return elem.name == NulledHashId; } + ); + + // No more threads. Clear next thread counter + _next_thread = 0; +} - // Save thread counter - _backup_next_thread = _next_thread; - } +void basic_stack::save() +{ + base::save(); - void basic_stack::restore() - { - base::restore(); + // Save thread counter + _backup_next_thread = _next_thread; +} - // Restore thread counter - _next_thread = _backup_next_thread; - } +void basic_stack::restore() +{ + base::restore(); - void basic_stack::forget() - { - base::forget([](entry& elem) { elem.name = ~0; }); - } + // Restore thread counter + _next_thread = _backup_next_thread; +} - entry& basic_stack::add(hash_t name, const value& val) - { - return base::push({ name, val }); - } +void basic_stack::forget() +{ + base::forget([](entry& elem) { elem.name = ~0U; }); +} - basic_eval_stack::basic_eval_stack(value* data, size_t size) - : base(data, size) - { +entry& basic_stack::add(hash_t name, const value& val) { return base::push({name, val}); } - } +basic_eval_stack::basic_eval_stack(value* data, size_t size) + : base(data, size) +{ +} - void basic_eval_stack::push(const value& val) - { - base::push(val); - } +void basic_eval_stack::push(const value& val) { base::push(val); } - value basic_eval_stack::pop() - { - return base::pop([](const value& v) { return v.type() == value_type::none; }); - } +value basic_eval_stack::pop() +{ + return base::pop([](const value& v) { return v.type() == value_type::none; }); +} - const value& basic_eval_stack::top() const - { - return base::top([](const value& v){ return false; }); - } +const value& basic_eval_stack::top() const +{ + return base::top([](const value&) { return false; }); +} - const value& basic_eval_stack::top_value() const - { - return base::top([](const value& v){ return v.type() == value_type::none; }); - } +const value& basic_eval_stack::top_value() const +{ + return base::top([](const value& v) { return v.type() == value_type::none; }); +} - bool basic_eval_stack::is_empty() const - { - return base::is_empty(); - } +bool basic_eval_stack::is_empty() const { return base::is_empty(); } - void basic_eval_stack::clear() - { - base::clear(); - } +void basic_eval_stack::clear() { base::clear(); } - 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,&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()); - } - }); - } +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, &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()); + } + }); +} - void basic_eval_stack::save() - { - base::save(); - } +void basic_eval_stack::save() { base::save(); } - void basic_eval_stack::restore() - { - base::restore(); - } +void basic_eval_stack::restore() { base::restore(); } - void basic_eval_stack::forget() - { - // Clear out - value x; x.set(); - value none = value(x); - base::forget([&none](value& elem) { elem = none; }); - } +void basic_eval_stack::forget() +{ + // Clear out + value x; + x.set(); + value none = value(x); + base::forget([&none](value& elem) { elem = none; }); +} - void basic_stack::fetch_values(basic_stack& stack) { - auto itr = base::begin(); - auto predicat = [](entry& e) - { return !(e.name == InvalidHash || e.data.type() == value_type::value_pointer); }; - - if(!itr.done() && predicat(*itr.get())) { itr.next(predicat); } - for(; !itr.done() && itr.get()->name != InvalidHash; itr.next(predicat)) { - auto [name, ci] = itr.get()->data.get(); - inkAssert(ci != 0, "Global refs should not exists on ref stack!"); - inkAssert(ci == -1, "only support ci = -1 for now!"); - if(ci == -1) { - set(name, *stack.get(itr.get()->name)); - } - } - } +void basic_stack::fetch_values(basic_stack& stack) +{ + auto itr = base::begin(); + auto predicat = [](entry& e) { + return ! (e.name == InvalidHash || e.data.type() == value_type::value_pointer); + }; - void basic_stack::push_values(basic_stack& stack) { - for(auto itr = base::begin(); - itr.get()->name != InvalidHash && itr.get()->data.type() != value_type::value_pointer; - itr.next()) - { - stack.set(itr.get()->name, itr.get()->data); + if (! itr.done() && predicat(*itr.get())) { + itr.next(predicat); + } + for (; ! itr.done() && itr.get()->name != InvalidHash; itr.next(predicat)) { + auto [name, ci] = itr.get()->data.get(); + inkAssert(ci != 0, "Global refs should not exists on ref stack!"); + inkAssert(ci == -1, "only support ci = -1 for now!"); + if (ci == -1) { + set(name, *stack.get(itr.get()->name)); } } +} - 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; +void basic_stack::push_values(basic_stack& stack) +{ + for (auto itr = base::begin(); + itr.get()->name != InvalidHash && itr.get()->data.type() != value_type::value_pointer; + itr.next()) { + stack.set(itr.get()->name, itr.get()->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; - } +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 static_cast(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; } +} // namespace ink::runtime::internal diff --git a/inkcpp/stack.h b/inkcpp/stack.h index 66dd0ae2..eb06cac2 100644 --- a/inkcpp/stack.h +++ b/inkcpp/stack.h @@ -105,7 +105,7 @@ namespace runtime thread_t _next_thread = 0; thread_t _backup_next_thread = 0; - static const hash_t NulledHashId = ~0; + static const hash_t NulledHashId = ~0U; }; template<> diff --git a/inkcpp/story_impl.cpp b/inkcpp/story_impl.cpp index f072d95a..48288f57 100644 --- a/inkcpp/story_impl.cpp +++ b/inkcpp/story_impl.cpp @@ -227,13 +227,14 @@ 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, - } - ); + snapshot.strings().clear(); + 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); } @@ -347,7 +348,7 @@ void story_impl::setup_pointers() _container_list = ( uint32_t* ) (ptr); while (true) { uint32_t val = *( uint32_t* ) ptr; - if (val == ~0) { + if (val == ~0U) { ptr += sizeof(uint32_t); break; } else { @@ -360,7 +361,7 @@ void story_impl::setup_pointers() _container_hash_start = ( hash_t* ) (ptr); while (true) { uint32_t val = *( uint32_t* ) ptr; - if (val == ~0) { + if (val == ~0U) { _container_hash_end = ( hash_t* ) (ptr); ptr += sizeof(uint32_t); break; diff --git a/inkcpp/story_impl.h b/inkcpp/story_impl.h index 02d0fca3..e8cc1217 100644 --- a/inkcpp/story_impl.h +++ b/inkcpp/story_impl.h @@ -30,9 +30,9 @@ class story_impl : public story const char* string(uint32_t index) const; - inline const ip_t instructions() const { return _instruction_data; } + inline ip_t instructions() const { return _instruction_data; } - inline const ip_t end() const { return _file + _length; } + inline ip_t end() const { return _file + _length; } inline uint32_t num_containers() const { return _num_containers; } @@ -88,7 +88,7 @@ class story_impl : public story // instruction info ip_t _instruction_data; - // story block used to creat various weak pointers + // story block used to create various weak pointers ref_block* _block; // whether we need to delete our binary data after we destruct diff --git a/inkcpp/string_table.cpp b/inkcpp/string_table.cpp index 40dda321..2389ec00 100644 --- a/inkcpp/string_table.cpp +++ b/inkcpp/string_table.cpp @@ -107,7 +107,7 @@ size_t string_table::snap(unsigned char* data, const snapper&) const for (size_t i = 0; i < _table.size(); ++i) { for (auto itr = _table.begin(); itr != _table.end(); ++itr) { if (itr.temp_identifier() == i) { - size_t length = strlen(itr.key()) + 1; + size_t length = static_cast(strlen(itr.key())) + 1; if (length == 1) { ptr = snap_write(ptr, EMPTY_STRING, 2, should_write); } else { @@ -118,13 +118,12 @@ size_t string_table::snap(unsigned char* data, const snapper&) const } } ptr = snap_write(ptr, "\0", 1, should_write); - return ptr - data; + return static_cast(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) @@ -136,7 +135,6 @@ const unsigned char* string_table::snap_load(const unsigned char* data, const lo if (len == 2 && str[0] == EMPTY_STRING[0]) { str[0] = 0; } - mark_used(str); } return ptr + 1; } diff --git a/inkcpp/string_utils.h b/inkcpp/string_utils.h index 00df3111..1ca406df 100644 --- a/inkcpp/string_utils.h +++ b/inkcpp/string_utils.h @@ -23,13 +23,13 @@ namespace ink::runtime::internal inline int toStr(char* buffer, size_t size, uint32_t value) { #ifdef WIN32 - return _itoa_s(value, buffer, size, 10); + return _itoa_s(static_cast(value), buffer, size, 10); #else if (buffer == nullptr || size < 1) { return EINVAL; } int res = snprintf(buffer, size, "%d", value); - if (res > 0 && res < size) { + if (res > 0 && static_cast(res) < size) { return 0; } return EINVAL; @@ -47,7 +47,7 @@ inline int toStr(char* buffer, size_t size, int32_t value) return EINVAL; } int res = snprintf(buffer, size, "%d", value); - if (res > 0 && res < size) { + if (res > 0 && static_cast(res) < size) { return 0; } return EINVAL; @@ -69,7 +69,7 @@ inline int toStr(char* buffer, size_t size, float value) return EINVAL; } int res = snprintf(buffer, size, "%.7f", value); - if (res < 0 || res >= size) { + if (res < 0 || static_cast(res) >= size) { return EINVAL; } // trunc cat zeros B007 @@ -143,7 +143,7 @@ inline constexpr size_t value_length(const value& v) case value_type::float32: return decimal_digits(v.get()); case value_type::string: return c_str_len(v.get()); case value_type::newline: return 1; - default: inkFail("Can't determine length of this value type"); return -1; + default: inkFail("Can't determine length of this value type"); return ~0U; } } @@ -188,15 +188,22 @@ inline constexpr ITR clean_string(ITR begin, ITR end) auto dst = begin; for (auto src = begin; src != end; ++src) { if (dst == begin) { - if (LEADING_SPACES && isspace(static_cast(src[0]))) { - continue; + if constexpr (LEADING_SPACES) { + if (isspace(static_cast(src[0]))) { + continue; + } } } else if (src[-1] == '\n' && isspace(static_cast(src[0]))) { continue; - } else if ((isspace(static_cast(src[0])) && src[0] != '\n') - && ((src + 1 == end && TAILING_SPACES) - || ((src + 1 != end) && isspace(static_cast(src[1]))))) { - continue; + } else if (isspace(static_cast(src[0])) && src[0] != '\n') { + if constexpr (TAILING_SPACES) { + if (src + 1 == end) { + continue; + } + } + if (src + 1 != end && isspace(static_cast(src[1]))) { + continue; + } } else if (src[0] == '\n' && dst != begin && dst[-1] == '\n') { continue; } diff --git a/inkcpp/value.cpp b/inkcpp/value.cpp index d16c4452..6152cab2 100644 --- a/inkcpp/value.cpp +++ b/inkcpp/value.cpp @@ -20,7 +20,7 @@ template bool truthy_impl(const value& v, const list_table& lists); template<> -bool truthy_impl(const value& v, const list_table& lists) +bool truthy_impl(const value&, const list_table&) { inkFail("Type was not found in operational types or it has no conversion to boolean"); return false; @@ -197,8 +197,9 @@ value::value(const ink::runtime::value& val) case types::String: set(val.get()); break; case types::Float: set(val.get()); break; case types::List: - set(list_table::list{ - static_cast(val.get())->get_lid()}); + set( + list_table::list{static_cast(val.get())->get_lid()} + ); } } @@ -260,7 +261,7 @@ size_t value::snap(unsigned char* data, const snapper& snapper) const // TODO more space efficent? ptr = snap_write(ptr, &bool_value, max_value_size, should_write); } - return ptr - data; + return static_cast(ptr - data); } const unsigned char* value::snap_load(const unsigned char* ptr, const loader& loader) @@ -269,9 +270,11 @@ const unsigned char* value::snap_load(const unsigned char* ptr, const loader& lo 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)]; + string_value.str + = loader.string_table[static_cast(reinterpret_cast(string_value.str))]; } else { - string_value.str = loader.story_string_table + (std::uintptr_t)(string_value.str); + string_value.str = loader.story_string_table + + static_cast(reinterpret_cast(string_value.str)); } } return ptr; diff --git a/inkcpp/value.h b/inkcpp/value.h index 70d70ee9..aef705da 100644 --- a/inkcpp/value.h +++ b/inkcpp/value.h @@ -225,7 +225,7 @@ class value : public snapshot_interface }; template -value redefine::operator()(const T& lh, const T& rh) +value redefine::operator()(const T&, const T& rh) { return value{}.set(rh); } diff --git a/inkcpp_cl/inkcpp_cl.cpp b/inkcpp_cl/inkcpp_cl.cpp index b9bd4813..1d9bbdde 100644 --- a/inkcpp_cl/inkcpp_cl.cpp +++ b/inkcpp_cl/inkcpp_cl.cpp @@ -97,7 +97,7 @@ int main(int argc, const char** argv) // Parse options std::string outputFilename; - bool playMode = false, testMode = false, testDirectory = false, ommit_choice_tags = false; + bool playMode = false, ommit_choice_tags = false; std::string snapshotFile; bool show_statistics = false; const char* inklecateOverwrite = nullptr; @@ -114,11 +114,6 @@ int main(int argc, const char** argv) } } else if (option == "--ommit-choice-tags") { ommit_choice_tags = true; - } else if (option == "-t") { - testMode = true; - } else if (option == "-td") { - testMode = true; - testDirectory = true; } else if (option == "--inklecate") { if (i + 1 < argc - 1 && argv[i + 1][0] != '-') { ++i; @@ -134,26 +129,14 @@ int main(int argc, const char** argv) // Get input filename std::string inputFilename = argv[argc - 1]; - // Test mode - // if (testMode) { - // bool result; - // if (testDirectory) { - // result = test_directory(inputFilename); - // } else { - // result = test(inputFilename); - // } - - // return result ? 0 : -1; - // } - // If output filename not specified, use input filename as guideline if (outputFilename.empty()) { outputFilename = std::regex_replace(inputFilename, std::regex("\\.[^\\.]+$"), ".bin"); } // If input filename is an .ink file - int val = inputFilename.find(".ink"); - bool json_file_is_tmp_file = false; + size_t val = inputFilename.find(".ink"); + bool json_file_is_tmp_file = false; if (val == inputFilename.length() - 4) { // Create temporary filename std::string jsonFile = std::regex_replace(inputFilename, std::regex("\\.[^\\.]+$"), ".tmp"); @@ -229,7 +212,7 @@ int main(int argc, const char** argv) std::cout << thread->getline(); if (thread->has_tags()) { std::cout << "# tags: "; - for (int i = 0; i < thread->num_tags(); ++i) { + for (ink::size_t i = 0; i < thread->num_tags(); ++i) { if (i != 0) { std::cout << ", "; } @@ -247,7 +230,7 @@ int main(int argc, const char** argv) std::cout << index++ << ": " << c.text(); if (! ommit_choice_tags && c.has_tags()) { std::cout << "\n\t"; - for (size_t i = 0; i < c.num_tags(); ++i) { + for (ink::size_t i = 0; i < c.num_tags(); ++i) { std::cout << "# " << c.get_tag(i) << " "; } } diff --git a/inkcpp_cl/test.cpp b/inkcpp_cl/test.cpp index b5b48a79..3982e938 100644 --- a/inkcpp_cl/test.cpp +++ b/inkcpp_cl/test.cpp @@ -124,8 +124,8 @@ bool test(const std::string& inkFilename) } // Load story - auto file = story::from_file("test.bin"); - auto runner = file->new_runner(); + std::unique_ptr file{story::from_file("test.bin")}; + auto runner = file->new_runner(); while (true) { // Run continuously diff --git a/inkcpp_compiler/binary_emitter.cpp b/inkcpp_compiler/binary_emitter.cpp index 4f281843..aec80eea 100644 --- a/inkcpp_compiler/binary_emitter.cpp +++ b/inkcpp_compiler/binary_emitter.cpp @@ -12,7 +12,6 @@ #include #include -#include #ifndef _MSC_VER # include @@ -59,7 +58,7 @@ struct container_data { uint32_t end_offset = 0; // Index used in CNT? operations - container_t counter_index = ~0; + container_t counter_index = ~0U; ~container_data() { @@ -240,7 +239,7 @@ void binary_emitter::output(std::ostream& out) write_container_map(out, _container_map, _max_container_index); // Write a separator - uint32_t END_MARKER = ~0; + uint32_t END_MARKER = ~0U; out.write(( const char* ) &END_MARKER, sizeof(uint32_t)); // Write container hash list @@ -320,7 +319,7 @@ void binary_emitter::process_paths() bool firstParent = true; // We need to parse the path - offset_t noop_offset = ~0; + offset_t noop_offset = ~0U; char* _context = nullptr; const char* token = ink::compiler::internal::strtok_s(const_cast(path_cstr), ".", &_context); @@ -361,13 +360,13 @@ void binary_emitter::process_paths() token = ink::compiler::internal::strtok_s(nullptr, ".", &_context); } - if (noop_offset != ~0) { + if (noop_offset != ~0U) { inkAssert(! useCountIndex, "Can't count visits to a noop!"); _containers.set(position, noop_offset); } else { // If we want the count index, write that out if (useCountIndex) { - inkAssert(container->counter_index != ~0, "No count index available for this container!"); + inkAssert(container->counter_index != ~0U, "No count index available for this container!"); _containers.set(position, container->counter_index); } else { // Otherwise, write container address @@ -435,11 +434,17 @@ void binary_emitter::set_list_meta(const list_data& list_defs) _lists.write(flag.flag); if (flag.flag.list_id != list_id) { list_id = flag.flag.list_id; - _lists.write(reinterpret_cast(list_names->data()), list_names->size()); + _lists.write( + reinterpret_cast(list_names->data()), + static_cast(list_names->size()) + ); ++list_names; _lists.write('\0'); } - _lists.write(reinterpret_cast(flag.name->c_str()), flag.name->size() + 1); + _lists.write( + reinterpret_cast(flag.name->c_str()), + static_cast(flag.name->size()) + 1 + ); } _lists.write(null_flag); } diff --git a/inkcpp_compiler/binary_stream.cpp b/inkcpp_compiler/binary_stream.cpp index d601a08e..b22d5caf 100644 --- a/inkcpp_compiler/binary_stream.cpp +++ b/inkcpp_compiler/binary_stream.cpp @@ -10,157 +10,151 @@ namespace ink { - namespace compiler +namespace compiler +{ + namespace internal { - namespace internal + template<> + size_t binary_stream::write(const std::string& value) { - template<> - size_t binary_stream::write(const std::string& value) - { - constexpr byte_t ZERO = 0; - size_t len; - if(value.length()) { - len = write((const byte_t*)value.c_str(), value.length()); - } else { - len = write(' '); - } - len += write(ZERO); - return len; + constexpr byte_t ZERO = 0; + size_t len; + if (value.length()) { + len = write( + reinterpret_cast(value.c_str()), static_cast(value.length()) + ); + } else { + len = write(' '); } + len += write(ZERO); + return len; + } - binary_stream::binary_stream() - : _currentSlab(nullptr) - , _ptr(nullptr) - { } + binary_stream::binary_stream() + : _currentSlab(nullptr) + , _ptr(nullptr) + { + } - binary_stream::~binary_stream() - { - reset(); - } + binary_stream::~binary_stream() { reset(); } - size_t binary_stream::write(const byte_t* data, size_t len) - { - // Create first slab if none exist - if (_currentSlab == nullptr) - { - _currentSlab = new byte_t[DATA_SIZE]; - _ptr = _currentSlab; - } - - // Check how much space we have left - size_t slab_remaining = _currentSlab + DATA_SIZE - _ptr; - - // If we're out of space... - if (slab_remaining < len) - { - // Write what we can into the slab - memcpy(_ptr, data, slab_remaining); - - // Create a new slab - _slabs.push_back(_currentSlab); - _currentSlab = new byte_t[DATA_SIZE]; - _ptr = _currentSlab; - - // Recurse - return slab_remaining + write(data + slab_remaining, len - slab_remaining); - } - - // We have the space - memcpy(_ptr, data, len); - _ptr += len; - return len; + size_t binary_stream::write(const byte_t* data, size_t len) + { + // Create first slab if none exist + if (_currentSlab == nullptr) { + _currentSlab = new byte_t[DATA_SIZE]; + _ptr = _currentSlab; } - void binary_stream::write_to(std::ostream& out) const - { - // Write previous slabs - for (byte_t* slab : _slabs) - { - out.write(reinterpret_cast(slab), DATA_SIZE); - } - - // Write current slab (if it exists) - if (_currentSlab != nullptr && _ptr != _currentSlab) - { - out.write(reinterpret_cast(_currentSlab), _ptr - _currentSlab); - } + // Check how much space we have left + size_t slab_remaining = static_cast(_currentSlab + DATA_SIZE - _ptr); + + // If we're out of space... + if (slab_remaining < len) { + // Write what we can into the slab + memcpy(_ptr, data, slab_remaining); + + // Create a new slab + _slabs.push_back(_currentSlab); + _currentSlab = new byte_t[DATA_SIZE]; + _ptr = _currentSlab; + + // Recurse + return slab_remaining + write(data + slab_remaining, len - slab_remaining); } - size_t binary_stream::pos() const - { - // If we have no data, we're at position 0 - if (_currentSlab == nullptr) - return 0; + // We have the space + memcpy(_ptr, data, len); + _ptr += len; + return len; + } - // Each slabs is size DATA_SIZE then add the position in the current slab - return _slabs.size() * DATA_SIZE + (_ptr - _currentSlab); + void binary_stream::write_to(std::ostream& out) const + { + // Write previous slabs + for (byte_t* slab : _slabs) { + out.write(reinterpret_cast(slab), DATA_SIZE); } - void binary_stream::set(size_t offset, const byte_t* data, size_t len) - { - // 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; - - if (slab == nullptr) - return; // TODO: Error? - - byte_t* ptr = slab + pos; - - // Check if data will fit into slab - if (pos + len > DATA_SIZE) - { - // Write only what we can fit - size_t new_length = DATA_SIZE - pos; - memcpy(ptr, data, new_length); - - // Recurse - set(offset + new_length, data + new_length, len - new_length); - return; - } - - // Otherwise write the whole data - memcpy(ptr, data, len); + // Write current slab (if it exists) + if (_currentSlab != nullptr && _ptr != _currentSlab) { + out.write(reinterpret_cast(_currentSlab), _ptr - _currentSlab); } + } - 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]; + size_t binary_stream::pos() const + { + // If we have no data, we're at position 0 + if (_currentSlab == nullptr) + return 0; + + // Each slabs is size DATA_SIZE then add the position in the current slab + return static_cast(_slabs.size() * DATA_SIZE + (_ptr - _currentSlab)); + } + + void binary_stream::set(size_t offset, const byte_t* data, size_t len) + { + // 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; + + if (slab == nullptr) + return; // TODO: Error? + + byte_t* ptr = slab + pos; + + // Check if data will fit into slab + if (pos + len > DATA_SIZE) { + // Write only what we can fit + size_t new_length = DATA_SIZE - pos; + memcpy(ptr, data, new_length); + + // Recurse + set(offset + new_length, data + new_length, len - new_length); + return; } - void binary_stream::reset() - { - // Delete all slabs - for (byte_t* slab : _slabs) - { - delete[] slab; - } - _slabs.clear(); - - // Delete active slab (if it exists) - if (_currentSlab != nullptr) - delete[] _currentSlab; - _currentSlab = _ptr = nullptr; + // Otherwise write the whole data + 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 + for (byte_t* slab : _slabs) { + delete[] slab; } + _slabs.clear(); + + // Delete active slab (if it exists) + if (_currentSlab != nullptr) + delete[] _currentSlab; + _currentSlab = _ptr = nullptr; } - } -} + } // namespace internal +} // namespace compiler +} // namespace ink diff --git a/inkcpp_compiler/json_compiler.cpp b/inkcpp_compiler/json_compiler.cpp index d7c7dc82..e3c8632e 100644 --- a/inkcpp_compiler/json_compiler.cpp +++ b/inkcpp_compiler/json_compiler.cpp @@ -58,7 +58,7 @@ void json_compiler::compile( struct container_meta { std::string name; - container_t indexToReturn = ~0; + container_t indexToReturn = ~0U; bool recordInContainerMap = false; vector deferred; CommandFlag cmd_flags = CommandFlag::NO_FLAGS; @@ -247,7 +247,7 @@ void json_compiler::compile_container( // Write end container marker, End pointer should point to End command (form symetry with START // command) - if (meta.indexToReturn != ~0) + if (meta.indexToReturn != ~0U) _emitter->write(Command::END_CONTAINER_MARKER, meta.indexToReturn, meta.cmd_flags); // Record end position in map @@ -412,7 +412,8 @@ void json_compiler::compile_complex_command(const nlohmann::json& command) else if (get(command, "#", val)) { if (_ink_version > 20) { - ink_exception("with inkVerison 21 the tag system chages, and the '#: ' is deprecated now" + throw ink_exception( + "with inkVerison 21 the tag system chages, and the '#: ' is deprecated now" ); } _emitter->write_string(Command::TAG, CommandFlag::NO_FLAGS, val); diff --git a/inkcpp_test/Callstack.cpp b/inkcpp_test/Callstack.cpp index 23edb36f..4dbeef80 100644 --- a/inkcpp_test/Callstack.cpp +++ b/inkcpp_test/Callstack.cpp @@ -12,7 +12,8 @@ const hash_t X = ink::hash_string("X"); const hash_t Y = ink::hash_string("Y"); const hash_t Z = ink::hash_string("Z"); -value operator "" _v(unsigned long long i) { +value operator""_v(unsigned long long i) +{ return value{}.set(static_cast(i)); } @@ -157,10 +158,7 @@ SCENARIO("threading with the callstack", "[callstack]") stack.push_frame(555, false); stack.complete_thread(thread); - THEN("there should be no frames on the stack") - { - REQUIRE(stack.has_frame() == false); - } + THEN("there should be no frames on the stack") { REQUIRE(stack.has_frame() == false); } } } @@ -189,8 +187,8 @@ SCENARIO("threading with the callstack", "[callstack]") WHEN("that thread does a tunnel return") { frame_type type; - auto offset = stack.pop_frame(&type, eval_mode); - + auto offset = stack.pop_frame(&type, eval_mode); + THEN("that thread should be outside the tunnel") { REQUIRE(type == frame_type::tunnel); @@ -228,7 +226,7 @@ SCENARIO("threading with the callstack", "[callstack]") WHEN("we do a tunnel return") { frame_type type; - auto offset = stack.pop_frame(&type, eval_mode); + auto offset = stack.pop_frame(&type, eval_mode); THEN("we should be back outside") { @@ -247,7 +245,7 @@ SCENARIO("threading with the callstack", "[callstack]") { stack.complete_thread(thread); frame_type type; - auto offset = stack.pop_frame(&type, eval_mode); + stack.pop_frame(&type, eval_mode); THEN("we should be outside the tunnel") { @@ -274,7 +272,7 @@ SCENARIO("threading with the callstack", "[callstack]") { // Create the stack auto stack = ink::runtime::internal::stack<50>(); - + // Create the thread thread_t thread = stack.fork_thread(); @@ -365,7 +363,7 @@ SCENARIO("threading with the callstack", "[callstack]") WHEN("we then try to pop both frames") { frame_type _ignore; - bool eval_mode; + bool eval_mode; stack.pop_frame(&_ignore, eval_mode); stack.pop_frame(&_ignore, eval_mode); diff --git a/inkcpp_test/EmptyStringForDivert.cpp b/inkcpp_test/EmptyStringForDivert.cpp index 341f0754..cd40b0cb 100644 --- a/inkcpp_test/EmptyStringForDivert.cpp +++ b/inkcpp_test/EmptyStringForDivert.cpp @@ -12,8 +12,8 @@ SCENARIO("a story with a white space infront of an conditional Divert", "[Output // based on https://github.com/JBenda/inkcpp/issues/71 GIVEN("A story") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "EmptyStringForDivert.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "EmptyStringForDivert.bin")}; + runner thread = ink->new_runner(); WHEN("run") { diff --git a/inkcpp_test/ExternalFunctionsExecuteProperly.cpp b/inkcpp_test/ExternalFunctionsExecuteProperly.cpp index 747c8fde..57ed8a78 100644 --- a/inkcpp_test/ExternalFunctionsExecuteProperly.cpp +++ b/inkcpp_test/ExternalFunctionsExecuteProperly.cpp @@ -12,8 +12,9 @@ SCENARIO("a story with an external function evaluates the function at the right { GIVEN("a story with an external function") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "ExternalFunctionsExecuteProperly.bin"); - auto thread = ink->new_runner().cast(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR + "ExternalFunctionsExecuteProperly.bin")}; + auto thread = ink->new_runner().cast(); std::stringstream debug; thread->set_debug_enabled(&debug); diff --git a/inkcpp_test/FallbackFunction.cpp b/inkcpp_test/FallbackFunction.cpp index 35990ac1..2d18cd9d 100644 --- a/inkcpp_test/FallbackFunction.cpp +++ b/inkcpp_test/FallbackFunction.cpp @@ -14,8 +14,8 @@ SCENARIO("run a story with external function and fallback function", "[external { GIVEN("story with two external functions, one with fallback") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "FallBack.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "FallBack.bin")}; + runner thread = ink->new_runner(); WHEN("bind both external functions") { diff --git a/inkcpp_test/Fixes.cpp b/inkcpp_test/Fixes.cpp index 33134408..7c5209c7 100644 --- a/inkcpp_test/Fixes.cpp +++ b/inkcpp_test/Fixes.cpp @@ -1,5 +1,6 @@ #include "catch.hpp" -#include "system.h" +#include "snapshot.h" +#include "../snapshot_impl.h" #include #include @@ -15,9 +16,9 @@ SCENARIO("string_table fill up #97", "[fixes]") { GIVEN("story murder_scene") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "murder_scene.bin"); - globals globStore = ink->new_globals(); - runner main = ink->new_runner(globStore); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "murder_scene.bin")}; + globals globStore = ink->new_globals(); + runner main = ink->new_runner(globStore); WHEN("Run first choice 50 times") { @@ -62,10 +63,10 @@ SCENARIO("unknown command _ #109", "[fixes]") for (size_t i = 0; i < out_str.size(); ++i) { data[i] = out_str[i]; } - auto ink = story::from_binary(data, out_str.size()); - globals globStore = ink->new_globals(); - runner main = ink->new_runner(globStore); - std::string story = main->getall(); + std::unique_ptr ink{story::from_binary(data, out_str.size())}; + globals globStore = ink->new_globals(); + runner main = ink->new_runner(globStore); + std::string story = main->getall(); THEN("expect correct output") { REQUIRE(res.warnings.size() == 0); @@ -87,16 +88,16 @@ SCENARIO("snapshot failed inside execution _ #111", "[fixes]") { GIVEN("story with multiline output with a knot") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "111_crash.bin"); - auto ink2 = story::from_file(INK_TEST_RESOURCE_DIR "111_crash.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "111_crash.bin")}; + std::unique_ptr ink2{story::from_file(INK_TEST_RESOURCE_DIR "111_crash.bin")}; + runner thread = ink->new_runner(); WHEN("run store and reload") { auto line = thread->getline(); THEN("outputs first line") { REQUIRE(line == "First line of text\n"); } - auto snapshot = thread->create_snapshot(); - runner thread2 = ink2->new_runner_from_snapshot(*snapshot); - line = thread->getline(); + std::unique_ptr snapshot{thread->create_snapshot()}; + runner thread2 = ink2->new_runner_from_snapshot(*snapshot); + line = thread->getline(); THEN("outputs second line") { REQUIRE(line == "Second line of test\n"); } } } @@ -106,8 +107,9 @@ SCENARIO("missing leading whitespace inside choice-only text and glued text _ #1 { GIVEN("story with problematic text") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "130_131_missing_whitespace.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR + "130_131_missing_whitespace.bin")}; + runner thread = ink->new_runner(); WHEN("run story") { auto line = thread->getline(); @@ -126,3 +128,44 @@ SCENARIO("missing leading whitespace inside choice-only text and glued text _ #1 } } } + +SCENARIO( + "choice tag references are not correctly stored (as pointer instead of index) _ #116", "[fixes]" +) +{ + GIVEN("story with choice tag") + { + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR + "116_story_with_choice_tags.bin")}; + runner thread = ink->new_runner(); + WHEN("run story, store, and reload") + { + thread->getall(); + REQUIRE(thread->num_choices() == 1); + REQUIRE(thread->get_choice(0)->num_tags() == 1); + REQUIRE(thread->get_choice(0)->get_tag(0) == std::string("Type:Idle")); + std::unique_ptr snap{thread->create_snapshot()}; + THEN("snapshot loaded works") + { + runner loaded = ink->new_runner_from_snapshot(*snap); + loaded->getall(); + REQUIRE(loaded->num_choices() == 1); + REQUIRE(loaded->get_choice(0)->num_tags() == 1); + REQUIRE(loaded->get_choice(0)->get_tag(0) == std::string("Type:Idle")); + } + } + WHEN("loading a snipshot multiple times") + { + thread->getall(); + std::unique_ptr snap{thread->create_snapshot()}; + runner thread = ink->new_runner_from_snapshot(*snap); + const size_t s = reinterpret_cast(snap.get())->strings().size(); + THEN("loading it again will not change the string_table size") + { + runner thread2 = ink->new_runner_from_snapshot(*snap); + const size_t s2 = reinterpret_cast(snap.get())->strings().size(); + REQUIRE(s == s2); + } + } + } +} diff --git a/inkcpp_test/Globals.cpp b/inkcpp_test/Globals.cpp index c2a6e8a1..2a9cc3f0 100644 --- a/inkcpp_test/Globals.cpp +++ b/inkcpp_test/Globals.cpp @@ -9,13 +9,13 @@ using namespace ink::runtime; SCENARIO("run story with global variable", "[global variables]") { - GIVEN ("a story with global variables") + GIVEN("a story with global variables") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "GlobalStory.bin"); - globals globStore = ink->new_globals(); - runner thread = ink->new_runner(globStore); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "GlobalStory.bin")}; + globals globStore = ink->new_globals(); + runner thread = ink->new_runner(globStore); - WHEN( "just runs") + WHEN("just runs") { THEN("variables should contain values as in inkScript") { @@ -24,12 +24,10 @@ SCENARIO("run story with global variable", "[global variables]") REQUIRE(*globStore->get("friendly_name_of_player") == std::string{"Jackie"}); } } - WHEN ("edit number") + WHEN("edit number") { - bool resi - = globStore->set("age", 30); - bool resc - = globStore->set("friendly_name_of_player", "Freddy"); + bool resi = globStore->set("age", 30); + bool resc = globStore->set("friendly_name_of_player", "Freddy"); THEN("execution should success") { REQUIRE(resi == true); @@ -41,7 +39,7 @@ SCENARIO("run story with global variable", "[global variables]") REQUIRE(*globStore->get("age") == 30); REQUIRE(*globStore->get("friendly_name_of_player") == std::string{"Freddy"}); } - WHEN ("something added to string") + WHEN("something added to string") { // concat in GlobalsStory.ink thread->getall(); @@ -51,9 +49,9 @@ SCENARIO("run story with global variable", "[global variables]") } } } - WHEN ("name or type not exist") + WHEN("name or type not exist") { - auto wrongType = globStore->get("age"); + auto wrongType = globStore->get("age"); auto notExistingName = globStore->get("foo"); THEN("should return nullptr") { diff --git a/inkcpp_test/InkyJson.cpp b/inkcpp_test/InkyJson.cpp index 1de37df4..f97ab32e 100644 --- a/inkcpp_test/InkyJson.cpp +++ b/inkcpp_test/InkyJson.cpp @@ -19,8 +19,8 @@ SCENARIO("run inklecate 1.1.1 story") { auto input_file = std::string(INK_TEST_RESOURCE_DIR "simple-1.1.1-") + compiler + ".json"; ink::compiler::run(input_file.c_str(), "simple.bin"); - auto ink = story::from_file("simple.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file("simple.bin")}; + runner thread = ink->new_runner(); THEN("Expect normal output") { diff --git a/inkcpp_test/LabelCondition.cpp b/inkcpp_test/LabelCondition.cpp index 3b6744d6..77737741 100644 --- a/inkcpp_test/LabelCondition.cpp +++ b/inkcpp_test/LabelCondition.cpp @@ -8,52 +8,52 @@ using namespace ink::runtime; -SCENARIO( "run story with hidden choice" ) +SCENARIO("run story with hidden choice") { GIVEN("a story with choice visible by second visit") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "LabelConditionStory.bin"); - globals globals = ink->new_globals(); - runner thread = ink->new_runner( globals ); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "LabelConditionStory.bin")}; + globals globals = ink->new_globals(); + runner thread = ink->new_runner(globals); - WHEN( "normal run" ) + WHEN("normal run") { std::string out = thread->getall(); - REQUIRE( thread->num_choices() == 1 ); - std::string choice1a = thread->get_choice( 0 )->text(); - thread->choose( 0 ); + REQUIRE(thread->num_choices() == 1); + std::string choice1a = thread->get_choice(0)->text(); + thread->choose(0); std::string out2 = thread->getall(); - REQUIRE( thread->num_choices() == 1 ); - std::string choice2a = thread->get_choice( 0 )->text(); + REQUIRE(thread->num_choices() == 1); + std::string choice2a = thread->get_choice(0)->text(); - THEN( "second choice keeps hidden" ) + THEN("second choice keeps hidden") { - REQUIRE( out == "" ); - REQUIRE( choice1a == "labeled choice" ); - REQUIRE( out2 == "" ); - REQUIRE( choice2a == "labeled choice" ); + REQUIRE(out == ""); + REQUIRE(choice1a == "labeled choice"); + REQUIRE(out2 == ""); + REQUIRE(choice2a == "labeled choice"); } } - WHEN( "set global variable to enable hidden choice" ) + WHEN("set global variable to enable hidden choice") { - globals->set( "bool_variable", false ); + globals->set("bool_variable", false); std::string out = thread->getall(); - REQUIRE( thread->num_choices() == 1 ); - std::string choice1a = thread->get_choice( 0 )->text(); - thread->choose( 0 ); + REQUIRE(thread->num_choices() == 1); + std::string choice1a = thread->get_choice(0)->text(); + thread->choose(0); std::string out2 = thread->getall(); - REQUIRE( thread->num_choices() == 2 ); - std::string choice2a = thread->get_choice( 0 )->text(); - std::string choice2b = thread->get_choice( 1 )->text(); + REQUIRE(thread->num_choices() == 2); + std::string choice2a = thread->get_choice(0)->text(); + std::string choice2b = thread->get_choice(1)->text(); - THEN( "second choice is visible" ) + THEN("second choice is visible") { - REQUIRE( out == "" ); - REQUIRE( choice1a == "labeled choice" ); - REQUIRE( out2 == "" ); - REQUIRE( choice2a == "labeled choice" ); - REQUIRE( choice2b == "hidden choice" ); + REQUIRE(out == ""); + REQUIRE(choice1a == "labeled choice"); + REQUIRE(out2 == ""); + REQUIRE(choice2a == "labeled choice"); + REQUIRE(choice2b == "hidden choice"); } } } diff --git a/inkcpp_test/Lists.cpp b/inkcpp_test/Lists.cpp index 51be2d8a..d5c86526 100644 --- a/inkcpp_test/Lists.cpp +++ b/inkcpp_test/Lists.cpp @@ -14,8 +14,8 @@ SCENARIO("List logic operations", "[lists]") { GIVEN("a demo story") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "ListLogicStory.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "ListLogicStory.bin")}; + runner thread = ink->new_runner(); WHEN("just run") { std::string out = thread->getall(); @@ -45,17 +45,18 @@ Hey } } } + SCENARIO("run a story with lists", "[lists]") { GIVEN("a story with multi lists") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "ListStory.bin"); - globals globals = ink->new_globals(); - runner thread = ink->new_runner(globals); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "ListStory.bin")}; + globals globals = ink->new_globals(); + runner thread = ink->new_runner(globals); WHEN("just run") { - std::string out = thread->getall(); + std::string out = thread->getall(); std::string choice1 = thread->get_choice(0)->text(); thread->choose(0); std::string out2 = thread->getall(); @@ -72,8 +73,8 @@ SCENARIO("run a story with lists", "[lists]") std::string out = thread->getall(); std::string choice1 = thread->get_choice(0)->text(); thread->choose(0); - - list l1 = *globals->get("list"); + auto x = globals->get("list"); + list l1 = x.value(); l1->add("animals.dog"); l1->remove("colors.red"); REQUIRE(globals->set("list", l1)); @@ -88,7 +89,7 @@ SCENARIO("run a story with lists", "[lists]") WHEN("modify") { - std::string out = thread->getall(); + std::string out = thread->getall(); std::string choice1 = thread->get_choice(0)->text(); thread->choose(0); @@ -130,13 +131,14 @@ SCENARIO("run a story with lists", "[lists]") THEN("should iterate all contained flags") { l1 = *globals->get("list"); - for(auto flag : *l1) { + for (auto flag : *l1) { INFO(flag); - REQUIRE((strcmp(flag.list_name, "colors")==0 || strcmp(flag.list_name, "animals") == 0)); - REQUIRE((strcmp(flag.flag_name, "bird") == 0 - || strcmp(flag.flag_name, "dog") == 0 - || strcmp(flag.flag_name, "yellow") == 0 - )); + REQUIRE((strcmp(flag.list_name, "colors") == 0 || strcmp(flag.list_name, "animals") == 0) + ); + REQUIRE( + (strcmp(flag.flag_name, "bird") == 0 || strcmp(flag.flag_name, "dog") == 0 + || strcmp(flag.flag_name, "yellow") == 0) + ); } } } diff --git a/inkcpp_test/LookaheadSafe.cpp b/inkcpp_test/LookaheadSafe.cpp index 7ae878e0..1dd5c1db 100644 --- a/inkcpp_test/LookaheadSafe.cpp +++ b/inkcpp_test/LookaheadSafe.cpp @@ -12,7 +12,7 @@ SCENARIO("a story with external functions and glue", "[external]") { GIVEN("the story") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "LookaheadSafe.bin"); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "LookaheadSafe.bin")}; int cnt = 0; auto foo = [&cnt]() { diff --git a/inkcpp_test/MoveTo.cpp b/inkcpp_test/MoveTo.cpp index 87803bf3..fa3c3f2b 100644 --- a/inkcpp_test/MoveTo.cpp +++ b/inkcpp_test/MoveTo.cpp @@ -12,10 +12,10 @@ SCENARIO("run a story, but jump around manually", "[move_to]") { GIVEN("a story with side talking points") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "MoveTo.bin"); - globals globStore = ink->new_globals(); - runner main = ink->new_runner(globStore); - runner side = ink->new_runner(globStore); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "MoveTo.bin")}; + globals globStore = ink->new_globals(); + runner main = ink->new_runner(globStore); + runner side = ink->new_runner(globStore); WHEN("just run main story") { diff --git a/inkcpp_test/NewLines.cpp b/inkcpp_test/NewLines.cpp index 35350ba9..fb3664a6 100644 --- a/inkcpp_test/NewLines.cpp +++ b/inkcpp_test/NewLines.cpp @@ -7,8 +7,8 @@ using namespace ink::runtime; -auto lines_ink = story::from_file(INK_TEST_RESOURCE_DIR "LinesStory.bin"); -runner lines_thread = lines_ink->new_runner(); +std::unique_ptr lines_ink{story::from_file(INK_TEST_RESOURCE_DIR "LinesStory.bin")}; +runner lines_thread = lines_ink->new_runner(); SCENARIO("a story has the proper line breaks", "[lines]") { @@ -52,8 +52,8 @@ SCENARIO("a story has the proper line breaks", "[lines]") } GIVEN("a complex story") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "TheIntercept.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "TheIntercept.bin")}; + runner thread = ink->new_runner(); // based on issue #82 WHEN("run sequence 1 3 3 3 2 3") { diff --git a/inkcpp_test/NoEarlyTags.cpp b/inkcpp_test/NoEarlyTags.cpp index 5ca5cf3a..16ab40f3 100644 --- a/inkcpp_test/NoEarlyTags.cpp +++ b/inkcpp_test/NoEarlyTags.cpp @@ -7,8 +7,8 @@ using namespace ink::runtime; -auto tg_ink = story::from_file(INK_TEST_RESOURCE_DIR "NoEarlyTags.bin"); -auto tg_thread = tg_ink->new_runner(); +std::unique_ptr tg_ink{story::from_file(INK_TEST_RESOURCE_DIR "NoEarlyTags.bin")}; +auto tg_thread = tg_ink->new_runner(); SCENARIO("Story with tags and glues", "[tags][glue]") { diff --git a/inkcpp_test/Observer.cpp b/inkcpp_test/Observer.cpp index 77286fe4..234bb817 100644 --- a/inkcpp_test/Observer.cpp +++ b/inkcpp_test/Observer.cpp @@ -1,6 +1,7 @@ #include "catch.hpp" +#include "system.h" +#include "../runner_impl.h" -#include <../runner_impl.h> #include #include #include @@ -13,9 +14,9 @@ SCENARIO("Observer", "[variables][observer]") { GIVEN("a story which changes variables") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "ObserverStory.bin"); - auto globals = ink->new_globals(); - auto thread = ink->new_runner(globals).cast(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "ObserverStory.bin")}; + auto globals = ink->new_globals(); + auto thread = ink->new_runner(globals).cast(); std::stringstream debug; thread->set_debug_enabled(&debug); @@ -101,9 +102,9 @@ SCENARIO("Observer", "[variables][observer]") } WHEN("Run with missmatching type") { - auto var1 = [](uint32_t i) { + auto var1 = [](uint32_t) { }; - CHECK_THROWS(globals->observe("var1", var1)); + CHECK_THROWS_AS(globals->observe("var1", var1), ink::ink_exception); } WHEN("Just get pinged") { diff --git a/inkcpp_test/Restorable.cpp b/inkcpp_test/Restorable.cpp index 2da96f97..5cb43c6c 100644 --- a/inkcpp_test/Restorable.cpp +++ b/inkcpp_test/Restorable.cpp @@ -10,11 +10,13 @@ SCENARIO("a restorable collection can operate like a stack", "[restorable]") { // Create the collection constexpr size_t size = 128; - int buffer[size]; - auto collection = restorable(buffer, size); + int buffer[size]; + auto collection = restorable(buffer, size); // Lambdas - auto isNull = [](const int&) { return false; }; + auto isNull = [](const int&) { + return false; + }; THEN("it should have zero size") REQUIRE(collection.size(isNull) == 0); @@ -56,29 +58,37 @@ void VerifyStack(restorable& stack, const std::vector& expected) { THEN("it should match the expected array in both directions") { - auto isNull = [](const int& e) { return e == -1; }; + auto isNull = [](const int& e) { + return e == -1; + }; // Check REQUIRE(stack.size(isNull) == expected.size()); // Iterate and make sure each element matches int counter = 0; - stack.for_each([&counter, expected](const int& elem) { - REQUIRE(counter < expected.size()); - REQUIRE(counter >= 0); - REQUIRE(expected[counter] == elem); - counter++; - }, isNull); + stack.for_each( + [&counter, expected](const int& elem) { + REQUIRE(counter < static_cast(expected.size())); + REQUIRE(counter >= 0); + REQUIRE(expected[counter] == elem); + counter++; + }, + isNull + ); // Make sure we hit every element in the expected vector - REQUIRE(counter == expected.size()); + REQUIRE(counter == static_cast(expected.size())); // Try the other direction - stack.reverse_for_each([&counter, expected](const int& elem) { - counter--; - REQUIRE(counter >= 0); - REQUIRE(expected[counter] == elem); - }, isNull); + stack.reverse_for_each( + [&counter, expected](const int& elem) { + counter--; + REQUIRE(counter >= 0); + REQUIRE(expected[counter] == elem); + }, + isNull + ); REQUIRE(counter == 0); } } @@ -96,7 +106,10 @@ void RestoreAndVerifyStack(restorable& stack, const std::vector -void ForgetAndVerifyStack(restorable& stack, const std::vector& expected, NullifyCallback nullify) +void ForgetAndVerifyStack( + restorable& stack, const std::vector& expected, + NullifyCallback nullify +) { WHEN("the save state is forgotten") { @@ -111,19 +124,19 @@ SCENARIO("a collection can be restored no matter how many times you push or pop" { // Create the collection constexpr size_t size = 128; - int buffer[size]; - auto collection = restorable(buffer, size); + int buffer[size]; + auto collection = restorable(buffer, size); // Lambdas (we'll use negative one for null) - auto isNull = [](const int& elem) { return elem == -1; }; - auto nullify = [](int& elem) { elem = -1; }; + auto isNull = [](const int& elem) { + return elem == -1; + }; GIVEN("a stack with five items that has been saved") { // Create five elements std::vector expected; - for (int i = 0; i < 5; i++) - { + for (int i = 0; i < 5; i++) { collection.push(i); expected.push_back(i); } @@ -140,7 +153,7 @@ SCENARIO("a collection can be restored no matter how many times you push or pop" WHEN("elements are popped") { - collection.pop(isNull); + collection.pop(isNull); collection.pop(isNull); RestoreAndVerifyStack(collection, expected); } @@ -165,8 +178,9 @@ SCENARIO("a collection can be restored no matter how many times you push or pop" THEN("More are pushed") { - collection.push(100); collection.push(200); - VerifyStack(collection, { 100, 200 }); + collection.push(100); + collection.push(200); + VerifyStack(collection, {100, 200}); } } } @@ -176,19 +190,19 @@ SCENARIO("saving does not disrupt iteration", "[restorable]") { // Create the collection constexpr size_t size = 128; - int buffer[size]; - auto collection = restorable(buffer, size); + int buffer[size]; + auto collection = restorable(buffer, size); // Lambdas (we'll use negative one for null) - auto isNull = [](const int& elem) { return elem == -1; }; - auto nullify = [](int& elem) { elem = -1; }; + auto isNull = [](const int& elem) { + return elem == -1; + }; GIVEN("a stack with five items that has been saved") { // Create five elements std::vector expected; - for (int i = 0; i < 5; i++) - { + for (int i = 0; i < 5; i++) { collection.push(i); expected.push_back(i); } @@ -198,24 +212,32 @@ SCENARIO("saving does not disrupt iteration", "[restorable]") WHEN("elements are pushed") { - collection.push(10); expected.push_back(10); - collection.push(20); expected.push_back(20); + collection.push(10); + expected.push_back(10); + collection.push(20); + expected.push_back(20); VerifyStack(collection, expected); } WHEN("elements are popped") { - collection.pop(isNull); expected.pop_back(); - collection.pop(isNull); expected.pop_back(); + collection.pop(isNull); + expected.pop_back(); + collection.pop(isNull); + expected.pop_back(); VerifyStack(collection, expected); } WHEN("elements are popped and pushed") { - collection.pop(isNull); expected.pop_back(); - collection.pop(isNull); expected.pop_back(); - collection.push(10); expected.push_back(10); - collection.push(20); expected.push_back(20); + collection.pop(isNull); + expected.pop_back(); + collection.pop(isNull); + expected.pop_back(); + collection.push(10); + expected.push_back(10); + collection.push(20); + expected.push_back(20); VerifyStack(collection, expected); } } @@ -227,17 +249,23 @@ SCENARIO("saving does not disrupt iteration", "[restorable]") WHEN("elements are pushed") { - collection.push(10); expected.push_back(10); - collection.push(20); expected.push_back(20); + collection.push(10); + expected.push_back(10); + collection.push(20); + expected.push_back(20); VerifyStack(collection, expected); } WHEN("elements are pushed then popped") { - collection.push(10); expected.push_back(10); - collection.push(20); expected.push_back(20); - collection.pop(isNull); expected.pop_back(); - collection.pop(isNull); expected.pop_back(); + collection.push(10); + expected.push_back(10); + collection.push(20); + expected.push_back(20); + collection.pop(isNull); + expected.pop_back(); + collection.pop(isNull); + expected.pop_back(); VerifyStack(collection, expected); } } @@ -247,19 +275,22 @@ SCENARIO("save points can be forgotten", "[restorable]") { // Create the collection constexpr size_t size = 128; - int buffer[size]; - auto collection = restorable(buffer, size); + int buffer[size]; + auto collection = restorable(buffer, size); // Lambdas (we'll use negative one for null) - auto isNull = [](const int& elem) { return elem == -1; }; - auto nullify = [](int& elem) { elem = -1; }; + auto isNull = [](const int& elem) { + return elem == -1; + }; + auto nullify = [](int& elem) { + elem = -1; + }; GIVEN("a stack with five items that has been saved") { // Create five elements std::vector expected; - for (int i = 0; i < 5; i++) - { + for (int i = 0; i < 5; i++) { collection.push(i); expected.push_back(i); } @@ -269,25 +300,34 @@ SCENARIO("save points can be forgotten", "[restorable]") WHEN("elements are pushed") { - collection.push(10); expected.push_back(10); - collection.push(20); expected.push_back(20); + collection.push(10); + expected.push_back(10); + collection.push(20); + expected.push_back(20); ForgetAndVerifyStack(collection, expected, nullify); } WHEN("elements are popped") { - collection.pop(isNull); expected.pop_back(); - collection.pop(isNull); expected.pop_back(); + collection.pop(isNull); + expected.pop_back(); + collection.pop(isNull); + expected.pop_back(); ForgetAndVerifyStack(collection, expected, nullify); } WHEN("elements are popped and pushed") { - collection.pop(isNull); expected.pop_back(); - collection.pop(isNull); expected.pop_back(); - collection.push(10); expected.push_back(10); - collection.push(20); expected.push_back(20); - collection.push(30); expected.push_back(30); + collection.pop(isNull); + expected.pop_back(); + collection.pop(isNull); + expected.pop_back(); + collection.push(10); + expected.push_back(10); + collection.push(20); + expected.push_back(20); + collection.push(30); + expected.push_back(30); ForgetAndVerifyStack(collection, expected, nullify); } } diff --git a/inkcpp_test/SpaceAfterBracketChoice.cpp b/inkcpp_test/SpaceAfterBracketChoice.cpp index b11cb2e6..c4e692c6 100644 --- a/inkcpp_test/SpaceAfterBracketChoice.cpp +++ b/inkcpp_test/SpaceAfterBracketChoice.cpp @@ -11,8 +11,8 @@ SCENARIO("a story with bracketed choices and spaces can choose correctly", "[cho { GIVEN("a story with line breaks") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "ChoiceBracketStory.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "ChoiceBracketStory.bin")}; + runner thread = ink->new_runner(); thread->getall(); WHEN("start thread") { @@ -35,10 +35,7 @@ SCENARIO("a story with bracketed choices and spaces can choose correctly", "[cho { thread->choose(1); thread->getall(); - THEN("still has choices") - { - REQUIRE(thread->has_choices()); - } + THEN("still has choices") { REQUIRE(thread->has_choices()); } } } } diff --git a/inkcpp_test/Tags.cpp b/inkcpp_test/Tags.cpp index e30a5d1c..17ffb06d 100644 --- a/inkcpp_test/Tags.cpp +++ b/inkcpp_test/Tags.cpp @@ -12,10 +12,10 @@ using namespace ink::runtime; SCENARIO("tags", "[ahf]") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "AHF.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR "AHF.bin")}; + runner thread = ink->new_runner(); thread->move_to(ink::hash_string("test_knot")); - while(thread->can_continue()) { + while (thread->can_continue()) { auto line = thread->getline(); } REQUIRE(thread->can_continue() == false); @@ -25,8 +25,8 @@ SCENARIO("run story with tags", "[tags][story]") { GIVEN("a story with tags") { - story* _ink = story::from_file(INK_TEST_RESOURCE_DIR "TagsStory.bin"); - runner _thread = _ink->new_runner(); + std::unique_ptr _ink{story::from_file(INK_TEST_RESOURCE_DIR "TagsStory.bin")}; + runner _thread = _ink->new_runner(); WHEN("starting the thread") { CHECK_FALSE(_thread->has_tags()); diff --git a/inkcpp_test/ThirdTierChoiceAfterBrackets.cpp b/inkcpp_test/ThirdTierChoiceAfterBrackets.cpp index 5aeef107..207baae1 100644 --- a/inkcpp_test/ThirdTierChoiceAfterBrackets.cpp +++ b/inkcpp_test/ThirdTierChoiceAfterBrackets.cpp @@ -14,8 +14,9 @@ SCENARIO( { GIVEN("a story with brackets and nested choices") { - auto ink = story::from_file(INK_TEST_RESOURCE_DIR "ThirdTierChoiceAfterBracketsStory.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file(INK_TEST_RESOURCE_DIR + "ThirdTierChoiceAfterBracketsStory.bin")}; + runner thread = ink->new_runner(); WHEN("start thread") { diff --git a/inkcpp_test/UTF8.cpp b/inkcpp_test/UTF8.cpp index 1a03c55d..31fe6091 100644 --- a/inkcpp_test/UTF8.cpp +++ b/inkcpp_test/UTF8.cpp @@ -14,39 +14,43 @@ SCENARIO("a story supports UTF-8", "[utf-8]") GIVEN("a story with UTF8 characters") { ink::compiler::run(INK_TEST_RESOURCE_DIR "UTF8Story.ink.json", "UTF8Story.bin"); - auto ink = story::from_file("UTF8Story.bin"); - runner thread = ink->new_runner(); + std::unique_ptr ink{story::from_file("UTF8Story.bin")}; + runner thread = ink->new_runner(); std::ifstream demoFile("ink/UTF-8-demo.txt"); - if (!demoFile.is_open()) { + if (! demoFile.is_open()) { throw std::runtime_error("cannot open UTF-8 demo file"); } - char byte; + char byte; std::stringstream demo; std::stringstream current; while (demoFile.get(byte)) { - if (byte == '\r') continue; // skip windows carriage-return newlines + if (byte == '\r') + continue; // skip windows carriage-return newlines else if (byte == '\n' || byte == 0) { // newline or null byte std::string s = current.str(); - if (s.empty()) continue; + if (s.empty()) + continue; demo << s << '\n'; current.str(""); - } - else { // normal char + } else { // normal char current << byte; } } std::string s = current.str(); - if (!s.empty()) demo << s << '\n'; - + if (! s.empty()) + demo << s << '\n'; + - WHEN("consume lines") { + WHEN("consume lines") + { std::stringstream content; while (thread->can_continue()) { content << thread->getline(); } - THEN("lines match test file") { + THEN("lines match test file") + { std::string c = content.str(); std::string d = demo.str(); REQUIRE(c == d); diff --git a/inkcpp_test/ink/116_story_with_choice_tags.ink b/inkcpp_test/ink/116_story_with_choice_tags.ink new file mode 100644 index 00000000..0d649927 --- /dev/null +++ b/inkcpp_test/ink/116_story_with_choice_tags.ink @@ -0,0 +1,5 @@ +-> Entrance_cycle += Entrance_cycle ++ (look_around) [look around # Type:Idle ] + While watching around you, <> + -> Entrance_cycle diff --git a/shared/private/header.h b/shared/private/header.h index aac8a541..81e151d1 100644 --- a/shared/private/header.h +++ b/shared/private/header.h @@ -8,39 +8,43 @@ #include "system.h" -namespace ink::internal { +namespace ink::internal +{ - struct header { - static header parse_header(const char* data); +struct header { + static header parse_header(const char* data); - template - static T swap_bytes(const T& value) { - char data[sizeof(T)]; - for (int i = 0; i < sizeof(T); ++i) { - data[i] = reinterpret_cast(&value)[sizeof(T)-1-i]; - } - return *reinterpret_cast(data); - } - list_flag read_list_flag(const char*& ptr) const { - list_flag result = *reinterpret_cast(ptr); - ptr += sizeof(list_flag); - if (endien == ink::internal::header::endian_types::differ) { - result.flag = swap_bytes(result.flag); - result.list_id = swap_bytes(result.list_id); - } - return result; - } + template + static T swap_bytes(const T& value) + { + char data[sizeof(T)]; + for (size_t i = 0; i < sizeof(T); ++i) { + data[i] = reinterpret_cast(&value)[sizeof(T) - 1 - i]; + } + return *reinterpret_cast(data); + } - enum class endian_types: uint16_t { - none = 0, - same = 0x0001, - differ = 0x0100 - } endien = endian_types::none; - uint32_t ink_version_number = 0; - uint32_t ink_bin_version_number = 0; - static constexpr size_t Size = ///< actual data size of Header, - /// because padding of struct may - /// differ between platforms - sizeof(uint16_t) + 2 * sizeof(uint32_t); - }; -} + list_flag read_list_flag(const char*& ptr) const + { + list_flag result = *reinterpret_cast(ptr); + ptr += sizeof(list_flag); + if (endien == ink::internal::header::endian_types::differ) { + result.flag = swap_bytes(result.flag); + result.list_id = swap_bytes(result.list_id); + } + return result; + } + + enum class endian_types : uint16_t { + none = 0, + same = 0x0001, + differ = 0x0100 + } endien = endian_types::none; + uint32_t ink_version_number = 0; + uint32_t ink_bin_version_number = 0; + static constexpr size_t Size = ///< actual data size of Header, + /// because padding of struct may + /// differ between platforms + sizeof(uint16_t) + 2 * sizeof(uint32_t); +}; +} // namespace ink::internal diff --git a/shared/public/config.h b/shared/public/config.h index 4bb0877f..c89fff51 100644 --- a/shared/public/config.h +++ b/shared/public/config.h @@ -8,7 +8,7 @@ #ifdef INKCPP_API # define INK_ENABLE_UNREAL -#elif INKCPP_BUILD_CLIB +#elif defined(INKCPP_BUILD_CLIB) # define INK_ENABLE_CSTD #else # define INK_ENABLE_STL diff --git a/shared/public/system.h b/shared/public/system.h index d1b70816..7b996272 100644 --- a/shared/public/system.h +++ b/shared/public/system.h @@ -97,8 +97,16 @@ constexpr list_flag empty_flag{-1, 0}; namespace internal { +#ifdef __GNUC__ +#else +# pragma warning(push) +# pragma warning( \ + disable : 4514, \ + justification : "functions are defined in header file, they do not need to be used." \ + ) +#endif /** Checks if a string starts with a given prefix*/ - static bool starts_with(const char* string, const char* prefix) + static inline constexpr bool starts_with(const char* string, const char* prefix) { while (*prefix) { if (*string != *prefix) { @@ -111,7 +119,7 @@ namespace internal } /** Checks if a string is only whitespace*/ - static bool is_whitespace(const char* string, bool includeNewline = true) + static inline constexpr bool is_whitespace(const char* string, bool includeNewline = true) { // Iterate string while (true) { @@ -120,6 +128,7 @@ namespace internal case '\n': if (! includeNewline) return false; + [[fallthrough]]; case '\t': [[fallthrough]]; case ' ': continue; default: return false; @@ -130,9 +139,12 @@ namespace internal /** check if character can be only part of a word, when two part of word characters put together * the will be a space inserted I049 */ - inline bool is_part_of_word(char character) { return isalpha(character) || isdigit(character); } + static inline bool is_part_of_word(char character) + { + return isalpha(character) || isdigit(character); + } - inline constexpr bool is_whitespace(char character, bool includeNewline = true) + static inline constexpr bool is_whitespace(char character, bool includeNewline = true) { switch (character) { case '\n': @@ -148,6 +160,10 @@ namespace internal /** populate memory with Zero */ void zero_memory(void* buffer, size_t length); #endif +#ifdef __GNUC__ +#else +# pragma warning(pop) +#endif } // namespace internal #ifdef INK_ENABLE_STL @@ -201,7 +217,7 @@ template namespace runtime::internal { - constexpr unsigned abs(int i) { return i < 0 ? -i : i; } + constexpr unsigned abs(int i) { return static_cast(i < 0 ? -i : i); } template struct always_false { diff --git a/unreal/UE_example.ink b/unreal/UE_example.ink index 77cc9e9c..14ff0249 100644 --- a/unreal/UE_example.ink +++ b/unreal/UE_example.ink @@ -1,3 +1,4 @@ +# date:2025.03.22 LIST Potions = TalkWithAnimals, Invisibility LIST Clues = Skull, Feather VAR Inventory = (Skull, TalkWithAnimals) @@ -51,28 +52,31 @@ You startk walking to {to}. -> END === Faint +# background:Unconscious You collapse, the next thing you can remember is how you are given to the ambulance. No further action for today ... -> DONE === Mansion = Car +# background:Car You step outside your car. Its a wired feeling beehing here again. -> Car_cycle = Car_cycle -+ (look_around)[look around] - It is a strange day. Despite it beeing spring, the sky is one massive gray soup. ++ (look_around)[look around # Type:Idle] + It is a strange day. Despite it beeing spring, the sky is one massive gray soup. # style:Gray -> Car_cycle + [go to the mension] ~ walking("Mansion.Entrance") -> Entrance = Entrance +# background:Mansion {not Mansion.look_around: Just in time you are able to see the door, someone with with a yellow summer dress enters it.} You climbing the 56 steps up to the door, high water is a dump thing. -> Entrance_cycle = Entrance_cycle -+ (look_around) [look around] ++ (look_around) [look around # Type:Idle ] While watching around you, <> {Inventory hasnt Invisibility: see a small bottle in the Pot next to the door. @@ -82,11 +86,11 @@ You climbing the 56 steps up to the door, high water is a dump thing. -> Entrance_cycle * {look_around} [Pick up the bottle] ~ Inventory += Invisibility - You pick up the bottle and inspect it more. It is labeld "Invisible", just this one word written with and edding. + You pick up the bottle and inspect it more. It is labeld "Invisible, just this one word written with and edding. -> Entrance_cycle -+ [Knock] - "Ahh", you cry while reaching for the door bell. Saying it was charched would be an understatement. ++ (knock)[Knock {knock: again?} # {knock: Type:Danger} ] + "Ahh", you cry while reaching for the door bell. Saying it was charched would be an understatement. ~ Health -= 20 { Health <= 0: -> Faint} -> Entrance_cycle --> DONE \ No newline at end of file +-> DONE