2016-05-20 12:56:16 -04:00
|
|
|
#ifndef PACKED_VECTOR_HPP
|
|
|
|
#define PACKED_VECTOR_HPP
|
|
|
|
|
2016-05-24 10:17:24 -04:00
|
|
|
#include "util/shared_memory_vector_wrapper.hpp"
|
2016-06-02 08:43:27 -04:00
|
|
|
#include "util/typedefs.hpp"
|
2016-05-20 12:56:16 -04:00
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
#include "storage/shared_memory_ownership.hpp"
|
2017-03-29 08:06:52 -04:00
|
|
|
|
2016-05-20 14:11:46 -04:00
|
|
|
#include <cmath>
|
2016-05-20 12:56:16 -04:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace util
|
|
|
|
{
|
|
|
|
|
2016-05-20 14:11:46 -04:00
|
|
|
/**
|
|
|
|
* Since OSM node IDs are (at the time of writing) not quite yet overflowing 32 bits, and
|
|
|
|
* will predictably be containable within 33 bits for a long time, the following packs
|
|
|
|
* 64-bit OSM IDs as 33-bit numbers within a 64-bit vector.
|
2016-05-27 13:30:30 -04:00
|
|
|
*
|
|
|
|
* NOTE: this type is templated for future use, but will require a slight refactor to
|
|
|
|
* configure BITSIZE and ELEMSIZE
|
2016-05-20 14:11:46 -04:00
|
|
|
*/
|
2017-04-04 03:52:00 -04:00
|
|
|
template <typename T, storage::Ownership Ownership = storage::Ownership::Container>
|
2017-03-29 08:07:03 -04:00
|
|
|
class PackedVector
|
2016-05-20 12:56:16 -04:00
|
|
|
{
|
2016-06-10 17:25:19 -04:00
|
|
|
static const constexpr std::size_t BITSIZE = 33;
|
|
|
|
static const constexpr std::size_t ELEMSIZE = 64;
|
|
|
|
static const constexpr std::size_t PACKSIZE = BITSIZE * ELEMSIZE;
|
|
|
|
|
2016-05-20 12:56:16 -04:00
|
|
|
public:
|
2016-06-10 17:25:19 -04:00
|
|
|
/**
|
2016-06-21 10:54:16 -04:00
|
|
|
* Returns the size of the packed vector datastructure with `elements` packed elements (the size
|
|
|
|
* of
|
2016-06-10 17:25:19 -04:00
|
|
|
* its underlying uint64 vector)
|
|
|
|
*/
|
|
|
|
inline static std::size_t elements_to_blocks(std::size_t elements)
|
|
|
|
{
|
|
|
|
return std::ceil(static_cast<double>(elements) * BITSIZE / ELEMSIZE);
|
|
|
|
}
|
|
|
|
|
2016-05-27 13:30:30 -04:00
|
|
|
void push_back(T incoming_node_id)
|
2016-05-20 12:56:16 -04:00
|
|
|
{
|
2016-05-20 14:11:46 -04:00
|
|
|
std::uint64_t node_id = static_cast<std::uint64_t>(incoming_node_id);
|
2016-05-24 10:17:24 -04:00
|
|
|
|
2016-05-20 12:56:16 -04:00
|
|
|
// mask incoming values, just in case they are > bitsize
|
2016-05-20 14:11:46 -04:00
|
|
|
const std::uint64_t incoming_mask = static_cast<std::uint64_t>(pow(2, BITSIZE)) - 1;
|
2016-05-20 12:56:16 -04:00
|
|
|
node_id = node_id & incoming_mask;
|
|
|
|
|
|
|
|
const std::size_t available = (PACKSIZE - BITSIZE * num_elements) % ELEMSIZE;
|
|
|
|
|
|
|
|
if (available == 0)
|
|
|
|
{
|
|
|
|
// insert ID at the left side of this element
|
|
|
|
std::uint64_t at_left = node_id << (ELEMSIZE - BITSIZE);
|
2016-05-23 20:13:32 -04:00
|
|
|
|
|
|
|
add_last_elem(at_left);
|
2016-05-20 12:56:16 -04:00
|
|
|
}
|
|
|
|
else if (available >= BITSIZE)
|
|
|
|
{
|
|
|
|
// insert ID somewhere in the middle of this element; ID can be contained
|
|
|
|
// entirely within one element
|
2016-05-20 14:11:46 -04:00
|
|
|
const std::uint64_t shifted = node_id << (available - BITSIZE);
|
2016-05-23 20:13:32 -04:00
|
|
|
|
|
|
|
replace_last_elem(vec_back() | shifted);
|
2016-05-20 12:56:16 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ID will be split between the end of this element and the beginning
|
|
|
|
// of the next element
|
2016-05-20 14:11:46 -04:00
|
|
|
const std::uint64_t left = node_id >> (BITSIZE - available);
|
2016-05-20 12:56:16 -04:00
|
|
|
|
|
|
|
std::uint64_t right = node_id << (ELEMSIZE - (BITSIZE - available));
|
2016-05-23 20:13:32 -04:00
|
|
|
|
|
|
|
replace_last_elem(vec_back() | left);
|
|
|
|
add_last_elem(right);
|
2016-05-20 12:56:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
num_elements++;
|
|
|
|
}
|
|
|
|
|
2016-05-27 13:30:30 -04:00
|
|
|
T at(const std::size_t &a_index) const
|
2016-05-20 12:56:16 -04:00
|
|
|
{
|
2016-05-20 14:11:46 -04:00
|
|
|
BOOST_ASSERT(a_index < num_elements);
|
2016-05-20 12:56:16 -04:00
|
|
|
|
|
|
|
const std::size_t pack_group = trunc(a_index / ELEMSIZE);
|
2016-05-20 14:11:46 -04:00
|
|
|
const std::size_t pack_index = (a_index + ELEMSIZE) % ELEMSIZE;
|
2016-05-20 12:56:16 -04:00
|
|
|
const std::size_t left_index = (PACKSIZE - BITSIZE * pack_index) % ELEMSIZE;
|
|
|
|
|
|
|
|
const bool back_half = pack_index >= BITSIZE;
|
2016-05-20 14:11:46 -04:00
|
|
|
const std::size_t index = pack_group * BITSIZE + trunc(pack_index / BITSIZE) +
|
|
|
|
trunc((pack_index - back_half) / 2);
|
2016-05-20 12:56:16 -04:00
|
|
|
|
2016-05-20 14:11:46 -04:00
|
|
|
BOOST_ASSERT(index < vec.size());
|
2016-05-23 20:13:32 -04:00
|
|
|
const std::uint64_t elem = static_cast<std::uint64_t>(vec.at(index));
|
2016-05-20 12:56:16 -04:00
|
|
|
|
|
|
|
if (left_index == 0)
|
|
|
|
{
|
|
|
|
// ID is at the far left side of this element
|
2016-06-24 01:01:37 -04:00
|
|
|
return T{elem >> (ELEMSIZE - BITSIZE)};
|
2016-05-20 12:56:16 -04:00
|
|
|
}
|
|
|
|
else if (left_index >= BITSIZE)
|
|
|
|
{
|
|
|
|
// ID is entirely contained within this element
|
2016-05-20 14:11:46 -04:00
|
|
|
const std::uint64_t at_right = elem >> (left_index - BITSIZE);
|
|
|
|
const std::uint64_t left_mask = static_cast<std::uint64_t>(pow(2, BITSIZE)) - 1;
|
2016-06-24 01:01:37 -04:00
|
|
|
return T{at_right & left_mask};
|
2016-05-20 12:56:16 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ID is split between this and the next element
|
2016-05-20 14:11:46 -04:00
|
|
|
const std::uint64_t left_mask = static_cast<std::uint64_t>(pow(2, left_index)) - 1;
|
|
|
|
const std::uint64_t left_side = (elem & left_mask) << (BITSIZE - left_index);
|
2016-05-20 12:56:16 -04:00
|
|
|
|
2016-05-20 14:11:46 -04:00
|
|
|
BOOST_ASSERT(index < vec.size() - 1);
|
2016-05-23 20:13:32 -04:00
|
|
|
const std::uint64_t next_elem = static_cast<std::uint64_t>(vec.at(index + 1));
|
2016-05-20 12:56:16 -04:00
|
|
|
|
2016-05-20 14:11:46 -04:00
|
|
|
const std::uint64_t right_side = next_elem >> (ELEMSIZE - (BITSIZE - left_index));
|
2016-06-24 01:01:37 -04:00
|
|
|
return T{left_side | right_side};
|
2016-05-20 12:56:16 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-24 10:33:05 -04:00
|
|
|
std::size_t size() const { return num_elements; }
|
2016-05-23 10:39:57 -04:00
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
template <bool enabled = (Ownership == storage::Ownership::View)>
|
2016-05-23 20:13:32 -04:00
|
|
|
void reserve(typename std::enable_if<!enabled, std::size_t>::type capacity)
|
2016-05-23 10:39:57 -04:00
|
|
|
{
|
2016-06-10 17:25:19 -04:00
|
|
|
vec.reserve(elements_to_blocks(capacity));
|
2016-05-23 20:13:32 -04:00
|
|
|
}
|
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
template <bool enabled = (Ownership == storage::Ownership::View)>
|
2016-06-10 17:25:19 -04:00
|
|
|
void reset(typename std::enable_if<enabled, std::uint64_t>::type *ptr,
|
2016-05-24 10:33:05 -04:00
|
|
|
typename std::enable_if<enabled, std::size_t>::type size)
|
2016-05-23 20:13:32 -04:00
|
|
|
{
|
2016-06-10 17:25:19 -04:00
|
|
|
vec.reset(ptr, size);
|
2016-05-23 20:13:32 -04:00
|
|
|
}
|
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
template <bool enabled = (Ownership == storage::Ownership::View)>
|
2016-05-23 20:13:32 -04:00
|
|
|
void set_number_of_entries(typename std::enable_if<enabled, std::size_t>::type count)
|
|
|
|
{
|
|
|
|
num_elements = count;
|
2016-05-23 10:39:57 -04:00
|
|
|
}
|
|
|
|
|
2016-06-10 17:25:19 -04:00
|
|
|
std::size_t capacity() const
|
|
|
|
{
|
|
|
|
return std::floor(static_cast<double>(vec.capacity()) * ELEMSIZE / BITSIZE);
|
|
|
|
}
|
2016-05-23 10:39:57 -04:00
|
|
|
|
2016-05-20 12:56:16 -04:00
|
|
|
private:
|
2017-04-03 03:51:41 -04:00
|
|
|
typename util::ShM<std::uint64_t, Ownership>::vector vec;
|
2016-05-23 20:13:32 -04:00
|
|
|
|
2016-05-20 12:56:16 -04:00
|
|
|
std::size_t num_elements = 0;
|
2016-05-23 20:13:32 -04:00
|
|
|
|
|
|
|
signed cursor = -1;
|
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
template <bool enabled = (Ownership == storage::Ownership::View)>
|
2016-05-23 20:13:32 -04:00
|
|
|
void replace_last_elem(typename std::enable_if<enabled, std::uint64_t>::type last_elem)
|
|
|
|
{
|
|
|
|
vec[cursor] = last_elem;
|
|
|
|
}
|
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
template <bool enabled = (Ownership == storage::Ownership::View)>
|
2016-05-23 20:13:32 -04:00
|
|
|
void replace_last_elem(typename std::enable_if<!enabled, std::uint64_t>::type last_elem)
|
|
|
|
{
|
|
|
|
vec.back() = last_elem;
|
|
|
|
}
|
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
template <bool enabled = (Ownership == storage::Ownership::View)>
|
2016-05-23 20:13:32 -04:00
|
|
|
void add_last_elem(typename std::enable_if<enabled, std::uint64_t>::type last_elem)
|
|
|
|
{
|
|
|
|
vec[cursor + 1] = last_elem;
|
|
|
|
cursor++;
|
|
|
|
}
|
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
template <bool enabled = (Ownership == storage::Ownership::View)>
|
2016-05-23 20:13:32 -04:00
|
|
|
void add_last_elem(typename std::enable_if<!enabled, std::uint64_t>::type last_elem)
|
|
|
|
{
|
|
|
|
vec.push_back(last_elem);
|
|
|
|
}
|
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
template <bool enabled = (Ownership == storage::Ownership::View)>
|
2016-05-24 10:33:05 -04:00
|
|
|
std::uint64_t vec_back(typename std::enable_if<enabled>::type * = nullptr)
|
2016-05-23 20:13:32 -04:00
|
|
|
{
|
|
|
|
return vec[cursor];
|
|
|
|
}
|
|
|
|
|
2017-04-04 03:52:00 -04:00
|
|
|
template <bool enabled = (Ownership == storage::Ownership::View)>
|
2016-05-24 10:33:05 -04:00
|
|
|
std::uint64_t vec_back(typename std::enable_if<!enabled>::type * = nullptr)
|
2016-05-23 20:13:32 -04:00
|
|
|
{
|
|
|
|
return vec.back();
|
|
|
|
}
|
2016-05-20 12:56:16 -04:00
|
|
|
};
|
2016-05-20 14:11:46 -04:00
|
|
|
}
|
|
|
|
}
|
2016-05-20 12:56:16 -04:00
|
|
|
|
|
|
|
#endif /* PACKED_VECTOR_HPP */
|