/* * Copyright 2015 - 2024 gary@drinkingtea.net * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include #include #include #include #include #include "err.hpp" namespace ox { template class FieldBitmapReader { protected: mutable std::size_t m_mapBlockIdx = ~std::size_t{0}; mutable uint64_t m_mapBlock = 0; std::size_t m_mapStart = 0; Reader &m_reader; public: explicit constexpr FieldBitmapReader(Reader &reader) noexcept; constexpr Result get(std::size_t i) const noexcept; private: constexpr ox::Error loadMapBlock(std::size_t id) const noexcept; }; template constexpr FieldBitmapReader::FieldBitmapReader(Reader &reader) noexcept: m_mapStart(reader.tellg()), m_reader(reader) { } template constexpr Result FieldBitmapReader::get(std::size_t idx) const noexcept { constexpr auto blockBits = sizeof(m_mapBlock); auto const blockIdx = idx / blockBits; if (m_mapBlockIdx != blockIdx) [[unlikely]] { OX_RETURN_ERROR(loadMapBlock(blockIdx)); } idx %= blockBits; return (m_mapBlock >> idx) & 1; } template constexpr ox::Error FieldBitmapReader::loadMapBlock(std::size_t idx) const noexcept { OX_REQUIRE(g, m_reader.tellg()); OX_RETURN_ERROR(m_reader.seekg(static_cast(m_mapStart + idx), ox::ios_base::beg)); ox::Array mapBlock{}; OX_RETURN_ERROR(m_reader.read(mapBlock.data(), sizeof(m_mapBlock))); // Warning: narrow-conv OX_RETURN_ERROR(m_reader.seekg(static_cast(g), ox::ios_base::beg)); m_mapBlock = 0; for (auto i = 0ull; auto b : mapBlock) { m_mapBlock |= static_cast(std::bit_cast(b)) << i; i += 8; } m_mapBlockIdx = idx; return {}; } template class FieldBitmapWriterBase { protected: T m_map = nullptr; std::size_t m_mapLen = 0; public: constexpr FieldBitmapWriterBase(T map, std::size_t maxLen) noexcept; constexpr auto setBuffer(T map, std::size_t maxLen) noexcept; constexpr Result get(std::size_t i) const noexcept; constexpr void setFields(int) noexcept; constexpr void setMaxLen(int) noexcept; [[nodiscard]] constexpr int64_t getMaxLen() const noexcept; }; template constexpr FieldBitmapWriterBase::FieldBitmapWriterBase(T map, std::size_t maxLen) noexcept { m_map = map; m_mapLen = maxLen; } template constexpr auto FieldBitmapWriterBase::setBuffer(T map, std::size_t maxLen) noexcept { m_map = map; m_mapLen = maxLen; } template constexpr Result FieldBitmapWriterBase::get(std::size_t i) const noexcept { if (i / 8 < m_mapLen) { return (m_map[i / 8] >> (i % 8)) & 1; } else { return ox::Error(McPresenceMapOverflow); } } template constexpr void FieldBitmapWriterBase::setFields(int fields) noexcept { m_mapLen = static_cast((fields / 8 + 1) - (fields % 8 == 0)); } template constexpr void FieldBitmapWriterBase::setMaxLen(int maxLen) noexcept { m_mapLen = static_cast(maxLen); } template constexpr int64_t FieldBitmapWriterBase::getMaxLen() const noexcept { return static_cast(m_mapLen); } extern template class FieldBitmapWriterBase; extern template class FieldBitmapWriterBase; class FieldBitmap: public FieldBitmapWriterBase { public: constexpr FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept; constexpr Error set(std::size_t i, bool on) noexcept; }; constexpr FieldBitmap::FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept: FieldBitmapWriterBase(map, maxLen) { } constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept { if (i / 8 < m_mapLen) { OX_ALLOW_UNSAFE_BUFFERS_BEGIN if (on) { m_map[i / 8] |= 1 << (i % 8); } else { m_map[i / 8] &= ~static_cast(1 << (i % 8)); } OX_ALLOW_UNSAFE_BUFFERS_END return {}; } else { return ox::Error(McPresenceMapOverflow); } } }