diff --git a/Arena.cc b/Arena.cc index f77c075..feaabe8 100644 --- a/Arena.cc +++ b/Arena.cc @@ -10,40 +10,56 @@ #include #endif +#if defined(DESKTOP_BUILD) +#include +#include +#endif + #include "Arena.h" #define ARENA_UNINIT 0 #define ARENA_STATIC 1 #define ARENA_ALLOC 2 +#if defined(__linux__) #define ARENA_MMAP 3 - #define PROT_RW PROT_READ|PROT_WRITE +#endif + + +void +InitializeArena(Arena &arena) +{ + arena.Store = NULL; + arena.Size = 0; + arena.Type = ARENA_UNINIT; + arena.fd = 0; +} int -new_arena(Arena &arena, uint8_t *mem, size_t size) +NewStaticArena(Arena &arena, uint8_t *mem, size_t size) { - arena.store = mem; - arena.size = size; - arena.type = ARENA_STATIC; + arena.Store = mem; + arena.Size = size; + arena.Type = ARENA_STATIC; return 0; } int -alloc_new_arena(Arena &arena, size_t size) +AllocNewArena(Arena & arena, size_t size) { - if (arena.size > 0) { - if (arena_destroy(arena) != 0) { + if (arena.Size > 0) { + if (DestroyArena(arena) != 0) { return -1; } } - arena.type = ARENA_ALLOC; - arena.size = size; - arena.store = (uint8_t *)calloc(sizeof(uint8_t), size); - if (arena.store == NULL) { + arena.Type = ARENA_ALLOC; + arena.Size = size; + arena.Store = (uint8_t *)calloc(sizeof(uint8_t), size); + if (arena.Store == NULL) { return -1; } @@ -53,17 +69,17 @@ alloc_new_arena(Arena &arena, size_t size) #if defined(__linux__) int -mmap_arena(Arena &arena, int fd, size_t size) +MMapArena(Arena &arena, int fd, size_t Size) { - if (arena.size > 0) { + if (arena.Size > 0) { if (arena_destroy(arena) != 0) { return -1; } } - arena.type = ARENA_MMAP; - arena.size = size; - arena.store = (uint8_t *)mmap(NULL, size, PROT_RW, MAP_SHARED, fd, 0); + arena.Type = ARENA_MMAP; + arena.Size = Size; + arena.store = (uint8_t *)mmap(NULL, Size, PROT_RW, MAP_SHARED, fd, 0); if ((void *)arena.store == MAP_FAILED) { return -1; } @@ -73,11 +89,11 @@ mmap_arena(Arena &arena, int fd, size_t size) int -open_arena(Arena &arena, const char *path) +OpenArena(Arena &arena, const char *path) { struct stat st; - if (arena.size > 0) { + if (arena.Size > 0) { if (arena_destroy(arena) != 0) { return -1; } @@ -92,16 +108,16 @@ open_arena(Arena &arena, const char *path) return -1; } - return mmap_arena(arena, arena.fd, (size_t)st.st_size); + return MMapArena(arena, arena.fd, (size_t)st.st_size); } int -create_arena(Arena &arena, const char *path, size_t size, mode_t mode) +CreateArena(Arena &arena, const char *path, size_t Size, mode_t mode) { int fd = 0; - if (arena.size > 0) { + if (arena.Size > 0) { if (arena_destroy(arena) != 0) { return -1; } @@ -112,43 +128,49 @@ create_arena(Arena &arena, const char *path, size_t size, mode_t mode) return -1; } - if (ftruncate(fd, size) == -1) { + if (ftruncate(fd, Size) == -1) { return -1; } close(fd); - return open_arena(arena, path); + return OpenArena(arena, path); } #endif +/* + * ClearArena clears the memory being used, removing any data + * present. It does not free the memory; it is effectively a + * wrapper around memset. + */ void -arena_clear(Arena &arena) +ClearArena(Arena &arena) { - if (arena.size == 0) { + if (arena.Size == 0) { return; } - memset(arena.store, 0, arena.size); + memset(arena.Store, 0, arena.Size); } int -arena_destroy(Arena &arena) +DestroyArena(Arena &arena) { - if (arena.type == ARENA_UNINIT) { + if (arena.Type == ARENA_UNINIT) { return 0; } - switch (arena.type) { + switch (arena.Type) { case ARENA_STATIC: break; case ARENA_ALLOC: - free(arena.store); + free(arena.Store); break; + #if defined(__linux__) case ARENA_MMAP: - if (munmap(arena.store, arena.size) == -1) { + if (munmap(arena.store, arena.Size) == -1) { return -1; } @@ -158,20 +180,63 @@ arena_destroy(Arena &arena) arena.fd = 0; break; + #endif default: - abort(); + #if defined(NDEBUG) return -1; + #else + abort(); + #endif + } - arena.type = ARENA_UNINIT; - arena.size = 0; - arena.store = NULL; + arena.Type = ARENA_UNINIT; + arena.Size = 0; + arena.Store = NULL; return 0; } +#if defined(DESKTOP_BUILD) +void +DisplayArena(const Arena &arena) +{ + std::cout << "Arena @ 0x"; + std::cout << std::hex << (uintptr_t)&arena << std::endl; + std::cout << std::dec; + std::cout << "\tStore is " << arena.Size << " bytes at address 0x"; + std::cout << std::hex << (uintptr_t)&(arena.Store) << std::endl; + std::cout << "\tType: "; + + switch (arena.Type) { + case ARENA_UNINIT: + std::cout << "uninitialized"; + break; + case ARENA_STATIC: + std::cout << "static"; + break; + case ARENA_ALLOC: + std::cout << "allocated"; + break; +#if defined(__linux__) + case ARENA_MMAP: + std::cout << "mmap/file" + break; +#endif + default: + std::cout << "unknown (this is a bug)"; + } + std::cout << std::endl; +} +#else +void +DisplayArena(const Arena &arena) +{ + +} +#endif int -write_arena(Arena &arena, const char *path) +WriteArena(const Arena &arena, const char *path) { FILE *arenaFile = NULL; int retc = -1; @@ -181,8 +246,8 @@ write_arena(Arena &arena, const char *path) return -1; } - if (fwrite(arena.store, sizeof(*arena.store), arena.size, - arenaFile) == arena.size) { + if (fwrite(arena.Store, sizeof(*arena.Store), arena.Size, + arenaFile) == arena.Size) { retc = 0; } diff --git a/Arena.h b/Arena.h index c77fb36..61be019 100644 --- a/Arena.h +++ b/Arena.h @@ -8,27 +8,38 @@ typedef struct { - uint8_t *store; - size_t size; + uint8_t *Store; + size_t Size; int fd; - uint8_t type; + uint8_t Type; } Arena; -int new_arena(Arena &, uint8_t *, size_t); -int alloc_new_arena(Arena &, size_t); +/* + * InitializeArena is intended for use only with systems that + * do not initialize new variables to zero. It should be called + * exactly once, at the start of the program. Any other time the + * arena needs to be reset, it should be called with clear_arena + * or destroy_arena. + */ +void InitializeArena(Arena &arena); +int NewStaticArena(Arena &, uint8_t *, size_t); +int AllocNewArena(Arena &, size_t); #if defined(__linux__) -int mmap_arena(Arena &, int); /* arena will own fd */ -int create_arena(Arena &arena, const char *path, size_t size, mode_t mode); -int open_arena(Arena &, const char *, size_t); +int MMapArena(Arena &, int); /* arena will own fd */ +int CreateArena(Arena &arena, const char *path, size_t size, mode_t mode); +int OpenArena(Arena &, const char *, size_t); #endif -void arena_clear(Arena &); -int arena_destroy(Arena &); /* dispose of any memory used by arena */ +void ClearArena(Arena &); +int DestroyArena(Arena &); /* dispose of any memory used by arena */ /* DANGER: if arena is file backed (mmap or open), DO NOT WRITE TO THE * BACKING FILE! */ -int write_arena(const char *); +int WriteArena(const Arena &arena, const char *path); + +void +DisplayArena(const Arena &arena); #endif diff --git a/CMakeLists.txt b/CMakeLists.txt index a1023eb..ff3840e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,26 @@ cmake_minimum_required(VERSION 3.25) project(klib CXX) set(CMAKE_CXX_STANDARD 14) +if(MSVC) + add_compile_options("/W4" "$<$:/O2>") +else() + add_compile_options("-Wall" "-Wextra" "-Werror" "$<$:-O3>") + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + add_compile_options("-stdlib=libc++") + else() + # nothing special for gcc at the moment + endif() +endif() +add_compile_options("-DDESKTOP_BUILD") add_library(klib STATIC Arena.cc - TLV.cc) + TLV.cc + Phonebook.cc) add_executable(tlv_test tlv_test.cc) target_link_libraries(tlv_test klib) + +add_executable(phonebook_test phonebook_test.cc) +target_link_libraries(phonebook_test klib) + diff --git a/Phonebook.cc b/Phonebook.cc index 386fdfc..e11acf9 100644 --- a/Phonebook.cc +++ b/Phonebook.cc @@ -2,22 +2,26 @@ #include #include "Phonebook.h" +#if defined(DESKTOP_BUILD) +#include +#endif + bool -Phonebook::lookup(const char *key, uint8_t klen, TLV::Record &res) +Phonebook::Lookup(const char *key, uint8_t klen, TLV::Record &res) { - res.Tag = this->ktag; - uint8_t *cursor = TLV::find_tag(this->arena, NULL, res); + res.Tag = this->kTag; + uint8_t *cursor = TLV::FindTag(this->arena, NULL, res); while (cursor != NULL) { if ((klen == res.Len) && (memcmp(res.Val, key, klen) == 0)) { - TLV::read_from_memory(res, cursor); - if (res.Tag != this->vtag) { + TLV::ReadFromMemory(res, cursor); + if (res.Tag != this->vTag) { abort(); } return true; } - cursor = TLV::find_tag(this->arena, cursor, res); + cursor = TLV::FindTag(this->arena, cursor, res); } return false; @@ -26,29 +30,29 @@ Phonebook::lookup(const char *key, uint8_t klen, TLV::Record &res) int -Phonebook::set(const char *key, uint8_t klen, const char *val, uint8_t vlen) +Phonebook::Set(const char *key, uint8_t klen, const char *val, uint8_t vlen) { TLV::Record rec; uint8_t *cursor = NULL; - set_record(rec, this->ktag, klen, key); + SetRecord(rec, this->kTag, klen, key); cursor = this->seek(key, klen); if (cursor != NULL) { - TLV::delete_record(this->arena, cursor); - TLV::delete_record(this->arena, cursor); + TLV::DeleteRecord(this->arena, cursor); + TLV::DeleteRecord(this->arena, cursor); } - if (!space_available(klen, vlen)) { + if (!spaceAvailable(klen, vlen)) { return -1; } - cursor = TLV::write_to_memory(this->arena, NULL, rec); + cursor = TLV::WriteToMemory(this->arena, NULL, rec); if (cursor == NULL) { return -1; } - set_record(rec, this->vtag, vlen, val); - if (TLV::write_to_memory(this->arena, NULL, rec) == NULL) { + SetRecord(rec, this->vTag, vlen, val); + if (TLV::WriteToMemory(this->arena, NULL, rec) == NULL) { return -1; } @@ -62,15 +66,17 @@ Phonebook::seek(const char *key, uint8_t klen) { TLV::Record rec; - rec.Tag = this->ktag; - uint8_t *cursor = TLV::find_tag(this->arena, NULL, rec); + rec.Tag = this->kTag; + uint8_t *cursor = TLV::LocateTag(this->arena, NULL, rec); while (cursor != NULL) { - if ((klen == rec.Len) && - (memcmp(rec.Val, key, klen) == 0)) { - return cursor; + if ((klen == rec.Len) && (this->kTag == rec.Tag)) { + if (memcmp(rec.Val, key, klen) == 0) { + return cursor; + } } - cursor = TLV::skip_record(rec, cursor); + cursor = TLV::SkipRecord(rec, cursor); + cursor = TLV::LocateTag(this->arena, cursor, rec); } return NULL; @@ -78,29 +84,68 @@ Phonebook::seek(const char *key, uint8_t klen) bool -Phonebook::has(const char *key, uint8_t klen) +Phonebook::Has(const char *key, uint8_t klen) { return this->seek(key, klen) != NULL; } bool -Phonebook::space_available(uint8_t kl, uint8_t vl) +Phonebook::spaceAvailable(uint8_t klen, uint8_t vlen) { size_t required = 0; uintptr_t remaining = 0; uint8_t *cursor = NULL; - - cursor = TLV::find_empty(this->arena, NULL); + cursor = TLV::FindEmpty(this->arena, NULL); if (cursor == NULL) { return false; } - required += kl + 2; - required += vl + 2; + required += klen + 2; + required += vlen + 2; - remaining = (uintptr_t)cursor - (uintptr_t)arena.store; - remaining = arena.size - remaining; + remaining = (uintptr_t)cursor - (uintptr_t)arena.Store; + remaining = arena.Size - remaining; return ((size_t)remaining >= required); } + + +#if defined(DESKTOP_BUILD) +void +Phonebook::DumpKVPairs() +{ + uint8_t *cursor = (this->arena).Store; + TLV::Record rec; + + TLV::ReadFromMemory(rec, cursor); + std::cout << "Phonebook KV pairs" << std::endl; + if (rec.Tag == TAG_EMPTY) { + std::cout << "\t(NONE)" << std::endl; + return; + } + + while ((cursor != NULL) && (rec.Tag != TAG_EMPTY)) { + std::cout << "\t" << rec.Val << "->"; + cursor = TLV::SkipRecord(rec, cursor); + TLV::ReadFromMemory(rec, cursor); + std::cout << rec.Val << std::endl; + cursor = TLV::SkipRecord(rec, cursor); + TLV::ReadFromMemory(rec, cursor); + } + +} + +void +Phonebook::DumpToFile(const char *path) +{ + WriteArena(this->arena, path); +} + +#else +void +Phonebook::dump_kvpairs() +{ + +} +#endif diff --git a/Phonebook.h b/Phonebook.h index 1eee678..1f14172 100644 --- a/Phonebook.h +++ b/Phonebook.h @@ -14,26 +14,27 @@ class Phonebook { public: Phonebook(Arena &arena) : - arena(arena), - ktag(PHONEBOOK_KEY_TAG), - vtag(PHONEBOOK_VAL_TAG) {} ; + arena(arena), + kTag(PHONEBOOK_KEY_TAG), + vTag(PHONEBOOK_VAL_TAG) {} ; Phonebook(Arena &arena, uint8_t kt, uint8_t vt) : - arena(arena), - ktag(kt), - vtag(vt) {}; - - bool lookup(const char *key, uint8_t klen, TLV::Record &res); - int set(const char *key, uint8_t klen, const char *val, - uint8_t vlen); - bool has(const char *key, uint8_t klen); + arena(arena), + kTag(kt), + vTag(vt) {}; + bool Lookup(const char *key, uint8_t klen, TLV::Record &res); + int Set(const char *key, uint8_t klen, const char *val, + uint8_t vlen); + bool Has(const char *key, uint8_t klen); + void DumpKVPairs(); + void DumpToFile(const char *path); private: uint8_t *seek(const char *key, uint8_t klen); - bool space_available(uint8_t klen, uint8_t vlen); + bool spaceAvailable(uint8_t klen, uint8_t vlen); Arena &arena; - uint8_t ktag; - uint8_t vtag; + uint8_t kTag; + uint8_t vTag; }; diff --git a/TLV.cc b/TLV.cc index bf52f4a..4a2b49c 100644 --- a/TLV.cc +++ b/TLV.cc @@ -9,7 +9,7 @@ namespace TLV { static bool -space_available(Arena &arena, uint8_t *cursor, uint8_t len) +spaceAvailable(Arena &arena, uint8_t *cursor, uint8_t len) { uintptr_t remaining = 0; @@ -17,76 +17,95 @@ space_available(Arena &arena, uint8_t *cursor, uint8_t len) return false; } - remaining = (uintptr_t)cursor - (uintptr_t)arena.store; - remaining = arena.size - remaining; + remaining = (uintptr_t)cursor - (uintptr_t)arena.Store; + remaining = arena.Size - remaining; return ((size_t)remaining >= ((size_t)len+2)); } +static inline void +clearUnused(Record &rec) +{ + uint8_t trail = TLV_MAX_LEN-rec.Len; + + memset(rec.Val+rec.Len, 0, trail); +} + uint8_t * -write_to_memory(Arena &arena, uint8_t *cursor, Record &rec) +WriteToMemory(Arena &arena, uint8_t *cursor, Record &rec) { // If cursor is NULL, the user needs us to select an empty // slot for the record. If we can't find one, that's an // error. // // If, however, the user gives us a cursor, we'll trust it - // (though space_available will sanity check that cursor). + // (though spaceAvailable will sanity check that cursor). if (cursor == NULL) { - cursor = find_empty(arena, cursor); + cursor = FindEmpty(arena, cursor); if (cursor == NULL) { return NULL; } } - if (!space_available(arena, cursor, rec.Len)) { + if (!spaceAvailable(arena, cursor, rec.Len)) { return NULL; } memcpy(cursor, &rec, REC_SIZE(rec)); - cursor = skip_record(rec, cursor); + cursor = SkipRecord(rec, cursor); return cursor; } void -set_record(Record &rec, uint8_t tag, uint8_t len, const char *val) +SetRecord(Record &rec, uint8_t tag, uint8_t len, const char *val) { - uint8_t trail = TLV_MAX_LEN-len; - rec.Tag = tag; rec.Len = len; memcpy(rec.Val, val, len); - memset(rec.Val+len, 0, trail); + clearUnused(rec); } void -read_from_memory(Record &rec, uint8_t *cursor) +ReadFromMemory(Record &rec, uint8_t *cursor) { rec.Tag = cursor[0]; rec.Len = cursor[1]; memcpy(rec.Val, cursor+2, rec.Len); + clearUnused(rec); } /* * returns a pointer to memory where the record was found, - * e.g. find_tag(...)[0] is the tag of the found record. + * e.g. FindTag(...)[0] is the tag of the found record. */ uint8_t * -find_tag(Arena &arena, uint8_t *cursor, Record &rec) +FindTag(Arena &arena, uint8_t *cursor, Record &rec) +{ + cursor = LocateTag(arena, cursor, rec); + if (rec.Tag != TAG_EMPTY) { + cursor = SkipRecord(rec, cursor); + } + + return cursor; +} + + +uint8_t * +LocateTag(Arena &arena, uint8_t *cursor, Record &rec) { uint8_t tag, len; if (cursor == NULL) { - cursor = arena.store; + cursor = arena.Store; } while ((tag = cursor[0]) != rec.Tag) { len = cursor[1]; - if (!space_available(arena, cursor, len)) { + if (!spaceAvailable(arena, cursor, len)) { return NULL; } cursor += len; @@ -98,40 +117,38 @@ find_tag(Arena &arena, uint8_t *cursor, Record &rec) } if (tag != TAG_EMPTY) { - read_from_memory(rec, cursor); - cursor = skip_record(rec, cursor); + ReadFromMemory(rec, cursor); } return cursor; } uint8_t * -find_empty(Arena &arena, uint8_t *cursor) { +FindEmpty(Arena &arena, uint8_t *cursor) { Record rec; rec.Tag = TAG_EMPTY; - return find_tag(arena, cursor, rec); + return FindTag(arena, cursor, rec); } uint8_t * -skip_record(Record &rec, uint8_t *cursor) +SkipRecord(Record &rec, uint8_t *cursor) { return (uint8_t *)((uintptr_t)cursor + rec.Len + 2); } void -delete_record(Arena &arena, uint8_t *cursor) +DeleteRecord(Arena &arena, uint8_t *cursor) { - // if (cursor == NULL) { return; } uint8_t len = cursor[1] + 2; - uint8_t *stop = arena.store + arena.size; + uint8_t *stop = arena.Store + arena.Size; stop -= len; diff --git a/TLV.h b/TLV.h index e3c5cd1..e1c7e84 100644 --- a/TLV.h +++ b/TLV.h @@ -24,18 +24,22 @@ struct Record { }; -uint8_t *write_to_memory(Arena &, uint8_t *, Record &); -void read_from_memory(Record &, uint8_t *); -void set_record(Record &, uint8_t, uint8_t, const char *); -void delete_record(Arena &, uint8_t *); +uint8_t *WriteToMemory(Arena &, uint8_t *, Record &); +void ReadFromMemory(Record &, uint8_t *); +void SetRecord(Record &, uint8_t, uint8_t, const char *); +void DeleteRecord(Arena &, uint8_t *); -/* +/* * returns a pointer to memory where the record was found, - * e.g. find_tag(...)[0] is the tag of the found record. + * e.g. LocateTag(...)[0] is the tag of the found record. + * FindTag will call LocateTag and then SkipRecord if the + * tag was found. */ -uint8_t *find_tag(Arena &, uint8_t *, Record &); -uint8_t *find_empty(Arena &, uint8_t *); -uint8_t *skip_record(Record &, uint8_t *); +uint8_t *FindTag(Arena &, uint8_t *, Record &); +uint8_t *LocateTag(Arena &, uint8_t *, Record &); + +uint8_t *FindEmpty(Arena &, uint8_t *); +uint8_t *SkipRecord(Record &, uint8_t *); } // namespace TLV diff --git a/phonebook_test.cc b/phonebook_test.cc index eabe089..39f2c9f 100644 --- a/phonebook_test.cc +++ b/phonebook_test.cc @@ -12,14 +12,12 @@ constexpr char TEST_PBSTR2[] = "baz"; constexpr uint8_t TEST_PBSTRLEN2 = 3; constexpr char TEST_PBSTR3[] = "quux"; constexpr uint8_t TEST_PBSTRLEN3 = 4; -/* constexpr char TEST_PBSTR4[] = "spam"; constexpr uint8_t TEST_PBSTRLEN4 = 4; constexpr char TEST_PBSTR5[] = "xyzzx"; constexpr uint8_t TEST_PBSTRLEN5 = 5; constexpr char TEST_PBSTR6[] = "corvid"; constexpr uint8_t TEST_PBSTRLEN6 = 6; - */ static bool @@ -27,9 +25,9 @@ test_setpb(Phonebook &pb, const char *k, uint8_t kl, const char *v, uint8_t vl) { bool ok; - std::cout << "test set " << k << "->" << v << std::endl; - ok = pb.set(k, kl, v, vl) == 0; - std::cout << "\tset complete\n"; + std::cout << "test Set " << k << "->" << v << std::endl; + ok = pb.Set(k, kl, v, vl) == 0; + std::cout << "\tSet complete\n"; return ok; } @@ -38,21 +36,69 @@ int main(int argc, const char *argv[]) { Arena arena; - //TLV::Record value; - //TLV::Record expect; + TLV::Record value; + TLV::Record expect; - std::cout << "TESTPROG: " << argv[0] << std::endl; - if (create_arena(arena, ARENA_FILE, ARENA_SIZE, 0644) == -1) { + std::cout << "TESTPROG: " << argv[0] << std::endl; + InitializeArena(arena); + + #if defined(__linux__) + if (CreateArena(arena, ARENA_FILE, ARENA_SIZE, 0644) == -1) { abort(); } + #else + if (AllocNewArena(arena, ARENA_SIZE) == -1) { + abort(); + } + #endif + DisplayArena(arena); + + TLV::SetRecord(expect, PHONEBOOK_VAL_TAG, TEST_PBSTRLEN3, TEST_PBSTR3); Phonebook pb(arena); - assert(!pb.has(TEST_PBSTR2, TEST_PBSTRLEN2)); + assert(!pb.Has(TEST_PBSTR2, TEST_PBSTRLEN2)); assert(test_setpb(pb, TEST_PBSTR1, TEST_PBSTRLEN1, TEST_PBSTR3, TEST_PBSTRLEN3)); + pb.DumpKVPairs(); assert(test_setpb(pb, TEST_PBSTR2, TEST_PBSTRLEN2, TEST_PBSTR3, TEST_PBSTRLEN3)); - + pb.DumpKVPairs(); + assert(pb.Has(TEST_PBSTR2, TEST_PBSTRLEN2)); + assert(test_setpb(pb, TEST_PBSTR4, TEST_PBSTRLEN4, TEST_PBSTR5, + TEST_PBSTRLEN5)); + pb.DumpKVPairs(); + assert(pb.Lookup(TEST_PBSTR2, TEST_PBSTRLEN2, value)); + + assert(cmp_record(value, expect)); + + std::cout << "test overwriting key" << std::endl; + assert(test_setpb(pb, TEST_PBSTR2, TEST_PBSTRLEN2, TEST_PBSTR6, + TEST_PBSTRLEN6)); + pb.DumpKVPairs(); + TLV::SetRecord(expect, PHONEBOOK_VAL_TAG, TEST_PBSTRLEN6, TEST_PBSTR6); + std::cout << "\tlookup" << std::endl; + assert(pb.Lookup(TEST_PBSTR2, TEST_PBSTRLEN2, value)); + std::cout << "\tcompare records" << std::endl; + assert(cmp_record(value, expect)); + + std::cout << "\tadd new key to phonebook" << std::endl; + assert(test_setpb(pb, TEST_PBSTR3, TEST_PBSTRLEN3, TEST_PBSTR5, + TEST_PBSTRLEN5)); + pb.DumpKVPairs(); + + TLV::SetRecord(expect, PHONEBOOK_VAL_TAG, TEST_PBSTRLEN5, TEST_PBSTR5); + assert(pb.Lookup(TEST_PBSTR4, TEST_PBSTRLEN4, value)); + assert(cmp_record(value, expect)); + std::cout << "OK" <