1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
/* Implements the mid-layer processing for osm2pgsql
* using data structures in RAM.
*
* This layer stores data read in from the planet.osm file
* and is then read by the backend processing code to
* emit the final geometry-enabled output formats
*/
#ifndef MIDDLE_RAM_H
#define MIDDLE_RAM_H
#include <memory>
#include "middle.hpp"
#include <vector>
#include <array>
struct node_ram_cache;
struct options_t;
template <typename T, size_t N>
class cache_block_t
{
std::array<std::unique_ptr<T>, N> arr;
public:
void set(size_t idx, T *ele) { arr[idx].reset(ele); }
T const *get(size_t idx) const { return arr[idx].get(); }
};
template <typename T, size_t BLOCK_SHIFT>
class elem_cache_t
{
constexpr static size_t per_block() { return 1 << BLOCK_SHIFT; }
constexpr static size_t num_blocks() { return 1 << (32 - BLOCK_SHIFT); }
constexpr static size_t id2block(osmid_t id)
{
/* + NUM_BLOCKS/2 allows for negative IDs */
return (id >> BLOCK_SHIFT) + num_blocks()/2;
}
constexpr static size_t id2offset(osmid_t id)
{
return id & (per_block()-1);
}
typedef cache_block_t<T, 1 << BLOCK_SHIFT> element_t;
std::vector<std::unique_ptr<element_t>> arr;
public:
elem_cache_t() : arr(num_blocks()) {}
void set(osmid_t id, T *ele)
{
const size_t block = id2block(id);
if (!arr[block]) {
arr[block].reset(new element_t());
}
arr[block]->set(id2offset(id), ele);
}
T const *get(osmid_t id) const
{
const size_t block = id2block(id);
if (!arr[block]) {
return 0;
}
return arr[block]->get(id2offset(id));
}
void clear()
{
for (auto &ele : arr) {
ele.reset();
}
}
};
struct middle_ram_t : public middle_t {
middle_ram_t();
virtual ~middle_ram_t();
void start(const options_t *out_options_) override;
void stop(osmium::thread::Pool &pool) override;
void analyze(void) override;
void end(void) override;
void commit(void) override;
void nodes_set(osmium::Node const &node) override;
size_t nodes_get_list(osmium::WayNodeList *nodes) const override;
int nodes_delete(osmid_t id);
int node_changed(osmid_t id);
void ways_set(osmium::Way const &way) override;
bool ways_get(osmid_t id, osmium::memory::Buffer &buffer) const override;
size_t rel_way_members_get(osmium::Relation const &rel, rolelist_t *roles,
osmium::memory::Buffer &buffer) const override;
int ways_delete(osmid_t id);
int way_changed(osmid_t id);
bool relations_get(osmid_t id, osmium::memory::Buffer &buffer) const override;
void relations_set(osmium::Relation const &rel) override;
int relations_delete(osmid_t id);
int relation_changed(osmid_t id);
idlist_t relations_using_way(osmid_t way_id) const override;
void iterate_ways(middle_t::pending_processor& pf) override;
void iterate_relations(pending_processor& pf) override;
size_t pending_count() const override;
std::shared_ptr<const middle_query_t> get_instance() const override;
private:
void release_ways();
void release_relations();
struct ramWay {
taglist_t tags;
idlist_t ndids;
ramWay(osmium::Way const &way, bool add_attributes)
: tags(way.tags()), ndids(way.nodes())
{
if (add_attributes)
tags.add_attributes(way);
}
};
struct ramRel {
taglist_t tags;
memberlist_t members;
ramRel(osmium::Relation const &rel, bool add_attributes)
: tags(rel.tags()), members(rel.members())
{
if (add_attributes)
tags.add_attributes(rel);
}
};
elem_cache_t<ramWay, 10> ways;
elem_cache_t<ramRel, 10> rels;
std::unique_ptr<node_ram_cache> cache;
/* the previous behaviour of iterate_ways was to delete all ways as they
* were being iterated. this doesn't work now that the output handles its
* own "done" status and output-specific "pending" status. however, the
* tests depend on the behaviour that ways will be unavailable once
* iterate_ways is complete, so this flag emulates that. */
bool simulate_ways_deleted;
};
#endif
|