#pragma once #include #include #include #include #include // UNIMPLEMENTED: see filename 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; } else { pivot = value_workspace.size()/2 + 1; } 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(); } }; }