diff --git a/deps/ox/src/ox/mc/CMakeLists.txt b/deps/ox/src/ox/mc/CMakeLists.txt index 578028a2..389fca45 100644 --- a/deps/ox/src/ox/mc/CMakeLists.txt +++ b/deps/ox/src/ox/mc/CMakeLists.txt @@ -1,6 +1,5 @@ add_library( OxMetalClaw - presenceindicator.cpp read.cpp write.cpp ) diff --git a/deps/ox/src/ox/mc/presenceindicator.cpp b/deps/ox/src/ox/mc/presenceindicator.cpp deleted file mode 100644 index 98877aae..00000000 --- a/deps/ox/src/ox/mc/presenceindicator.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2015 - 2025 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/. - */ - -#include "err.hpp" -#include "presenceindicator.hpp" - -namespace ox { - -template class FieldBitmapWriterBase; -template class FieldBitmapWriterBase; - -} diff --git a/deps/ox/src/ox/mc/presenceindicator.hpp b/deps/ox/src/ox/mc/presenceindicator.hpp index 1288ce8c..7d5e8d57 100644 --- a/deps/ox/src/ox/mc/presenceindicator.hpp +++ b/deps/ox/src/ox/mc/presenceindicator.hpp @@ -22,145 +22,101 @@ namespace ox { template class FieldBitmapReader { protected: - mutable size_t m_mapBlockIdx = ~size_t{0}; - mutable uint64_t m_mapBlock = 0; - size_t m_mapStart = 0; + mutable size_t m_mapBlockIdx = ~size_t{}; + mutable uint64_t m_mapBlock{}; + size_t m_mapStart{}; Reader &m_reader; public: - explicit constexpr FieldBitmapReader(Reader &reader) noexcept; + explicit constexpr FieldBitmapReader(Reader &reader) noexcept: + m_mapStart(reader.tellg()), + m_reader(reader) { + } - constexpr Result get(size_t idx) const noexcept; + constexpr Result get(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; + } private: - constexpr Error loadMapBlock(size_t idx) const noexcept; - -}; - -template -constexpr FieldBitmapReader::FieldBitmapReader(Reader &reader) noexcept: - m_mapStart(reader.tellg()), - m_reader(reader) { -} - -template -constexpr Result FieldBitmapReader::get(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 Error FieldBitmapReader::loadMapBlock(size_t const idx) const noexcept { - OX_REQUIRE(g, m_reader.tellg()); - OX_RETURN_ERROR(m_reader.seekg(static_cast(m_mapStart + idx), ox::ios_base::beg)); - 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 (uint64_t i{}; auto b : mapBlock) { - m_mapBlock |= static_cast(std::bit_cast(b)) << i; - i += 8; - } - m_mapBlockIdx = idx; - return {}; -} - - -template -class FieldBitmapWriterBase { - protected: - Span m_map; - size_t m_mapLen = 0; - - public: - explicit constexpr FieldBitmapWriterBase(Span map) noexcept; - - constexpr auto setBuffer(Span map) noexcept; - - constexpr Result get(size_t i) const noexcept; - - constexpr Error setFields(int) noexcept; - - constexpr void setMaxLen(int) noexcept; - - [[nodiscard]] - constexpr int64_t getMaxLen() const noexcept; - -}; - -template -constexpr FieldBitmapWriterBase::FieldBitmapWriterBase(Span map) noexcept: - m_map(map), - m_mapLen(m_map.size()) { -} - -template -constexpr auto FieldBitmapWriterBase::setBuffer(Span map) noexcept { - m_map = map; - m_mapLen = map.size(); -} - -template -constexpr Result FieldBitmapWriterBase::get(size_t const i) const noexcept { - if (i / 8 < m_mapLen) { - return (m_map[i / 8] >> (i % 8)) & 1; - } else { - return Error{McPresenceMapOverflow}; - } -} - -template -constexpr Error FieldBitmapWriterBase::setFields(int const fields) noexcept { - m_mapLen = static_cast((fields / 8 + 1) - (fields % 8 == 0)); - if (m_mapLen > m_map.size()) [[unlikely]] { - return Error{McPresenceMapOverflow}; - } - return {}; -} - -template -constexpr void FieldBitmapWriterBase::setMaxLen(int const 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: - explicit constexpr FieldBitmap(Span map) noexcept; - - constexpr Error set(size_t i, bool on) noexcept; - -}; - -constexpr FieldBitmap::FieldBitmap(Span map) noexcept: - FieldBitmapWriterBase(map) { -} - -constexpr Error FieldBitmap::set(size_t const i, bool const on) noexcept { - if (i / 8 < m_mapLen) { - if (on) { - m_map[i / 8] |= 1 << (i % 8); - } else { - m_map[i / 8] &= ~static_cast(1 << (i % 8)); + constexpr Error loadMapBlock(size_t const idx) const noexcept { + OX_REQUIRE(g, m_reader.tellg()); + OX_RETURN_ERROR(m_reader.seekg(static_cast(m_mapStart + idx), ox::ios_base::beg)); + 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 (uint64_t i{}; auto b : mapBlock) { + m_mapBlock |= static_cast(std::bit_cast(b)) << i; + i += 8; + } + m_mapBlockIdx = idx; + return {}; } - return {}; - } else { - return Error(McPresenceMapOverflow); - } -} + +}; + + +class FieldBitmapWriter { + protected: + Span m_map; + size_t m_mapLen{}; + + public: + explicit constexpr FieldBitmapWriter(Span const &map) noexcept: + m_map(map), + m_mapLen(m_map.size()) { + } + + constexpr auto setBuffer(Span const &map) noexcept { + m_map = map; + m_mapLen = map.size(); + } + + constexpr Result get(size_t const i) const noexcept { + if (i / 8 < m_mapLen) { + return (std::bit_cast(m_map[i / 8]) >> (i % 8)) & 1; + } + return Error{McPresenceMapOverflow}; + } + + constexpr Error setFields(int const fields) noexcept { + m_mapLen = static_cast((fields / 8 + 1) - (fields % 8 == 0)); + if (m_mapLen > m_map.size()) [[unlikely]] { + return Error{McPresenceMapOverflow}; + } + return {}; + } + + constexpr void setMaxLen(int const maxLen) noexcept { + m_mapLen = static_cast(maxLen); + } + + constexpr int64_t getMaxLen() const noexcept { + return static_cast(m_mapLen); + } + + constexpr Error set(size_t const i, bool const on) noexcept { + if (i / 8 < m_mapLen) { + char &actual = m_map[i / 8]; + uint8_t v = std::bit_cast(actual); + if (on) { + v |= 1 << (i % 8); + } else { + v &= ~static_cast(1 << (i % 8)); + } + actual = std::bit_cast(v); + return {}; + } + return Error{McPresenceMapOverflow}; + } + +}; } diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index 4adbc16c..5e2f4d26 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -29,12 +29,12 @@ namespace ox { template -class MetalClawWriter { +class MetalClawWriter: public ModelHandlerBase, OpType::Write> { private: - Vector m_presenceMapBuff{}; - FieldBitmap m_fieldPresence; - int m_field = 0; + Vector m_presenceMapBuff{}; + FieldBitmapWriter m_fieldPresence{m_presenceMapBuff}; + int m_field{}; Optional m_unionIdx; size_t m_writerBeginP{}; Writer &m_writer; @@ -105,12 +105,7 @@ class MetalClawWriter { return 0; } - [[nodiscard]] - static constexpr auto opType() noexcept { - return OpType::Write; - } - - Error finalize() noexcept; + constexpr Error finalize() noexcept; private: constexpr Error appendInteger(Integer_c auto val) noexcept { @@ -132,7 +127,6 @@ extern template class ModelHandlerInterface>; template constexpr MetalClawWriter::MetalClawWriter(Writer &writer, Optional const &unionIdx) noexcept: - m_fieldPresence(m_presenceMapBuff), m_unionIdx(unionIdx), m_writerBeginP(writer.tellp()), m_writer(writer) { @@ -267,9 +261,8 @@ constexpr Error MetalClawWriter::field(CString, T const *val) noexcept { bool fieldSet = false; if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) { auto const writeIdx = m_writer.tellp(); - MetalClawWriter writer(m_writer); - ModelHandlerInterface> handler{writer}; - OX_RETURN_ERROR(model(&handler, val)); + MetalClawWriter writer(m_writer); + OX_RETURN_ERROR(model(writer.interface(), val)); OX_RETURN_ERROR(writer.finalize()); fieldSet = writeIdx != m_writer.tellp(); } @@ -285,9 +278,8 @@ constexpr Error MetalClawWriter::field(CString, UnionView val) bool fieldSet = false; if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) { auto const writeIdx = m_writer.tellp(); - MetalClawWriter writer(m_writer, Optional(in_place, val.idx())); - ModelHandlerInterface handler{writer}; - OX_RETURN_ERROR(model(&handler, val.get())); + MetalClawWriter writer(m_writer, Optional(in_place, val.idx())); + OX_RETURN_ERROR(model(writer.interface(), val.get())); OX_RETURN_ERROR(writer.finalize()); fieldSet = writeIdx != m_writer.tellp(); } @@ -305,13 +297,12 @@ constexpr Error MetalClawWriter::field(CString, T const *val, size_t con auto const arrLen = mc::encodeInteger(len); OX_RETURN_ERROR(m_writer.write(reinterpret_cast(arrLen.data.data()), arrLen.length)); auto const writeIdx = m_writer.tellp(); - MetalClawWriter writer(m_writer); - ModelHandlerInterface handler{writer}; - OX_RETURN_ERROR(handler.template setTypeInfo("List", 0, {}, static_cast(len))); + MetalClawWriter writer(m_writer); + OX_RETURN_ERROR(writer.interface()->template setTypeInfo("List", 0, {}, static_cast(len))); // write the array for (size_t i{}; i < len; ++i) { OX_ALLOW_UNSAFE_BUFFERS_BEGIN - OX_RETURN_ERROR(handler.field("", &val[i])); + OX_RETURN_ERROR(writer.interface()->field("", &val[i])); OX_ALLOW_UNSAFE_BUFFERS_END } OX_RETURN_ERROR(writer.finalize()); @@ -333,10 +324,9 @@ constexpr Error MetalClawWriter::field(CString, HashMap const auto const arrLen = mc::encodeInteger(len); OX_RETURN_ERROR(m_writer.write(reinterpret_cast(arrLen.data.data()), arrLen.length)); // write map - MetalClawWriter writer(m_writer); - ModelHandlerInterface handler{writer}; + MetalClawWriter writer(m_writer); // double len for both key and value - OX_RETURN_ERROR(handler.setTypeInfo("Map", 0, {}, len * 2)); + OX_RETURN_ERROR(writer.interface()->setTypeInfo("Map", 0, {}, len * 2)); // this loop body needs to be in a lambda because of the potential alloca call constexpr auto loopBody = [](auto &handler, auto const &key, auto const &val) -> Error { auto const keyLen = key.size(); @@ -349,7 +339,7 @@ constexpr Error MetalClawWriter::field(CString, HashMap const // write the array for (size_t i{}; i < len; ++i) { auto const &key = keys[i]; - OX_RETURN_ERROR(loopBody(handler, key, *val)); + OX_RETURN_ERROR(loopBody(*writer.interface(), key, *val)); } OX_RETURN_ERROR(writer.finalize()); fieldSet = true; @@ -374,20 +364,19 @@ constexpr Error MetalClawWriter::setTypeInfo( } template -Error MetalClawWriter::finalize() noexcept { +constexpr Error MetalClawWriter::finalize() noexcept { auto const end = m_writer.tellp(); OX_RETURN_ERROR(m_writer.seekp(m_writerBeginP)); OX_RETURN_ERROR(m_writer.write( - reinterpret_cast(m_presenceMapBuff.data()), - m_presenceMapBuff.size())); + m_presenceMapBuff.data(), + m_presenceMapBuff.size())); OX_RETURN_ERROR(m_writer.seekp(end)); return {}; } Result writeMC(Writer_c auto &writer, auto const &val) noexcept { MetalClawWriter mcWriter(writer); - ModelHandlerInterface handler{mcWriter}; - OX_RETURN_ERROR(model(&handler, &val)); + OX_RETURN_ERROR(model(mcWriter.interface(), &val)); OX_RETURN_ERROR(mcWriter.finalize()); return {}; } diff --git a/deps/ox/src/ox/model/modelhandleradaptor.hpp b/deps/ox/src/ox/model/modelhandleradaptor.hpp index 4589f5b6..89f3fdf0 100644 --- a/deps/ox/src/ox/model/modelhandleradaptor.hpp +++ b/deps/ox/src/ox/model/modelhandleradaptor.hpp @@ -123,7 +123,7 @@ class ModelHandlerInterface { { auto &u = v->template get(); if constexpr(opType_v == OpType::Read) { - u.setActiveField(m_handler.whichFieldPresent(name, u)); + u.setActiveField(whichFieldPresent(m_handler, name, u)); return m_handler.field(name, UnionView(&u, u.unionIdx())); } else { return m_handler.field(name, UnionView(&u, u.unionIdx())); @@ -199,6 +199,20 @@ class ModelHandlerInterface { constexpr auto handler() noexcept { return m_handler; } + + private: + template + static constexpr int whichFieldPresent(H &h, const char *name, ModelUnion const &u) noexcept + requires(H::opType() == OpType::Read) { + return h.whichFieldPresent(name, u); + } + + template + static constexpr int whichFieldPresent(H&, const char*, ModelUnion const&) noexcept + requires(H::opType() != OpType::Read) { + return 0; + } + }; template diff --git a/deps/ox/src/ox/model/modelvalue.hpp b/deps/ox/src/ox/model/modelvalue.hpp index 251ac40c..ac09ec53 100644 --- a/deps/ox/src/ox/model/modelvalue.hpp +++ b/deps/ox/src/ox/model/modelvalue.hpp @@ -200,8 +200,6 @@ class ModelValue { template constexpr Error set(T &&v) noexcept; - constexpr ModelValue &operator=(ModelValue &val) noexcept; - constexpr ModelValue &operator=(const ModelValue &val) noexcept; constexpr ModelValue &operator=(ModelValue &&val) noexcept; @@ -1202,10 +1200,6 @@ constexpr Error ModelValue::set(T &&v) noexcept { return {}; } -constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept { - return this->operator=(const_cast(other)); -} - constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept { if (this == &other) [[unlikely]] { return *this;