diff --git a/.vscode/settings.json b/.vscode/settings.json index aca7075..79053e4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,6 +19,52 @@ "functional": "cpp", "tuple": "cpp", "type_traits": "cpp", - "utility": "cpp" + "utility": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "string": "cpp", + "string_view": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "limits": "cpp", + "new": "cpp", + "numbers": "cpp", + "ranges": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "typeinfo": "cpp" } } \ No newline at end of file diff --git a/include/gp/algorithms/sort.hpp b/include/gp/algorithms/sort.hpp new file mode 100644 index 0000000..9181ed7 --- /dev/null +++ b/include/gp/algorithms/sort.hpp @@ -0,0 +1,25 @@ +#pragma once +#include + +namespace gp { + template + void selection_sort(it_t first, it_t last, pred predicate = pred{}) { + + while(first != last) { + auto traveler = first; + auto it = first; + it++; + for(;it!=last;it++) { + if(predicate(*it, *traveler)) traveler = it; + } + gp::swap(*first, *traveler); + first++; + } + } + + + template + void sort(it_t first, it_t last, pred predicate = pred{}) { + return selection_sort(first, last, predicate); + } +} \ No newline at end of file diff --git a/include/gp/containers/flat_tree.hpp b/include/gp/containers/flat_tree.hpp index 932fd99..5722efb 100644 --- a/include/gp/containers/flat_tree.hpp +++ b/include/gp/containers/flat_tree.hpp @@ -1,12 +1,177 @@ -#pragma one +#pragma once +#include #include -#include -#include +#include +#include +#include // UNIMPLEMENTED: see filename -template -class flat_tree { - gp::array data_; +namespace gp { -}; + namespace ordinators { + struct less { + template + bool operator() (const T& lhs, const T& rhs){ + return lhs < rhs; + } + }; + } + + /** + * @brief + * + * @tparam T The type to store, must be either final or primitive + * @tparam capacity The number of elements that can be stored in the structure + */ + template + class flat_tree { + using node_t = gp::optional; + gp::array data_; + + static void ordain(auto destination_space, auto value_workspace, index_to_1 idx) { + if(!value_workspace.size()) return; + size_t pivot; + + if(value_workspace.size()%2) { + pivot = value_workspace.size()/2 + 1; + } else { + pivot = value_workspace.size()/2; + } + + destination_space[idx] = gp::move(value_workspace[pivot]); + auto left = idx; + left.left(); + ordain(destination_space, value_workspace.slice_start(pivot), left); + auto right = idx; + right.right(); + ordain(destination_space, value_workspace.trim_start(pivot+1), left); + }; + + public: + using iterator = gp::flat_tree_iterator; + using riterator = gp::flat_tree_iterator; + + friend iterator; + friend riterator; + + flat_tree(auto data) { + gp_config::assertion(data.size() <= data_.size(), "Couldn't construct flat tree from C array"); + for(auto v : data) { + insert(v); + } + } + + bool insert(T& value) { + index_to_1 idx(0); + while(idx < data_.size() && data()[idx].has_value()) { + if(ordinator()(data()[idx].value(), value)) { + idx.left(); + } else { + idx.right(); + } + } + + if (idx >= data_.size()) [[unlikely]] { + if(rebalance_with_value(value)) return true; + if constexpr (gp_config::has_exceptions) { + + } + return false; + } + + data()[idx] = value; + return true; + } + + /** + * @brief Rebalance the tree + * + * @param value The value to try to push along with the rebalance + * + * @return true if the operation suceeded + * @return false if the operation failed + */ + bool rebalance_with_value(T& value) { + // TODO: Add constant memory shenanigans + /* + auto workspace = data_.as_buffer(); + + bool ok = false; + for(auto& elem : workspace) { + if(!elem.has_value()) { + ok = true; + break; + } + } + + if(!ok) return false; + + gp::sort(workspace.begin(), workspace.end(), [](const node_t& lhs, const node_t& rhs){ return lhs.has_value() > rhs.has_value(); }); + + size_t cnt = 0; + for(auto& elem : workspace) { + if(elem.has_value()) break; + ++cnt; + } + + --cnt; + workspace[cnt] = value; + + auto value_workspace = workspace.trim_start(cnt); + + gp::sort(value_workspace.begin(), value_workspace.end(), [](const node_t& lhs, const node_t& rhs){ return ordinator(lhs.value(), rhs.value()); }); + + auto destination_space = workspace.slice_start(value_workspace.size()); + + for(auto ) + */ + + auto oth = gp::move(data_); + auto workspace = oth.as_buffer(); + + bool ok = false; + for(auto& elem : workspace) { + if(!elem.has_value()) { + ok = true; + break; + } + } + + if(!ok) return false; + + gp::sort(workspace.begin(), workspace.end(), [](const node_t& lhs, const node_t& rhs){ return lhs.has_value() > rhs.has_value(); }); + + size_t cnt = 0; + for(auto& elem : workspace) { + if(elem.has_value()) break; + ++cnt; + } + + --cnt; + workspace[cnt] = value; + + auto value_workspace = workspace.trim_start(cnt); + + gp::sort(value_workspace.begin(), value_workspace.end(), [](const node_t& lhs, const node_t& rhs){ return ordinator()(lhs.value(), rhs.value()); }); + + auto destination_space = workspace.slice_start(value_workspace.size()); + + ordain(destination_space, value_workspace, 0); + + return true; + } + + iterator begin() { + return ++iterator{.tree = *this, .index = (size_t)-1}; + } + + iterator end() { + return iterator{.tree = *this, .index = (size_t)-1}; + } + + auto data() { + return data_.as_buffer(); + } + }; +} diff --git a/include/gp/utils/iterator.hpp b/include/gp/utils/iterator.hpp index 9a9654f..a5577f0 100644 --- a/include/gp/utils/iterator.hpp +++ b/include/gp/utils/iterator.hpp @@ -1,239 +1,5 @@ #pragma once -#include -#include - -// TODO: Specify the concept of an iterator - -namespace gp { - - /** - * @brief An enumeration that may be used to determine iterator categories - * - */ - enum class iterator_type_t{ - contiguous_iterator, /**< Defines an iterator for something that is continuous and random access */ - non_contiguous_iterator, /**< Defines an iterator for a non contiguous datastructure, for example an iterator over a hashmap or a tree*/ - lazy_iterator /**< Defines an iterator for which the actual data layout and availability are still unknown*/ - }; - - /** - * @brief An abstraction of a pointer to iterate against, in both normal and reverse order - * - * @tparam T The type of data pointed by the iterator - * @tparam sign the direction in which data is scrutinized, should be either 1 or -1, behaviour for other value is left undefined - */ - template - struct pointer_iterator final - { - T* data; /**< the only data field of the class */ - typedef T value_type; /**< The type of which a reference will be returned on dereferencing */ - typedef std::size_t difference_type; /**< The type of the substraction of two pointers */ - static constexpr iterator_type_t iterator_type = iterator_type_t::contiguous_iterator; /**< @see iterator_type_t */ - - /** - * @brief Generates an empty iterator - */ - constexpr pointer_iterator() - : data{nullptr} - {} - - constexpr pointer_iterator(const pointer_iterator& oth) - : data{oth.data} - {} - - /** - * @brief Generates an iterator from any pointer - */ - constexpr pointer_iterator(T* ptr) - : data{ptr} - {} - - /** - * @brief Dereference unary operator - * - * @return constexpr T& returns a reference to the pointed value - */ - constexpr T& operator*() const - { - return *data; - } - - constexpr pointer_iterator& operator++() - { - data += sign; - return *this; - } - - constexpr pointer_iterator operator++(int) - { - auto p = *this; - data += sign; - return p; - } - - constexpr pointer_iterator& operator--() - { - data -= sign; - return *this; - } - - constexpr pointer_iterator operator--(int) - { - auto p = *this; - data -= sign; - return p; - } - - constexpr pointer_iterator operator+(const std::size_t offset) const - { - return pointer_iterator{data+sign*offset}; - } - - constexpr pointer_iterator operator+(const int offset) const - { - return pointer_iterator{data+sign*offset}; - } - - constexpr pointer_iterator operator-(const std::size_t offset) const - { - return pointer_iterator{data-sign*offset}; - } - - constexpr pointer_iterator operator-(const int offset) const - { - return pointer_iterator{data-sign*offset}; - } - - constexpr difference_type operator-(const pointer_iterator& oth) const - { - return ((T*)data-(T*)oth.data)*sign; - } - - constexpr bool operator==(const pointer_iterator oth) const - { - return data==oth.data; - } - - constexpr bool operator!=(pointer_iterator oth) const - { - return data!=oth.data; - } - - constexpr bool before_or_equal(const pointer_iterator oth) const - { - return reinterpret_cast(data) <= reinterpret_cast(oth.data); - } - - constexpr bool operator<=(const pointer_iterator oth) const - { - return before_or_equal(oth); - } - }; - - /** - * @brief An identical twin to the pointer_iterator, but which dereference to a const reference - * - * @see pointer_iterator - * @tparam T @see pointer_iterator - * @tparam sign @see pointer_iterator - */ - template - struct const_pointer_iterator final - { - const T* data; /**< @see pointer_iterator */ - typedef T value_type; /**< @see pointer_iterator */ - typedef std::size_t difference_type; /**< @see pointer_iterator */ - static constexpr iterator_type_t iterator_type = iterator_type_t::contiguous_iterator; /**< @see pointer_iterator */ - - constexpr const_pointer_iterator(const const_pointer_iterator& oth) - : data{oth.data} - {} - - /** - * @brief @see pointer_iterator - */ - constexpr const_pointer_iterator(const T* ptr) - : data{ptr} - {} - - /** - * @brief Dereferencing returns a const version of what a pointer_iterator would return - */ - constexpr const T& operator*() const - { - return *data; - } - - constexpr const_pointer_iterator& operator++() - { - data += sign; - return *this; - } - - constexpr const_pointer_iterator operator++(int) - { - auto p = data; - data += sign; - return const_pointer_iterator{p}; - } - - constexpr const_pointer_iterator& operator--() - { - data -= sign; - return *this; - } - - constexpr const_pointer_iterator operator--(int) - { - auto p = data; - data -= sign; - return const_pointer_iterator{p}; - } - - constexpr const_pointer_iterator operator+(const std::size_t offset) const - { - return const_pointer_iterator{data+sign*offset}; - } - - constexpr const_pointer_iterator operator+(const int offset) const - { - return const_pointer_iterator{data+sign*offset}; - } - - constexpr const_pointer_iterator operator-(const std::size_t offset) const - { - return const_pointer_iterator{data-sign*offset}; - } - - constexpr const_pointer_iterator operator-(const int offset) - { - return const_pointer_iterator{data-sign*offset}; - } - - constexpr difference_type operator-(const const_pointer_iterator& oth) const - { - return ((T*)data-(T*)oth.data)*sign; - } - - constexpr bool operator==(const const_pointer_iterator oth) const - { - return data==oth.data; - } - - constexpr bool operator!=(const_pointer_iterator oth) const - { - return data!=oth.data; - } - - constexpr bool before_or_equal(const const_pointer_iterator oth) const - { - return reinterpret_cast(data) <= reinterpret_cast(oth.data); - } - - constexpr bool operator<=(const const_pointer_iterator oth) const - { - return before_or_equal(oth); - } - }; -} \ No newline at end of file +#include +#include +#include \ No newline at end of file diff --git a/include/gp/utils/iterators/flat_tree_iterator.hpp b/include/gp/utils/iterators/flat_tree_iterator.hpp new file mode 100644 index 0000000..b827b15 --- /dev/null +++ b/include/gp/utils/iterators/flat_tree_iterator.hpp @@ -0,0 +1,129 @@ +#pragma once + +#include + +#include +#include + +namespace gp { + + struct index_to_1 { + size_t value; + + index_to_1(size_t v) : value{v + 1} + {} + + void left() { + value <<= 1; + } + + void right() { + value = (value << 1) + 1; + } + + void up() { + value >>= 1; + } + + bool is_right() const { + return value & 1; + } + + bool is_left() const { + return !(value & 1); + } + + bool is_root() const { + return value == 1; + } + + operator size_t() { + return value - 1; + } + }; + + template + struct flat_tree_iterator { + reflect& tree; + size_t index; + + bool has_right(index_to_1 v) const { + v.right(); + return (v < tree.data().size()) && (tree.data()[v].has_value()); + } + + bool has_left(index_to_1 v) const { + v.left(); + return (v < tree.data().size()) && (tree.data()[v].has_value()); + } + + flat_tree_iterator& operator++() { + index = next(); + return *this; + } + + flat_tree_iterator operator++(int) { + auto cpy = *this; + index = next(); + return cpy; + } + + size_t next() const { + index_to_1 it{index}; + + enum class cases { + right_climber, + left_climber, + descender, + starter + }; + + const cases current_case = [&](){ + if(index == (size_t)-1) { + return cases::starter; + } else if(has_right(it)) { + return cases::descender; + } else if(it.is_left()) { + return cases::left_climber; + } else { + return cases::right_climber; + } + }(); + + switch(current_case) { + case cases::starter: { + it = index_to_1{0}; + while(has_left(it)) { + it.left(); + } + } break; + case cases::descender: { + it.right(); + while(has_left(it)) { + it.left(); + } + } break; + case cases::left_climber: { + it.up(); + } break; + case cases::right_climber: { + while(it.is_right()) { + it.up(); + } + if(it.is_root()) { + it.value = -1; + } + } break; + } + return it; + } + + bool operator!=(flat_tree_iterator rhs) { + return index != rhs.index; + } + + T& operator*() { + return tree.data_[index].value(); + } + }; +} \ No newline at end of file diff --git a/include/gp/utils/iterators/iterator_properties.hpp b/include/gp/utils/iterators/iterator_properties.hpp new file mode 100644 index 0000000..fb5e35e --- /dev/null +++ b/include/gp/utils/iterators/iterator_properties.hpp @@ -0,0 +1,16 @@ +#pragma once + +// TODO: Specify the concept of an iterator + +namespace gp { + + /** + * @brief An enumeration that may be used to determine iterator categories + * + */ + enum class iterator_type_t{ + contiguous_iterator, /**< Defines an iterator for something that is continuous and random access */ + non_contiguous_iterator, /**< Defines an iterator for a non contiguous datastructure, for example an iterator over a hashmap or a tree */ + lazy_iterator /**< Defines an iterator for which the actual data layout and availability are still unknown */ + }; +} \ No newline at end of file diff --git a/include/gp/utils/iterators/pointer_iterator.hpp b/include/gp/utils/iterators/pointer_iterator.hpp new file mode 100644 index 0000000..b470942 --- /dev/null +++ b/include/gp/utils/iterators/pointer_iterator.hpp @@ -0,0 +1,230 @@ +#pragma once + +#include + +#include +#include + +// TODO: Specify the concept of an iterator + +namespace gp { + /** + * @brief An abstraction of a pointer to iterate against, in both normal and reverse order + * + * @tparam T The type of data pointed by the iterator + * @tparam sign the direction in which data is scrutinized, should be either 1 or -1, behaviour for other value is left undefined + */ + template + struct pointer_iterator final + { + T* data; /**< the only data field of the class */ + typedef T value_type; /**< The type of which a reference will be returned on dereferencing */ + typedef std::size_t difference_type; /**< The type of the substraction of two pointers */ + static constexpr iterator_type_t iterator_type = iterator_type_t::contiguous_iterator; /**< @see iterator_type_t */ + + /** + * @brief Generates an empty iterator + */ + constexpr pointer_iterator() + : data{nullptr} + {} + + constexpr pointer_iterator(const pointer_iterator& oth) + : data{oth.data} + {} + + /** + * @brief Generates an iterator from any pointer + */ + constexpr pointer_iterator(T* ptr) + : data{ptr} + {} + + /** + * @brief Dereference unary operator + * + * @return constexpr T& returns a reference to the pointed value + */ + constexpr T& operator*() const + { + return *data; + } + + constexpr pointer_iterator& operator++() + { + data += sign; + return *this; + } + + constexpr pointer_iterator operator++(int) + { + auto p = *this; + data += sign; + return p; + } + + constexpr pointer_iterator& operator--() + { + data -= sign; + return *this; + } + + constexpr pointer_iterator operator--(int) + { + auto p = *this; + data -= sign; + return p; + } + + constexpr pointer_iterator operator+(const std::size_t offset) const + { + return pointer_iterator{data+sign*offset}; + } + + constexpr pointer_iterator operator+(const int offset) const + { + return pointer_iterator{data+sign*offset}; + } + + constexpr pointer_iterator operator-(const std::size_t offset) const + { + return pointer_iterator{data-sign*offset}; + } + + constexpr pointer_iterator operator-(const int offset) const + { + return pointer_iterator{data-sign*offset}; + } + + constexpr difference_type operator-(const pointer_iterator& oth) const + { + return ((T*)data-(T*)oth.data)*sign; + } + + constexpr bool operator==(const pointer_iterator oth) const + { + return data==oth.data; + } + + constexpr bool operator!=(pointer_iterator oth) const + { + return data!=oth.data; + } + + constexpr bool before_or_equal(const pointer_iterator oth) const + { + return reinterpret_cast(data) <= reinterpret_cast(oth.data); + } + + constexpr bool operator<=(const pointer_iterator oth) const + { + return before_or_equal(oth); + } + }; + + /** + * @brief An identical twin to the pointer_iterator, but which dereference to a const reference + * + * @see pointer_iterator + * @tparam T @see pointer_iterator + * @tparam sign @see pointer_iterator + */ + template + struct const_pointer_iterator final + { + const T* data; /**< @see pointer_iterator */ + typedef T value_type; /**< @see pointer_iterator */ + typedef std::size_t difference_type; /**< @see pointer_iterator */ + static constexpr iterator_type_t iterator_type = iterator_type_t::contiguous_iterator; /**< @see pointer_iterator */ + + constexpr const_pointer_iterator(const const_pointer_iterator& oth) + : data{oth.data} + {} + + /** + * @brief @see pointer_iterator + */ + constexpr const_pointer_iterator(const T* ptr) + : data{ptr} + {} + + /** + * @brief Dereferencing returns a const version of what a pointer_iterator would return + */ + constexpr const T& operator*() const + { + return *data; + } + + constexpr const_pointer_iterator& operator++() + { + data += sign; + return *this; + } + + constexpr const_pointer_iterator operator++(int) + { + auto p = data; + data += sign; + return const_pointer_iterator{p}; + } + + constexpr const_pointer_iterator& operator--() + { + data -= sign; + return *this; + } + + constexpr const_pointer_iterator operator--(int) + { + auto p = data; + data -= sign; + return const_pointer_iterator{p}; + } + + constexpr const_pointer_iterator operator+(const std::size_t offset) const + { + return const_pointer_iterator{data+sign*offset}; + } + + constexpr const_pointer_iterator operator+(const int offset) const + { + return const_pointer_iterator{data+sign*offset}; + } + + constexpr const_pointer_iterator operator-(const std::size_t offset) const + { + return const_pointer_iterator{data-sign*offset}; + } + + constexpr const_pointer_iterator operator-(const int offset) + { + return const_pointer_iterator{data-sign*offset}; + } + + constexpr difference_type operator-(const const_pointer_iterator& oth) const + { + return ((T*)data-(T*)oth.data)*sign; + } + + constexpr bool operator==(const const_pointer_iterator oth) const + { + return data==oth.data; + } + + constexpr bool operator!=(const_pointer_iterator oth) const + { + return data!=oth.data; + } + + constexpr bool before_or_equal(const const_pointer_iterator oth) const + { + return reinterpret_cast(data) <= reinterpret_cast(oth.data); + } + + constexpr bool operator<=(const const_pointer_iterator oth) const + { + return before_or_equal(oth); + } + }; +} \ No newline at end of file diff --git a/include/gp_config.hpp b/include/gp_config.hpp index 9fd5c07..068f6b5 100644 --- a/include/gp_config.hpp +++ b/include/gp_config.hpp @@ -99,6 +99,7 @@ namespace gp_config{ namespace memory_module{ constexpr bool is_ok = true; + constexpr bool prefer_constant_memory = true; } typedef uint32_t file_descriptor_t; diff --git a/tests/flat_tree_test.cpp b/tests/flat_tree_test.cpp new file mode 100644 index 0000000..cdcf895 --- /dev/null +++ b/tests/flat_tree_test.cpp @@ -0,0 +1,22 @@ +#include "test_scaffold.h" +#include +#include + +struct flat_tree_test : public test_scaffold { + flat_tree_test() { + name = __FILE__ ":1"; + } + + virtual int run() { + gp::array v = {1,2,3,4,5,6,7}; + gp::flat_tree hello(v); + + for(auto elem : hello) { + std::cout << elem << std::endl; + } + + return 0; + } +}; + +append_test dummy_sdfjlm6543(new flat_tree_test{}); \ No newline at end of file