Skip to content

Commit

Permalink
feat:enhance trie
Browse files Browse the repository at this point in the history
  • Loading branch information
chenxuan520 committed Nov 29, 2024
1 parent 9b92eab commit e3d1e11
Show file tree
Hide file tree
Showing 7 changed files with 359 additions and 146 deletions.
4 changes: 3 additions & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
## Repository Address
- [github](https://github.com/chenxuan520/cppnet)
- [gitee](https://gitee.com/chenxuan520/cppnet)
## Official Website
- [chenxuanweb.top/cppnet/index.html](https://chenxuanweb.top/cppnet/index.html)
## Docs
- [cppnet online docs](https://chenxuan520.github.io/cppnet/)
## Advantages
Expand Down Expand Up @@ -124,7 +126,7 @@ int main() {
- More demo references can be found in the "demo" folder and the "test" folder.
### Create a TcpServer
```cpp
Address addr{"128.0.0.1", 8080};
Address addr{"127.0.0.1", 8080};
TcpServer server{addr};
// init server
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
## 仓库地址
- [github](https://github.com/chenxuan520/cppnet)
- [gitee](https://gitee.com/chenxuan520/cppnet)
## 官网
- [chenxuanweb.top/cppnet/index.html](https://chenxuanweb.top/cppnet/index.html)
## Docs
- [cppnet 在线文档地址](https://chenxuan520.github.io/cppnet/)
## 优势
Expand Down Expand Up @@ -126,7 +128,7 @@ int main() {
- 更多demo参考 demo 文件夹和 test 文件夹
### 创建TcpServer
```cpp
Address addr{"128.0.0.1", 8080};
Address addr{"127.0.0.1", 8080};
TcpServer server{addr};

// init server
Expand Down Expand Up @@ -430,4 +432,4 @@ cppnet
- [x] accept 改造
- [x] 完善多线程
- [x] 添加压力测试
- [ ] 提升trie
- [x] 提升trie
50 changes: 25 additions & 25 deletions src/cppnet/http/server/http_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ int HttpGroup::RegisterHandler(
const std::string &path, HttpCallback callback,
const std::vector<std::shared_ptr<HttpFilter>> &filters,
bool is_exact_match) {
auto pdata = trie_.Get(path);
auto pdata = trie_.Get<TrieDataType>(path);
if (pdata == nullptr) {
auto set_data = std::make_shared<TrieDataType>();
set_data->push_back(HttpTrieData{callback, is_exact_match, filters});
Expand Down Expand Up @@ -366,30 +366,30 @@ void HttpServer::HandleRead(TcpServer &server, Socket &event_soc) {

// step2:find route and run func
HttpContext ctx(req, resp, soc);
trie_.Search(path,
[&](std::shared_ptr<TrieDataType> pdata, bool is_end) -> bool {
auto &data = *pdata;
for (auto &node : data) {
auto route_func = node.callback;
if (!is_end && node.is_exact_match) {
continue;
}
for (auto filter : node.filters) {
auto is_match = filter->IsMatchFilter(req);
if (!is_match) {
route_func = nullptr;
break;
}
}
if (route_func) {
route_func(ctx);
if (!is_continue_) {
return false;
}
}
}
return true;
});
trie_.Search<TrieDataType>(
path, [&](std::shared_ptr<TrieDataType> pdata, bool is_end) -> bool {
auto &data = *pdata;
for (auto &node : data) {
auto route_func = node.callback;
if (!is_end && node.is_exact_match) {
continue;
}
for (auto filter : node.filters) {
auto is_match = filter->IsMatchFilter(req);
if (!is_match) {
route_func = nullptr;
break;
}
}
if (route_func) {
route_func(ctx);
if (!is_continue_) {
return false;
}
}
}
return true;
});

// step3:build resp and send
if (resp.status_code() == HttpStatusCode::UNKNOWN) {
Expand Down
6 changes: 3 additions & 3 deletions src/cppnet/http/server/http_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ using TrieDataType = std::vector<HttpTrieData>;

class HttpGroup {
protected:
HttpGroup(const std::string &route, Trie<TrieDataType> &trie,
HttpGroup(const std::string &route, Trie &trie,
std::shared_ptr<Logger> logger)
: route_(route), trie_(trie), logger_(logger) {};

Expand Down Expand Up @@ -169,7 +169,7 @@ class HttpGroup {

protected:
std::string route_;
Trie<TrieDataType> &trie_;
Trie &trie_;
std::string err_msg_;
std::shared_ptr<Logger> logger_ = std::make_shared<Logger>();
};
Expand Down Expand Up @@ -238,7 +238,7 @@ class HttpServer : public HttpGroup {

private:
TcpServer server_;
Trie<TrieDataType> trie_;
Trie trie_;
bool is_continue_ = false;
std::pair<int, int> read_timeout_{0, 0};
std::pair<int, int> write_timeout_{0, 0};
Expand Down
205 changes: 205 additions & 0 deletions src/cppnet/utils/trie.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
#include "trie.hpp"

namespace cppnet {

Trie::Trie() { root_ = new Node; }

Trie::~Trie() {
CleanMemory(root_);
root_ = nullptr;
}

void Trie::CleanMemory(Node *root) {
if (root == nullptr) {
return;
}

for (unsigned i = 0; i < root->next_.size(); i++) {
if (root->next_[i] != nullptr) {
CleanMemory(root->next_[i]);
}
}
delete root;
root = nullptr;
}

void Trie::Reset() {
CleanMemory(root_);
root_ = new Node;
}

bool Trie::Check(const std::string &key) const {
Node *temp = root_;
for (unsigned i = 0; i < key.size(); i++) {
if (temp->next_[key[i]] == nullptr) {
return false;
} else {
temp = temp->next_[key[i]];
}
}
if (temp->stop_ == false) {
return false;
}
return true;
}

void Trie::ForkNode(Node *node, int key_pos) {
if (node == nullptr) {
return;
}
if (key_pos <= 0 || key_pos >= node->key_.size()) {
return;
}

auto new_node = new Node(*node);
new_node->key_ = node->key_.substr(key_pos);

// clean node
node->data_ = nullptr;
node->stop_ = false;
node->next_.clear();
node->next_[node->key_[key_pos]] = new_node;
node->key_ = node->key_.substr(0, key_pos);
}

void Trie::SetNode(const std::string &key, std::any data) {
auto now = root_;
auto pos = 0;

if (key.empty()) {
now->data_ = data;
now->stop_ = true;
return;
}

if (now->next_[key[0]] == nullptr) {
now->next_[key[0]] = new Node();
}
now = now->next_[key[0]];

if (now->key_.empty()) {
now->key_ = key;
now->data_ = data;
now->stop_ = true;
return;
}

for (unsigned i = 0; i < key.size(); i++) {
if (pos < now->key_.size()) {
if (now->key_[pos] == key[i]) {
pos++;
} else {
ForkNode(now, pos);
// for avoid i++
i--;
}
} else {
if (now->next_[key[i]] == nullptr) {
auto tmp = new Node();
now->next_[key[i]] = tmp;
tmp->key_ = key.substr(i);
now = tmp;
pos = now->key_.size();
break;
} else {
now = now->next_[key[i]];
// first is same to key[i]
pos = 1;
}
}
}
if (pos != now->key_.size()) {
ForkNode(now, pos);
}
now->data_ = data;
now->stop_ = true;
}

const Trie::Node *Trie::GetNode(const std::string &key) const {
auto now = root_;
auto pos = 0;

if (key.empty()) {
if (now->stop_) {
return now;
} else {
return nullptr;
}
}

if (now->next_[key[0]] == nullptr) {
return nullptr;
}
now = now->next_[key[0]];

for (unsigned i = 0; i < key.size(); i++) {
if (pos < now->key_.size()) {
if (now->key_[pos] == key[i]) {
pos++;
} else {
return nullptr;
}
} else {
if (now->next_[key[i]] == nullptr) {
return nullptr;
}
now = now->next_[key[i]];
// first is same to key[i]
pos = 1;
}
}
if (now->stop_ == false) {
return nullptr;
}
return now;
}

void Trie::SearchNode(const std::string &key,
std::function<bool(const Node *, bool)> callback) const {
auto now = root_;
auto pos = 0;
if (now->stop_) {
auto is_continue = callback(now, key.empty());
if (!is_continue) {
return;
}
}
if (key.empty()) {
return;
}

if (now->next_[key[0]] == nullptr) {
return;
}
now = now->next_[key[0]];

for (unsigned i = 0; i < key.size(); i++) {
if (pos < now->key_.size()) {
if (now->key_[pos] == key[i]) {
pos++;
} else {
return;
}
} else {
if (now->stop_) {
auto is_continue = callback(now, false);
if (!is_continue) {
return;
}
}

if (now->next_[key[i]] == nullptr) {
return;
}
now = now->next_[key[i]];
// first is same to key[i]
pos = 1;
}
}

if (now->stop_ && pos == now->key_.size()) {
callback(now, true);
}
}

} // namespace cppnet
Loading

0 comments on commit e3d1e11

Please sign in to comment.