From e954a37fd6649bf1d9bff4669b136f02c351f977 Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Tue, 23 Jan 2024 13:07:45 +0100 Subject: core: Changed file endings in core --- modules/core/c++/array.h | 96 ------------ modules/core/c++/array.hpp | 96 ++++++++++++ modules/core/c++/buffer.cpp | 2 +- modules/core/c++/buffer.h | 199 ------------------------- modules/core/c++/buffer.hpp | 199 +++++++++++++++++++++++++ modules/core/c++/common.cpp | 2 +- modules/core/c++/common.h | 83 ----------- modules/core/c++/common.hpp | 83 +++++++++++ modules/core/c++/error.h | 288 ------------------------------------ modules/core/c++/error.hpp | 288 ++++++++++++++++++++++++++++++++++++ modules/core/c++/id.h | 54 ------- modules/core/c++/id.hpp | 54 +++++++ modules/core/c++/id_map.h | 143 ------------------ modules/core/c++/id_map.hpp | 143 ++++++++++++++++++ modules/core/c++/mcts.h | 52 ------- modules/core/c++/mcts.hpp | 52 +++++++ modules/core/c++/platonic.h | 103 ------------- modules/core/c++/platonic.hpp | 103 +++++++++++++ modules/core/c++/string_literal.h | 57 ------- modules/core/c++/string_literal.hpp | 57 +++++++ modules/core/c++/templates.h | 150 ------------------- modules/core/c++/templates.hpp | 150 +++++++++++++++++++ modules/core/c++/tree.h | 248 ------------------------------- modules/core/c++/tree.hpp | 248 +++++++++++++++++++++++++++++++ 24 files changed, 1475 insertions(+), 1475 deletions(-) delete mode 100644 modules/core/c++/array.h create mode 100644 modules/core/c++/array.hpp delete mode 100644 modules/core/c++/buffer.h create mode 100644 modules/core/c++/buffer.hpp delete mode 100644 modules/core/c++/common.h create mode 100644 modules/core/c++/common.hpp delete mode 100644 modules/core/c++/error.h create mode 100644 modules/core/c++/error.hpp delete mode 100644 modules/core/c++/id.h create mode 100644 modules/core/c++/id.hpp delete mode 100644 modules/core/c++/id_map.h create mode 100644 modules/core/c++/id_map.hpp delete mode 100644 modules/core/c++/mcts.h create mode 100644 modules/core/c++/mcts.hpp delete mode 100644 modules/core/c++/platonic.h create mode 100644 modules/core/c++/platonic.hpp delete mode 100644 modules/core/c++/string_literal.h create mode 100644 modules/core/c++/string_literal.hpp delete mode 100644 modules/core/c++/templates.h create mode 100644 modules/core/c++/templates.hpp delete mode 100644 modules/core/c++/tree.h create mode 100644 modules/core/c++/tree.hpp (limited to 'modules/core/c++') diff --git a/modules/core/c++/array.h b/modules/core/c++/array.h deleted file mode 100644 index f82b8d6..0000000 --- a/modules/core/c++/array.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include - -namespace saw { -/** - * Array container avoiding exceptions - */ -template -class array { -private: - std::vector data_; -public: - array() = default; - - SAW_FORBID_COPY(array); - - T& at(size_t i) noexcept { - return data_.at(i); - } - - const T& at(size_t i) noexcept const { - return data_.at(i); - } - - size_t size() noexcept const { - return data_.size(); - } - - T& front() noexcept { - return data_.front(); - } - - const T& front() noexcept const { - return data_.front(); - } - - T& back() noexcept { - return data_.back(); - } - - const T& back() noexcept const { - return data_.back(); - } - - error_or push(T val) noexcept { - try{ - data_.push_back(std::move(val)); - }catch(std::exception& e){ - return make_error(); - } - - return void_t{}; - } - - error_or pop() noexcept { - try{ - data_.pop_back(); - }catch(std::exception& e){ - return make_error(); - } - - return void_t{}; - } - - error_or resize(size_t i) noexcept { - try{ - data_.resize(i); - }catch(std::exception& e){ - return make_error(); - } - - return void_t{}; - } - - error_or reserve(size_t i) noexcept { - try{ - data_.reserve(i); - }catch(std::exception& e){ - return make_error(); - } - - return void_t{}; - } - - error_or shrink_to_fit() noexcept { - try{ - data_.shrink_to_fit(); - }catch(std::exception& e){ - return make_error(); - } - - return void_t{}; - } -}; -} diff --git a/modules/core/c++/array.hpp b/modules/core/c++/array.hpp new file mode 100644 index 0000000..f82b8d6 --- /dev/null +++ b/modules/core/c++/array.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include + +namespace saw { +/** + * Array container avoiding exceptions + */ +template +class array { +private: + std::vector data_; +public: + array() = default; + + SAW_FORBID_COPY(array); + + T& at(size_t i) noexcept { + return data_.at(i); + } + + const T& at(size_t i) noexcept const { + return data_.at(i); + } + + size_t size() noexcept const { + return data_.size(); + } + + T& front() noexcept { + return data_.front(); + } + + const T& front() noexcept const { + return data_.front(); + } + + T& back() noexcept { + return data_.back(); + } + + const T& back() noexcept const { + return data_.back(); + } + + error_or push(T val) noexcept { + try{ + data_.push_back(std::move(val)); + }catch(std::exception& e){ + return make_error(); + } + + return void_t{}; + } + + error_or pop() noexcept { + try{ + data_.pop_back(); + }catch(std::exception& e){ + return make_error(); + } + + return void_t{}; + } + + error_or resize(size_t i) noexcept { + try{ + data_.resize(i); + }catch(std::exception& e){ + return make_error(); + } + + return void_t{}; + } + + error_or reserve(size_t i) noexcept { + try{ + data_.reserve(i); + }catch(std::exception& e){ + return make_error(); + } + + return void_t{}; + } + + error_or shrink_to_fit() noexcept { + try{ + data_.shrink_to_fit(); + }catch(std::exception& e){ + return make_error(); + } + + return void_t{}; + } +}; +} diff --git a/modules/core/c++/buffer.cpp b/modules/core/c++/buffer.cpp index 15f4cae..f94f82f 100644 --- a/modules/core/c++/buffer.cpp +++ b/modules/core/c++/buffer.cpp @@ -1,4 +1,4 @@ -#include "buffer.h" +#include "buffer.hpp" #include #include diff --git a/modules/core/c++/buffer.h b/modules/core/c++/buffer.h deleted file mode 100644 index f0cf76e..0000000 --- a/modules/core/c++/buffer.h +++ /dev/null @@ -1,199 +0,0 @@ -#pragma once - -#include "error.h" - -#include -#include -#include -#include -#include -#include - -namespace saw { -/* - * Access class to reduce templated BufferSegments bloat - */ -class buffer { -protected: - ~buffer() = default; - -public: - virtual size_t read_position() const = 0; - virtual size_t read_composite_length() const = 0; - virtual size_t read_segment_length(size_t offset = 0) const = 0; - virtual void read_advance(size_t bytes) = 0; - - virtual uint8_t &read(size_t i = 0) = 0; - virtual const uint8_t &read(size_t i = 0) const = 0; - - virtual size_t write_position() const = 0; - virtual size_t write_composite_length() const = 0; - virtual size_t write_segment_length(size_t offset = 0) const = 0; - virtual void write_advance(size_t bytes) = 0; - - virtual uint8_t &write(size_t i = 0) = 0; - virtual const uint8_t &write(size_t i = 0) const = 0; - - /* - * Sometime buffers need to grow with a little more control - * than with push and pop for more efficient calls. - * There is nothing you can do if read hasn't been filled, but at - * least write can be increased if it is demanded. - */ - virtual error write_require_length(size_t bytes) = 0; - - error push(const uint8_t &value); - error push(const uint8_t &buffer, size_t size); - error pop(uint8_t &value); - error pop(uint8_t &buffer, size_t size); - -}; - -/** - * Converts a buffer to a string for convenience cases - */ -std::string convert_to_string(const buffer& buf); - -/** - * - */ - -/* - * A viewer class for buffers. - * Working on the reference buffer invalidates the buffer view - */ -class buffer_view : public buffer { -private: - buffer *buffer_; - size_t read_offset_; - size_t write_offset_; - -public: - buffer_view(buffer &); - - size_t read_position() const override; - size_t read_composite_length() const override; - size_t read_segment_length(size_t offset = 0) const override; - void read_advance(size_t bytes) override; - - uint8_t &read(size_t i = 0) override; - const uint8_t &read(size_t i = 0) const override; - - size_t write_position() const override; - size_t write_composite_length() const override; - size_t write_segment_length(size_t offset = 0) const override; - void write_advance(size_t bytes) override; - - uint8_t &write(size_t i = 0) override; - const uint8_t &write(size_t i = 0) const override; - - error write_require_length(size_t bytes) override; - - size_t read_offset() const; - size_t write_offset() const; -}; - -/* - * Buffer size meant for default allocation size of the ringbuffer since - * this class currently doesn't support proper resizing - */ -constexpr size_t RING_BUFFER_MAX_SIZE = 4096; -/* - * Buffer wrapping around if read caught up - */ -class ring_buffer final : public buffer { -private: - std::vector buffer_; - size_t read_position_; - size_t write_position_; - bool write_reached_read_ = false; - -public: - ring_buffer(); - ring_buffer(size_t size); - - inline size_t size() const { return buffer_.size(); } - - inline uint8_t &operator[](size_t i) { return buffer_[i]; } - inline const uint8_t &operator[](size_t i) const { return buffer_[i]; } - - size_t read_position() const override; - size_t read_composite_length() const override; - size_t read_segment_length(size_t offset = 0) const override; - void read_advance(size_t bytes) override; - - uint8_t &read(size_t i = 0) override; - const uint8_t &read(size_t i = 0) const override; - - size_t write_position() const override; - size_t write_composite_length() const override; - size_t write_segment_length(size_t offset = 0) const override; - void write_advance(size_t bytes) override; - - uint8_t &write(size_t i = 0) override; - const uint8_t &write(size_t i = 0) const override; - - error write_require_length(size_t bytes) override; -}; - -/* - * One time buffer - */ -class array_buffer : public buffer { -private: - std::vector buffer_; - - size_t read_position_; - size_t write_position_; - -public: - array_buffer(size_t size); - - size_t read_position() const override; - size_t read_composite_length() const override; - size_t read_segment_length(size_t offset = 0) const override; - void read_advance(size_t bytes) override; - - uint8_t &read(size_t i = 0) override; - const uint8_t &read(size_t i = 0) const override; - - size_t write_position() const override; - size_t write_composite_length() const override; - size_t write_segment_length(size_t offset = 0) const override; - void write_advance(size_t bytes) override; - - uint8_t &write(size_t i = 0) override; - const uint8_t &write(size_t i = 0) const override; - - error write_require_length(size_t bytes) override; -}; - -class chain_array_buffer : public buffer { -private: - std::deque buffer_; - - size_t read_position_; - size_t write_position_; - -public: - chain_array_buffer(); - - size_t read_position() const override; - size_t read_composite_length() const override; - size_t read_segment_length(size_t offset = 0) const override; - void read_advance(size_t bytes) override; - - uint8_t &read(size_t i = 0) override; - const uint8_t &read(size_t i = 0) const override; - - size_t write_position() const override; - size_t write_composite_length() const override; - size_t write_segment_length(size_t offset = 0) const override; - void write_advance(size_t bytes) override; - - uint8_t &write(size_t i = 0) override; - const uint8_t &write(size_t i = 0) const override; - - error write_require_length(size_t bytes) override; -}; -} // namespace saw diff --git a/modules/core/c++/buffer.hpp b/modules/core/c++/buffer.hpp new file mode 100644 index 0000000..92e8e7d --- /dev/null +++ b/modules/core/c++/buffer.hpp @@ -0,0 +1,199 @@ +#pragma once + +#include "error.hpp" + +#include +#include +#include +#include +#include +#include + +namespace saw { +/* + * Access class to reduce templated BufferSegments bloat + */ +class buffer { +protected: + ~buffer() = default; + +public: + virtual size_t read_position() const = 0; + virtual size_t read_composite_length() const = 0; + virtual size_t read_segment_length(size_t offset = 0) const = 0; + virtual void read_advance(size_t bytes) = 0; + + virtual uint8_t &read(size_t i = 0) = 0; + virtual const uint8_t &read(size_t i = 0) const = 0; + + virtual size_t write_position() const = 0; + virtual size_t write_composite_length() const = 0; + virtual size_t write_segment_length(size_t offset = 0) const = 0; + virtual void write_advance(size_t bytes) = 0; + + virtual uint8_t &write(size_t i = 0) = 0; + virtual const uint8_t &write(size_t i = 0) const = 0; + + /* + * Sometime buffers need to grow with a little more control + * than with push and pop for more efficient calls. + * There is nothing you can do if read hasn't been filled, but at + * least write can be increased if it is demanded. + */ + virtual error write_require_length(size_t bytes) = 0; + + error push(const uint8_t &value); + error push(const uint8_t &buffer, size_t size); + error pop(uint8_t &value); + error pop(uint8_t &buffer, size_t size); + +}; + +/** + * Converts a buffer to a string for convenience cases + */ +std::string convert_to_string(const buffer& buf); + +/** + * + */ + +/* + * A viewer class for buffers. + * Working on the reference buffer invalidates the buffer view + */ +class buffer_view : public buffer { +private: + buffer *buffer_; + size_t read_offset_; + size_t write_offset_; + +public: + buffer_view(buffer &); + + size_t read_position() const override; + size_t read_composite_length() const override; + size_t read_segment_length(size_t offset = 0) const override; + void read_advance(size_t bytes) override; + + uint8_t &read(size_t i = 0) override; + const uint8_t &read(size_t i = 0) const override; + + size_t write_position() const override; + size_t write_composite_length() const override; + size_t write_segment_length(size_t offset = 0) const override; + void write_advance(size_t bytes) override; + + uint8_t &write(size_t i = 0) override; + const uint8_t &write(size_t i = 0) const override; + + error write_require_length(size_t bytes) override; + + size_t read_offset() const; + size_t write_offset() const; +}; + +/* + * Buffer size meant for default allocation size of the ringbuffer since + * this class currently doesn't support proper resizing + */ +constexpr size_t RING_BUFFER_MAX_SIZE = 4096; +/* + * Buffer wrapping around if read caught up + */ +class ring_buffer final : public buffer { +private: + std::vector buffer_; + size_t read_position_; + size_t write_position_; + bool write_reached_read_ = false; + +public: + ring_buffer(); + ring_buffer(size_t size); + + inline size_t size() const { return buffer_.size(); } + + inline uint8_t &operator[](size_t i) { return buffer_[i]; } + inline const uint8_t &operator[](size_t i) const { return buffer_[i]; } + + size_t read_position() const override; + size_t read_composite_length() const override; + size_t read_segment_length(size_t offset = 0) const override; + void read_advance(size_t bytes) override; + + uint8_t &read(size_t i = 0) override; + const uint8_t &read(size_t i = 0) const override; + + size_t write_position() const override; + size_t write_composite_length() const override; + size_t write_segment_length(size_t offset = 0) const override; + void write_advance(size_t bytes) override; + + uint8_t &write(size_t i = 0) override; + const uint8_t &write(size_t i = 0) const override; + + error write_require_length(size_t bytes) override; +}; + +/* + * One time buffer + */ +class array_buffer : public buffer { +private: + std::vector buffer_; + + size_t read_position_; + size_t write_position_; + +public: + array_buffer(size_t size); + + size_t read_position() const override; + size_t read_composite_length() const override; + size_t read_segment_length(size_t offset = 0) const override; + void read_advance(size_t bytes) override; + + uint8_t &read(size_t i = 0) override; + const uint8_t &read(size_t i = 0) const override; + + size_t write_position() const override; + size_t write_composite_length() const override; + size_t write_segment_length(size_t offset = 0) const override; + void write_advance(size_t bytes) override; + + uint8_t &write(size_t i = 0) override; + const uint8_t &write(size_t i = 0) const override; + + error write_require_length(size_t bytes) override; +}; + +class chain_array_buffer : public buffer { +private: + std::deque buffer_; + + size_t read_position_; + size_t write_position_; + +public: + chain_array_buffer(); + + size_t read_position() const override; + size_t read_composite_length() const override; + size_t read_segment_length(size_t offset = 0) const override; + void read_advance(size_t bytes) override; + + uint8_t &read(size_t i = 0) override; + const uint8_t &read(size_t i = 0) const override; + + size_t write_position() const override; + size_t write_composite_length() const override; + size_t write_segment_length(size_t offset = 0) const override; + void write_advance(size_t bytes) override; + + uint8_t &write(size_t i = 0) override; + const uint8_t &write(size_t i = 0) const override; + + error write_require_length(size_t bytes) override; +}; +} // namespace saw diff --git a/modules/core/c++/common.cpp b/modules/core/c++/common.cpp index 4812c66..b254850 100644 --- a/modules/core/c++/common.cpp +++ b/modules/core/c++/common.cpp @@ -1,4 +1,4 @@ -#include "common.h" +#include "common.hpp" namespace saw { void_t make_void(){ diff --git a/modules/core/c++/common.h b/modules/core/c++/common.h deleted file mode 100644 index d892efe..0000000 --- a/modules/core/c++/common.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace saw { - -#define SAW_CONCAT_(x, y) x##y -#define SAW_CONCAT(x, y) SAW_CONCAT_(x, y) -#define SAW_UNIQUE_NAME(prefix) SAW_CONCAT(prefix, __LINE__) - -#define SAW_FORBID_COPY(classname) \ - classname(const classname &) = delete; \ - classname &operator=(const classname &) = delete - -#define SAW_FORBID_MOVE(classname) \ - classname(classname &&) = delete; \ - classname &operator=(classname &&) = delete - -#define SAW_DEFAULT_COPY(classname) \ - classname(const classname &) = default; \ - classname &operator=(const classname &) = default - -#define SAW_DEFAULT_MOVE(classname) \ - classname(classname &&) = default; \ - classname &operator=(classname &&) = default - -// In case of C++20 -#define SAW_ASSERT(expression) \ - assert(expression); \ - if (!(expression)) [[unlikely]] - -template using maybe = std::optional; - -template using own = std::unique_ptr; - -template using our = std::shared_ptr; - -template using lent = std::weak_ptr; - -template own heap(Args &&...args) { - return own(new T(std::forward(args)...)); -} - -template our share(Args &&...args) { - return std::make_shared(std::forward(args)...); -} - -template T instance() noexcept; - -template struct return_type_helper { - typedef decltype(instance()(instance())) Type; -}; -template struct return_type_helper { - typedef decltype(instance()()) Type; -}; - -template -using return_type = typename return_type_helper::Type; - -/** - * Struct describing a void type - */ -struct void_t {}; - -/** - * Helper function since changing returns between void_t{} and make_error<...>() is a bit annoying. - */ -void_t make_void(); - -template struct void_fix { typedef T Type; }; -template <> struct void_fix { typedef void_t Type; }; -template using fix_void = typename void_fix::Type; - -template struct void_unfix { typedef T Type; }; -template <> struct void_unfix { typedef void Type; }; -template using unfix_void = typename void_unfix::Type; - -template constexpr bool always_false = false; - -} // namespace saw diff --git a/modules/core/c++/common.hpp b/modules/core/c++/common.hpp new file mode 100644 index 0000000..d892efe --- /dev/null +++ b/modules/core/c++/common.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include + +namespace saw { + +#define SAW_CONCAT_(x, y) x##y +#define SAW_CONCAT(x, y) SAW_CONCAT_(x, y) +#define SAW_UNIQUE_NAME(prefix) SAW_CONCAT(prefix, __LINE__) + +#define SAW_FORBID_COPY(classname) \ + classname(const classname &) = delete; \ + classname &operator=(const classname &) = delete + +#define SAW_FORBID_MOVE(classname) \ + classname(classname &&) = delete; \ + classname &operator=(classname &&) = delete + +#define SAW_DEFAULT_COPY(classname) \ + classname(const classname &) = default; \ + classname &operator=(const classname &) = default + +#define SAW_DEFAULT_MOVE(classname) \ + classname(classname &&) = default; \ + classname &operator=(classname &&) = default + +// In case of C++20 +#define SAW_ASSERT(expression) \ + assert(expression); \ + if (!(expression)) [[unlikely]] + +template using maybe = std::optional; + +template using own = std::unique_ptr; + +template using our = std::shared_ptr; + +template using lent = std::weak_ptr; + +template own heap(Args &&...args) { + return own(new T(std::forward(args)...)); +} + +template our share(Args &&...args) { + return std::make_shared(std::forward(args)...); +} + +template T instance() noexcept; + +template struct return_type_helper { + typedef decltype(instance()(instance())) Type; +}; +template struct return_type_helper { + typedef decltype(instance()()) Type; +}; + +template +using return_type = typename return_type_helper::Type; + +/** + * Struct describing a void type + */ +struct void_t {}; + +/** + * Helper function since changing returns between void_t{} and make_error<...>() is a bit annoying. + */ +void_t make_void(); + +template struct void_fix { typedef T Type; }; +template <> struct void_fix { typedef void_t Type; }; +template using fix_void = typename void_fix::Type; + +template struct void_unfix { typedef T Type; }; +template <> struct void_unfix { typedef void Type; }; +template using unfix_void = typename void_unfix::Type; + +template constexpr bool always_false = false; + +} // namespace saw diff --git a/modules/core/c++/error.h b/modules/core/c++/error.h deleted file mode 100644 index 2728c8e..0000000 --- a/modules/core/c++/error.h +++ /dev/null @@ -1,288 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -#include "common.h" - -namespace saw { -/** - * Utility class for generating errors. Has a base distinction between - * critical and recoverable errors. Additional code ids can be provided to the - * constructor if additional distinctions are necessary. - */ -class error { -public: - /** - * Type alias - */ - using code = uint32_t; -private: - /** - * Type representing the error code used to distinguish the different error types - */ - code error_code_; - /** - * Helper variable for ease of checking if it's a critical error. - */ - bool is_critical_; - /** - * Member holding the message. It's a variant for edge cases where we are out of memory. - */ - std::variant error_message_; - -public: - error(error::code id, bool is_critical); - error(error::code id, bool is_critical, const std::string_view &msg); - error(error &&error); - - SAW_FORBID_COPY(error); - - error &operator=(error &&) = default; - - /** - * Returns a string view to the message - */ - const std::string_view get_message() const; - - /** - * Returns a string view which describes which error this is. - */ - const std::string_view get_category() const; - - /** - * Checks if it's an error at all, since 0 is reserved for no error. - */ - bool failed() const; - - /** - * Checks if the error is critical. - */ - bool is_critical() const; - - /** - * Checks if the error is recoverable. - */ - bool is_recoverable() const; - - /** - * Replaces the copy constructor. We need this since we want to explicitly copy and not implicitly - */ - error copy_error() const; - - /** - * Return the id. - */ - code get_id() const; - - /** - * Provide an error struct and check if it matches the type - */ - template - bool is_type() const; -}; - -/** - * Class which is basically a variant. Replaces exceptions - */ -template -class error_or; - -namespace impl { - -/** - * Internal registry for all error types. Is generated dynamically. - */ -class error_registry { -private: - struct error_info { - error_info() = delete; - error_info(const std::string_view& d_, bool critical_):description{d_}, is_critical{critical_}{} - - std::string_view description; - bool is_critical; - }; - - std::vector infos_; -public: - error_registry(); - - SAW_FORBID_COPY(error_registry); - SAW_FORBID_MOVE(error_registry); - - error_or search_category(const error::code& id) const; - - error_or search_id(const std::string_view& desc) const; - - error_or search_or_register_id(const std::string_view& desc, bool is_critical); -}; - -error_registry& get_error_registry(); - -template -error::code get_template_id(){ - static error::code id = std::numeric_limits::max(); - - if(id == std::numeric_limits::max()){ - auto& reg = get_error_registry(); - - auto err_or_id = reg.search_or_register_id(T::description, T::is_critical); - if(err_or_id.is_error()){ - return std::numeric_limits::max(); - } - - id = err_or_id.get_value(); - } - - return id; -} -} - -template error make_error(const std::string_view& generic){ - error::code id = impl::get_template_id(); - - return error{id, T::is_critical, generic}; -} - -template error make_error(){ - error::code id = impl::get_template_id(); - - return error{id, T::is_critical}; -} - -error make_error(error::code code, const std::string_view &generic); - - -namespace err { -struct no_error { - static constexpr std::string_view description = "No error has occured"; - static constexpr bool is_critical = false; -}; - -struct recoverable { - static constexpr std::string_view description = "Generic recoverable error"; - static constexpr bool is_critical = false; -}; - -struct critical { - static constexpr std::string_view description = "Generic critical error"; - static constexpr bool is_critical = true; -}; - -struct buffer_exhausted { - static constexpr std::string_view description = "Buffer Exhausted"; - static constexpr bool is_critical = false; -}; - -struct not_found { - static constexpr std::string_view description = "Not found"; - static constexpr bool is_critical = false; -}; - -struct out_of_memory { - static constexpr std::string_view description = "Out of memory"; - static constexpr bool is_critical = true; -}; - -struct invalid_state { - static constexpr std::string_view description = "Invalid state"; - static constexpr bool is_critical = true; -}; - -struct not_supported { - static constexpr std::string_view description = "Not supported"; - static constexpr bool is_critical = false; -}; - -struct not_implemented { - static constexpr std::string_view description = "Not implemented"; - static constexpr bool is_critical = true; -}; - -struct already_exists { - static constexpr std::string_view description = "Already exists"; - static constexpr bool is_critical = false; -}; -} - -/** - * Shorthand for no error happened - */ -error no_error(); - -/** - * Exception alternative. Since I code without exceptions this class is - * essentially a kind of exception replacement. - */ -template class error_or; - -class error_or_value { -public: - virtual ~error_or_value() = default; - - template error_or> &as() { - return static_cast> &>(*this); - } - - template const error_or> &as() const { - return static_cast> &>(*this); - } -}; - -template class error_or final : public error_or_value { -private: - std::variant> value_or_error_; - - static_assert(!std::is_same_v, - "Don't use internal private types"); - -public: - error_or():value_or_error_{fix_void{}}{} - error_or(const fix_void &value) : value_or_error_{value} {} - - error_or(fix_void &&value) : value_or_error_{std::move(value)} {} - - error_or(const error &error) : value_or_error_{error} {} - error_or(error &&error) : value_or_error_{std::move(error)} {} - - bool is_value() const { - return std::holds_alternative>(value_or_error_); - } - - bool is_error() const { - return std::holds_alternative(value_or_error_); - } - - class error &get_error() { - return std::get(value_or_error_); - } - - const class error &get_error() const { - return std::get(value_or_error_); - } - - fix_void &get_value() { return std::get>(value_or_error_); } - - const fix_void &get_value() const { - return std::get>(value_or_error_); - } -}; - -template class error_or> { -private: - error_or() = delete; -}; - -template -bool error::is_type() const { - - return error_code_ == impl::get_template_id(); -} - -} // namespace saw diff --git a/modules/core/c++/error.hpp b/modules/core/c++/error.hpp new file mode 100644 index 0000000..798b923 --- /dev/null +++ b/modules/core/c++/error.hpp @@ -0,0 +1,288 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#include "common.hpp + +namespace saw { +/** + * Utility class for generating errors. Has a base distinction between + * critical and recoverable errors. Additional code ids can be provided to the + * constructor if additional distinctions are necessary. + */ +class error { +public: + /** + * Type alias + */ + using code = uint32_t; +private: + /** + * Type representing the error code used to distinguish the different error types + */ + code error_code_; + /** + * Helper variable for ease of checking if it's a critical error. + */ + bool is_critical_; + /** + * Member holding the message. It's a variant for edge cases where we are out of memory. + */ + std::variant error_message_; + +public: + error(error::code id, bool is_critical); + error(error::code id, bool is_critical, const std::string_view &msg); + error(error &&error); + + SAW_FORBID_COPY(error); + + error &operator=(error &&) = default; + + /** + * Returns a string view to the message + */ + const std::string_view get_message() const; + + /** + * Returns a string view which describes which error this is. + */ + const std::string_view get_category() const; + + /** + * Checks if it's an error at all, since 0 is reserved for no error. + */ + bool failed() const; + + /** + * Checks if the error is critical. + */ + bool is_critical() const; + + /** + * Checks if the error is recoverable. + */ + bool is_recoverable() const; + + /** + * Replaces the copy constructor. We need this since we want to explicitly copy and not implicitly + */ + error copy_error() const; + + /** + * Return the id. + */ + code get_id() const; + + /** + * Provide an error struct and check if it matches the type + */ + template + bool is_type() const; +}; + +/** + * Class which is basically a variant. Replaces exceptions + */ +template +class error_or; + +namespace impl { + +/** + * Internal registry for all error types. Is generated dynamically. + */ +class error_registry { +private: + struct error_info { + error_info() = delete; + error_info(const std::string_view& d_, bool critical_):description{d_}, is_critical{critical_}{} + + std::string_view description; + bool is_critical; + }; + + std::vector infos_; +public: + error_registry(); + + SAW_FORBID_COPY(error_registry); + SAW_FORBID_MOVE(error_registry); + + error_or search_category(const error::code& id) const; + + error_or search_id(const std::string_view& desc) const; + + error_or search_or_register_id(const std::string_view& desc, bool is_critical); +}; + +error_registry& get_error_registry(); + +template +error::code get_template_id(){ + static error::code id = std::numeric_limits::max(); + + if(id == std::numeric_limits::max()){ + auto& reg = get_error_registry(); + + auto err_or_id = reg.search_or_register_id(T::description, T::is_critical); + if(err_or_id.is_error()){ + return std::numeric_limits::max(); + } + + id = err_or_id.get_value(); + } + + return id; +} +} + +template error make_error(const std::string_view& generic){ + error::code id = impl::get_template_id(); + + return error{id, T::is_critical, generic}; +} + +template error make_error(){ + error::code id = impl::get_template_id(); + + return error{id, T::is_critical}; +} + +error make_error(error::code code, const std::string_view &generic); + + +namespace err { +struct no_error { + static constexpr std::string_view description = "No error has occured"; + static constexpr bool is_critical = false; +}; + +struct recoverable { + static constexpr std::string_view description = "Generic recoverable error"; + static constexpr bool is_critical = false; +}; + +struct critical { + static constexpr std::string_view description = "Generic critical error"; + static constexpr bool is_critical = true; +}; + +struct buffer_exhausted { + static constexpr std::string_view description = "Buffer Exhausted"; + static constexpr bool is_critical = false; +}; + +struct not_found { + static constexpr std::string_view description = "Not found"; + static constexpr bool is_critical = false; +}; + +struct out_of_memory { + static constexpr std::string_view description = "Out of memory"; + static constexpr bool is_critical = true; +}; + +struct invalid_state { + static constexpr std::string_view description = "Invalid state"; + static constexpr bool is_critical = true; +}; + +struct not_supported { + static constexpr std::string_view description = "Not supported"; + static constexpr bool is_critical = false; +}; + +struct not_implemented { + static constexpr std::string_view description = "Not implemented"; + static constexpr bool is_critical = true; +}; + +struct already_exists { + static constexpr std::string_view description = "Already exists"; + static constexpr bool is_critical = false; +}; +} + +/** + * Shorthand for no error happened + */ +error no_error(); + +/** + * Exception alternative. Since I code without exceptions this class is + * essentially a kind of exception replacement. + */ +template class error_or; + +class error_or_value { +public: + virtual ~error_or_value() = default; + + template error_or> &as() { + return static_cast> &>(*this); + } + + template const error_or> &as() const { + return static_cast> &>(*this); + } +}; + +template class error_or final : public error_or_value { +private: + std::variant> value_or_error_; + + static_assert(!std::is_same_v, + "Don't use internal private types"); + +public: + error_or():value_or_error_{fix_void{}}{} + error_or(const fix_void &value) : value_or_error_{value} {} + + error_or(fix_void &&value) : value_or_error_{std::move(value)} {} + + error_or(const error &error) : value_or_error_{error} {} + error_or(error &&error) : value_or_error_{std::move(error)} {} + + bool is_value() const { + return std::holds_alternative>(value_or_error_); + } + + bool is_error() const { + return std::holds_alternative(value_or_error_); + } + + class error &get_error() { + return std::get(value_or_error_); + } + + const class error &get_error() const { + return std::get(value_or_error_); + } + + fix_void &get_value() { return std::get>(value_or_error_); } + + const fix_void &get_value() const { + return std::get>(value_or_error_); + } +}; + +template class error_or> { +private: + error_or() = delete; +}; + +template +bool error::is_type() const { + + return error_code_ == impl::get_template_id(); +} + +} // namespace saw diff --git a/modules/core/c++/id.h b/modules/core/c++/id.h deleted file mode 100644 index d836648..0000000 --- a/modules/core/c++/id.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -namespace saw { -/** - * ID class which is tied to it's representing class - */ -template -class id { -private: - /** - * Alias for the value type representing the ID - */ - using type = uint64_t; - - /** - * The low level value - */ - type value_; -public: - /** - * Basic constructor for the id class - */ - id(type val): - value_{val} - {} - - SAW_DEFAULT_COPY(id); - SAW_DEFAULT_MOVE(id); - - /** - * Equal operator for the id. - * Returns true if equal, false otherwise. - */ - bool operator==(const id& rhs) const { - return value_ == rhs.value_; - } - - /** - * Unequal operator for the id. - * Returns false if equal, true otherwise. - */ - bool operator!=(const id& rhs) const { - return !(*this == rhs); - } - - /** - * Returns a const ref of the underlying base type. - * Mostly used for internal purposes. - */ - const type& get_value() const { - return value_; - } -}; -} diff --git a/modules/core/c++/id.hpp b/modules/core/c++/id.hpp new file mode 100644 index 0000000..d836648 --- /dev/null +++ b/modules/core/c++/id.hpp @@ -0,0 +1,54 @@ +#pragma once + +namespace saw { +/** + * ID class which is tied to it's representing class + */ +template +class id { +private: + /** + * Alias for the value type representing the ID + */ + using type = uint64_t; + + /** + * The low level value + */ + type value_; +public: + /** + * Basic constructor for the id class + */ + id(type val): + value_{val} + {} + + SAW_DEFAULT_COPY(id); + SAW_DEFAULT_MOVE(id); + + /** + * Equal operator for the id. + * Returns true if equal, false otherwise. + */ + bool operator==(const id& rhs) const { + return value_ == rhs.value_; + } + + /** + * Unequal operator for the id. + * Returns false if equal, true otherwise. + */ + bool operator!=(const id& rhs) const { + return !(*this == rhs); + } + + /** + * Returns a const ref of the underlying base type. + * Mostly used for internal purposes. + */ + const type& get_value() const { + return value_; + } +}; +} diff --git a/modules/core/c++/id_map.h b/modules/core/c++/id_map.h deleted file mode 100644 index 9ad2847..0000000 --- a/modules/core/c++/id_map.h +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once - -#include "id.h" -#include "error.h" - -#include - -namespace saw { -/** - * Fast random access id based container. - * - * Access - O(1) - * Insert - O(1) - * Erase - O(n) ? Dunno - */ -template -class id_map final { -private: - /** - * Container which stores the primary data - */ - std::vector data_; - /** - * Container which tracks free'd/fragmented elements within the - * main container - */ - std::deque> free_ids_; - -private: - /** - * Tries to reduce top ids - */ - void reduce_free_ids() noexcept { - for(;;){ - /** - * If we have no free ids left, we also have nothing to reduce - */ - if(free_ids_.empty()){ - break; - } - - /** - * The front contains the highest free id. - */ - if((free_ids_.front().get_value() + 1) < data_.size()){ - break; - } - - /** - * Can this throw? - */ - free_ids_.pop_front(); - } - } -public: - /** - * Default constructor - */ - id_map() = default; - - SAW_FORBID_COPY(id_map); - SAW_DEFAULT_MOVE(id_map); - - /** - * Inserts an element into the container and returns either an id on success - * or an error on failure. - */ - error_or> insert(T val) noexcept { - /// @todo Fix size_t and id base type - if(free_ids_.empty()){ - try { - size_t i = data_.size(); - data_.emplace_back(std::move(val)); - return saw::id{i}; - } catch(std::exception& e) { - return make_error(); - } - } else { - auto f_id = std::move(free_ids_.back()); - free_ids_.pop_back(); - data_.at(f_id.get_value()) = std::move(val); - return f_id; - } - - exit(-1); - // Dummy return since this is not reachable - return make_error(); - } - - /** - * Erase a value at this id. - */ - error_or erase(const id& val) noexcept { - /** - * If id is bigger than the available vector then return an error. - */ - if(val.get_value() >= data_.size()){ - return make_error("ID is too large"); - } - - /** - * Check if it's the highest ID. Then we can just try to reduce the highest - * IDs. - */ - if((val.get_value() + 1) == data_.size()){ - data_.pop_back(); - this->reduce_free_ids(); - if(data_.size()*2 <= data_.capacity()){ - try { - data_.shrink_to_fit(); - }catch(std::exception& e){ - return make_error(); - } - } - return void_t{}; - } - - /** - * Check if ID already exists with the free IDs. - * This would mean that a double free has occured. - */ - auto find_id = std::find(free_ids_.begin(), free_ids_.end(), val); - if(find_id != free_ids_.end()){ - return make_error("ID value has already been freed"); - } - - /** - * Insert id into deque and sort it. - */ - try { - free_ids_.push_back(val); - } catch(std::exception& e){ - return make_error(); - } - std::stable_sort(free_ids_.begin(), free_ids_.end(), - [](const id& left, const id& right) -> bool { - return left.get_value() > right.get_value(); - } - ); - return void_t{}; - } -}; -} diff --git a/modules/core/c++/id_map.hpp b/modules/core/c++/id_map.hpp new file mode 100644 index 0000000..0ffe4e0 --- /dev/null +++ b/modules/core/c++/id_map.hpp @@ -0,0 +1,143 @@ +#pragma once + +#include "id.hpp +#include "error.hpp + +#include + +namespace saw { +/** + * Fast random access id based container. + * + * Access - O(1) + * Insert - O(1) + * Erase - O(n) ? Dunno + */ +template +class id_map final { +private: + /** + * Container which stores the primary data + */ + std::vector data_; + /** + * Container which tracks free'd/fragmented elements within the + * main container + */ + std::deque> free_ids_; + +private: + /** + * Tries to reduce top ids + */ + void reduce_free_ids() noexcept { + for(;;){ + /** + * If we have no free ids left, we also have nothing to reduce + */ + if(free_ids_.empty()){ + break; + } + + /** + * The front contains the highest free id. + */ + if((free_ids_.front().get_value() + 1) < data_.size()){ + break; + } + + /** + * Can this throw? + */ + free_ids_.pop_front(); + } + } +public: + /** + * Default constructor + */ + id_map() = default; + + SAW_FORBID_COPY(id_map); + SAW_DEFAULT_MOVE(id_map); + + /** + * Inserts an element into the container and returns either an id on success + * or an error on failure. + */ + error_or> insert(T val) noexcept { + /// @todo Fix size_t and id base type + if(free_ids_.empty()){ + try { + size_t i = data_.size(); + data_.emplace_back(std::move(val)); + return saw::id{i}; + } catch(std::exception& e) { + return make_error(); + } + } else { + auto f_id = std::move(free_ids_.back()); + free_ids_.pop_back(); + data_.at(f_id.get_value()) = std::move(val); + return f_id; + } + + exit(-1); + // Dummy return since this is not reachable + return make_error(); + } + + /** + * Erase a value at this id. + */ + error_or erase(const id& val) noexcept { + /** + * If id is bigger than the available vector then return an error. + */ + if(val.get_value() >= data_.size()){ + return make_error("ID is too large"); + } + + /** + * Check if it's the highest ID. Then we can just try to reduce the highest + * IDs. + */ + if((val.get_value() + 1) == data_.size()){ + data_.pop_back(); + this->reduce_free_ids(); + if(data_.size()*2 <= data_.capacity()){ + try { + data_.shrink_to_fit(); + }catch(std::exception& e){ + return make_error(); + } + } + return void_t{}; + } + + /** + * Check if ID already exists with the free IDs. + * This would mean that a double free has occured. + */ + auto find_id = std::find(free_ids_.begin(), free_ids_.end(), val); + if(find_id != free_ids_.end()){ + return make_error("ID value has already been freed"); + } + + /** + * Insert id into deque and sort it. + */ + try { + free_ids_.push_back(val); + } catch(std::exception& e){ + return make_error(); + } + std::stable_sort(free_ids_.begin(), free_ids_.end(), + [](const id& left, const id& right) -> bool { + return left.get_value() > right.get_value(); + } + ); + return void_t{}; + } +}; +} diff --git a/modules/core/c++/mcts.h b/modules/core/c++/mcts.h deleted file mode 100644 index 8a8f5ea..0000000 --- a/modules/core/c++/mcts.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include "tree.h" - -namespace saw { -template -class mcts_tree { -private: - struct value { - uint64_t numerater; - uint64_t denominater; - T state; - - value() = default; - value(T st): - numerater{0}, - denominater{0}, - state{std::move(st)} - {} - }; - - tree_container> data_; -public: - mcts_tree() = default{ - data_.add(value{}); - } - - mcts_tree(T state){ - data_.add(value{std::move(state)}); - } - - size_t size() const { - return data_.size() - 1; - } - - T& get_state(){ - return data_.at(0).get_value().state; - } - - const T& get_state() const { - return data_.at(0).get_value().state; - } - - mcts_tree& get_tree(size_t i){ - return data_.at(i+1).get_tree(); - } - - const mcts_tree& get_tree(size_t i) const { - return data_.at(i+1).get_tree(); - } -}; -} diff --git a/modules/core/c++/mcts.hpp b/modules/core/c++/mcts.hpp new file mode 100644 index 0000000..bfb7459 --- /dev/null +++ b/modules/core/c++/mcts.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "tree.hpp + +namespace saw { +template +class mcts_tree { +private: + struct value { + uint64_t numerater; + uint64_t denominater; + T state; + + value() = default; + value(T st): + numerater{0}, + denominater{0}, + state{std::move(st)} + {} + }; + + tree_container> data_; +public: + mcts_tree() = default{ + data_.add(value{}); + } + + mcts_tree(T state){ + data_.add(value{std::move(state)}); + } + + size_t size() const { + return data_.size() - 1; + } + + T& get_state(){ + return data_.at(0).get_value().state; + } + + const T& get_state() const { + return data_.at(0).get_value().state; + } + + mcts_tree& get_tree(size_t i){ + return data_.at(i+1).get_tree(); + } + + const mcts_tree& get_tree(size_t i) const { + return data_.at(i+1).get_tree(); + } +}; +} diff --git a/modules/core/c++/platonic.h b/modules/core/c++/platonic.h deleted file mode 100644 index eefe99f..0000000 --- a/modules/core/c++/platonic.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include "error.h" - -namespace saw { -namespace impl { -/** - * - */ -template -struct platonic_helper { - static_assert(always_false, "Unsupported platonic body. Alternatively it's not a platonic body"); -}; - -template -struct platonic_helper { - static constexpr surface_edges = 3u; -/* - static constexpr std::array, 4u> normals = { - {0.0, 0.0, -1.0}, // 1 - {}, // 2 - {}, // 3 - {} // 4 - }; -*/ -}; - -template -struct platonic_helper { - static constexpr surface_edges = 4u; - - static constexpr std::array, 6u> normals = { - { 1.0, 0.0, 0.0}, // 1 - {-1.0, 0.0, 0.0}, // 2 - { 0.0, 1.0, 0.0}, // 3 - { 0.0,-1.0, 0.0}, // 4 - { 0.0, 0.0, 1.0}, // 5 - { 0.0, 0.0,-1.0} // 6 - }; -}; - -template -struct platonic_helper { - static constexpr uint8_t surface_edges = 3u; -/* - static constexpr std::array, 20u> normals = { - {}, // 1 - {}, // 2 - {}, // 3 - {}, // 4 - {}, // 5 - {}, // 6 - {}, // 7 - {}, // 8 - {}, // 9 - {}, // 10 - {}, // 11 - {}, // 12 - {}, // 13 - {}, // 14 - {}, // 15 - {}, // 16 - {}, // 17 - {}, // 18 - {}, // 19 - {} // 20 - }; -*/ -}; -} -/** - * Container for describing each platonic body with - * helpers describing the orientation of each body. - */ -template -class platonic { -private: - /** - * Storage for the surfaces - */ - std::array surfaces_; -public: - constexpr uint8_t get_surface_edge_size() constexpr { - return platonic_helper::surface_edges; - } - - constexpr uint8_t get_surface_size() constexpr { - return N; - } - - T& at(uint8_t i){ - return surface_.at(i); - } - - const T& at(uint8_t i) const { - return surface_.at(i); - } - - constexpr std::array& get_surface_normal(size_t i) constexpr { - - } -}; -} diff --git a/modules/core/c++/platonic.hpp b/modules/core/c++/platonic.hpp new file mode 100644 index 0000000..a84a080 --- /dev/null +++ b/modules/core/c++/platonic.hpp @@ -0,0 +1,103 @@ +#pragma once + +#include "error.hpp + +namespace saw { +namespace impl { +/** + * + */ +template +struct platonic_helper { + static_assert(always_false, "Unsupported platonic body. Alternatively it's not a platonic body"); +}; + +template +struct platonic_helper { + static constexpr surface_edges = 3u; +/* + static constexpr std::array, 4u> normals = { + {0.0, 0.0, -1.0}, // 1 + {}, // 2 + {}, // 3 + {} // 4 + }; +*/ +}; + +template +struct platonic_helper { + static constexpr surface_edges = 4u; + + static constexpr std::array, 6u> normals = { + { 1.0, 0.0, 0.0}, // 1 + {-1.0, 0.0, 0.0}, // 2 + { 0.0, 1.0, 0.0}, // 3 + { 0.0,-1.0, 0.0}, // 4 + { 0.0, 0.0, 1.0}, // 5 + { 0.0, 0.0,-1.0} // 6 + }; +}; + +template +struct platonic_helper { + static constexpr uint8_t surface_edges = 3u; +/* + static constexpr std::array, 20u> normals = { + {}, // 1 + {}, // 2 + {}, // 3 + {}, // 4 + {}, // 5 + {}, // 6 + {}, // 7 + {}, // 8 + {}, // 9 + {}, // 10 + {}, // 11 + {}, // 12 + {}, // 13 + {}, // 14 + {}, // 15 + {}, // 16 + {}, // 17 + {}, // 18 + {}, // 19 + {} // 20 + }; +*/ +}; +} +/** + * Container for describing each platonic body with + * helpers describing the orientation of each body. + */ +template +class platonic { +private: + /** + * Storage for the surfaces + */ + std::array surfaces_; +public: + constexpr uint8_t get_surface_edge_size() constexpr { + return platonic_helper::surface_edges; + } + + constexpr uint8_t get_surface_size() constexpr { + return N; + } + + T& at(uint8_t i){ + return surface_.at(i); + } + + const T& at(uint8_t i) const { + return surface_.at(i); + } + + constexpr std::array& get_surface_normal(size_t i) constexpr { + + } +}; +} diff --git a/modules/core/c++/string_literal.h b/modules/core/c++/string_literal.h deleted file mode 100644 index ccc8f49..0000000 --- a/modules/core/c++/string_literal.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include - -namespace saw { -/** - * Helper object which creates a templated string from the provided string - * literal. It guarantees compile time uniqueness and thus allows using strings - * in template parameters. - */ -template class string_literal { -public: - static_assert(N > 0, "string_literal needs a null terminator"); - - constexpr string_literal(const CharT (&input)[N]) noexcept { - for (size_t i = 0; i < N; ++i) { - data[i] = input[i]; - } - } - - std::array data{}; - - constexpr std::string_view view() const noexcept { - return std::string_view{data.data()}; - } - - constexpr bool - operator==(const string_literal &) const noexcept = default; - - template - constexpr bool - operator==(const string_literal &) const noexcept { - return false; - } - - template - constexpr string_literal operator+(const string_literal& rhs) const noexcept { - CharT sum[N+NR-1]; - - // The weird i+1 happens due to needing to skip the '\0' terminator - for(size_t i = 0; (i+1) < N; ++i){ - sum[i] = data[i]; - } - for(size_t i = 0; i < NR; ++i){ - sum[i+N-1] = rhs.data[i]; - } - - return string_literal{sum}; - } -}; - -template -constexpr string_literal operator""_sl() { - return string_literal{{Chars..., '\0'}}; -} -} // namespace saw diff --git a/modules/core/c++/string_literal.hpp b/modules/core/c++/string_literal.hpp new file mode 100644 index 0000000..ccc8f49 --- /dev/null +++ b/modules/core/c++/string_literal.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +namespace saw { +/** + * Helper object which creates a templated string from the provided string + * literal. It guarantees compile time uniqueness and thus allows using strings + * in template parameters. + */ +template class string_literal { +public: + static_assert(N > 0, "string_literal needs a null terminator"); + + constexpr string_literal(const CharT (&input)[N]) noexcept { + for (size_t i = 0; i < N; ++i) { + data[i] = input[i]; + } + } + + std::array data{}; + + constexpr std::string_view view() const noexcept { + return std::string_view{data.data()}; + } + + constexpr bool + operator==(const string_literal &) const noexcept = default; + + template + constexpr bool + operator==(const string_literal &) const noexcept { + return false; + } + + template + constexpr string_literal operator+(const string_literal& rhs) const noexcept { + CharT sum[N+NR-1]; + + // The weird i+1 happens due to needing to skip the '\0' terminator + for(size_t i = 0; (i+1) < N; ++i){ + sum[i] = data[i]; + } + for(size_t i = 0; i < NR; ++i){ + sum[i+N-1] = rhs.data[i]; + } + + return string_literal{sum}; + } +}; + +template +constexpr string_literal operator""_sl() { + return string_literal{{Chars..., '\0'}}; +} +} // namespace saw diff --git a/modules/core/c++/templates.h b/modules/core/c++/templates.h deleted file mode 100644 index 2eb0f7e..0000000 --- a/modules/core/c++/templates.h +++ /dev/null @@ -1,150 +0,0 @@ -#pragma once - -#include "string_literal.h" - -namespace saw { - -template struct parameter_pack_index; - -template struct parameter_pack_index { - static constexpr size_t value = 0u; -}; - -template -struct parameter_pack_index { - static constexpr size_t value = - 1u + parameter_pack_index::value; -}; - -template struct parameter_pack_type { - static_assert(always_false, "Should've been caught by the specializations"); -}; - -template struct parameter_pack_type<0, TN, T...> { - using type = TN; -}; - -template -struct parameter_pack_type { - static_assert(sizeof...(T) > 0, "Exhausted parameters"); - static_assert(N > 0, "Invalid number. Should've been caught"); - using type = typename parameter_pack_type::type; -}; -/* - * Nightmare inducing compiler problems found here. Somehow non-type - * string_literals cannot be resolved as non-type primitive template values can. - * This is the workaround - */ -template -struct parameter_key_pack_index_helper { - static constexpr size_t value = - (V == Key0) - ? (0u) - : (1u + parameter_key_pack_index_helper::value); -}; - -template -struct parameter_key_pack_index_helper { - static constexpr size_t value = (V == Key0) ? (0u) : (1u); -}; - -template -struct parameter_key_pack_index { - static constexpr size_t value = - parameter_key_pack_index_helper::value; - static_assert(value < sizeof...(Keys), - "Provided string_literal doesn't exist in searched list"); -}; - -template -struct parameter_key_pack_type_helper { - static constexpr string_literal literal = parameter_key_pack_type_helper::literal; -}; - -template -struct parameter_key_pack_type_helper { - static constexpr string_literal literal = Key0; -}; - -template -struct parameter_key_pack_type { - static constexpr string_literal literal = parameter_key_pack_type_helper::literal; - - static_assert(i < sizeof...(Keys), "Provided index is too large for list"); -}; - -template -struct parameter_pack_value_helper { - static constexpr T value = parameter_pack_value_helper::value; -}; - -template -struct parameter_pack_value_helper { - static constexpr T value = V0; -}; - -template -struct parameter_pack_value { - static constexpr T value = parameter_pack_value_helper::value; - static_assert(i < sizeof...(Values), "Provided index is too large for list"); -}; - -template -struct ct_multiply; - -template -struct ct_multiply { - static constexpr T value = 1; -}; - -template -struct ct_multiply { - static constexpr T value = V0 * ct_multiply::value; -}; - -namespace impl { -template -struct ct_convert_digits_table_helper { - static_assert(i <= 15, "Only conversion up to hex is supported"); - - static constexpr std::array table = { - '0', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', 'A', 'B', - 'C', 'D', 'E', 'F' - }; - - static constexpr T value = table[i]; -}; - -template -struct ct_convert_digits_helper { - static constexpr size_t size = ct_convert_digits_helper::size; - static constexpr std::array value = ct_convert_digits_helper::value; - static constexpr string_literal literal = ct_convert_digits_helper::literal; -}; - -template -struct ct_convert_digits_helper<0, Base, Digs...> { - static constexpr size_t size = sizeof...(Digs); - static constexpr std::array value = {Digs...}; - static constexpr string_literal literal = {{ct_convert_digits_table_helper::value..., '\0'}}; -}; - -template -struct ct_convert_digits_helper<0, Base> { - static constexpr size_t size = 0; - static constexpr std::array value = {0}; - static constexpr string_literal literal = "0"_sl; -}; -} - -template -struct ct_convert_to_digits { - static_assert(Base <= 16, "Only conversion up to hex is supported"); - - static constexpr size_t size = impl::ct_convert_digits_helper::size; - static constexpr std::array value = impl::ct_convert_digits_helper::value; - static constexpr string_literal literal = impl::ct_convert_digits_helper::literal; -}; -} diff --git a/modules/core/c++/templates.hpp b/modules/core/c++/templates.hpp new file mode 100644 index 0000000..9baaf9f --- /dev/null +++ b/modules/core/c++/templates.hpp @@ -0,0 +1,150 @@ +#pragma once + +#include "string_literal.hpp + +namespace saw { + +template struct parameter_pack_index; + +template struct parameter_pack_index { + static constexpr size_t value = 0u; +}; + +template +struct parameter_pack_index { + static constexpr size_t value = + 1u + parameter_pack_index::value; +}; + +template struct parameter_pack_type { + static_assert(always_false, "Should've been caught by the specializations"); +}; + +template struct parameter_pack_type<0, TN, T...> { + using type = TN; +}; + +template +struct parameter_pack_type { + static_assert(sizeof...(T) > 0, "Exhausted parameters"); + static_assert(N > 0, "Invalid number. Should've been caught"); + using type = typename parameter_pack_type::type; +}; +/* + * Nightmare inducing compiler problems found here. Somehow non-type + * string_literals cannot be resolved as non-type primitive template values can. + * This is the workaround + */ +template +struct parameter_key_pack_index_helper { + static constexpr size_t value = + (V == Key0) + ? (0u) + : (1u + parameter_key_pack_index_helper::value); +}; + +template +struct parameter_key_pack_index_helper { + static constexpr size_t value = (V == Key0) ? (0u) : (1u); +}; + +template +struct parameter_key_pack_index { + static constexpr size_t value = + parameter_key_pack_index_helper::value; + static_assert(value < sizeof...(Keys), + "Provided string_literal doesn't exist in searched list"); +}; + +template +struct parameter_key_pack_type_helper { + static constexpr string_literal literal = parameter_key_pack_type_helper::literal; +}; + +template +struct parameter_key_pack_type_helper { + static constexpr string_literal literal = Key0; +}; + +template +struct parameter_key_pack_type { + static constexpr string_literal literal = parameter_key_pack_type_helper::literal; + + static_assert(i < sizeof...(Keys), "Provided index is too large for list"); +}; + +template +struct parameter_pack_value_helper { + static constexpr T value = parameter_pack_value_helper::value; +}; + +template +struct parameter_pack_value_helper { + static constexpr T value = V0; +}; + +template +struct parameter_pack_value { + static constexpr T value = parameter_pack_value_helper::value; + static_assert(i < sizeof...(Values), "Provided index is too large for list"); +}; + +template +struct ct_multiply; + +template +struct ct_multiply { + static constexpr T value = 1; +}; + +template +struct ct_multiply { + static constexpr T value = V0 * ct_multiply::value; +}; + +namespace impl { +template +struct ct_convert_digits_table_helper { + static_assert(i <= 15, "Only conversion up to hex is supported"); + + static constexpr std::array table = { + '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F' + }; + + static constexpr T value = table[i]; +}; + +template +struct ct_convert_digits_helper { + static constexpr size_t size = ct_convert_digits_helper::size; + static constexpr std::array value = ct_convert_digits_helper::value; + static constexpr string_literal literal = ct_convert_digits_helper::literal; +}; + +template +struct ct_convert_digits_helper<0, Base, Digs...> { + static constexpr size_t size = sizeof...(Digs); + static constexpr std::array value = {Digs...}; + static constexpr string_literal literal = {{ct_convert_digits_table_helper::value..., '\0'}}; +}; + +template +struct ct_convert_digits_helper<0, Base> { + static constexpr size_t size = 0; + static constexpr std::array value = {0}; + static constexpr string_literal literal = "0"_sl; +}; +} + +template +struct ct_convert_to_digits { + static_assert(Base <= 16, "Only conversion up to hex is supported"); + + static constexpr size_t size = impl::ct_convert_digits_helper::size; + static constexpr std::array value = impl::ct_convert_digits_helper::value; + static constexpr string_literal literal = impl::ct_convert_digits_helper::literal; +}; +} diff --git a/modules/core/c++/tree.h b/modules/core/c++/tree.h deleted file mode 100644 index 68fa20a..0000000 --- a/modules/core/c++/tree.h +++ /dev/null @@ -1,248 +0,0 @@ -#pragma once - -#include -#include - -#include "error.h" - -namespace saw { -/** - * Container with a simplistic approach to a branch - */ -template -class branch; - -/** - * Tree object holding branches. - * - * The name comes from the fact a tree is acting as a node while the branch class is the - * edge to a leaf or other nodes. A tree holds the branches while the branch either has - * a leaf or another sub tree. - */ -template -class tree_container final { -private: - /** - * Object holding the treeed branch instances - */ - std::vector> children_; -public: - /** - * Default constructor - */ - tree_container() = default; - - /** - * Destructor - */ - ~tree_container() = default; - - SAW_FORBID_COPY(tree_container); - SAW_DEFAULT_MOVE(tree_container); - - /** - * Reserve space for siz elements - */ - error_or reserve(std::size_t siz){ - try{ - children_.reserve(siz); - }catch(const std::exception& e){ - (void) e; - - return make_error(); - } - - return void_t{}; - } - - /** - * Add a branch with a leaf attached to the tree - */ - error_or add(T leaf) { - std::size_t index = size(); - try { - /** - * Technically we're adding a leaf on a branch - */ - children_.emplace_back(std::move(leaf)); - }catch(const std::exception& e){ - (void)e; - - return make_error(); - } - - return index; - } - - /** - * Add a branch to the tree with a tree attached - */ - error_or add() { - std::size_t index = size(); - try { - - children_.emplace_back(Tree{}); - }catch(const std::exception& e){ - (void)e; - - return make_error(); - } - - return index; - } - - /** - * Returns the amount of branches contained within this tree level - */ - std::size_t size() const { - return children_.size(); - } - - /** - * Returns the branch at i - */ - branch& at(std::size_t i){ - return children_.at(i); - } - - /** - * Returns the branch at i - */ - const branch& at(std::size_t i) const { - return children_.at(i); - } -}; - -template -class branch final { -private: - using type = std::variant; - type tov_; - - /** - * We're friend classing the tree since it's way easier this way and the branch and tree - * class are intertwined heavily anyway. - */ -public: - /** - * - */ - branch():tov_{Tree{}}{} - - branch(Tree nd):tov_{std::move(nd)}{} - - branch(T val):tov_{std::move(val)}{} - - SAW_FORBID_COPY(branch); - SAW_DEFAULT_MOVE(branch); - - template - bool is() const { - return std::holds_alternative(tov_); - } - - bool is_tree() const { - return std::holds_alternative(tov_); - } - - bool is_value() const { - return std::holds_alternative(tov_); - } - - template - NT& get() { - return std::get(tov_); - } - - template - const NT& get() const { - return std::get(tov_); - } - - Tree& get_tree(){ - return std::get(tov_); - } - - const Tree& get_tree() const { - return std::get(tov_); - } - - T& get_value(){ - return std::get(tov_); - } - - const T& get_value() const { - return std::get(tov_); - } - - template - error_or extract(){ - if(!is()){ - return make_error(); - } - - NT nd = std::move(std::get(tov_)); - tov_ = Tree{}; - - return nd; - } - - template - error_or replace(type nd){ - auto eon = extract(); - if(eon.is_error()){ - return eon; - } - - tov_ = std::move(nd); - - return eon; - } - - error_or extract_tree() { - return extract(); - } - - error_or replace_tree(type nd){ - return replace(std::move(nd)); - } - - error_or extract_value() { - return extract(); - } - - error_or replace_value(type nd){ - return replace(std::move(nd)); - } -}; - -template -class tree { - private: - tree_container> data_; - public: - error_or reserve(std::size_t size){ - return data_.reserve(size); - } - - size_t size() const { - return data_.size(); - } - - error_or add() { - return data_.add(); - } - - error_or add(T leaf){ - return data_.add(std::move(leaf)); - } - - branch>& at(size_t i){ - return data_.at(i); - } - - const branch>& at(size_t i) const { - return data_.at(i); - } -}; -} diff --git a/modules/core/c++/tree.hpp b/modules/core/c++/tree.hpp new file mode 100644 index 0000000..4a721b5 --- /dev/null +++ b/modules/core/c++/tree.hpp @@ -0,0 +1,248 @@ +#pragma once + +#include +#include + +#include "error.hpp + +namespace saw { +/** + * Container with a simplistic approach to a branch + */ +template +class branch; + +/** + * Tree object holding branches. + * + * The name comes from the fact a tree is acting as a node while the branch class is the + * edge to a leaf or other nodes. A tree holds the branches while the branch either has + * a leaf or another sub tree. + */ +template +class tree_container final { +private: + /** + * Object holding the treeed branch instances + */ + std::vector> children_; +public: + /** + * Default constructor + */ + tree_container() = default; + + /** + * Destructor + */ + ~tree_container() = default; + + SAW_FORBID_COPY(tree_container); + SAW_DEFAULT_MOVE(tree_container); + + /** + * Reserve space for siz elements + */ + error_or reserve(std::size_t siz){ + try{ + children_.reserve(siz); + }catch(const std::exception& e){ + (void) e; + + return make_error(); + } + + return void_t{}; + } + + /** + * Add a branch with a leaf attached to the tree + */ + error_or add(T leaf) { + std::size_t index = size(); + try { + /** + * Technically we're adding a leaf on a branch + */ + children_.emplace_back(std::move(leaf)); + }catch(const std::exception& e){ + (void)e; + + return make_error(); + } + + return index; + } + + /** + * Add a branch to the tree with a tree attached + */ + error_or add() { + std::size_t index = size(); + try { + + children_.emplace_back(Tree{}); + }catch(const std::exception& e){ + (void)e; + + return make_error(); + } + + return index; + } + + /** + * Returns the amount of branches contained within this tree level + */ + std::size_t size() const { + return children_.size(); + } + + /** + * Returns the branch at i + */ + branch& at(std::size_t i){ + return children_.at(i); + } + + /** + * Returns the branch at i + */ + const branch& at(std::size_t i) const { + return children_.at(i); + } +}; + +template +class branch final { +private: + using type = std::variant; + type tov_; + + /** + * We're friend classing the tree since it's way easier this way and the branch and tree + * class are intertwined heavily anyway. + */ +public: + /** + * + */ + branch():tov_{Tree{}}{} + + branch(Tree nd):tov_{std::move(nd)}{} + + branch(T val):tov_{std::move(val)}{} + + SAW_FORBID_COPY(branch); + SAW_DEFAULT_MOVE(branch); + + template + bool is() const { + return std::holds_alternative(tov_); + } + + bool is_tree() const { + return std::holds_alternative(tov_); + } + + bool is_value() const { + return std::holds_alternative(tov_); + } + + template + NT& get() { + return std::get(tov_); + } + + template + const NT& get() const { + return std::get(tov_); + } + + Tree& get_tree(){ + return std::get(tov_); + } + + const Tree& get_tree() const { + return std::get(tov_); + } + + T& get_value(){ + return std::get(tov_); + } + + const T& get_value() const { + return std::get(tov_); + } + + template + error_or extract(){ + if(!is()){ + return make_error(); + } + + NT nd = std::move(std::get(tov_)); + tov_ = Tree{}; + + return nd; + } + + template + error_or replace(type nd){ + auto eon = extract(); + if(eon.is_error()){ + return eon; + } + + tov_ = std::move(nd); + + return eon; + } + + error_or extract_tree() { + return extract(); + } + + error_or replace_tree(type nd){ + return replace(std::move(nd)); + } + + error_or extract_value() { + return extract(); + } + + error_or replace_value(type nd){ + return replace(std::move(nd)); + } +}; + +template +class tree { + private: + tree_container> data_; + public: + error_or reserve(std::size_t size){ + return data_.reserve(size); + } + + size_t size() const { + return data_.size(); + } + + error_or add() { + return data_.add(); + } + + error_or add(T leaf){ + return data_.add(std::move(leaf)); + } + + branch>& at(size_t i){ + return data_.at(i); + } + + const branch>& at(size_t i) const { + return data_.at(i); + } +}; +} -- cgit v1.2.3