refactor: rename TernaryTrie to Trie
	
		
			
	
		
	
	
		
			
				
	
				ci/woodpecker/push/woodpecker Pipeline was successful
				
					Details
				
			
		
	
				
					
				
			
				
	
				ci/woodpecker/push/woodpecker Pipeline was successful
				
					Details
				
			
		
	
							parent
							
								
									cc8cfaeace
								
							
						
					
					
						commit
						4bcdd5c4d9
					
				| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										20
									
								
								src/main.cpp
								
								
								
								
							
							
						
						
									
										20
									
								
								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, "/<string>")
 | 
			
		||||
      .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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,23 +4,23 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#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; }
 | 
			
		||||
| 
						 | 
				
			
			@ -2,21 +2,21 @@
 | 
			
		|||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#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--;
 | 
			
		||||
		Loading…
	
		Reference in New Issue