mirror of
https://github.com/systemed/tilemaker
synced 2025-02-21 13:24:09 +01:00

When I replaced #604 with #626, I botched extracting this part of the code. I had the trait, which taught kaguya how to serialize `PossiblyKnownTagValue`, but I missed updating the parameter type of `Attribute` to actually use it, so it was a no-op. This PR restores the behaviour of avoiding string copies, but now that we have protozero's data_view class, we can use that rather than our own weirdo struct.
233 lines
5.4 KiB
C++
233 lines
5.4 KiB
C++
#include <iostream>
|
|
#include "external/minunit.h"
|
|
#include "sorted_way_store.h"
|
|
#include "node_store.h"
|
|
|
|
class TestNodeStore : public NodeStore {
|
|
void clear() override {}
|
|
void reopen() override {}
|
|
void batchStart() override {}
|
|
void finalize(size_t threadNum) override {}
|
|
size_t size() const override { return 1; }
|
|
LatpLon at(NodeID id) const override {
|
|
return { (int32_t)id, -(int32_t)id };
|
|
}
|
|
void insert(const std::vector<std::pair<NodeID, LatpLon>>& elements) override {}
|
|
|
|
bool contains(size_t shard, NodeID id) const override { return true; }
|
|
NodeStore& shard(size_t shard) override { return *this; }
|
|
const NodeStore& shard(size_t shard) const override { return *this; }
|
|
|
|
size_t shards() const override { return 1; }
|
|
};
|
|
|
|
void roundtripWay(const std::vector<NodeID>& way) {
|
|
bool compress = false;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
std::vector<uint8_t> output;
|
|
uint16_t flags = SortedWayStore::encodeWay(way, output, compress);
|
|
|
|
if (false) {
|
|
std::cout << "input=";
|
|
for (const auto& node : way) {
|
|
std::cout << node << " ";
|
|
}
|
|
std::cout << std::endl;
|
|
std::cout << "flags=" << flags << ", output.size()=" << output.size() << ", ";
|
|
|
|
for (const uint8_t byte : output)
|
|
std::cout << " " << std::to_string(byte);
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
const std::vector<NodeID> roundtrip = SortedWayStore::decodeWay(flags, &output[0]);
|
|
|
|
mu_check(roundtrip.size() == way.size());
|
|
for (int i = 0; i < way.size(); i++) {
|
|
//std::cout << "roundtrip[" << i << "]=" << roundtrip[i] << ", way[" << i << "]=" << way[i] << std::endl;
|
|
mu_check(roundtrip[i] == way[i]);
|
|
}
|
|
compress = !compress;
|
|
}
|
|
}
|
|
|
|
MU_TEST(test_encode_way) {
|
|
roundtripWay({ 1 });
|
|
roundtripWay({ 1, 2 });
|
|
roundtripWay({ 1, 2, 1 });
|
|
roundtripWay({ 1, 2, 3, 4 });
|
|
roundtripWay({ 4294967295, 4294967297, 8589934592, 4, 5 });
|
|
// 11386679771 uses the full lower 32-bits, so is a good test case that
|
|
// zigzag encoding hasn't broken anything.
|
|
roundtripWay({ 5056880431, 538663248, 538663257, 538663260, 538663263, 11386679771, 538663266 });
|
|
|
|
// When the high bytes are all the same, it should take
|
|
// less space to encode.
|
|
{
|
|
std::vector<uint8_t> output;
|
|
SortedWayStore::encodeWay({ 1, 2, 3, 4 }, output, false);
|
|
const uint16_t l1 = output.size();
|
|
|
|
SortedWayStore::encodeWay({ 1, 8589934592, 3, 4 }, output, false);
|
|
const uint16_t l2 = output.size();
|
|
|
|
mu_check(l1 < l2);
|
|
}
|
|
}
|
|
|
|
MU_TEST(test_multiple_stores) {
|
|
bool compressed = false;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
compressed = !compressed;
|
|
TestNodeStore ns;
|
|
SortedWayStore s1(compressed, ns), s2(compressed, ns);
|
|
s1.batchStart();
|
|
s2.batchStart();
|
|
|
|
s1.insertNodes({{ 1, { 1 } }});
|
|
|
|
// We store small ways differently than large ways, so
|
|
// store both kinds for testing.
|
|
std::vector<NodeID> longWay;
|
|
for (int i = 200; i < 2048; i++)
|
|
longWay.push_back(i + 3 * (i % 37));
|
|
|
|
s1.insertNodes({{ 42, longWay }});
|
|
s2.insertNodes({{ 2, { 2 } }});
|
|
|
|
s1.finalize(1);
|
|
s2.finalize(1);
|
|
|
|
mu_check(s1.size() == 2);
|
|
mu_check(s2.size() == 1);
|
|
|
|
mu_check(s1.contains(0, 1));
|
|
mu_check(s1.contains(0, 42));
|
|
mu_check(!s1.contains(0, 2));
|
|
}
|
|
}
|
|
|
|
MU_TEST(test_way_store) {
|
|
TestNodeStore ns;
|
|
SortedWayStore sws(true, ns);
|
|
sws.batchStart();
|
|
|
|
std::vector<std::pair<WayID, std::vector<NodeID>>> ways;
|
|
std::vector<NodeID> shortWay;
|
|
shortWay.push_back(123);
|
|
ways.push_back(std::make_pair(1, shortWay));
|
|
ways.push_back(std::make_pair(2, shortWay));
|
|
ways.push_back(std::make_pair(513, shortWay));
|
|
|
|
std::vector<NodeID> longWay;
|
|
for(int i = 200; i < 300; i++)
|
|
longWay.push_back(i);
|
|
ways.push_back(std::make_pair(65536, longWay));
|
|
ways.push_back(std::make_pair(131072, longWay));
|
|
|
|
sws.insertNodes(ways);
|
|
sws.finalize(1);
|
|
|
|
mu_check(sws.size() == 5);
|
|
|
|
{
|
|
const auto& rv = sws.at(1);
|
|
mu_check(rv.size() == 1);
|
|
mu_check(rv[0].latp == 123);
|
|
}
|
|
|
|
{
|
|
const auto& rv = sws.at(2);
|
|
mu_check(rv.size() == 1);
|
|
mu_check(rv[0].latp == 123);
|
|
}
|
|
|
|
{
|
|
const auto& rv = sws.at(513);
|
|
mu_check(rv.size() == 1);
|
|
mu_check(rv[0].latp == 123);
|
|
}
|
|
|
|
{
|
|
const auto& rv = sws.at(65536);
|
|
mu_check(rv.size() == 100);
|
|
mu_check(rv[0].latp == 200);
|
|
mu_check(rv[99].latp == 299);
|
|
}
|
|
|
|
{
|
|
const auto& rv = sws.at(131072);
|
|
mu_check(rv.size() == 100);
|
|
mu_check(rv[0].latp == 200);
|
|
mu_check(rv[99].latp == 299);
|
|
}
|
|
|
|
// missing things should throw std::out_of_range
|
|
|
|
bool threw = false;
|
|
try {
|
|
sws.at(123123123);
|
|
} catch (std::out_of_range &e) {
|
|
threw = true;
|
|
} catch (...) {}
|
|
mu_check(threw == true);
|
|
|
|
threw = false;
|
|
try {
|
|
sws.at(3);
|
|
} catch (std::out_of_range &e) {
|
|
threw = true;
|
|
} catch (...) {}
|
|
mu_check(threw == true);
|
|
|
|
}
|
|
|
|
MU_TEST(test_populate_mask) {
|
|
uint8_t mask[32];
|
|
std::vector<uint8_t> ids;
|
|
|
|
{
|
|
// No ids: all 0s
|
|
populateMask(mask, ids);
|
|
for(int i = 0; i < 32; i++)
|
|
mu_check(mask[i] == 0);
|
|
}
|
|
|
|
{
|
|
// Every id: all 1s
|
|
for(int i = 0; i < 256; i++)
|
|
ids.push_back(i);
|
|
populateMask(mask, ids);
|
|
for(int i = 0; i < 32; i++)
|
|
mu_check(mask[i] == 255);
|
|
}
|
|
|
|
{
|
|
// Every other ID
|
|
ids.clear();
|
|
for (int i = 0; i < 256; i += 2)
|
|
ids.push_back(i);
|
|
populateMask(mask, ids);
|
|
for(int i = 0; i < 32; i++)
|
|
mu_check(mask[i] == 0b01010101);
|
|
}
|
|
}
|
|
|
|
MU_TEST_SUITE(test_suite_sorted_way_store) {
|
|
MU_RUN_TEST(test_encode_way);
|
|
MU_RUN_TEST(test_multiple_stores);
|
|
MU_RUN_TEST(test_way_store);
|
|
}
|
|
|
|
MU_TEST_SUITE(test_suite_bitmask) {
|
|
MU_RUN_TEST(test_populate_mask);
|
|
}
|
|
|
|
int main() {
|
|
MU_RUN_SUITE(test_suite_sorted_way_store);
|
|
MU_RUN_SUITE(test_suite_bitmask);
|
|
MU_REPORT();
|
|
return MU_EXIT_CODE;
|
|
}
|