fcecb14545
Summary: Phase 2. Phase 3. Phase 4. Phase 5. Complete refactor. Reviewers: florijan, mislav.bradac Reviewed By: mislav.bradac Subscribers: mislav.bradac, pullbot Differential Revision: https://phabricator.memgraph.io/D895
111 lines
4.5 KiB
C++
111 lines
4.5 KiB
C++
#include <algorithm>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "glog/logging.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "data_structures/concurrent/skiplist.hpp"
|
|
|
|
/* The following tests validate the SkipList::position_and_count estimation
|
|
* functionality. That function has a tunable speed vs. accuracy. The tests
|
|
* here test the absolutely-accurate parameterization, as well as the default
|
|
* one that should be optimal parametrization. As such the tests are
|
|
* stochastic and defined to validate generally acceptable behavior in
|
|
* a vast majority of cases. The probability of test failure due to
|
|
* stochasticity should be extremely small, but isn't zero.
|
|
*/
|
|
|
|
auto SkiplistRange(int count) {
|
|
auto sl = std::make_unique<SkipList<int>>();
|
|
auto access = sl->access();
|
|
for (int i = 0; i < count; i++) access.insert(i);
|
|
return sl;
|
|
}
|
|
|
|
auto Median(std::vector<int> &elements) {
|
|
auto elem_size = elements.size();
|
|
DCHECK(elem_size > 0) << "Provide some elements to get median!";
|
|
std::sort(elements.begin(), elements.end());
|
|
if (elem_size % 2)
|
|
return elements[elem_size / 2];
|
|
else
|
|
return (elements[elem_size / 2 - 1] + elements[elem_size / 2]) / 2;
|
|
}
|
|
|
|
auto Less(int granularity) {
|
|
return [granularity](const int &a, const int &b) {
|
|
return a / granularity < b / granularity;
|
|
};
|
|
}
|
|
|
|
auto Equal(int granularity) {
|
|
return [granularity](const int &a, const int &b) {
|
|
return a / granularity == b / granularity;
|
|
};
|
|
}
|
|
|
|
#define EXPECT_ABS_POS_COUNT(granularity, position, expected_position, \
|
|
expected_count) \
|
|
{ \
|
|
auto sl = SkiplistRange(10000); \
|
|
auto position_and_count = sl->access().position_and_count( \
|
|
position, Less(granularity), Equal(granularity), 1000, 0); \
|
|
EXPECT_EQ(position_and_count.first, expected_position); \
|
|
EXPECT_EQ(position_and_count.second, expected_count); \
|
|
}
|
|
|
|
TEST(SkiplistPosAndCount, AbsoluteAccuracy) {
|
|
EXPECT_ABS_POS_COUNT(1, 42, 42, 1);
|
|
EXPECT_ABS_POS_COUNT(3, 42, 42, 3);
|
|
EXPECT_ABS_POS_COUNT(10, 42, 40, 10);
|
|
}
|
|
|
|
#define EXPECT_POS_COUNT(skiplist_size, position, expected_count, \
|
|
position_error_margin, count_error_margin) \
|
|
{ \
|
|
std::vector<int> pos_errors; \
|
|
std::vector<int> count_errors; \
|
|
\
|
|
for (int i = 0; i < 30; i++) { \
|
|
auto sl = SkiplistRange(skiplist_size); \
|
|
auto position_count = sl->access().position_and_count(position); \
|
|
pos_errors.push_back(std::abs((long)position_count.first - position)); \
|
|
count_errors.push_back( \
|
|
std::abs((long)position_count.second - expected_count)); \
|
|
} \
|
|
EXPECT_LE(Median(pos_errors), position_error_margin); \
|
|
EXPECT_LE(Median(count_errors), count_error_margin); \
|
|
}
|
|
|
|
TEST(SkiplistPosAndCount, DefaultSpeedAndAccuracy) {
|
|
EXPECT_POS_COUNT(5000, 42, 1, 20, 3);
|
|
EXPECT_POS_COUNT(5000, 2500, 1, 100, 3);
|
|
EXPECT_POS_COUNT(5000, 4500, 1, 200, 3);
|
|
|
|
// for an item greater then all list elements the returned
|
|
// estimations are always absolutely accurate
|
|
EXPECT_POS_COUNT(5000, 5000, 0, 0, 0);
|
|
}
|
|
|
|
#define EXPECT_FOR_OUT_OF_RANGE(skiplist_size, value) \
|
|
{ \
|
|
auto sl = SkiplistRange(skiplist_size); \
|
|
auto position_and_count = sl->access().position_and_count(value); \
|
|
EXPECT_EQ(position_and_count.first, value < 0 ? 0 : skiplist_size); \
|
|
EXPECT_EQ(position_and_count.second, 0); \
|
|
}
|
|
|
|
TEST(SkiplistPosAndCount, EdgeValues) {
|
|
// small list
|
|
EXPECT_FOR_OUT_OF_RANGE(100, -20);
|
|
EXPECT_FOR_OUT_OF_RANGE(100, -1);
|
|
EXPECT_FOR_OUT_OF_RANGE(100, 100);
|
|
EXPECT_FOR_OUT_OF_RANGE(100, 120);
|
|
// big list
|
|
EXPECT_FOR_OUT_OF_RANGE(100000, -20);
|
|
EXPECT_FOR_OUT_OF_RANGE(100000, -1);
|
|
EXPECT_FOR_OUT_OF_RANGE(100000, 100000);
|
|
EXPECT_FOR_OUT_OF_RANGE(100000, 100300);
|
|
}
|