2010-09-15 01:33:11 +04:00
|
|
|
#ifndef UTIL_SORTED_UNIFORM__
|
|
|
|
#define UTIL_SORTED_UNIFORM__
|
2010-09-10 04:36:07 +04:00
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cstddef>
|
|
|
|
|
2010-09-15 01:33:11 +04:00
|
|
|
#include <assert.h>
|
2010-09-10 04:36:07 +04:00
|
|
|
#include <inttypes.h>
|
|
|
|
|
|
|
|
namespace util {
|
|
|
|
|
|
|
|
inline std::size_t Pivot(uint64_t off, uint64_t range, std::size_t width) {
|
|
|
|
std::size_t ret = static_cast<std::size_t>(static_cast<float>(off) / static_cast<float>(range) * static_cast<float>(width));
|
|
|
|
// Cap for floating point rounding
|
|
|
|
return (ret < width) ? ret : width - 1;
|
|
|
|
}
|
2010-09-15 01:33:11 +04:00
|
|
|
/*inline std::size_t Pivot(uint32_t off, uint32_t range, std::size_t width) {
|
2010-09-10 04:36:07 +04:00
|
|
|
return static_cast<std::size_t>(static_cast<uint64_t>(off) * static_cast<uint64_t>(width) / static_cast<uint64_t>(range));
|
|
|
|
}
|
|
|
|
inline std::size_t Pivot(uint16_t off, uint16_t range, std::size_t width) {
|
|
|
|
return static_cast<std::size_t>(static_cast<std::size_t>(off) * width / static_cast<std::size_t>(range));
|
|
|
|
}
|
2010-09-15 01:33:11 +04:00
|
|
|
inline std::size_t Pivot(unsigned char off, unsigned char range, std::size_t width) {
|
2010-09-10 04:36:07 +04:00
|
|
|
return static_cast<std::size_t>(static_cast<std::size_t>(off) * width / static_cast<std::size_t>(range));
|
2010-09-15 01:33:11 +04:00
|
|
|
}*/
|
|
|
|
|
|
|
|
template <class Iterator, class Key> bool SortedUniformFind(Iterator begin, Iterator end, const Key key, Iterator &out) {
|
|
|
|
if (begin == end) return false;
|
|
|
|
Key below(begin->GetKey());
|
|
|
|
if (key <= below) {
|
|
|
|
if (key == below) { out = begin; return true; }
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Make the range [begin, end].
|
|
|
|
--end;
|
|
|
|
Key above(end->GetKey());
|
|
|
|
if (key >= above) {
|
|
|
|
if (key == above) { out = end; return true; }
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Search the range [begin + 1, end - 1] knowing that *begin == below, *end == above.
|
|
|
|
while (end - begin > 1) {
|
|
|
|
Iterator pivot(begin + (1 + Pivot(key - below, above - below, static_cast<std::size_t>(end - begin - 1))));
|
|
|
|
Key mid(pivot->GetKey());
|
|
|
|
if (mid < key) {
|
|
|
|
begin = pivot;
|
|
|
|
below = mid;
|
|
|
|
} else if (mid > key) {
|
|
|
|
end = pivot;
|
|
|
|
above = mid;
|
|
|
|
} else {
|
|
|
|
out = pivot;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2010-09-10 04:36:07 +04:00
|
|
|
}
|
|
|
|
|
2010-09-15 01:33:11 +04:00
|
|
|
// To use this template, you need to define a Pivot function to match Key.
|
|
|
|
template <class PackingT> class SortedUniformMap {
|
2010-09-10 04:36:07 +04:00
|
|
|
public:
|
2010-09-15 01:33:11 +04:00
|
|
|
typedef PackingT Packing;
|
|
|
|
typedef typename Packing::ConstIterator ConstIterator;
|
2010-09-10 04:36:07 +04:00
|
|
|
|
2010-09-15 01:33:11 +04:00
|
|
|
public:
|
|
|
|
// Offer consistent API with probing hash.
|
2010-09-27 04:57:11 +04:00
|
|
|
static std::size_t Size(std::size_t entries, float /*ignore*/ = 0.0) {
|
2010-09-15 01:33:11 +04:00
|
|
|
return sizeof(uint64_t) + entries * Packing::kBytes;
|
2010-09-10 04:36:07 +04:00
|
|
|
}
|
|
|
|
|
2010-09-15 01:33:11 +04:00
|
|
|
SortedUniformMap()
|
|
|
|
#ifdef DEBUG
|
|
|
|
: initialized_(false), loaded_(false)
|
|
|
|
#endif
|
|
|
|
{}
|
|
|
|
|
2010-10-27 21:50:40 +04:00
|
|
|
SortedUniformMap(void *start, std::size_t /*allocated*/) :
|
2010-09-15 01:33:11 +04:00
|
|
|
begin_(Packing::FromVoid(reinterpret_cast<uint64_t*>(start) + 1)),
|
|
|
|
end_(begin_), size_ptr_(reinterpret_cast<uint64_t*>(start))
|
|
|
|
#ifdef DEBUG
|
|
|
|
, initialized_(true), loaded_(false)
|
|
|
|
#endif
|
|
|
|
{}
|
|
|
|
|
|
|
|
void LoadedBinary() {
|
|
|
|
#ifdef DEBUG
|
|
|
|
assert(initialized_);
|
|
|
|
assert(!loaded_);
|
|
|
|
loaded_ = true;
|
|
|
|
#endif
|
|
|
|
// Restore the size.
|
|
|
|
end_ = begin_ + *size_ptr_;
|
|
|
|
}
|
2010-09-10 04:36:07 +04:00
|
|
|
|
|
|
|
// Caller responsible for not exceeding specified size. Do not call after FinishedInserting.
|
2010-09-15 01:33:11 +04:00
|
|
|
template <class T> void Insert(const T &t) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
assert(initialized_);
|
|
|
|
assert(!loaded_);
|
|
|
|
#endif
|
|
|
|
*end_ = t;
|
2010-09-10 04:36:07 +04:00
|
|
|
++end_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FinishedInserting() {
|
2010-09-15 01:33:11 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
assert(initialized_);
|
|
|
|
assert(!loaded_);
|
|
|
|
loaded_ = true;
|
|
|
|
#endif
|
|
|
|
std::sort(begin_, end_);
|
|
|
|
*size_ptr_ = (end_ - begin_);
|
2010-09-10 04:36:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Do not call before FinishedInserting.
|
2010-09-15 01:33:11 +04:00
|
|
|
template <class Key> bool Find(const Key key, ConstIterator &out) const {
|
|
|
|
#ifdef DEBUG
|
|
|
|
assert(initialized_);
|
|
|
|
assert(loaded_);
|
|
|
|
#endif
|
|
|
|
return SortedUniformFind<ConstIterator, Key>(ConstIterator(begin_), ConstIterator(end_), key, out);
|
2010-09-10 04:36:07 +04:00
|
|
|
}
|
|
|
|
|
2010-09-15 01:33:11 +04:00
|
|
|
ConstIterator begin() const { return begin_; }
|
|
|
|
ConstIterator end() const { return end_; }
|
|
|
|
|
2010-09-10 04:36:07 +04:00
|
|
|
private:
|
2010-09-15 01:33:11 +04:00
|
|
|
typename Packing::MutableIterator begin_, end_;
|
|
|
|
uint64_t *size_ptr_;
|
|
|
|
#ifdef DEBUG
|
|
|
|
bool initialized_;
|
|
|
|
bool loaded_;
|
|
|
|
#endif
|
2010-09-10 04:36:07 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace util
|
|
|
|
|
2010-09-15 01:33:11 +04:00
|
|
|
#endif // UTIL_SORTED_UNIFORM__
|