From 31b20248cd44b80a5652d13ecd28ef8e5bd389f8 Mon Sep 17 00:00:00 2001 From: cong1920 Date: Mon, 30 Dec 2024 01:01:23 -0800 Subject: [PATCH 1/5] [http_server] Manage srings by unordered_set efficiently --- .../http_server/dynamic_routing_table.hh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/http_server/http_server/dynamic_routing_table.hh b/libraries/http_server/http_server/dynamic_routing_table.hh index 783c262..fe5fc22 100644 --- a/libraries/http_server/http_server/dynamic_routing_table.hh +++ b/libraries/http_server/http_server/dynamic_routing_table.hh @@ -5,6 +5,7 @@ #include #include #include +#include namespace li { @@ -114,14 +115,14 @@ template struct dynamic_routing_table { // Find a route and return reference to a procedure. auto& operator[](const std::string_view& r) { - strings.push_back(std::make_shared(r)); - std::string_view r2(*strings.back()); + auto [itr, is_inserted] = strings.emplace(std::string(r)); + std::string_view r2(*itr); return root.find_or_create(r2, 0); } - auto& operator[](const std::string& r) { - strings.push_back(std::make_shared(r)); - std::string_view r2(*strings.back()); - return root.find_or_create(r2, 0); + auto& operator[](const std::string& s) { + auto [itr, is_inserted] = strings.emplace(s); + std::string_view r(*itr); + return root.find_or_create(r, 0); } // Find a route and return an iterator. @@ -130,7 +131,7 @@ template struct dynamic_routing_table { template void for_all_routes(F f) const { root.for_all_routes(f); } auto end() const { return root.end(); } - std::vector> strings; + std::unordered_set strings; internal::drt_node root; }; From dfcb27e357bdb8c2d09c144b5fc04638070e437d Mon Sep 17 00:00:00 2001 From: cong1920 Date: Mon, 30 Dec 2024 23:20:08 -0800 Subject: [PATCH 2/5] [http_server] Use classic impl wrapper to have one shared_ptr ...other than shared_ptr everywhere on each small drt_node objects. --- .../http_server/dynamic_routing_table.hh | 71 ++++++++++++++----- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/libraries/http_server/http_server/dynamic_routing_table.hh b/libraries/http_server/http_server/dynamic_routing_table.hh index fe5fc22..66d91ef 100644 --- a/libraries/http_server/http_server/dynamic_routing_table.hh +++ b/libraries/http_server/http_server/dynamic_routing_table.hh @@ -11,9 +11,21 @@ namespace li { namespace internal { -template struct drt_node { +// A simple memory pool for drt_node objects +template struct drt_node_pool { + template T* allocate(Args&&... args) { + auto new_node = std::make_unique(std::forward(args)...); + T* ptr = new_node.get(); + pool_.emplace_back(std::move(new_node)); + return ptr; + } + + std::vector> pool_; +}; - drt_node() : v_{0, nullptr} {} +template struct drt_node { + drt_node() : pool_(nullptr), v_{0, nullptr} {} + drt_node(drt_node_pool& pool) : pool_(pool), v_{0, nullptr} {} struct iterator { const drt_node* ptr; @@ -38,17 +50,10 @@ template struct drt_node { c++; std::string_view k = r.substr(s, c - s); - auto it = children_.find(k); - if (it != children_.end()) - return children_[k]->find_or_create(r, c); - else { - auto new_node = std::make_shared(); - children_shared_pointers_.push_back(new_node); - children_.insert({k, new_node.get()}); - return new_node->find_or_create(r, c); + if (children_.find(k) == children_.end()) { + children_[k] = pool_.allocate(pool_); } - - return v_; + return children_[k]->find_or_create(r, c); } template void for_all_routes(F f, std::string prefix = "") const { @@ -57,8 +62,8 @@ template struct drt_node { else { if (prefix.size() && prefix.back() != '/') prefix += '/'; - for (auto pair : children_) - pair.second->for_all_routes(f, prefix + std::string(pair.first)); + for (const auto& kv : children_) + kv.second->for_all_routes(f, prefix + std::string(kv.first)); } } @@ -95,7 +100,7 @@ template struct drt_node { { // if one child is a url param {{param_name}}, choose it - for (auto& kv : children_) { + for (const auto& kv : children_) { auto name = kv.first; if (name.size() > 4 and name[0] == '{' and name[1] == '{' and name[name.size() - 2] == '}' and name[name.size() - 1] == '}') @@ -107,11 +112,11 @@ template struct drt_node { V v_; std::unordered_map children_; - std::vector> children_shared_pointers_; + drt_node_pool& pool_; }; -} // namespace internal -template struct dynamic_routing_table { +template struct dynamic_routing_table_impl { + dynamic_routing_table_impl() : root(pool) {} // Find a route and return reference to a procedure. auto& operator[](const std::string_view& r) { @@ -132,7 +137,35 @@ template struct dynamic_routing_table { auto end() const { return root.end(); } std::unordered_set strings; - internal::drt_node root; + drt_node_pool> pool; + drt_node root; +}; +} // namespace internal + +template struct dynamic_routing_table { + dynamic_routing_table() : impl_(std::make_shared>()) {} + dynamic_routing_table(const dynamic_routing_table& other) : impl_(other.impl_) {} + + // Assignment operator + dynamic_routing_table& operator=(const dynamic_routing_table& other) { + if (this != &other) { + impl_ = other.impl_; + } + return *this; + } + + // Find a route and return reference to a procedure. + auto& operator[](const std::string_view& r) { return impl_->operator[](r); } + auto& operator[](const std::string& s) { return impl_->operator[](s); } + + // Find a route and return an iterator. + auto find(const std::string_view& r) const { return impl_->find(r); } + + template void for_all_routes(F f) const { impl_->for_all_routes(f); } + auto end() const { return impl_->end(); } + + private: + std::shared_ptr> impl_; }; } // namespace li From 50f71f00481890a22265b74c87fe6aec88348972 Mon Sep 17 00:00:00 2001 From: cong1920 Date: Mon, 30 Dec 2024 23:49:27 -0800 Subject: [PATCH 3/5] [single_headers] Add the generated files --- single_headers/lithium.hh | 86 +++++++++++++++++++-------- single_headers/lithium_http_server.hh | 86 +++++++++++++++++++-------- 2 files changed, 120 insertions(+), 52 deletions(-) diff --git a/single_headers/lithium.hh b/single_headers/lithium.hh index 69acc41..263ec0f 100644 --- a/single_headers/lithium.hh +++ b/single_headers/lithium.hh @@ -73,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -6513,9 +6514,21 @@ namespace li { namespace internal { -template struct drt_node { +// A simple memory pool for drt_node objects +template struct drt_node_pool { + template T* allocate(Args&&... args) { + auto new_node = std::make_unique(std::forward(args)...); + T* ptr = new_node.get(); + pool_.emplace_back(std::move(new_node)); + return ptr; + } - drt_node() : v_{0, nullptr} {} + std::vector> pool_; +}; + +template struct drt_node { + drt_node() : pool_(nullptr), v_{0, nullptr} {} + drt_node(drt_node_pool& pool) : pool_(pool), v_{0, nullptr} {} struct iterator { const drt_node* ptr; @@ -6540,17 +6553,10 @@ template struct drt_node { c++; std::string_view k = r.substr(s, c - s); - auto it = children_.find(k); - if (it != children_.end()) - return children_[k]->find_or_create(r, c); - else { - auto new_node = std::make_shared(); - children_shared_pointers_.push_back(new_node); - children_.insert({k, new_node.get()}); - return new_node->find_or_create(r, c); + if (children_.find(k) == children_.end()) { + children_[k] = pool_.allocate(pool_); } - - return v_; + return children_[k]->find_or_create(r, c); } template void for_all_routes(F f, std::string prefix = "") const { @@ -6559,8 +6565,8 @@ template struct drt_node { else { if (prefix.size() && prefix.back() != '/') prefix += '/'; - for (auto pair : children_) - pair.second->for_all_routes(f, prefix + std::string(pair.first)); + for (const auto& kv : children_) + kv.second->for_all_routes(f, prefix + std::string(kv.first)); } } @@ -6597,7 +6603,7 @@ template struct drt_node { { // if one child is a url param {{param_name}}, choose it - for (auto& kv : children_) { + for (const auto& kv : children_) { auto name = kv.first; if (name.size() > 4 and name[0] == '{' and name[1] == '{' and name[name.size() - 2] == '}' and name[name.size() - 1] == '}') @@ -6609,22 +6615,22 @@ template struct drt_node { V v_; std::unordered_map children_; - std::vector> children_shared_pointers_; + drt_node_pool& pool_; }; -} // namespace internal -template struct dynamic_routing_table { +template struct dynamic_routing_table_impl { + dynamic_routing_table_impl() : root(pool) {} // Find a route and return reference to a procedure. auto& operator[](const std::string_view& r) { - strings.push_back(std::make_shared(r)); - std::string_view r2(*strings.back()); + auto [itr, is_inserted] = strings.emplace(std::string(r)); + std::string_view r2(*itr); return root.find_or_create(r2, 0); } - auto& operator[](const std::string& r) { - strings.push_back(std::make_shared(r)); - std::string_view r2(*strings.back()); - return root.find_or_create(r2, 0); + auto& operator[](const std::string& s) { + auto [itr, is_inserted] = strings.emplace(s); + std::string_view r(*itr); + return root.find_or_create(r, 0); } // Find a route and return an iterator. @@ -6633,8 +6639,36 @@ template struct dynamic_routing_table { template void for_all_routes(F f) const { root.for_all_routes(f); } auto end() const { return root.end(); } - std::vector> strings; - internal::drt_node root; + std::unordered_set strings; + drt_node_pool> pool; + drt_node root; +}; +} // namespace internal + +template struct dynamic_routing_table { + dynamic_routing_table() : impl_(std::make_shared>()) {} + dynamic_routing_table(const dynamic_routing_table& other) : impl_(other.impl_) {} + + // Assignment operator + dynamic_routing_table& operator=(const dynamic_routing_table& other) { + if (this != &other) { + impl_ = other.impl_; + } + return *this; + } + + // Find a route and return reference to a procedure. + auto& operator[](const std::string_view& r) { return impl_->operator[](r); } + auto& operator[](const std::string& s) { return impl_->operator[](s); } + + // Find a route and return an iterator. + auto find(const std::string_view& r) const { return impl_->find(r); } + + template void for_all_routes(F f) const { impl_->for_all_routes(f); } + auto end() const { return impl_->end(); } + + private: + std::shared_ptr> impl_; }; } // namespace li diff --git a/single_headers/lithium_http_server.hh b/single_headers/lithium_http_server.hh index e475f45..71ae75e 100644 --- a/single_headers/lithium_http_server.hh +++ b/single_headers/lithium_http_server.hh @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -3330,9 +3331,21 @@ namespace li { namespace internal { -template struct drt_node { +// A simple memory pool for drt_node objects +template struct drt_node_pool { + template T* allocate(Args&&... args) { + auto new_node = std::make_unique(std::forward(args)...); + T* ptr = new_node.get(); + pool_.emplace_back(std::move(new_node)); + return ptr; + } - drt_node() : v_{0, nullptr} {} + std::vector> pool_; +}; + +template struct drt_node { + drt_node() : pool_(nullptr), v_{0, nullptr} {} + drt_node(drt_node_pool& pool) : pool_(pool), v_{0, nullptr} {} struct iterator { const drt_node* ptr; @@ -3357,17 +3370,10 @@ template struct drt_node { c++; std::string_view k = r.substr(s, c - s); - auto it = children_.find(k); - if (it != children_.end()) - return children_[k]->find_or_create(r, c); - else { - auto new_node = std::make_shared(); - children_shared_pointers_.push_back(new_node); - children_.insert({k, new_node.get()}); - return new_node->find_or_create(r, c); + if (children_.find(k) == children_.end()) { + children_[k] = pool_.allocate(pool_); } - - return v_; + return children_[k]->find_or_create(r, c); } template void for_all_routes(F f, std::string prefix = "") const { @@ -3376,8 +3382,8 @@ template struct drt_node { else { if (prefix.size() && prefix.back() != '/') prefix += '/'; - for (auto pair : children_) - pair.second->for_all_routes(f, prefix + std::string(pair.first)); + for (const auto& kv : children_) + kv.second->for_all_routes(f, prefix + std::string(kv.first)); } } @@ -3414,7 +3420,7 @@ template struct drt_node { { // if one child is a url param {{param_name}}, choose it - for (auto& kv : children_) { + for (const auto& kv : children_) { auto name = kv.first; if (name.size() > 4 and name[0] == '{' and name[1] == '{' and name[name.size() - 2] == '}' and name[name.size() - 1] == '}') @@ -3426,22 +3432,22 @@ template struct drt_node { V v_; std::unordered_map children_; - std::vector> children_shared_pointers_; + drt_node_pool& pool_; }; -} // namespace internal -template struct dynamic_routing_table { +template struct dynamic_routing_table_impl { + dynamic_routing_table_impl() : root(pool) {} // Find a route and return reference to a procedure. auto& operator[](const std::string_view& r) { - strings.push_back(std::make_shared(r)); - std::string_view r2(*strings.back()); + auto [itr, is_inserted] = strings.emplace(std::string(r)); + std::string_view r2(*itr); return root.find_or_create(r2, 0); } - auto& operator[](const std::string& r) { - strings.push_back(std::make_shared(r)); - std::string_view r2(*strings.back()); - return root.find_or_create(r2, 0); + auto& operator[](const std::string& s) { + auto [itr, is_inserted] = strings.emplace(s); + std::string_view r(*itr); + return root.find_or_create(r, 0); } // Find a route and return an iterator. @@ -3450,8 +3456,36 @@ template struct dynamic_routing_table { template void for_all_routes(F f) const { root.for_all_routes(f); } auto end() const { return root.end(); } - std::vector> strings; - internal::drt_node root; + std::unordered_set strings; + drt_node_pool> pool; + drt_node root; +}; +} // namespace internal + +template struct dynamic_routing_table { + dynamic_routing_table() : impl_(std::make_shared>()) {} + dynamic_routing_table(const dynamic_routing_table& other) : impl_(other.impl_) {} + + // Assignment operator + dynamic_routing_table& operator=(const dynamic_routing_table& other) { + if (this != &other) { + impl_ = other.impl_; + } + return *this; + } + + // Find a route and return reference to a procedure. + auto& operator[](const std::string_view& r) { return impl_->operator[](r); } + auto& operator[](const std::string& s) { return impl_->operator[](s); } + + // Find a route and return an iterator. + auto find(const std::string_view& r) const { return impl_->find(r); } + + template void for_all_routes(F f) const { impl_->for_all_routes(f); } + auto end() const { return impl_->end(); } + + private: + std::shared_ptr> impl_; }; } // namespace li From 3e79e2e44e61f1630fc9969e66e6343e9147dfa2 Mon Sep 17 00:00:00 2001 From: cong1920 Date: Sat, 8 Feb 2025 23:41:32 -0800 Subject: [PATCH 4/5] [http_server] Update comments and add noexcept to proper methods --- .../http_server/dynamic_routing_table.hh | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/libraries/http_server/http_server/dynamic_routing_table.hh b/libraries/http_server/http_server/dynamic_routing_table.hh index 66d91ef..6b89861 100644 --- a/libraries/http_server/http_server/dynamic_routing_table.hh +++ b/libraries/http_server/http_server/dynamic_routing_table.hh @@ -11,9 +11,11 @@ namespace li { namespace internal { -// A simple memory pool for drt_node objects +/** + * A memory pool for drt_node objects that manages node allocation and lifetime + */ template struct drt_node_pool { - template T* allocate(Args&&... args) { + template T* allocate(Args&&... args) noexcept { auto new_node = std::make_unique(std::forward(args)...); T* ptr = new_node.get(); pool_.emplace_back(std::move(new_node)); @@ -24,20 +26,20 @@ template struct drt_node_pool { }; template struct drt_node { - drt_node() : pool_(nullptr), v_{0, nullptr} {} - drt_node(drt_node_pool& pool) : pool_(pool), v_{0, nullptr} {} + drt_node() noexcept : pool_(nullptr), v_{0, nullptr} {} + drt_node(drt_node_pool& pool) noexcept : pool_(pool), v_{0, nullptr} {} struct iterator { const drt_node* ptr; std::string_view first; V second; - auto operator->() { return this; } - bool operator==(const iterator& b) const { return this->ptr == b.ptr; } - bool operator!=(const iterator& b) const { return this->ptr != b.ptr; } + auto operator->() noexcept { return this; } + bool operator==(const iterator& b) const noexcept { return this->ptr == b.ptr; } + bool operator!=(const iterator& b) const noexcept { return this->ptr != b.ptr; } }; - auto end() const { return iterator{nullptr, std::string_view(), V()}; } + auto end() const noexcept { return iterator{nullptr, std::string_view(), V()}; } auto& find_or_create(std::string_view r, unsigned int c) { if (c == r.size()) @@ -68,7 +70,7 @@ template struct drt_node { } // Find a route. - iterator find(const std::string_view& r, unsigned int c) const { + iterator find(const std::string_view& r, unsigned int c) const noexcept { // We found the route r. if ((c == r.size() and v_.handler != nullptr) or (children_.size() == 0)) return iterator{this, r, v_}; @@ -116,9 +118,8 @@ template struct drt_node { }; template struct dynamic_routing_table_impl { - dynamic_routing_table_impl() : root(pool) {} + dynamic_routing_table_impl() noexcept : root(pool) {} - // Find a route and return reference to a procedure. auto& operator[](const std::string_view& r) { auto [itr, is_inserted] = strings.emplace(std::string(r)); std::string_view r2(*itr); @@ -130,11 +131,10 @@ template struct dynamic_routing_table_impl { return root.find_or_create(r, 0); } - // Find a route and return an iterator. - auto find(const std::string_view& r) const { return root.find(r, 0); } + auto find(const std::string_view& r) const noexcept { return root.find(r, 0); } template void for_all_routes(F f) const { root.for_all_routes(f); } - auto end() const { return root.end(); } + auto end() const noexcept { return root.end(); } std::unordered_set strings; drt_node_pool> pool; @@ -142,29 +142,29 @@ template struct dynamic_routing_table_impl { }; } // namespace internal +/** + * A dynamic routing table that supports route registration and lookup. + */ template struct dynamic_routing_table { - dynamic_routing_table() : impl_(std::make_shared>()) {} - dynamic_routing_table(const dynamic_routing_table& other) : impl_(other.impl_) {} + dynamic_routing_table() noexcept + : impl_(std::make_shared>()) {} + dynamic_routing_table(const dynamic_routing_table& other) noexcept : impl_(other.impl_) {} - // Assignment operator - dynamic_routing_table& operator=(const dynamic_routing_table& other) { + dynamic_routing_table& operator=(const dynamic_routing_table& other) noexcept { if (this != &other) { impl_ = other.impl_; } return *this; } - // Find a route and return reference to a procedure. auto& operator[](const std::string_view& r) { return impl_->operator[](r); } auto& operator[](const std::string& s) { return impl_->operator[](s); } - // Find a route and return an iterator. - auto find(const std::string_view& r) const { return impl_->find(r); } - + auto find(const std::string_view& r) const noexcept { return impl_->find(r); } template void for_all_routes(F f) const { impl_->for_all_routes(f); } - auto end() const { return impl_->end(); } + auto end() const noexcept { return impl_->end(); } - private: +private: std::shared_ptr> impl_; }; From 7a5aa97324a34458103dad104611e18b52e09810 Mon Sep 17 00:00:00 2001 From: cong1920 Date: Sun, 9 Feb 2025 00:43:31 -0800 Subject: [PATCH 5/5] [http_server] Use pure data wrapper other than an impl instance ...because the function forwardings to the impl are redundant. --- .../http_server/dynamic_routing_table.hh | 48 ++++------- single_headers/lithium.hh | 82 ++++++++----------- single_headers/lithium_http_server.hh | 82 ++++++++----------- 3 files changed, 88 insertions(+), 124 deletions(-) diff --git a/libraries/http_server/http_server/dynamic_routing_table.hh b/libraries/http_server/http_server/dynamic_routing_table.hh index 6b89861..7448371 100644 --- a/libraries/http_server/http_server/dynamic_routing_table.hh +++ b/libraries/http_server/http_server/dynamic_routing_table.hh @@ -117,28 +117,14 @@ template struct drt_node { drt_node_pool& pool_; }; -template struct dynamic_routing_table_impl { - dynamic_routing_table_impl() noexcept : root(pool) {} +template struct dynamic_routing_table_data { + dynamic_routing_table_data() noexcept : root(pool_) {} - auto& operator[](const std::string_view& r) { - auto [itr, is_inserted] = strings.emplace(std::string(r)); - std::string_view r2(*itr); - return root.find_or_create(r2, 0); - } - auto& operator[](const std::string& s) { - auto [itr, is_inserted] = strings.emplace(s); - std::string_view r(*itr); - return root.find_or_create(r, 0); - } - - auto find(const std::string_view& r) const noexcept { return root.find(r, 0); } - - template void for_all_routes(F f) const { root.for_all_routes(f); } - auto end() const noexcept { return root.end(); } - - std::unordered_set strings; - drt_node_pool> pool; + std::unordered_set paths; drt_node root; + +private: + drt_node_pool> pool_; }; } // namespace internal @@ -147,25 +133,27 @@ template struct dynamic_routing_table_impl { */ template struct dynamic_routing_table { dynamic_routing_table() noexcept - : impl_(std::make_shared>()) {} - dynamic_routing_table(const dynamic_routing_table& other) noexcept : impl_(other.impl_) {} + : data_(std::make_shared>()) {} + dynamic_routing_table(const dynamic_routing_table& other) noexcept : data_(other.data_) {} dynamic_routing_table& operator=(const dynamic_routing_table& other) noexcept { if (this != &other) { - impl_ = other.impl_; + data_ = other.data_; } return *this; } - auto& operator[](const std::string_view& r) { return impl_->operator[](r); } - auto& operator[](const std::string& s) { return impl_->operator[](s); } - - auto find(const std::string_view& r) const noexcept { return impl_->find(r); } - template void for_all_routes(F f) const { impl_->for_all_routes(f); } - auto end() const noexcept { return impl_->end(); } + auto& operator[](const std::string_view& r) { return this->operator[](std::string(r)); } + auto& operator[](const std::string& s) { + auto [itr, is_inserted] = data_->paths.emplace(s); + return data_->root.find_or_create(*itr, 0); + } + auto find(const std::string_view& r) const noexcept { return data_->root.find(r, 0); } + template void for_all_routes(F f) const { data_->root.for_all_routes(f); } + auto end() const noexcept { return data_->root.end(); } private: - std::shared_ptr> impl_; + std::shared_ptr> data_; }; } // namespace li diff --git a/single_headers/lithium.hh b/single_headers/lithium.hh index 263ec0f..5ad0b83 100644 --- a/single_headers/lithium.hh +++ b/single_headers/lithium.hh @@ -6514,9 +6514,11 @@ namespace li { namespace internal { -// A simple memory pool for drt_node objects +/** + * A memory pool for drt_node objects that manages node allocation and lifetime + */ template struct drt_node_pool { - template T* allocate(Args&&... args) { + template T* allocate(Args&&... args) noexcept { auto new_node = std::make_unique(std::forward(args)...); T* ptr = new_node.get(); pool_.emplace_back(std::move(new_node)); @@ -6527,20 +6529,20 @@ template struct drt_node_pool { }; template struct drt_node { - drt_node() : pool_(nullptr), v_{0, nullptr} {} - drt_node(drt_node_pool& pool) : pool_(pool), v_{0, nullptr} {} + drt_node() noexcept : pool_(nullptr), v_{0, nullptr} {} + drt_node(drt_node_pool& pool) noexcept : pool_(pool), v_{0, nullptr} {} struct iterator { const drt_node* ptr; std::string_view first; V second; - auto operator->() { return this; } - bool operator==(const iterator& b) const { return this->ptr == b.ptr; } - bool operator!=(const iterator& b) const { return this->ptr != b.ptr; } + auto operator->() noexcept { return this; } + bool operator==(const iterator& b) const noexcept { return this->ptr == b.ptr; } + bool operator!=(const iterator& b) const noexcept { return this->ptr != b.ptr; } }; - auto end() const { return iterator{nullptr, std::string_view(), V()}; } + auto end() const noexcept { return iterator{nullptr, std::string_view(), V()}; } auto& find_or_create(std::string_view r, unsigned int c) { if (c == r.size()) @@ -6571,7 +6573,7 @@ template struct drt_node { } // Find a route. - iterator find(const std::string_view& r, unsigned int c) const { + iterator find(const std::string_view& r, unsigned int c) const noexcept { // We found the route r. if ((c == r.size() and v_.handler != nullptr) or (children_.size() == 0)) return iterator{this, r, v_}; @@ -6618,57 +6620,43 @@ template struct drt_node { drt_node_pool& pool_; }; -template struct dynamic_routing_table_impl { - dynamic_routing_table_impl() : root(pool) {} +template struct dynamic_routing_table_data { + dynamic_routing_table_data() noexcept : root(pool_) {} - // Find a route and return reference to a procedure. - auto& operator[](const std::string_view& r) { - auto [itr, is_inserted] = strings.emplace(std::string(r)); - std::string_view r2(*itr); - return root.find_or_create(r2, 0); - } - auto& operator[](const std::string& s) { - auto [itr, is_inserted] = strings.emplace(s); - std::string_view r(*itr); - return root.find_or_create(r, 0); - } - - // Find a route and return an iterator. - auto find(const std::string_view& r) const { return root.find(r, 0); } - - template void for_all_routes(F f) const { root.for_all_routes(f); } - auto end() const { return root.end(); } - - std::unordered_set strings; - drt_node_pool> pool; + std::unordered_set paths; drt_node root; + +private: + drt_node_pool> pool_; }; } // namespace internal +/** + * A dynamic routing table that supports route registration and lookup. + */ template struct dynamic_routing_table { - dynamic_routing_table() : impl_(std::make_shared>()) {} - dynamic_routing_table(const dynamic_routing_table& other) : impl_(other.impl_) {} + dynamic_routing_table() noexcept + : data_(std::make_shared>()) {} + dynamic_routing_table(const dynamic_routing_table& other) noexcept : data_(other.data_) {} - // Assignment operator - dynamic_routing_table& operator=(const dynamic_routing_table& other) { + dynamic_routing_table& operator=(const dynamic_routing_table& other) noexcept { if (this != &other) { - impl_ = other.impl_; + data_ = other.data_; } return *this; } - // Find a route and return reference to a procedure. - auto& operator[](const std::string_view& r) { return impl_->operator[](r); } - auto& operator[](const std::string& s) { return impl_->operator[](s); } - - // Find a route and return an iterator. - auto find(const std::string_view& r) const { return impl_->find(r); } - - template void for_all_routes(F f) const { impl_->for_all_routes(f); } - auto end() const { return impl_->end(); } + auto& operator[](const std::string_view& r) { return this->operator[](std::string(r)); } + auto& operator[](const std::string& s) { + auto [itr, is_inserted] = data_->paths.emplace(s); + return data_->root.find_or_create(*itr, 0); + } + auto find(const std::string_view& r) const noexcept { return data_->root.find(r, 0); } + template void for_all_routes(F f) const { data_->root.for_all_routes(f); } + auto end() const noexcept { return data_->root.end(); } - private: - std::shared_ptr> impl_; +private: + std::shared_ptr> data_; }; } // namespace li diff --git a/single_headers/lithium_http_server.hh b/single_headers/lithium_http_server.hh index 71ae75e..0f0bb11 100644 --- a/single_headers/lithium_http_server.hh +++ b/single_headers/lithium_http_server.hh @@ -3331,9 +3331,11 @@ namespace li { namespace internal { -// A simple memory pool for drt_node objects +/** + * A memory pool for drt_node objects that manages node allocation and lifetime + */ template struct drt_node_pool { - template T* allocate(Args&&... args) { + template T* allocate(Args&&... args) noexcept { auto new_node = std::make_unique(std::forward(args)...); T* ptr = new_node.get(); pool_.emplace_back(std::move(new_node)); @@ -3344,20 +3346,20 @@ template struct drt_node_pool { }; template struct drt_node { - drt_node() : pool_(nullptr), v_{0, nullptr} {} - drt_node(drt_node_pool& pool) : pool_(pool), v_{0, nullptr} {} + drt_node() noexcept : pool_(nullptr), v_{0, nullptr} {} + drt_node(drt_node_pool& pool) noexcept : pool_(pool), v_{0, nullptr} {} struct iterator { const drt_node* ptr; std::string_view first; V second; - auto operator->() { return this; } - bool operator==(const iterator& b) const { return this->ptr == b.ptr; } - bool operator!=(const iterator& b) const { return this->ptr != b.ptr; } + auto operator->() noexcept { return this; } + bool operator==(const iterator& b) const noexcept { return this->ptr == b.ptr; } + bool operator!=(const iterator& b) const noexcept { return this->ptr != b.ptr; } }; - auto end() const { return iterator{nullptr, std::string_view(), V()}; } + auto end() const noexcept { return iterator{nullptr, std::string_view(), V()}; } auto& find_or_create(std::string_view r, unsigned int c) { if (c == r.size()) @@ -3388,7 +3390,7 @@ template struct drt_node { } // Find a route. - iterator find(const std::string_view& r, unsigned int c) const { + iterator find(const std::string_view& r, unsigned int c) const noexcept { // We found the route r. if ((c == r.size() and v_.handler != nullptr) or (children_.size() == 0)) return iterator{this, r, v_}; @@ -3435,57 +3437,43 @@ template struct drt_node { drt_node_pool& pool_; }; -template struct dynamic_routing_table_impl { - dynamic_routing_table_impl() : root(pool) {} +template struct dynamic_routing_table_data { + dynamic_routing_table_data() noexcept : root(pool_) {} - // Find a route and return reference to a procedure. - auto& operator[](const std::string_view& r) { - auto [itr, is_inserted] = strings.emplace(std::string(r)); - std::string_view r2(*itr); - return root.find_or_create(r2, 0); - } - auto& operator[](const std::string& s) { - auto [itr, is_inserted] = strings.emplace(s); - std::string_view r(*itr); - return root.find_or_create(r, 0); - } - - // Find a route and return an iterator. - auto find(const std::string_view& r) const { return root.find(r, 0); } - - template void for_all_routes(F f) const { root.for_all_routes(f); } - auto end() const { return root.end(); } - - std::unordered_set strings; - drt_node_pool> pool; + std::unordered_set paths; drt_node root; + +private: + drt_node_pool> pool_; }; } // namespace internal +/** + * A dynamic routing table that supports route registration and lookup. + */ template struct dynamic_routing_table { - dynamic_routing_table() : impl_(std::make_shared>()) {} - dynamic_routing_table(const dynamic_routing_table& other) : impl_(other.impl_) {} + dynamic_routing_table() noexcept + : data_(std::make_shared>()) {} + dynamic_routing_table(const dynamic_routing_table& other) noexcept : data_(other.data_) {} - // Assignment operator - dynamic_routing_table& operator=(const dynamic_routing_table& other) { + dynamic_routing_table& operator=(const dynamic_routing_table& other) noexcept { if (this != &other) { - impl_ = other.impl_; + data_ = other.data_; } return *this; } - // Find a route and return reference to a procedure. - auto& operator[](const std::string_view& r) { return impl_->operator[](r); } - auto& operator[](const std::string& s) { return impl_->operator[](s); } - - // Find a route and return an iterator. - auto find(const std::string_view& r) const { return impl_->find(r); } - - template void for_all_routes(F f) const { impl_->for_all_routes(f); } - auto end() const { return impl_->end(); } + auto& operator[](const std::string_view& r) { return this->operator[](std::string(r)); } + auto& operator[](const std::string& s) { + auto [itr, is_inserted] = data_->paths.emplace(s); + return data_->root.find_or_create(*itr, 0); + } + auto find(const std::string_view& r) const noexcept { return data_->root.find(r, 0); } + template void for_all_routes(F f) const { data_->root.for_all_routes(f); } + auto end() const noexcept { return data_->root.end(); } - private: - std::shared_ptr> impl_; +private: + std::shared_ptr> data_; }; } // namespace li