Commit 1f5581d8 authored by Yi Cheng's avatar Yi Cheng Committed by Facebook Github Bot

Add previous for EliasFano

Summary: Add previous for EliasFano reader. Here the equation is: reader == reader.next().previous();

Reviewed By: ot

Differential Revision: D7497171

fbshipit-source-id: 33dc3316036b94a5da278c328322ea4c3322588e
parent 57e4ac80
...@@ -364,6 +364,16 @@ class UpperBitsReader : ForwardPointers<Encoder::forwardQuantum>, ...@@ -364,6 +364,16 @@ class UpperBitsReader : ForwardPointers<Encoder::forwardQuantum>,
return value_; return value_;
} }
ValueType previous() {
size_t inner;
block_t block;
getPreviousInfo(block, inner, outer_);
block_ = folly::loadUnaligned<block_t>(start_ + outer_);
block_ ^= block;
--position_;
return setValue(inner);
}
ValueType next() { ValueType next() {
// Skip to the first non-zero block. // Skip to the first non-zero block.
while (block_ == 0) { while (block_ == 0) {
...@@ -504,21 +514,10 @@ class UpperBitsReader : ForwardPointers<Encoder::forwardQuantum>, ...@@ -504,21 +514,10 @@ class UpperBitsReader : ForwardPointers<Encoder::forwardQuantum>,
} }
ValueType previousValue() const { ValueType previousValue() const {
DCHECK_NE(position(), std::numeric_limits<SizeType>::max()); block_t block;
DCHECK_GT(position(), 0); size_t inner;
OuterType outer;
auto outer = outer_; getPreviousInfo(block, inner, outer);
auto inner = size_t(value_) - 8 * outer_ + position_;
block_t block = folly::loadUnaligned<block_t>(start_ + outer);
block &= (block_t(1) << inner) - 1;
while (UNLIKELY(block == 0)) {
DCHECK_GT(outer, 0);
outer -= std::min<OuterType>(sizeof(block_t), outer);
block = folly::loadUnaligned<block_t>(start_ + outer);
}
inner = 8 * sizeof(block_t) - 1 - Instructions::clz(block);
return static_cast<ValueType>(8 * outer + inner - (position_ - 1)); return static_cast<ValueType>(8 * outer + inner - (position_ - 1));
} }
...@@ -543,6 +542,22 @@ class UpperBitsReader : ForwardPointers<Encoder::forwardQuantum>, ...@@ -543,6 +542,22 @@ class UpperBitsReader : ForwardPointers<Encoder::forwardQuantum>,
// so a type that can hold either sizes or values is sufficient. // so a type that can hold either sizes or values is sufficient.
using OuterType = typename std::common_type<ValueType, SizeType>::type; using OuterType = typename std::common_type<ValueType, SizeType>::type;
void getPreviousInfo(block_t& block, size_t& inner, OuterType& outer) const {
DCHECK_NE(position(), std::numeric_limits<SizeType>::max());
DCHECK_GT(position(), 0);
outer = outer_;
block = folly::loadUnaligned<block_t>(start_ + outer);
inner = size_t(value_) - 8 * outer_ + position_;
block &= (block_t(1) << inner) - 1;
while (UNLIKELY(block == 0)) {
DCHECK_GT(outer, 0);
outer -= std::min<OuterType>(sizeof(block_t), outer);
block = folly::loadUnaligned<block_t>(start_ + outer);
}
inner = 8 * sizeof(block_t) - 1 - Instructions::clz(block);
}
const unsigned char* const start_; const unsigned char* const start_;
block_t block_; block_t block_;
SizeType position_; // Index of current value (= #reads - 1). SizeType position_; // Index of current value (= #reads - 1).
...@@ -591,6 +606,17 @@ class EliasFanoReader { ...@@ -591,6 +606,17 @@ class EliasFanoReader {
value_ = kInvalidValue; value_ = kInvalidValue;
} }
bool previous() {
if (!kUnchecked && UNLIKELY(position() == 0)) {
reset();
return false;
}
upper_.previous();
value_ =
readLowerPart(upper_.position()) | (upper_.value() << numLowerBits_);
return true;
}
bool next() { bool next() {
if (!kUnchecked && UNLIKELY(position() + 1 >= size_)) { if (!kUnchecked && UNLIKELY(position() + 1 >= size_)) {
return setDone(); return setDone();
...@@ -687,6 +713,11 @@ class EliasFanoReader { ...@@ -687,6 +713,11 @@ class EliasFanoReader {
return true; return true;
} }
ValueType lastValue() const {
CHECK(!kUnchecked);
return lastValue_;
}
ValueType previousValue() const { ValueType previousValue() const {
DCHECK_GT(position(), 0); DCHECK_GT(position(), 0);
DCHECK_LT(position(), size()); DCHECK_LT(position(), size());
......
...@@ -89,6 +89,27 @@ auto maybeTestPreviousValue(const Vector& data, Reader& reader, Index i) ...@@ -89,6 +89,27 @@ auto maybeTestPreviousValue(const Vector& data, Reader& reader, Index i)
} }
} }
// Test previous only if Reader has it.
template <class... Args>
void maybeTestPrevious(Args&&...) {}
// Make all the arguments template because if the types are not exact,
// the above overload will be picked (for example i could be size_t or
// ssize_t).
template <class Vector, class Reader, class Index>
auto maybeTestPrevious(const Vector& data, Reader& reader, Index i)
-> decltype(reader.previous(), void()) {
auto r = reader.previous();
if (i != 0) {
EXPECT_TRUE(r);
EXPECT_EQ(reader.value(), data[i - 1]);
} else {
EXPECT_FALSE(r);
}
reader.next();
EXPECT_EQ(reader.value(), data[i]);
}
template <class Reader, class List> template <class Reader, class List>
void testNext(const std::vector<uint32_t>& data, const List& list) { void testNext(const std::vector<uint32_t>& data, const List& list) {
Reader reader(list); Reader reader(list);
...@@ -100,6 +121,7 @@ void testNext(const std::vector<uint32_t>& data, const List& list) { ...@@ -100,6 +121,7 @@ void testNext(const std::vector<uint32_t>& data, const List& list) {
EXPECT_EQ(reader.value(), data[i]); EXPECT_EQ(reader.value(), data[i]);
EXPECT_EQ(reader.position(), i); EXPECT_EQ(reader.position(), i);
maybeTestPreviousValue(data, reader, i); maybeTestPreviousValue(data, reader, i);
maybeTestPrevious(data, reader, i);
} }
EXPECT_FALSE(reader.next()); EXPECT_FALSE(reader.next());
EXPECT_FALSE(reader.valid()); EXPECT_FALSE(reader.valid());
...@@ -118,6 +140,7 @@ void testSkip(const std::vector<uint32_t>& data, const List& list, ...@@ -118,6 +140,7 @@ void testSkip(const std::vector<uint32_t>& data, const List& list,
EXPECT_EQ(reader.value(), data[i]); EXPECT_EQ(reader.value(), data[i]);
EXPECT_EQ(reader.position(), i); EXPECT_EQ(reader.position(), i);
maybeTestPreviousValue(data, reader, i); maybeTestPreviousValue(data, reader, i);
maybeTestPrevious(data, reader, i);
} }
EXPECT_FALSE(reader.skip(skipStep)); EXPECT_FALSE(reader.skip(skipStep));
EXPECT_FALSE(reader.valid()); EXPECT_FALSE(reader.valid());
...@@ -156,6 +179,7 @@ void testSkipTo(const std::vector<uint32_t>& data, const List& list, ...@@ -156,6 +179,7 @@ void testSkipTo(const std::vector<uint32_t>& data, const List& list,
EXPECT_EQ(reader.position(), std::distance(data.begin(), it)); EXPECT_EQ(reader.position(), std::distance(data.begin(), it));
value = reader.value() + delta; value = reader.value() + delta;
maybeTestPreviousValue(data, reader, std::distance(data.begin(), it)); maybeTestPreviousValue(data, reader, std::distance(data.begin(), it));
maybeTestPrevious(data, reader, std::distance(data.begin(), it));
} }
EXPECT_FALSE(reader.valid()); EXPECT_FALSE(reader.valid());
EXPECT_EQ(reader.position(), reader.size()); EXPECT_EQ(reader.position(), reader.size());
...@@ -215,6 +239,7 @@ void testJump(const std::vector<uint32_t>& data, const List& list) { ...@@ -215,6 +239,7 @@ void testJump(const std::vector<uint32_t>& data, const List& list) {
EXPECT_EQ(reader.value(), data[i]); EXPECT_EQ(reader.value(), data[i]);
EXPECT_EQ(reader.position(), i); EXPECT_EQ(reader.position(), i);
maybeTestPreviousValue(data, reader, i); maybeTestPreviousValue(data, reader, i);
maybeTestPrevious(data, reader, i);
} }
EXPECT_FALSE(reader.jump(data.size())); EXPECT_FALSE(reader.jump(data.size()));
EXPECT_FALSE(reader.valid()); EXPECT_FALSE(reader.valid());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment