From 817eb2fd87062603a144dfeac203df4a43344b44 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 11 Feb 2020 20:16:42 -0500 Subject: [PATCH 1/3] Add unit testing for the public Dictionary API --- src/Dict.cc | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/src/Dict.cc b/src/Dict.cc index fa1f9e2bc9..b60eaa16c4 100644 --- a/src/Dict.cc +++ b/src/Dict.cc @@ -6,6 +6,8 @@ #include #endif +#include "3rdparty/doctest.h" + #include "Dict.h" #include "Reporter.h" @@ -21,6 +23,8 @@ // increase the size of the hash table as needed. #define DEFAULT_DICT_SIZE 16 +TEST_SUITE_BEGIN("Dict"); + class DictEntry { public: DictEntry(void* k, int l, hash_t h, void* val) @@ -55,6 +59,140 @@ public: PList inserted; // inserted while iterating }; +TEST_CASE("dict construction") + { + PDict dict; + CHECK(dict.IsOrdered() == false); + CHECK(dict.Length() == 0); + + PDict dict2(ORDERED); + CHECK(dict2.IsOrdered() == true); + CHECK(dict2.Length() == 0); + } + +TEST_CASE("dict operation") + { + PDict dict; + + uint32_t val = 10; + uint32_t key_val = 5; + + HashKey* key = new HashKey(key_val); + dict.Insert(key, &val); + CHECK(dict.Length() == 1); + + HashKey* key2 = new HashKey(key_val); + uint32_t* lookup = dict.Lookup(key2); + CHECK(*lookup == val); + + dict.Remove(key2); + CHECK(dict.Length() == 0); + uint32_t* lookup2 = dict.Lookup(key2); + CHECK(lookup2 == (uint32_t*)0); + delete key2; + + CHECK(dict.MaxLength() == 1); + CHECK(dict.NumCumulativeInserts() == 1); + + dict.Insert(key, &val); + dict.Remove(key); + + CHECK(dict.MaxLength() == 1); + CHECK(dict.NumCumulativeInserts() == 2); + + uint32_t val2 = 15; + uint32_t key_val2 = 25; + key2 = new HashKey(key_val2); + + dict.Insert(key, &val); + dict.Insert(key2, &val2); + CHECK(dict.Length() == 2); + CHECK(dict.NumCumulativeInserts() == 4); + + dict.Clear(); + CHECK(dict.Length() == 0); + + delete key; + delete key2; + } + +TEST_CASE("dict nthentry") + { + PDict unordered(UNORDERED); + PDict ordered(ORDERED); + + uint32_t val = 15; + uint32_t key_val = 5; + HashKey* okey = new HashKey(key_val); + HashKey* ukey = new HashKey(key_val); + + uint32_t val2 = 10; + uint32_t key_val2 = 25; + HashKey* okey2 = new HashKey(key_val2); + HashKey* ukey2 = new HashKey(key_val2); + + unordered.Insert(ukey, &val); + unordered.Insert(ukey2, &val2); + + ordered.Insert(okey, &val); + ordered.Insert(okey2, &val2); + + // NthEntry returns null for unordered dicts + uint32_t* lookup = unordered.NthEntry(0); + CHECK(lookup == (uint32_t*)0); + + // Ordered dicts are based on order of insertion, nothing about the + // data itself + lookup = ordered.NthEntry(0); + CHECK(*lookup == 15); + + delete okey; + delete okey2; + delete ukey; + delete ukey2; + } + +TEST_CASE("dict iteration") + { + PDict dict; + + uint32_t val = 15; + uint32_t key_val = 5; + HashKey* key = new HashKey(key_val); + + uint32_t val2 = 10; + uint32_t key_val2 = 25; + HashKey* key2 = new HashKey(key_val2); + + dict.Insert(key, &val); + dict.Insert(key2, &val2); + + HashKey* it_key; + IterCookie* it = dict.InitForIteration(); + CHECK(it != nullptr); + int count = 0; + + while ( uint32_t* entry = dict.NextEntry(it_key, it) ) + { + if ( count == 0 ) + { + CHECK(it_key->Hash() == key2->Hash()); + CHECK(*entry == 10); + } + else + { + CHECK(it_key->Hash() == key->Hash()); + CHECK(*entry == 15); + } + count++; + + delete it_key; + } + + delete key; + delete key2; + } + Dictionary::Dictionary(dict_order ordering, int initial_size) { tbl = 0; @@ -632,3 +770,5 @@ void generic_delete_func(void* v) { free(v); } + +TEST_SUITE_END(); From a69463ac4655c8c2e0862de1aa7be81d2222d0a8 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 11 Feb 2020 20:28:49 -0500 Subject: [PATCH 2/3] Code cleanup in Dict.h --- src/Dict.cc | 44 ++++++++++++-------------------------------- src/Dict.h | 36 ++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 50 deletions(-) diff --git a/src/Dict.cc b/src/Dict.cc index b60eaa16c4..7177565a6c 100644 --- a/src/Dict.cc +++ b/src/Dict.cc @@ -27,8 +27,7 @@ TEST_SUITE_BEGIN("Dict"); class DictEntry { public: - DictEntry(void* k, int l, hash_t h, void* val) - { key = k; len = l; hash = h; value = val; } + DictEntry(void* k, int l, hash_t h, void* val) : key(k), len(l), hash(h), value(val) {} ~DictEntry() { @@ -45,17 +44,11 @@ public: // bucket at which to start looking for the next value to return. class IterCookie { public: - IterCookie(int b, int o) - { - bucket = b; - offset = o; - ttbl = 0; - num_buckets_p = 0; - } + IterCookie(int b, int o) : bucket(b), offset(o) {} int bucket, offset; - PList** ttbl; - const int* num_buckets_p; + PList** ttbl = nullptr; + const int* num_buckets_p = 0; PList inserted; // inserted while iterating }; @@ -195,22 +188,8 @@ TEST_CASE("dict iteration") Dictionary::Dictionary(dict_order ordering, int initial_size) { - tbl = 0; - tbl2 = 0; - if ( ordering == ORDERED ) order = new PList; - else - order = 0; - - delete_func = 0; - tbl_next_ind = 0; - - cumulative_entries = 0; - num_buckets = num_entries = max_num_entries = thresh_entries = 0; - den_thresh = 0; - num_buckets2 = num_entries2 = max_num_entries2 = thresh_entries2 = 0; - den_thresh2 = 0; if ( initial_size > 0 ) Init(initial_size); @@ -225,8 +204,8 @@ Dictionary::~Dictionary() void Dictionary::Clear() { DeInit(); - tbl = 0; - tbl2 = 0; + tbl = nullptr; + tbl2 = nullptr; } void Dictionary::DeInit() @@ -249,8 +228,9 @@ void Dictionary::DeInit() } delete [] tbl; + tbl = nullptr; - if ( tbl2 == 0 ) + if ( ! tbl2 ) return; for ( int i = 0; i < num_buckets2; ++i ) @@ -268,7 +248,7 @@ void Dictionary::DeInit() } delete [] tbl2; - tbl2 = 0; + tbl2 = nullptr; } void* Dictionary::Lookup(const void* key, int key_size, hash_t hash) const @@ -524,7 +504,7 @@ void Dictionary::Init(int size) tbl = new PList*[num_buckets]; for ( int i = 0; i < num_buckets; ++i ) - tbl[i] = 0; + tbl[i] = nullptr; max_num_entries = num_entries = 0; SetDensityThresh(DEFAULT_DENSITY_THRESH); @@ -536,7 +516,7 @@ void Dictionary::Init2(int size) tbl2 = new PList*[num_buckets2]; for ( int i = 0; i < num_buckets2; ++i ) - tbl2[i] = 0; + tbl2[i] = nullptr; max_num_entries2 = num_entries2 = 0; } @@ -713,7 +693,7 @@ void Dictionary::FinishChangeSize() delete [] tbl; tbl = tbl2; - tbl2 = 0; + tbl2 = nullptr; num_buckets = num_buckets2; num_entries = num_entries2; diff --git a/src/Dict.h b/src/Dict.h index dc9ee9982c..81a61baaf8 100644 --- a/src/Dict.h +++ b/src/Dict.h @@ -11,7 +11,7 @@ class IterCookie; // Type indicating whether the dictionary should keep track of the order // of insertions. -typedef enum { ORDERED, UNORDERED } dict_order; +enum dict_order { ORDERED, UNORDERED }; // Type for function to be called when deleting elements. typedef void (*dict_delete_func)(void*); @@ -70,7 +70,7 @@ public: } // True if the dictionary is ordered, false otherwise. - int IsOrdered() const { return order != 0; } + bool IsOrdered() const { return order != 0; } // If the dictionary is ordered then returns the n'th entry's value; // the second method also returns the key. The first entry inserted @@ -158,26 +158,26 @@ private: // When we're resizing, we'll have tbl (old) and tbl2 (new) // tbl_next_ind keeps track of how much we've moved to tbl2 // (it's the next index we're going to move). - PList** tbl; - int num_buckets; - int num_entries; - int max_num_entries; - uint64_t cumulative_entries; - double den_thresh; - int thresh_entries; + PList** tbl = nullptr; + int num_buckets = 0; + int num_entries = 0; + int max_num_entries = 0; + uint64_t cumulative_entries = 0; + double den_thresh = 0.0; + int thresh_entries = 0; // Resizing table (replicates tbl above). - PList** tbl2; - int num_buckets2; - int num_entries2; - int max_num_entries2; - double den_thresh2; - int thresh_entries2; + PList** tbl2 = nullptr; + int num_buckets2 = 0; + int num_entries2 = 0; + int max_num_entries2 = 0; + double den_thresh2 = 0; + int thresh_entries2 = 0; - hash_t tbl_next_ind; + hash_t tbl_next_ind = 0; - PList* order; - dict_delete_func delete_func; + PList* order = nullptr; + dict_delete_func delete_func = nullptr; PList cookies; }; From 1e499b08318ec87afd9956ad518c91c6390e0c21 Mon Sep 17 00:00:00 2001 From: Tim Wojtulewicz Date: Tue, 11 Feb 2020 20:29:06 -0500 Subject: [PATCH 3/3] Reset the number of entries in a dict when calling Clear() --- src/Dict.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Dict.cc b/src/Dict.cc index 7177565a6c..60cfbea562 100644 --- a/src/Dict.cc +++ b/src/Dict.cc @@ -206,6 +206,7 @@ void Dictionary::Clear() DeInit(); tbl = nullptr; tbl2 = nullptr; + num_entries = 0; } void Dictionary::DeInit()