mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 09:38:19 +00:00
Merge remote-tracking branch 'origin/topic/timw/dict-unit-tests'
* origin/topic/timw/dict-unit-tests: Reset the number of entries in a dict when calling Clear() Code cleanup in Dict.h Add unit testing for the public Dictionary API
This commit is contained in:
commit
a5166086db
4 changed files with 181 additions and 51 deletions
8
CHANGES
8
CHANGES
|
@ -1,4 +1,12 @@
|
||||||
|
|
||||||
|
3.2.0-dev.25 | 2020-02-13 19:05:56 -0800
|
||||||
|
|
||||||
|
* Reset the number of entries in a dict when calling Clear() (Tim Wojtulewicz, Corelight)
|
||||||
|
|
||||||
|
* Code cleanup in Dict.h (Tim Wojtulewicz, Corelight)
|
||||||
|
|
||||||
|
* Add unit testing for the public Dictionary API (Tim Wojtulewicz, Corelight)
|
||||||
|
|
||||||
3.2.0-dev.21 | 2020-02-13 17:14:26 -0800
|
3.2.0-dev.21 | 2020-02-13 17:14:26 -0800
|
||||||
|
|
||||||
* Check for failure when registering event manager with iosource manager
|
* Check for failure when registering event manager with iosource manager
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
3.2.0-dev.21
|
3.2.0-dev.25
|
||||||
|
|
186
src/Dict.cc
186
src/Dict.cc
|
@ -6,6 +6,8 @@
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "3rdparty/doctest.h"
|
||||||
|
|
||||||
#include "Dict.h"
|
#include "Dict.h"
|
||||||
#include "Reporter.h"
|
#include "Reporter.h"
|
||||||
|
|
||||||
|
@ -21,10 +23,11 @@
|
||||||
// increase the size of the hash table as needed.
|
// increase the size of the hash table as needed.
|
||||||
#define DEFAULT_DICT_SIZE 16
|
#define DEFAULT_DICT_SIZE 16
|
||||||
|
|
||||||
|
TEST_SUITE_BEGIN("Dict");
|
||||||
|
|
||||||
class DictEntry {
|
class DictEntry {
|
||||||
public:
|
public:
|
||||||
DictEntry(void* k, int l, hash_t h, void* val)
|
DictEntry(void* k, int l, hash_t h, void* val) : key(k), len(l), hash(h), value(val) {}
|
||||||
{ key = k; len = l; hash = h; value = val; }
|
|
||||||
|
|
||||||
~DictEntry()
|
~DictEntry()
|
||||||
{
|
{
|
||||||
|
@ -41,38 +44,152 @@ public:
|
||||||
// bucket at which to start looking for the next value to return.
|
// bucket at which to start looking for the next value to return.
|
||||||
class IterCookie {
|
class IterCookie {
|
||||||
public:
|
public:
|
||||||
IterCookie(int b, int o)
|
IterCookie(int b, int o) : bucket(b), offset(o) {}
|
||||||
{
|
|
||||||
bucket = b;
|
|
||||||
offset = o;
|
|
||||||
ttbl = 0;
|
|
||||||
num_buckets_p = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bucket, offset;
|
int bucket, offset;
|
||||||
PList<DictEntry>** ttbl;
|
PList<DictEntry>** ttbl = nullptr;
|
||||||
const int* num_buckets_p;
|
const int* num_buckets_p = nullptr;
|
||||||
PList<DictEntry> inserted; // inserted while iterating
|
PList<DictEntry> inserted; // inserted while iterating
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TEST_CASE("dict construction")
|
||||||
|
{
|
||||||
|
PDict<int> dict;
|
||||||
|
CHECK(dict.IsOrdered() == false);
|
||||||
|
CHECK(dict.Length() == 0);
|
||||||
|
|
||||||
|
PDict<int> dict2(ORDERED);
|
||||||
|
CHECK(dict2.IsOrdered() == true);
|
||||||
|
CHECK(dict2.Length() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("dict operation")
|
||||||
|
{
|
||||||
|
PDict<uint32_t> 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<uint32_t> unordered(UNORDERED);
|
||||||
|
PDict<uint32_t> 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<uint32_t> 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)
|
Dictionary::Dictionary(dict_order ordering, int initial_size)
|
||||||
{
|
{
|
||||||
tbl = 0;
|
|
||||||
tbl2 = 0;
|
|
||||||
|
|
||||||
if ( ordering == ORDERED )
|
if ( ordering == ORDERED )
|
||||||
order = new PList<DictEntry>;
|
order = new PList<DictEntry>;
|
||||||
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 )
|
if ( initial_size > 0 )
|
||||||
Init(initial_size);
|
Init(initial_size);
|
||||||
|
@ -87,8 +204,10 @@ Dictionary::~Dictionary()
|
||||||
void Dictionary::Clear()
|
void Dictionary::Clear()
|
||||||
{
|
{
|
||||||
DeInit();
|
DeInit();
|
||||||
tbl = 0;
|
tbl = nullptr;
|
||||||
tbl2 = 0;
|
tbl2 = nullptr;
|
||||||
|
num_entries = 0;
|
||||||
|
num_entries2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dictionary::DeInit()
|
void Dictionary::DeInit()
|
||||||
|
@ -111,8 +230,9 @@ void Dictionary::DeInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] tbl;
|
delete [] tbl;
|
||||||
|
tbl = nullptr;
|
||||||
|
|
||||||
if ( tbl2 == 0 )
|
if ( ! tbl2 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for ( int i = 0; i < num_buckets2; ++i )
|
for ( int i = 0; i < num_buckets2; ++i )
|
||||||
|
@ -130,7 +250,7 @@ void Dictionary::DeInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] tbl2;
|
delete [] tbl2;
|
||||||
tbl2 = 0;
|
tbl2 = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Dictionary::Lookup(const void* key, int key_size, hash_t hash) const
|
void* Dictionary::Lookup(const void* key, int key_size, hash_t hash) const
|
||||||
|
@ -386,7 +506,7 @@ void Dictionary::Init(int size)
|
||||||
tbl = new PList<DictEntry>*[num_buckets];
|
tbl = new PList<DictEntry>*[num_buckets];
|
||||||
|
|
||||||
for ( int i = 0; i < num_buckets; ++i )
|
for ( int i = 0; i < num_buckets; ++i )
|
||||||
tbl[i] = 0;
|
tbl[i] = nullptr;
|
||||||
|
|
||||||
max_num_entries = num_entries = 0;
|
max_num_entries = num_entries = 0;
|
||||||
SetDensityThresh(DEFAULT_DENSITY_THRESH);
|
SetDensityThresh(DEFAULT_DENSITY_THRESH);
|
||||||
|
@ -398,7 +518,7 @@ void Dictionary::Init2(int size)
|
||||||
tbl2 = new PList<DictEntry>*[num_buckets2];
|
tbl2 = new PList<DictEntry>*[num_buckets2];
|
||||||
|
|
||||||
for ( int i = 0; i < num_buckets2; ++i )
|
for ( int i = 0; i < num_buckets2; ++i )
|
||||||
tbl2[i] = 0;
|
tbl2[i] = nullptr;
|
||||||
|
|
||||||
max_num_entries2 = num_entries2 = 0;
|
max_num_entries2 = num_entries2 = 0;
|
||||||
}
|
}
|
||||||
|
@ -575,7 +695,7 @@ void Dictionary::FinishChangeSize()
|
||||||
delete [] tbl;
|
delete [] tbl;
|
||||||
|
|
||||||
tbl = tbl2;
|
tbl = tbl2;
|
||||||
tbl2 = 0;
|
tbl2 = nullptr;
|
||||||
|
|
||||||
num_buckets = num_buckets2;
|
num_buckets = num_buckets2;
|
||||||
num_entries = num_entries2;
|
num_entries = num_entries2;
|
||||||
|
@ -632,3 +752,5 @@ void generic_delete_func(void* v)
|
||||||
{
|
{
|
||||||
free(v);
|
free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_SUITE_END();
|
||||||
|
|
36
src/Dict.h
36
src/Dict.h
|
@ -11,7 +11,7 @@ class IterCookie;
|
||||||
|
|
||||||
// Type indicating whether the dictionary should keep track of the order
|
// Type indicating whether the dictionary should keep track of the order
|
||||||
// of insertions.
|
// of insertions.
|
||||||
typedef enum { ORDERED, UNORDERED } dict_order;
|
enum dict_order { ORDERED, UNORDERED };
|
||||||
|
|
||||||
// Type for function to be called when deleting elements.
|
// Type for function to be called when deleting elements.
|
||||||
typedef void (*dict_delete_func)(void*);
|
typedef void (*dict_delete_func)(void*);
|
||||||
|
@ -70,7 +70,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// True if the dictionary is ordered, false otherwise.
|
// 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;
|
// If the dictionary is ordered then returns the n'th entry's value;
|
||||||
// the second method also returns the key. The first entry inserted
|
// 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)
|
// 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
|
// tbl_next_ind keeps track of how much we've moved to tbl2
|
||||||
// (it's the next index we're going to move).
|
// (it's the next index we're going to move).
|
||||||
PList<DictEntry>** tbl;
|
PList<DictEntry>** tbl = nullptr;
|
||||||
int num_buckets;
|
int num_buckets = 0;
|
||||||
int num_entries;
|
int num_entries = 0;
|
||||||
int max_num_entries;
|
int max_num_entries = 0;
|
||||||
uint64_t cumulative_entries;
|
uint64_t cumulative_entries = 0;
|
||||||
double den_thresh;
|
double den_thresh = 0.0;
|
||||||
int thresh_entries;
|
int thresh_entries = 0;
|
||||||
|
|
||||||
// Resizing table (replicates tbl above).
|
// Resizing table (replicates tbl above).
|
||||||
PList<DictEntry>** tbl2;
|
PList<DictEntry>** tbl2 = nullptr;
|
||||||
int num_buckets2;
|
int num_buckets2 = 0;
|
||||||
int num_entries2;
|
int num_entries2 = 0;
|
||||||
int max_num_entries2;
|
int max_num_entries2 = 0;
|
||||||
double den_thresh2;
|
double den_thresh2 = 0;
|
||||||
int thresh_entries2;
|
int thresh_entries2 = 0;
|
||||||
|
|
||||||
hash_t tbl_next_ind;
|
hash_t tbl_next_ind = 0;
|
||||||
|
|
||||||
PList<DictEntry>* order;
|
PList<DictEntry>* order = nullptr;
|
||||||
dict_delete_func delete_func;
|
dict_delete_func delete_func = nullptr;
|
||||||
|
|
||||||
PList<IterCookie> cookies;
|
PList<IterCookie> cookies;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue