From 332e7a13cfc096c73114ca3e331062c9350c5c9c Mon Sep 17 00:00:00 2001 From: "Jeroen F.J. Laros" Date: Sat, 5 Nov 2022 14:11:55 +0100 Subject: [PATCH] Documentation and initialisation conventions. --- src/node.tcc | 19 +++--- src/trie.tcc | 127 +++++++++++++++++++--------------------- src/trieFunctions.tcc | 87 +++++++++++++++------------ tests/test_functions.cc | 2 +- tests/test_node.cc | 4 +- tests/test_trie.cc | 104 ++++++++++++++++---------------- 6 files changed, 176 insertions(+), 167 deletions(-) diff --git a/src/node.tcc b/src/node.tcc index b1ca899..8ca1ebd 100644 --- a/src/node.tcc +++ b/src/node.tcc @@ -8,28 +8,27 @@ using std::array; -/*! - * Leaf. - */ +/*! Leaf. */ struct Leaf { - size_t count = 0; + size_t count {0}; //!< Counter. }; -/*! - * Node. +/*! Node. + * + * \tparam alphabetSize Size of the alphabet. + * \tparam T Leaf type. */ template class Node { public: bool isEmpty() const; - array child = {}; - T* leaf = nullptr; + array child {}; //!< Children. + T* leaf {nullptr}; //!< Leaf. }; -/*! - * Check whether a node neither has any children, nor a leaf. +/*! Check whether a node neither has any children, nor a leaf. * * \return True is the node is empty, false otherwise. */ diff --git a/src/trie.tcc b/src/trie.tcc index 7bf8afd..24dfbde 100644 --- a/src/trie.tcc +++ b/src/trie.tcc @@ -4,102 +4,121 @@ #include "trieFunctions.tcc" -/*! - * Trie. - */ +/*! Trie. */ template class Trie { public: + /*! Constructor. */ Trie(); + + /*! Destructor. */ ~Trie(); + + /*! Add a word. + * + * \param word Word. + * + * \return Leaf. + */ T* add(vector const&) const; + + /*! Remove a word. + * + * \param word Word. + */ void remove(vector const&) const; + + /*! Find a word. + * + * \param word Word. + * + * \return `node` if found, `nullptr` otherwise. + */ Node* find(vector const&) const; + + /*! Traverse. + * + * \return Traversal results. + */ generator> walk() const; + + /*! Hamming. + * + * \param word Word. + * \param distance Maximum distance. + * + * \return Traversal results. + */ generator> hamming(vector const&, int const) const; + + /*! Asymmetric Hamming. + * + * \param word Word. + * \param distance Maximum distance. + * + * \return Traversal results. + */ generator> asymmetricHamming( vector const&, int const) const; + + /*! Levenshtein. + * + * \param word Word. + * \param distance Maximum distance. + * + * \return Traversal results. + */ generator> levenshtein(vector const&, int const) const; + + /*! Asymmetric Levenshtein. + * + * \param word Word. + * \param distance Maximum distance. + * + * \return Traversal results. + */ generator> asymmetricLevenshtein( vector const&, int const) const; private: - Node* root_ = nullptr; + Node* root_ {nullptr}; }; -/*! - * Constructor. - */ template Trie::Trie() { root_ = new Node; } -/*! - * Destructor. - */ template Trie::~Trie() { delete_(root_); } -/*! - * Add a word. - * - * \param word Word. - * - * \return Leaf. - */ template T* Trie::add(vector const& word) const { return add_(root_, word); } -/*! - * Remove a word. - * - * \param word Word. - */ template void Trie::remove(vector const& word) const { remove_(root_, word, 0); } -/*! - * Find a word. - * - * \param word Word. - * - * \return `node` if found, `nullptr` otherwise. - */ template Node* Trie::find( vector const& word) const { return find_(root_, word); } -/*! - * Traverse. - * - * \return Traversal results. - */ template generator> Trie::walk() const { vector path; co_yield walk_(root_, path); } -/*! - * Hamming. - * - * \param word Word. - * \param distance Maximum distance. - * - * \return Traversal results. - */ template generator> Trie::hamming( vector const& word, int const distance) const { @@ -107,14 +126,6 @@ generator> Trie::hamming( co_yield hamming_(root_, word, 0, distance, path); } -/*! - * Asymmetric Hamming. - * - * \param word Word. - * \param distance Maximum distance. - * - * \return Traversal results. - */ template generator> Trie::asymmetricHamming( vector const& word, int const distance) const { @@ -122,14 +133,6 @@ generator> Trie::asymmetricHamming( co_yield hamming_(root_, word, 0, distance, path); } -/*! - * Levenshtein. - * - * \param word Word. - * \param distance Maximum distance. - * - * \return Traversal results. - */ template generator> Trie::levenshtein( vector const& word, int const distance) const { @@ -137,14 +140,6 @@ generator> Trie::levenshtein( co_yield levenshtein_(root_, word, 0, distance, path); } -/*! - * Asymmetric Levenshtein. - * - * \param word Word. - * \param distance Maximum distance. - * - * \return Traversal results. - */ template generator> Trie::asymmetricLevenshtein( vector const& word, int const distance) const { diff --git a/src/trieFunctions.tcc b/src/trieFunctions.tcc index 6c2d842..a9edeab 100644 --- a/src/trieFunctions.tcc +++ b/src/trieFunctions.tcc @@ -6,8 +6,9 @@ using std::vector; -/*! - * Result. +/*! Result. + * + * \tparam T Leaf type. */ template struct Result { @@ -16,8 +17,10 @@ struct Result { }; -/* - * Delete a (sub)trie. +/* Delete a (sub)trie. + * + * \tparam alphabetSize Size of the alphabet. + * \tparam T Leaf type. * * \param node Root. */ @@ -34,8 +37,10 @@ void delete_(Node* const node) { delete node; } -/* - * Add a word to a (sub)trie. +/* Add a word to a (sub)trie. + * + * \tparam alphabetSize Size of the alphabet. + * \tparam T Leaf type. * * \param node Root. * \param word Word. @@ -45,12 +50,12 @@ void delete_(Node* const node) { template T* add_(Node* node, vector const& word) { for (uint8_t const& letter: word) { - if (!node->child[letter]) { + if (not node->child[letter]) { node->child[letter] = new Node; } node = node->child[letter]; } - if (!node->leaf) { + if (not node->leaf) { node->leaf = new T; } node->leaf->count++; @@ -58,8 +63,10 @@ T* add_(Node* node, vector const& word) { return node->leaf; } -/* - * Remove a word from a (sub)trie. +/* Remove a word from a (sub)trie. + * + * \tparam alphabetSize Size of the alphabet. + * \tparam T Leaf type. * * \param node Root. * \param word Word. @@ -74,7 +81,7 @@ bool remove_( if (position == word.size()) { if (node->leaf) { node->leaf->count--; - if (!node->leaf->count) { + if (not node->leaf->count) { delete node->leaf; node->leaf = nullptr; return true; @@ -83,11 +90,11 @@ bool remove_( return false; } - if (!node->child[word[position]]) { + if (not node->child[word[position]]) { return false; } - bool result = remove_(node->child[word[position]], word, position + 1); + bool result {remove_(node->child[word[position]], word, position + 1)}; if (result) { if (node->child[word[position]]->isEmpty()) { delete node->child[word[position]]; @@ -98,8 +105,10 @@ bool remove_( return result; } -/* - * Find a word in a (sub)trie. +/* Find a word in a (sub)trie. + * + * \tparam alphabetSize Size of the alphabet. + * \tparam T Leaf type. * * \param node Root. * \param word Word. @@ -110,7 +119,7 @@ template Node* find_( Node* node, vector const& word) { for (uint8_t const& letter: word) { - if (!node->child[letter]) { + if (not node->child[letter]) { return nullptr; } node = node->child[letter]; @@ -118,8 +127,10 @@ Node* find_( return node; } -/* - * Traverse a (sub)trie. +/* Traverse a (sub)trie. + * + * \tparam alphabetSize Size of the alphabet. + * \tparam T Leaf type. * * \param node Root. * \param path Path. @@ -130,10 +141,10 @@ template generator> walk_( Node const* const node, vector& path) { if (node->leaf) { - Result result = {path, node->leaf}; + Result result {path, node->leaf}; co_yield result; } - for (size_t i = 0; i < alphabetSize; i++) { + for (size_t i {0}; i < alphabetSize; i++) { if (node->child[i]) { path.push_back(i); co_yield walk_(node->child[i], path); @@ -142,8 +153,11 @@ generator> walk_( } } -/* - * Find all words within Hamming distance `distance` of `word`. +/* Find all words within Hamming distance `distance` of `word`. + * + * \tparam alphabetSize Size of the alphabet. + * \tparam T Leaf type. + * \tparam full Full traversal. * * \param node Root. * \param word Word. @@ -159,31 +173,32 @@ generator> hamming_( size_t const position, int const distance, vector& path) { if (distance >= 0) { if (position < word.size()) { - uint8_t start = 0; - if (!full) { + uint8_t start {0}; + if (not full) { start = word[position]; } - for (uint8_t i = start; i < alphabetSize; i++) { + for (uint8_t i {start}; i < alphabetSize; i++) { if (node->child[i]) { path.push_back(i); co_yield hamming_( node->child[i], word, position + 1, - distance - (uint8_t)(i != word[position]), path); + distance - (i != word[position]), path); path.pop_back(); } } } else { - Result result = {path, node->leaf}; + Result result {path, node->leaf}; co_yield result; } } } -/* - * Find all words within Levenshtein distance `distance` of `word`. +/* Find all words within Levenshtein distance `distance` of `word`. * - * \tparam full + * \tparam alphabetSize Size of the alphabet. + * \tparam T Leaf type. + * \tparam full Full traversal. * * \param node Root. * \param word Word. @@ -202,11 +217,11 @@ generator> levenshtein_( co_yield levenshtein_( node, word, position + 1, distance - 1, path); - uint8_t start = 0; - if (!full && position < word.size()) { + uint8_t start {0}; + if (not full and position < word.size()) { start = word[position]; } - for (uint8_t i = start; i < alphabetSize; i++) { + for (uint8_t i {start}; i < alphabetSize; i++) { if (node->child[i]) { path.push_back(i); @@ -214,7 +229,7 @@ generator> levenshtein_( if (position < word.size()) { co_yield levenshtein_( node->child[i], word, position + 1, - distance - (uint8_t)(i != word[position]), path); + distance - (i != word[position]), path); } // Insertion. @@ -225,8 +240,8 @@ generator> levenshtein_( } } - if (position >= word.size() && node->leaf) { - Result result = {path, node->leaf}; + if (position >= word.size() and node->leaf) { + Result result {path, node->leaf}; co_yield result; } } diff --git a/tests/test_functions.cc b/tests/test_functions.cc index 6e12911..dbb9bfb 100644 --- a/tests/test_functions.cc +++ b/tests/test_functions.cc @@ -9,7 +9,7 @@ using std::vector; TEST_CASE("Internal remove function", "[remove]") { Trie<4, Leaf> trie; - vector word = {0x00, 0x01, 0x02}; + vector word {0x00, 0x01, 0x02}; trie.add(word); trie.add(word); diff --git a/tests/test_node.cc b/tests/test_node.cc index b206490..bfdb94d 100644 --- a/tests/test_node.cc +++ b/tests/test_node.cc @@ -14,13 +14,13 @@ TEST_CASE("Node", "[node]") { Leaf leaf; node.leaf = &leaf; - REQUIRE(!node.isEmpty()); + REQUIRE(not node.isEmpty()); } SECTION("Internal node") { Node<4, Leaf> child; node.child[3] = &child; - REQUIRE(!node.isEmpty()); + REQUIRE(not node.isEmpty()); } } diff --git a/tests/test_trie.cc b/tests/test_trie.cc index de67230..d90d8b2 100644 --- a/tests/test_trie.cc +++ b/tests/test_trie.cc @@ -10,65 +10,65 @@ TEST_CASE("Trie", "[find][add]") { Trie<4, Leaf> trie; SECTION("Find non-existent word") { - vector word = {0x00, 0x01, 0x02}; - REQUIRE(trie.find(word) == NULL); + vector word {0x00, 0x01, 0x02}; + REQUIRE(trie.find(word) == nullptr); } SECTION("Add word") { - vector word = {0x00, 0x01, 0x02}; - Leaf* leaf = trie.add(word); - REQUIRE(leaf != NULL); + vector word {0x00, 0x01, 0x02}; + Leaf* leaf {trie.add(word)}; + REQUIRE(leaf); REQUIRE(leaf->count == 1); SECTION("Find newly added word") { - vector word = {0x00, 0x01, 0x02}; - Node<4, Leaf>* node = trie.find(word); - REQUIRE(node != NULL); + vector word {0x00, 0x01, 0x02}; + Node<4, Leaf>* node {trie.find(word)}; + REQUIRE(node); REQUIRE(node->leaf->count == 1); } SECTION("Add word again") { - vector word = {0x00, 0x01, 0x02}; - Leaf* leaf = trie.add(word); + vector word {0x00, 0x01, 0x02}; + Leaf* leaf {trie.add(word)}; REQUIRE(leaf->count == 2); SECTION("Find newly added word again") { - vector word = {0x00, 0x01, 0x02}; - Node<4, Leaf>* node = trie.find(word); - REQUIRE(node != NULL); + vector word {0x00, 0x01, 0x02}; + Node<4, Leaf>* node {trie.find(word)}; + REQUIRE(node); REQUIRE(node->leaf->count == 2); } SECTION("Remove word") { - vector word = {0x00, 0x01, 0x02}; + vector word {0x00, 0x01, 0x02}; trie.remove(word); - Node<4, Leaf>* node = trie.find(word); - REQUIRE(node != NULL); + Node<4, Leaf>* node {trie.find(word)}; + REQUIRE(node); REQUIRE(node->leaf->count == 1); SECTION("Remove word again") { - vector word = {0x00, 0x01, 0x02}; + vector word {0x00, 0x01, 0x02}; trie.remove(word); - Node<4, Leaf>* node = trie.find(word); - REQUIRE(node == NULL); + Node<4, Leaf>* node {trie.find(word)}; + REQUIRE(node == nullptr); SECTION("No prefixes remaining") { - vector prefix = {0x00, 0x01}; + vector prefix {0x00, 0x01}; - Node<4, Leaf>* node = trie.find(prefix); - REQUIRE(node == NULL); + Node<4, Leaf>* node {trie.find(prefix)}; + REQUIRE(node == nullptr); prefix = {0x00}; node = trie.find(prefix); - REQUIRE(node == NULL); + REQUIRE(node == nullptr); } SECTION("Add word after emptying trie") { - vector word = {0x00, 0x01, 0x02}; - Leaf* leaf = trie.add(word); - REQUIRE(leaf != NULL); + vector word {0x00, 0x01, 0x02}; + Leaf* leaf {trie.add(word)}; + REQUIRE(leaf); REQUIRE(leaf->count == 1); } } @@ -77,21 +77,21 @@ TEST_CASE("Trie", "[find][add]") { } SECTION("Add multiple words") { - vector> words = { + vector> words { {0x00, 0x01, 0x02}, {0x00, 0x01, 0x03}, {0x00, 0x02, 0x02}, {0x00, 0x02, 0x03}, {0x01, 0x01, 0x02}}; - for (vector word: words) { + for (vector const& word: words) { trie.add(word); - REQUIRE(trie.find(word) != NULL); + REQUIRE(trie.find(word)); } SECTION("Traverse") { - size_t i = 0; - for (Result result: trie.walk()) { + size_t i {0}; + for (Result const& result: trie.walk()) { REQUIRE(result.leaf->count == 1); REQUIRE(result.path == words[i++]); } @@ -99,27 +99,27 @@ TEST_CASE("Trie", "[find][add]") { } SECTION("Hamming") { - vector word = {0x00, 0x01, 0x03}; - vector> words = { + vector word {0x00, 0x01, 0x03}; + vector> words { {0x00, 0x01, 0x02}, {0x00, 0x01, 0x03}, {0x00, 0x02, 0x03}}; - size_t i = 0; - for (Result result: trie.hamming(word, 1)) { + size_t i {0}; + for (Result const& result: trie.hamming(word, 1)) { REQUIRE(result.path == words[i++]); } REQUIRE(i == words.size()); } SECTION("Asymmetric Hamming") { - vector word = {0x00, 0x01, 0x03}; - vector> words = { + vector word {0x00, 0x01, 0x03}; + vector> words { {0x00, 0x01, 0x03}, {0x00, 0x02, 0x03}}; - size_t i = 0; - for (Result result: trie.asymmetricHamming(word, 1)) { + size_t i {0}; + for (Result const& result: trie.asymmetricHamming(word, 1)) { REQUIRE(result.path == words[i++]); } REQUIRE(i == words.size()); @@ -127,7 +127,7 @@ TEST_CASE("Trie", "[find][add]") { } SECTION("Add multiple words of different length") { - vector> words = { + vector> words { {0x00, 0x00, 0x01, 0x02}, {0x00, 0x00, 0x02}, {0x00, 0x00, 0x03, 0x02}, @@ -138,14 +138,14 @@ TEST_CASE("Trie", "[find][add]") { {0x00, 0x02, 0x02}, {0x00, 0x03}}; - for (vector word: words) { + for (vector const& word: words) { trie.add(word); - REQUIRE(trie.find(word) != NULL); + REQUIRE(trie.find(word)); } SECTION("Traverse") { - size_t i = 0; - for (Result result: trie.walk()) { + size_t i {0}; + for (Result const& result: trie.walk()) { REQUIRE(result.leaf->count == 1); REQUIRE(result.path == words[i++]); } @@ -153,8 +153,8 @@ TEST_CASE("Trie", "[find][add]") { } SECTION("Levenshtein") { - vector word = {0x00, 0x01, 0x02}; - vector> words = { + vector word {0x00, 0x01, 0x02}; + vector> words { {0x00, 0x02}, {0x00, 0x00, 0x02}, {0x00, 0x00, 0x01, 0x02}, @@ -165,16 +165,16 @@ TEST_CASE("Trie", "[find][add]") { {0x00, 0x02, 0x02}, {0x00, 0x00, 0x01, 0x02}}; - size_t i = 0; - for (Result result: trie.levenshtein(word, 1)) { + size_t i {0}; + for (Result const& result: trie.levenshtein(word, 1)) { REQUIRE(result.path == words[i++]); } REQUIRE(i == words.size()); } SECTION("Asymmetric Levenshtein") { - vector word = {0x00, 0x01, 0x02}; - vector> words = { + vector word {0x00, 0x01, 0x02}; + vector> words { {0x00, 0x02}, {0x00, 0x01}, {0x00, 0x01, 0x02}, @@ -183,8 +183,8 @@ TEST_CASE("Trie", "[find][add]") { {0x00, 0x02, 0x02}, {0x00, 0x00, 0x01, 0x02}}; - size_t i = 0; - for (Result result: trie.asymmetricLevenshtein(word, 1)) { + size_t i {0}; + for (Result const& result: trie.asymmetricLevenshtein(word, 1)) { REQUIRE(result.path == words[i++]); } REQUIRE(i == words.size());