Verified Commit 148a72e9 authored by nagayama15's avatar nagayama15

feat: implement chunk reordering

parent dfdcaaa2
......@@ -12,11 +12,13 @@ namespace kyut {
explicit CircularBitStreamReader(std::vector<std::uint8_t>&& data)
: data_(std::move(data))
, pos_bits_(0) {
assert(data_.size() > 0);
}
explicit CircularBitStreamReader(std::string_view data)
: data_(reinterpret_cast<const std::uint8_t*>(data.data()), reinterpret_cast<const std::uint8_t*>(data.data() + data.size()))
, pos_bits_(0) {
assert(data_.size() > 0);
}
// Uncopyable and unmovable
......
#ifndef INCLUDE_kyut_Ordering_inl_hpp
#define INCLUDE_kyut_Ordering_inl_hpp
#include "Ordering.hpp"
#include <algorithm>
#include "CircularBitStreamReader.hpp"
namespace kyut {
namespace detail {
// {log2(n!) | x in [2, 20]}
constexpr std::size_t factorial_bit_width_table[max_chunk_size + 1] = {
0, 0, 1, 2, 4, 6, 9, 12, 15, 18, 21, 25, 28, 32, 36, 40, 44, 48, 52, 56, 61};
template <typename RandomAccessIterator, typename Less>
inline void embed_in_chunk(
std::uint64_t watermark,
RandomAccessIterator begin,
RandomAccessIterator end,
Less less) {
assert(std::distance(begin, end) >= 0);
std::sort(begin, end, less);
for (auto it = begin; it != end; ++it) {
const std::size_t count = std::distance(it, end);
const std::uint64_t w = watermark % count;
watermark /= count;
std::iter_swap(it, it + w);
}
}
template <typename RandomAccessIterator, typename Less>
inline std::size_t embed_by_ordering(
CircularBitStreamReader& r,
std::size_t chunk_size,
RandomAccessIterator begin,
RandomAccessIterator end,
Less less) {
assert(2 <= chunk_size && chunk_size <= max_chunk_size);
assert(std::distance(begin, end) >= 0);
const std::size_t count = std::distance(begin, end);
std::size_t size_bits = 0;
for (std::size_t i = 0; i < count; i += chunk_size) {
const std::size_t chunk_size = (std::min)(chunk_size, count - i);
const auto chunk_begin = begin + i;
const auto chunk_end = chunk_begin + chunk_size;
const auto bit_width = factorial_bit_width_table[chunk_size];
const auto watermark = r.read(bit_width);
embed_in_chunk(watermark, chunk_begin, chunk_end, less);
size_bits += bit_width;
}
return size_bits;
}
} // namespace detail
template <typename RandomAccessIterator, typename Less>
inline std::size_t embed_by_ordering(
CircularBitStreamReader& r,
std::size_t chunk_size,
RandomAccessIterator begin,
RandomAccessIterator end,
Less less) {
return detail::embed_by_ordering(r, chunk_size, begin, end, less);
}
} // namespace kyut
#endif // INCLUDE_kyut_Ordering_inl_hpp
#ifndef INCLUDE_kyut_Ordering_hpp
#define INCLUDE_kyut_Ordering_hpp
#include <cstddef>
namespace kyut {
class CircularBitStreamReader;
constexpr std::size_t max_chunk_size = 20;
template <typename RandomAccessIterator, typename Less>
std::size_t embed_by_ordering(
CircularBitStreamReader& r,
std::size_t chunk_size,
RandomAccessIterator begin,
RandomAccessIterator end,
Less less);
} // namespace kyut
#include "Ordering-inl.hpp"
#endif // INCLUDE_kyut_Ordering_hpp
......@@ -3,6 +3,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
add_executable(test_kyut
test_BitStreamWriter.cpp
test_CircularBitStreamReader.cpp
test_Ordering.cpp
)
target_link_libraries(test_kyut
......
#include "kyut/Ordering.hpp"
#include <gtest/gtest.h>
namespace {
void check_embed(
std::string data,
std::string_view watermark,
std::size_t chunk_size,
std::size_t expected_size_bits_embedded,
std::string_view expected_reordered_data) {
kyut::CircularBitStreamReader r{watermark};
const auto size_bits = kyut::embed_by_ordering(
r,
chunk_size,
std::begin(data),
std::end(data),
std::less<>{});
EXPECT_EQ(size_bits, expected_size_bits_embedded);
EXPECT_EQ(data, expected_reordered_data);
}
} // namespace
TEST(kyut_Ordering, embed_by_ordering) {
using namespace std::string_view_literals;
check_embed("1234", "\x00"sv, 20, 4, "1234");
check_embed("4321", "\x00"sv, 20, 4, "1234");
check_embed("1234", "\x10"sv, 20, 4, "2134");
check_embed("1234", "\x20"sv, 20, 4, "3214");
check_embed("1234", "\x30"sv, 20, 4, "4231");
check_embed("1234", "\x40"sv, 20, 4, "1324");
check_embed("1234", "\x50"sv, 20, 4, "2314");
check_embed("2314", "\x50"sv, 20, 4, "2314");
check_embed("2314", "\x00"sv, 20, 4, "1234");
}
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