Add FacadeTest
This commit is contained in:
@@ -148,6 +148,12 @@ if(BUILD_TESTING)
|
|||||||
target_link_options(api_test PRIVATE -fsanitize=address,undefined)
|
target_link_options(api_test PRIVATE -fsanitize=address,undefined)
|
||||||
add_test(NAME api_test COMMAND api_test)
|
add_test(NAME api_test COMMAND api_test)
|
||||||
|
|
||||||
|
add_executable(facade_test FacadeTest.cpp)
|
||||||
|
target_link_libraries(facade_test PRIVATE ${PROJECT_NAME})
|
||||||
|
target_compile_options(facade_test PRIVATE -fsanitize=address,undefined
|
||||||
|
${TEST_FLAGS})
|
||||||
|
target_link_options(facade_test PRIVATE -fsanitize=address,undefined)
|
||||||
|
|
||||||
# symbol visibility tests
|
# symbol visibility tests
|
||||||
if(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
if(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
167
Facade.h
Normal file
167
Facade.h
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VersionedMap.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using String = std::basic_string<uint8_t>;
|
||||||
|
|
||||||
|
struct Facade {
|
||||||
|
|
||||||
|
explicit Facade(int64_t version) : versioned{version} {}
|
||||||
|
|
||||||
|
struct View {
|
||||||
|
|
||||||
|
std::vector<std::pair<String, String>> rangeRead(const String &begin,
|
||||||
|
const String &end,
|
||||||
|
int limit,
|
||||||
|
bool reverse) const {
|
||||||
|
std::vector<std::pair<String, String>> result;
|
||||||
|
weaselab::VersionedMap::Iterator versionedIter[2];
|
||||||
|
const weaselab::VersionedMap::Key key[] = {
|
||||||
|
{begin.data(), int(begin.size())}, {end.data(), int(end.size())}};
|
||||||
|
const int64_t v[] = {version, version};
|
||||||
|
facade->versioned.firstGeq(key, v, versionedIter, 2);
|
||||||
|
|
||||||
|
const uint8_t zero[] = {0};
|
||||||
|
if (reverse) {
|
||||||
|
weaselab::VersionedMap::Iterator iter = versionedIter[1];
|
||||||
|
weaselab::VersionedMap::Iterator endIter = versionedIter[0];
|
||||||
|
String readUntil = end;
|
||||||
|
for (; iter != endIter; --iter) {
|
||||||
|
auto m = *iter;
|
||||||
|
auto mEnd = m.type == weaselab::VersionedMap::Set
|
||||||
|
? String(m.param1, m.param1Len) + String(zero, 1)
|
||||||
|
: String(m.param2, m.param2Len);
|
||||||
|
auto remaining =
|
||||||
|
facade->unversionedRead(mEnd, readUntil, limit, true);
|
||||||
|
result.insert(result.end(), remaining.begin(), remaining.end());
|
||||||
|
if (limit == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
switch (m.type) {
|
||||||
|
case weaselab::VersionedMap::Set: {
|
||||||
|
result.push_back(
|
||||||
|
{String(m.param1, m.param1Len), String(m.param2, m.param2Len)});
|
||||||
|
--limit;
|
||||||
|
if (limit == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
readUntil = String(m.param1, m.param1Len);
|
||||||
|
} break;
|
||||||
|
case weaselab::VersionedMap::Clear:
|
||||||
|
readUntil = String(m.param1, m.param1Len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto remaining = facade->unversionedRead(begin, readUntil, limit, true);
|
||||||
|
result.insert(result.end(), remaining.begin(), remaining.end());
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
weaselab::VersionedMap::Iterator iter = versionedIter[0];
|
||||||
|
weaselab::VersionedMap::Iterator endIter = versionedIter[1];
|
||||||
|
String readThrough = begin;
|
||||||
|
for (; iter != endIter; ++iter) {
|
||||||
|
auto m = *iter;
|
||||||
|
auto remaining = facade->unversionedRead(
|
||||||
|
readThrough, String(m.param1, m.param1Len), limit, false);
|
||||||
|
result.insert(result.end(), remaining.begin(), remaining.end());
|
||||||
|
if (limit == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
switch (m.type) {
|
||||||
|
case weaselab::VersionedMap::Set: {
|
||||||
|
result.push_back(
|
||||||
|
{String(m.param1, m.param1Len), String(m.param2, m.param2Len)});
|
||||||
|
--limit;
|
||||||
|
if (limit == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
uint8_t zero[] = {0};
|
||||||
|
readThrough = String(m.param1, m.param1Len) + String(zero, 1);
|
||||||
|
} break;
|
||||||
|
case weaselab::VersionedMap::Clear:
|
||||||
|
readThrough = String(m.param2, m.param2Len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto remaining =
|
||||||
|
facade->unversionedRead(readThrough, end, limit, false);
|
||||||
|
result.insert(result.end(), remaining.begin(), remaining.end());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @private */
|
||||||
|
View(const Facade *facade, int64_t version)
|
||||||
|
: facade{facade}, version{version} {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Facade *facade;
|
||||||
|
int64_t version;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addMutations(const weaselab::VersionedMap::Mutation *mutations,
|
||||||
|
int numMutations, int64_t version) {
|
||||||
|
versioned.addMutations(mutations, numMutations, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOldestVersion(int64_t version) {
|
||||||
|
for (auto iter = versioned.begin(version), end = versioned.end(version);
|
||||||
|
iter != end; ++iter) {
|
||||||
|
auto m = *iter;
|
||||||
|
switch (m.type) {
|
||||||
|
case weaselab::VersionedMap::Set:
|
||||||
|
unversioned[String(m.param1, m.param1Len)] =
|
||||||
|
String(m.param2, m.param2Len);
|
||||||
|
break;
|
||||||
|
case weaselab::VersionedMap::Clear:
|
||||||
|
for (auto unversionedIter =
|
||||||
|
unversioned.lower_bound(String(m.param1, m.param1Len));
|
||||||
|
unversionedIter != unversioned.end() &&
|
||||||
|
unversionedIter->first < String(m.param2, m.param2Len);) {
|
||||||
|
unversionedIter = unversioned.erase(unversionedIter);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
versioned.setOldestVersion(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
View viewAt(int64_t version) const { return View{this, version}; }
|
||||||
|
|
||||||
|
int64_t getVersion() const { return versioned.getVersion(); }
|
||||||
|
int64_t getOldestVersion() const { return versioned.getOldestVersion(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::pair<String, String>> unversionedRead(const String &begin,
|
||||||
|
const String &end,
|
||||||
|
int &limit,
|
||||||
|
bool reverse) const {
|
||||||
|
std::vector<std::pair<String, String>> result;
|
||||||
|
if (reverse) {
|
||||||
|
if (unversioned.empty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (auto iter = --unversioned.lower_bound(end);
|
||||||
|
iter->first >= begin && limit > 0; --iter) {
|
||||||
|
result.push_back(*iter);
|
||||||
|
--limit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (auto iter = unversioned.lower_bound(begin),
|
||||||
|
iterEnd = unversioned.lower_bound(end);
|
||||||
|
iter != iterEnd && limit > 0; ++iter) {
|
||||||
|
result.push_back(*iter);
|
||||||
|
--limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<String, String> unversioned;
|
||||||
|
weaselab::VersionedMap versioned;
|
||||||
|
};
|
65
FacadeTest.cpp
Normal file
65
FacadeTest.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "Facade.h"
|
||||||
|
#include "VersionedMap.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
inline weaselab::VersionedMap::Key operator"" _k(const char *str, size_t size) {
|
||||||
|
return {reinterpret_cast<const uint8_t *>(str), int(size)};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String operator"" _s(const char *str, size_t size) {
|
||||||
|
return String{reinterpret_cast<const uint8_t *>(str), size};
|
||||||
|
}
|
||||||
|
|
||||||
|
weaselab::VersionedMap::Mutation set(weaselab::VersionedMap::Key k,
|
||||||
|
weaselab::VersionedMap::Key v) {
|
||||||
|
return {k.p, v.p, k.len, v.len, weaselab::VersionedMap::Set};
|
||||||
|
}
|
||||||
|
|
||||||
|
weaselab::VersionedMap::Mutation clear(weaselab::VersionedMap::Key k) {
|
||||||
|
return {k.p, nullptr, k.len, 0, weaselab::VersionedMap::Clear};
|
||||||
|
}
|
||||||
|
|
||||||
|
weaselab::VersionedMap::Mutation clear(weaselab::VersionedMap::Key begin,
|
||||||
|
weaselab::VersionedMap::Key end) {
|
||||||
|
return {begin.p, end.p, begin.len, end.len, weaselab::VersionedMap::Clear};
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Facade f(0);
|
||||||
|
int64_t version = 1;
|
||||||
|
{
|
||||||
|
weaselab::VersionedMap::Mutation m[] = {
|
||||||
|
set("a"_k, "a"_k), set("b"_k, "b"_k), set("c"_k, "c"_k),
|
||||||
|
set("d"_k, "d"_k), set("e"_k, "e"_k),
|
||||||
|
};
|
||||||
|
f.addMutations(m, sizeof(m) / sizeof(m[0]), version++);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
weaselab::VersionedMap::Mutation m[] = {
|
||||||
|
clear("b"_k, "d"_k),
|
||||||
|
};
|
||||||
|
f.addMutations(m, sizeof(m) / sizeof(m[0]), version++);
|
||||||
|
}
|
||||||
|
for (int64_t i = 0; i < version; ++i) {
|
||||||
|
printf("--- version %" PRId64 " ---\n", i);
|
||||||
|
auto result = f.viewAt(i).rangeRead("a"_s, "d"_s, 10, false);
|
||||||
|
for (const auto &[k, v] : result) {
|
||||||
|
for (auto c : k) {
|
||||||
|
if (isprint(c)) {
|
||||||
|
printf("%c", c);
|
||||||
|
} else {
|
||||||
|
printf("0x%02x", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf(" -> ");
|
||||||
|
for (auto c : v) {
|
||||||
|
if (isprint(c)) {
|
||||||
|
printf("%c", c);
|
||||||
|
} else {
|
||||||
|
printf("0x%02x", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user