diff --git a/CMakeLists.txt b/CMakeLists.txt index 0eb42f9..9ccb216 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,4 +12,4 @@ if(CMAKE_BUILD_TYPE STREQUAL Release) add_compile_options(-O3 -flto) endif() -add_executable(lander src/main.cpp src/tries/ternarytrie.c) +add_executable(lander src/main.cpp src/trie.c) diff --git a/include/ternarytrie.h b/include/trie.h similarity index 82% rename from include/ternarytrie.h rename to include/trie.h index 2dafcd7..ca3ae9a 100644 --- a/include/ternarytrie.h +++ b/include/trie.h @@ -29,7 +29,7 @@ static const size_t charset_len = sizeof(charset) - 1; * * You can (and should) redefine this in your c-file with the concrete fields. */ -typedef struct ttrie TernaryTrie; +typedef struct ttrie Trie; typedef enum entry_type { Redirect, Paste, Unknown } EntryType; @@ -45,7 +45,7 @@ Entry *entry_new(EntryType type, const char *string); * * @return a pointer to an empty Trie struct */ -TernaryTrie *ternarytrie_init(); +Trie *trie_init(); /** * Populate trie with entries stored in the given file. @@ -54,14 +54,14 @@ TernaryTrie *ternarytrie_init(); * @param file_path path to file containing entries * @return amount of entries added; -1 if an error occured */ -int ternarytrie_populate(TernaryTrie *trie, const char *file_path); +int trie_populate(Trie *trie, const char *file_path); /** * De-allocate a trie by freeing the memory occupied by this trie. * * @param trie which should be freed */ -void ternarytrie_free(TernaryTrie *trie); +void trie_free(Trie *trie); /** * Search for an entry in the trie. @@ -70,7 +70,7 @@ void ternarytrie_free(TernaryTrie *trie); * @param key key representing the entry * @return pointer to entry; NULL if not found */ -Entry *ternarytrie_search(TernaryTrie *trie, const char *key); +Entry *trie_search(Trie *trie, const char *key); /** * Add a string to this trie. @@ -81,7 +81,7 @@ Entry *ternarytrie_search(TernaryTrie *trie, const char *key); * @return true if the trie was changed by this operation, false if it was * already present */ -bool ternarytrie_add(TernaryTrie *trie, const char *key, Entry *entry); +bool trie_add(Trie *trie, const char *key, Entry *entry); /** * Add an entry by generating a random string as the key. @@ -91,7 +91,7 @@ bool ternarytrie_add(TernaryTrie *trie, const char *key, Entry *entry); * @param secure whether to generate a longer, more secure random key * @return the generated key */ -char *ternarytrie_add_random(TernaryTrie *trie, Entry *entry, bool secure); +char *trie_add_random(Trie *trie, Entry *entry, bool secure); /** * Remove an entry from this trie given its key. @@ -101,7 +101,7 @@ char *ternarytrie_add_random(TernaryTrie *trie, Entry *entry, bool secure); * @return true if the entry was present and has been removed, false if it was * not present */ -bool ternarytrie_remove(TernaryTrie *trie, const char *key); +bool trie_remove(Trie *trie, const char *key); /** * Returns the number of entries in this trie. @@ -109,6 +109,6 @@ bool ternarytrie_remove(TernaryTrie *trie, const char *key); * @param trie * @return the number of entries in this trie */ -size_t ternarytrie_size(TernaryTrie *trie); +size_t trie_size(Trie *trie); #endif // AD3_TERNARYTRIE diff --git a/src/main.cpp b/src/main.cpp index 01fbf8d..1ece188 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,7 @@ #include "crow.h" extern "C" { -#include "ternarytrie.h" +#include "trie.h" } static const std::string index_page = R"( @@ -31,10 +31,10 @@ static const std::string index_page = R"( return crow::response(crow::status::UNAUTHORIZED); \ } -crow::response add_redirect(std::string base_url, TernaryTrie *trie, +crow::response add_redirect(std::string base_url, Trie *trie, const char *url, bool secure) { Entry *new_entry = entry_new(Redirect, url); - char *key = ternarytrie_add_random(trie, new_entry, secure); + char *key = trie_add_random(trie, new_entry, secure); if (key == NULL) { return crow::response(crow::status::INTERNAL_SERVER_ERROR); @@ -61,10 +61,10 @@ bool store_paste(const char *key, const char *body) { return true; } -crow::response add_paste(std::string base_url, TernaryTrie *trie, +crow::response add_paste(std::string base_url, Trie *trie, const char *body, bool secure) { Entry *new_entry = entry_new(Paste, ""); - char *key = ternarytrie_add_random(trie, new_entry, secure); + char *key = trie_add_random(trie, new_entry, secure); if (key == NULL) { return crow::response(crow::status::INTERNAL_SERVER_ERROR); @@ -88,14 +88,14 @@ int main() { ENV(base_url, "LANDER_BASE_URL"); // Initialize trie and populate from data file - TernaryTrie *trie = ternarytrie_init(); + Trie *trie = trie_init(); std::string file_path = "lander.data"; std::cout << "Populating trie from file '" << file_path << "'..." << std::endl; - int count = ternarytrie_populate(trie, file_path.c_str()); + int count = trie_populate(trie, file_path.c_str()); if (count == -1) { std::cout << "An error occured while populating the trie." << std::endl; @@ -119,7 +119,7 @@ int main() { CROW_ROUTE(app, "/") .methods(crow::HTTPMethod::Get)( [trie](crow::response &res, std::string key) { - Entry *entry = ternarytrie_search(trie, key.c_str()); + Entry *entry = trie_search(trie, key.c_str()); if (entry != NULL) { if (entry->type == Redirect) { @@ -160,7 +160,7 @@ int main() { Entry *new_entry = entry_new(Redirect, req.body.c_str()); - bool added = ternarytrie_add(trie, key.c_str(), new_entry); + bool added = trie_add(trie, key.c_str(), new_entry); if (!added) { return crow::response(crow::status::CONFLICT); @@ -194,7 +194,7 @@ int main() { AUTH(); Entry *new_entry = entry_new(Paste, ""); - bool added = ternarytrie_add(trie, key.c_str(), new_entry); + bool added = trie_add(trie, key.c_str(), new_entry); if (!added) { return crow::response(crow::status::CONFLICT); diff --git a/src/tries/ternarytrie.c b/src/trie.c similarity index 80% rename from src/tries/ternarytrie.c rename to src/trie.c index 8c9b06b..52708e9 100644 --- a/src/tries/ternarytrie.c +++ b/src/trie.c @@ -4,23 +4,23 @@ #include #include -#include "ternarytrie.h" -#include "ternarytrie_node.c" +#include "trie.h" +#include "trie_node.c" typedef struct ttrie { - TernaryTrieNode *root; + TrieNode *root; size_t size; char *file_path; pthread_rwlock_t lock; -} TernaryTrie; +} Trie; /** - * Allocate and initialize an empty TernaryTrie + * Allocate and initialize an empty Trie * - * @return pointer to the empty TernaryTrie + * @return pointer to the empty Trie */ -TernaryTrie *ternarytrie_init() { - TernaryTrie *trie = (TernaryTrie *)calloc(1, sizeof(TernaryTrie)); +Trie *trie_init() { + Trie *trie = calloc(1, sizeof(Trie)); trie->root = ttnode_init(); pthread_rwlock_init(&trie->lock, NULL); @@ -32,12 +32,12 @@ TernaryTrie *ternarytrie_init() { * * @param trie trie to free */ -void ternarytrie_free(TernaryTrie *trie) { +void trie_free(Trie *trie) { ttnode_free(trie->root); free(trie); } -bool ternarytrie_add_internal(TernaryTrie *trie, const char *key, Entry *entry); +bool trie_add_internal(Trie *trie, const char *key, Entry *entry); EntryType entry_type_from_char(char c) { switch (c) { @@ -62,7 +62,7 @@ char entry_type_to_char(EntryType et) { } Entry *entry_new(EntryType type, const char *string) { - Entry *entry = (Entry *)malloc(sizeof(Entry)); + Entry *entry = malloc(sizeof(Entry)); entry->type = type; if (string != NULL) { @@ -74,7 +74,7 @@ Entry *entry_new(EntryType type, const char *string) { return entry; } -int ternarytrie_populate(TernaryTrie *trie, const char *file_path) { +int trie_populate(Trie *trie, const char *file_path) { trie->file_path = strdup(file_path); FILE *fp = fopen(file_path, "r"); @@ -116,7 +116,7 @@ int ternarytrie_populate(TernaryTrie *trie, const char *file_path) { buffer[j] = '\0'; entry = entry_new(type, buffer + i + 3); - ternarytrie_add_internal(trie, buffer, entry); + trie_add_internal(trie, buffer, entry); entries++; } @@ -127,11 +127,11 @@ int ternarytrie_populate(TernaryTrie *trie, const char *file_path) { } typedef struct searchresult { - TernaryTrieNode *parent; - TernaryTrieNode *child; + TrieNode *parent; + TrieNode *child; } SearchResult; -SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *key) { +SearchResult trie_search_node(Trie *trie, const char *key) { SearchResult out = {NULL, NULL}; // Edge case for empty string @@ -144,8 +144,8 @@ SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *key) { } size_t i = 0; - TernaryTrieNode **node_ptr = &(trie->root); - TernaryTrieNode **child_ptr; + TrieNode **node_ptr = &(trie->root); + TrieNode **child_ptr; do { child_ptr = ttnode_search(*node_ptr, key[i], false); @@ -188,10 +188,10 @@ SearchResult ternarytrie_search_node(TernaryTrie *trie, const char *key) { * @param string string to look up * @return true if the string is present in the trie, false otherwise */ -Entry *ternarytrie_search(TernaryTrie *trie, const char *key) { +Entry *trie_search(Trie *trie, const char *key) { pthread_rwlock_rdlock(&trie->lock); - SearchResult res = ternarytrie_search_node(trie, key); + SearchResult res = trie_search_node(trie, key); Entry *return_value = NULL; @@ -205,14 +205,14 @@ Entry *ternarytrie_search(TernaryTrie *trie, const char *key) { } /** - * Add the given string to the TernaryTrie. + * Add the given string to the Trie. * * @param trie trie to add string to * @param string string to add * @return true if the string wasn't present in the trie and thus added, false * otherwise */ -bool ternarytrie_add_internal(TernaryTrie *trie, const char *string, +bool trie_add_internal(Trie *trie, const char *string, Entry *entry) { // Edge case for empty string if (string[0] == DELIMITER) { @@ -228,8 +228,8 @@ bool ternarytrie_add_internal(TernaryTrie *trie, const char *string, } size_t i = 0; - TernaryTrieNode **node_ptr = &(trie->root); - TernaryTrieNode **new_node_ptr; + TrieNode **node_ptr = &(trie->root); + TrieNode **new_node_ptr; do { new_node_ptr = ttnode_search(*node_ptr, string[i], true); @@ -256,7 +256,7 @@ bool ternarytrie_add_internal(TernaryTrie *trie, const char *string, // The next node in the string's path doesn't exist yet, so we add it to the // trie if (*node_ptr == NULL) { - TernaryTrieNode *new_node = ttnode_init(); + TrieNode *new_node = ttnode_init(); // If there's a remaining part of the string, we add it to the leaf if (string[i] != DELIMITER) { @@ -296,7 +296,7 @@ bool ternarytrie_add_internal(TernaryTrie *trie, const char *string, return true; } -bool ternarytrie_add_persistent(TernaryTrie *trie, const char *key, +bool trie_add_persistent(Trie *trie, const char *key, Entry *entry) { bool return_value = false; @@ -304,7 +304,7 @@ bool ternarytrie_add_persistent(TernaryTrie *trie, const char *key, // Easiest way to make sure we don't add duplicate entries // We use an internal function that doesn't require a read lock, as we're // already inside a write lock - if (ternarytrie_search_node(trie, key).child != NULL) { + if (trie_search_node(trie, key).child != NULL) { return false; } @@ -326,26 +326,26 @@ bool ternarytrie_add_persistent(TernaryTrie *trie, const char *key, // This function *should* always return true. Otherwise, the function would've // exited because the string was found in the trie. - return ternarytrie_add_internal(trie, key, entry); + return trie_add_internal(trie, key, entry); } -bool ternarytrie_add(TernaryTrie *trie, const char *key, Entry *entry) { +bool trie_add(Trie *trie, const char *key, Entry *entry) { pthread_rwlock_wrlock(&trie->lock); - bool return_value = ternarytrie_add_persistent(trie, key, entry); + bool return_value = trie_add_persistent(trie, key, entry); pthread_rwlock_unlock(&trie->lock); return return_value; } -char *ternarytrie_add_random(TernaryTrie *trie, Entry *entry, bool secure) { +char *trie_add_random(Trie *trie, Entry *entry, bool secure) { pthread_rwlock_wrlock(&trie->lock); // Generate random key bool ok = false; int key_length = secure ? RANDOM_KEY_LENGTH_LONG : RANDOM_KEY_LENGTH_SHORT; - char *key = (char *)malloc(key_length + 1); + char *key = malloc(key_length + 1); key[key_length] = '\0'; // We naively generate new keys until we find a key that isn't in the trie @@ -356,10 +356,10 @@ char *ternarytrie_add_random(TernaryTrie *trie, Entry *entry, bool secure) { key[i] = charset[rand() % charset_len]; } - ok = ternarytrie_search_node(trie, key).child == NULL; + ok = trie_search_node(trie, key).child == NULL; } - bool res = ternarytrie_add_persistent(trie, key, entry); + bool res = trie_add_persistent(trie, key, entry); char *return_value; if (res) { @@ -375,18 +375,18 @@ char *ternarytrie_add_random(TernaryTrie *trie, Entry *entry, bool secure) { } /** - * Remove the given string from a TernaryTrie. + * Remove the given string from a Trie. * * @param trie trie to remove string from * @param string string to remove * @return true if the string was in the trie and thus removed, false otherwise */ -bool ternarytrie_remove(TernaryTrie *trie, const char *string) { +bool trie_remove(Trie *trie, const char *string) { pthread_rwlock_wrlock(&trie->lock); bool return_value = false; - SearchResult res = ternarytrie_search_node(trie, string); + SearchResult res = trie_search_node(trie, string); if (res.child == NULL) { goto end; @@ -439,4 +439,4 @@ end: * @param trie trie to return size for * @return size of the trie */ -size_t ternarytrie_size(TernaryTrie *trie) { return trie->size; } +size_t trie_size(Trie *trie) { return trie->size; } diff --git a/src/tries/ternarytrie_node.c b/src/trie_node.c similarity index 76% rename from src/tries/ternarytrie_node.c rename to src/trie_node.c index 69daa44..9f7e86c 100644 --- a/src/tries/ternarytrie_node.c +++ b/src/trie_node.c @@ -2,21 +2,21 @@ #include #include -#include "ternarytrie.h" +#include "trie.h" /** * Represents a node of the binary tree contained within each non-leaf - * TernaryTrieNode. + * TrieNode. */ typedef struct ttinode { struct ttinode *left; struct ttinode *right; struct ttnode *next; char key; -} TernaryTrieInnerNode; +} TrieInnerNode; /** - * Represents a node inside a TernaryTrie. A node can be in one of three states: + * Represents a node inside a Trie. A node can be in one of three states: * - Internal node: a node that's part of a path to a leaf node. This node will * always have a size greater than one, and an initialized root. * - Leaf: a node solely used to represent a string ending there. Its size is 0, @@ -28,7 +28,7 @@ typedef struct ttinode { */ typedef struct ttnode { union { - TernaryTrieInnerNode *root; + TrieInnerNode *root; char *string; } ptr; Entry *entry; @@ -41,43 +41,40 @@ typedef struct ttnode { // 0, 1: size of underlying binary tree // 2: length of string uint8_t size; -} TernaryTrieNode; +} TrieNode; // Required for recursively freeing tree structure -void ttnode_free(TernaryTrieNode *node); +void ttnode_free(TrieNode *node); /** - * Allocate and initialize a new TernaryTrieInnerNode representing a given + * Allocate and initialize a new TrieInnerNode representing a given * character. * * @param c character to represent * @return pointer to newly allocated struct */ -TernaryTrieInnerNode *ttinode_init(char c) { - TernaryTrieInnerNode *node = - (TernaryTrieInnerNode *)calloc(1, sizeof(TernaryTrieInnerNode)); +TrieInnerNode *ttinode_init(char c) { + TrieInnerNode *node = calloc(1, sizeof(TrieInnerNode)); node->key = c; return node; } /** - * Allocate and initialize a new TernaryTrieNode. + * Allocate and initialize a new TrieNode. * * @return pointer to newly allocated struct */ -TernaryTrieNode *ttnode_init() { - return (TernaryTrieNode *)calloc(1, sizeof(TernaryTrieNode)); -} +TrieNode *ttnode_init() { return calloc(1, sizeof(TrieNode)); } /** - * Free a TernaryTrieInnerNode and its underlying tree structure. This should + * Free a TrieInnerNode and its underlying tree structure. This should * usually only be called on the root of a binary tree to free the entire * structure. * * @param node node whose tree to free */ -void ttinode_free_cascade(TernaryTrieInnerNode *node) { +void ttinode_free_cascade(TrieInnerNode *node) { if (node->left != NULL) { ttinode_free_cascade(node->left); } @@ -94,11 +91,11 @@ void ttinode_free_cascade(TernaryTrieInnerNode *node) { } /** - * Free a TernaryTrieNode and its underlying tree structure. + * Free a TrieNode and its underlying tree structure. * * @param node node to free */ -void ttnode_free(TernaryTrieNode *node) { +void ttnode_free(TrieNode *node) { if (node->type == 2) { free(node->ptr.string); } else if (node->size != 0) { @@ -119,7 +116,7 @@ void ttnode_free(TernaryTrieNode *node) { * @param node node to add string to * @param string string to add */ -void ttnode_set_string(TernaryTrieNode *node, const char *string) { +void ttnode_set_string(TrieNode *node, const char *string) { node->type = 2; node->size = strlen(string); node->ptr.string = strdup(string); @@ -127,8 +124,8 @@ void ttnode_set_string(TernaryTrieNode *node, const char *string) { /** * This function performs a lookup in the underlying binary tree of the given - * TernaryTrieNode. If found, the return value is a pointer to the memory - * location where the TernaryTrieInnerNode representing the given character + * TrieNode. If found, the return value is a pointer to the memory + * location where the TrieInnerNode representing the given character * stores its `next` field. If not found, the return value is NULL, unless * `create` is true. * @@ -138,12 +135,12 @@ void ttnode_set_string(TernaryTrieNode *node, const char *string) { * * @param node node to perform lookup in. If node is a full leaf, the return * value will always be NULL, regardless of the value of create. - * @param create whether to create the TernaryTrieInnerNode if it isn't present + * @param create whether to create the TrieInnerNode if it isn't present * yet. If this is set to true, the function will never return NULL unless the * node represents a leaf with a string, because the struct and therefore the * address is created if it doesn't exist yet. */ -TernaryTrieNode **ttnode_search(TernaryTrieNode *node, const char c, +TrieNode **ttnode_search(TrieNode *node, const char c, bool create) { // Full leafs will always return NULL if (node->type == 2) { @@ -162,8 +159,8 @@ TernaryTrieNode **ttnode_search(TernaryTrieNode *node, const char c, return NULL; } - TernaryTrieInnerNode *parent = node->ptr.root; - TernaryTrieInnerNode *child; + TrieInnerNode *parent = node->ptr.root; + TrieInnerNode *child; // Iterate through the tree until we either find the character or realize it's // not present in the tree @@ -189,7 +186,7 @@ TernaryTrieNode **ttnode_search(TernaryTrieNode *node, const char c, // If create is true, we create the new node so that we can still return a // non-NULL pointer. if (create) { - TernaryTrieInnerNode *new_node = ttinode_init(c); + TrieInnerNode *new_node = ttinode_init(c); if (c < parent->key) { parent->left = new_node; @@ -211,8 +208,8 @@ TernaryTrieNode **ttnode_search(TernaryTrieNode *node, const char c, * * @param node node to split */ -void ttnode_split(TernaryTrieNode *node) { - TernaryTrieNode *new_node = ttnode_init(); +void ttnode_split(TrieNode *node) { + TrieNode *new_node = ttnode_init(); char key = node->ptr.string[0]; // There's a chance the remaining string was only 1 character, meaning the new @@ -233,16 +230,16 @@ void ttnode_split(TernaryTrieNode *node) { node->ptr.string = NULL; // Initialize node's binary tree with the correct character - TernaryTrieNode **node_ptr = ttnode_search(node, key, true); + TrieNode **node_ptr = ttnode_search(node, key, true); *node_ptr = new_node; } /* - * Remove the given character from a TernaryTrieInnerNode's subtree. The + * Remove the given character from a TrieInnerNode's subtree. The * function assumes the character is indeed in the subtree. */ -void ttinode_remove(TernaryTrieInnerNode *node, const char c) { - TernaryTrieInnerNode **to_remove_ptr = &node; +void ttinode_remove(TrieInnerNode *node, const char c) { + TrieInnerNode **to_remove_ptr = &node; // We use pointers to pointers here so we can later free the removed node // without having to know what its parent is @@ -253,11 +250,11 @@ void ttinode_remove(TernaryTrieInnerNode *node, const char c) { // If the node isn't a leaf, we have to replace it with another if ((*to_remove_ptr)->left != NULL || (*to_remove_ptr)->right != NULL) { - TernaryTrieInnerNode *to_replace = *to_remove_ptr; + TrieInnerNode *to_replace = *to_remove_ptr; // Replace with its only right child if (to_replace->left == NULL) { - TernaryTrieInnerNode *to_remove = to_replace->right; + TrieInnerNode *to_remove = to_replace->right; to_replace->key = to_remove->key; to_replace->next = to_remove->next; @@ -268,7 +265,7 @@ void ttinode_remove(TernaryTrieInnerNode *node, const char c) { } // Replace with its only left child else if (to_replace->right == NULL) { - TernaryTrieInnerNode *to_remove = to_replace->left; + TrieInnerNode *to_remove = to_replace->left; to_replace->key = to_remove->key; to_replace->next = to_remove->next; @@ -279,8 +276,8 @@ void ttinode_remove(TernaryTrieInnerNode *node, const char c) { } // Node has two children, so replace with successor else { - TernaryTrieInnerNode *to_remove_parent = to_replace; - TernaryTrieInnerNode *to_remove = to_replace->right; + TrieInnerNode *to_remove_parent = to_replace; + TrieInnerNode *to_remove = to_replace->right; while (to_remove->left != NULL) { to_remove_parent = to_remove; @@ -307,14 +304,14 @@ void ttinode_remove(TernaryTrieInnerNode *node, const char c) { } /** - * Remove the given character from a TernaryTrieNode, respecting the rules + * Remove the given character from a TrieNode, respecting the rules * of a binary search tree. This function assumes the character is in the search * tree. * * @param node node to remove character from * @param c character to remove */ -void ttnode_remove(TernaryTrieNode *node, const char c) { +void ttnode_remove(TrieNode *node, const char c) { ttinode_remove(node->ptr.root, c); node->size--;