Fishnet 2.0.1
Framework for Graph-Based Analysis of GIS Vector Data
Loading...
Searching...
No Matches
BinaryAdjacency.hpp
Go to the documentation of this file.
1#pragma once
2#include <fstream>
3#include <string_view>
4#include <vector>
5#include <cstdint>
8
9namespace fishnet::graph{
10
11template<typename BaseContainer> requires AdjacencyContainer<BaseContainer,typename BaseContainer::node_type>
12class BinaryAdjacency : public AdjacencyContainerDecorator<BaseContainer>{
13private:
14 using N = typename BaseContainer::node_type;
18public:
19
20 BinaryAdjacency(BaseContainer && baseContainer,
21 util::UnaryFunction<N, std::vector<uint8_t>> auto toBinary,
22 util::UnaryFunction<std::vector<uint8_t>, N> auto fromBinary)
23 : AdjacencyContainerDecorator<BaseContainer>(std::move(baseContainer)), toBinary(std::move(toBinary)), fromBinary(std::move(fromBinary)) {}
24
25 std::vector<uint8_t> get() const noexcept {
26 std::vector<uint8_t> result;
27
28 auto write_bytes = [&](const void* data, size_t size) {
29 const uint8_t* bytes = static_cast<const uint8_t*>(data);
30 result.insert(result.end(), bytes, bytes + size);
31 };
32
33 auto write_u64 = [&](uint64_t value) {
34 write_bytes(&value, sizeof(uint64_t));
35 };
36
37 uint64_t nodeID = 0;
38 std::unordered_map<N,uint64_t,typename BaseContainer::hash_function,typename BaseContainer::equality_predicate> nodeToIDMap;
39
40 // Collect nodes and assign IDs
41 std::vector<std::pair<uint64_t,std::vector<uint8_t>>> nodeData;
42 for(const auto & node: this->nodes()){
43 uint64_t id = nodeID++;
44 nodeToIDMap[node] = id;
45 std::vector<uint8_t> data = toBinary(node);
46 nodeData.emplace_back(id, std::move(data));
47 }
48
49 // Write number of nodes
50 uint64_t numNodes = nodeData.size();
51 write_u64(numNodes);
52
53 // Write nodes
54 for(const auto & [id, data] : nodeData){
55 write_u64(id);
56 uint64_t dataSize = data.size();
57 write_u64(dataSize);
58 write_bytes(data.data(), dataSize);
59 }
60
61 // Collect edges
62 auto edges = this->getAdjacencyPairs();
63 uint64_t numEdges = fishnet::util::size(edges);
64
65 // Write number of edges
66 write_u64(numEdges);
67
68 // Write edges
69 for(const auto &[from,to]: edges){
70 uint64_t fromID = nodeToIDMap.at(from);
71 uint64_t toID = nodeToIDMap.at(to);
72 write_u64(fromID);
73 write_u64(toID);
74 }
75
76 return result;
77 }
78
79 void load(const std::vector<uint8_t> & data) {
80 if(data.empty()){
81 return;
82 }
83
84 size_t offset = 0;
85 auto ensure_bytes = [&](size_t need){
86 if(offset + need > data.size()){
87 throw std::runtime_error("Binary data truncated");
88 }
89 };
90
91 auto read_u64 = [&]() -> uint64_t {
92 ensure_bytes(sizeof(uint64_t));
93 uint64_t v = 0;
94 for(size_t i = 0; i < sizeof(uint64_t); ++i){
95 v |= static_cast<uint64_t>(data[offset + i]) << (8 * i);
96 }
97 offset += sizeof(uint64_t);
98 return v;
99 };
100
101 // Read number of nodes
102 uint64_t numNodes = read_u64();
103
104 std::unordered_map<uint64_t,N> idToNodeMap;
105 idToNodeMap.reserve(numNodes);
106
107 // Read nodes
108 for(uint64_t i = 0; i < numNodes; ++i){
109 uint64_t nodeID = read_u64();
110 uint64_t dataSize = read_u64();
111 if(dataSize > data.size() - offset){
112 throw std::runtime_error("Binary data truncated while reading node payload");
113 }
114 std::vector<uint8_t> nodeBytes(data.begin() + offset, data.begin() + offset + static_cast<size_t>(dataSize));
115 offset += static_cast<size_t>(dataSize);
116
117 N node = fromBinary(nodeBytes);
118 this->addNode(node);
119 idToNodeMap.emplace(nodeID, std::move(node));
120 }
121
122 // Read number of edges
123 uint64_t numEdges = read_u64();
124
125 // Read edges
126 for(uint64_t i = 0; i < numEdges; ++i){
127 uint64_t fromID = read_u64();
128 uint64_t toID = read_u64();
129 if(not idToNodeMap.contains(fromID) or not idToNodeMap.contains(toID)){
130 throw std::runtime_error("Binary data format error: edge references unknown node id");
131 }
132 this->addAdjacency(idToNodeMap.at(fromID), idToNodeMap.at(toID));
133 }
134 }
135};
136} // namespace fishnet::graph
A decorator for adjacency containers that adds additional functionality.
Definition AdjacencyContainerDecorator.hpp:16
auto getAdjacencyPairs() const noexcept
Definition AdjacencyContainerDecorator.hpp:86
auto nodes() const noexcept
Definition AdjacencyContainerDecorator.hpp:82
void addAdjacency(const N &from, const N &to)
Definition AdjacencyContainerDecorator.hpp:30
bool addNode(const N &node)
Definition AdjacencyContainerDecorator.hpp:42
Definition BinaryAdjacency.hpp:12
BinaryAdjacency(BaseContainer &&baseContainer, util::UnaryFunction< N, std::vector< uint8_t > > auto toBinary, util::UnaryFunction< std::vector< uint8_t >, N > auto fromBinary)
Definition BinaryAdjacency.hpp:20
void load(const std::vector< uint8_t > &data)
Definition BinaryAdjacency.hpp:79
std::vector< uint8_t > get() const noexcept
Definition BinaryAdjacency.hpp:25
Definition FunctionalConcepts.hpp:9
Definition AdjacencyContainer.hpp:4
constexpr size_t size(std::ranges::range auto &&range) noexcept
Definition CollectionConcepts.hpp:50
std::function< R(const T &)> UnaryFunction_t
Definition FunctionalConcepts.hpp:12
STL namespace.