diff --git a/src/libime/core/datrie.cpp b/src/libime/core/datrie.cpp index ca39660..388f8f5 100644 --- a/src/libime/core/datrie.cpp +++ b/src/libime/core/datrie.cpp @@ -14,8 +14,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -32,6 +34,7 @@ #include #include #include +#include "endian_p.h" #include "naivevector.h" #include "utils_p.h" @@ -85,6 +88,24 @@ constexpr T decodeImpl(int32_t raw) { return d.result_value; } +template +void decodeBigEndian(T &data) + requires(sizeof(T) == sizeof(uint32_t)) +{ + auto raw = std::bit_cast(data); + raw = be32toh(raw); + data = std::bit_cast(raw); +} + +template +void decodeBigEndian(T &data) + requires(sizeof(T) == sizeof(uint16_t)) +{ + auto raw = std::bit_cast(data); + raw = be16toh(raw); + data = std::bit_cast(raw); +} + } // namespace // template @@ -128,6 +149,11 @@ class DATriePrivate { FCITX_INLINE_DEFINE_DEFAULT_DTOR_AND_COPY(node); + void decode() { + decodeBigEndian(base); + decodeBigEndian(check); + } + friend std::ostream &operator<<(std::ostream &out, const node &n) { marshall(out, n.base) && marshall(out, n.check); return out; @@ -177,6 +203,15 @@ class DATriePrivate { throw_if_io_fail(unmarshall(in, ehead)); } + void decode() { + decodeBigEndian(prev); + decodeBigEndian(next); + decodeBigEndian(num); + decodeBigEndian(reject); + decodeBigEndian(trial); + decodeBigEndian(ehead); + } + friend std::ostream &operator<<(std::ostream &out, const block &b) { marshall(out, b.prev) && marshall(out, b.next) && marshall(out, b.num) && marshall(out, b.reject) && @@ -211,6 +246,16 @@ class DATriePrivate { int32_t m_bheadO; // first block of Open; 0 if no Open std::array m_reject; + static_assert(sizeof(node) == 8); + static_assert(offsetof(block, prev) == 0); + static_assert(offsetof(block, next) == 4); + static_assert(offsetof(block, num) == 8); + static_assert(offsetof(block, reject) == 10); + static_assert(offsetof(block, trial) == 12); + static_assert(offsetof(block, ehead) == 16); + static_assert(sizeof(block) == 20); + static_assert(sizeof(ninfo) == 2); + DATriePrivate() { init(); } FCITX_INLINE_DEFINE_DEFAULT_DTOR_AND_COPY(DATriePrivate) @@ -248,31 +293,32 @@ class DATriePrivate { m_tail.resize(length_); m_tail0.resize(0); - m_array.reserve(size_); - m_array.resize(0); - m_ninfo.reserve(size_); - m_ninfo.resize(0); - m_block.reserve(size_ >> 8); - m_block.resize(0); + m_array.resize(size_); + m_ninfo.resize(size_); + const auto blockSize = size_ >> 8; + m_block.resize(blockSize); throw_if_io_fail(fin.read(reinterpret_cast(m_tail.data()), sizeof(char) * length_)); - for (auto i = 0U; i < size_; i++) { - m_array.emplace_back(fin); + throw_if_io_fail(fin.read(reinterpret_cast(m_array.data()), + sizeof(node) * size_)); + for (auto &node : m_array) { + node.decode(); } - m_array.resize(size_); throw_if_io_fail(unmarshall(fin, m_bheadF)); throw_if_io_fail(unmarshall(fin, m_bheadC)); throw_if_io_fail(unmarshall(fin, m_bheadO)); - for (auto i = 0U; i < size_; i++) { - m_ninfo.emplace_back(fin); - } + throw_if_io_fail(fin.read(reinterpret_cast(m_ninfo.data()), + sizeof(ninfo) * size_)); + // ninfo is not endian issue. - for (auto i = 0U, end = size_ >> 8; i < end; i++) { - m_block.emplace_back(fin); + throw_if_io_fail(fin.read(reinterpret_cast(m_block.data()), + sizeof(block) * blockSize)); + for (auto &block : m_block) { + block.decode(); } } diff --git a/src/libime/core/utils_p.h b/src/libime/core/utils_p.h index 15d7ca0..64bfad7 100644 --- a/src/libime/core/utils_p.h +++ b/src/libime/core/utils_p.h @@ -7,6 +7,7 @@ #ifndef _LIBIME_LIBIME_CORE_UTILS_P_H_ #define _LIBIME_LIBIME_CORE_UTILS_P_H_ +#include #include #include #include @@ -71,15 +72,10 @@ template std::ostream &marshall(std::ostream &out, T data) requires(sizeof(T) == sizeof(uint32_t)) { - union { - uint32_t i; - T v; - } c; static_assert(sizeof(T) == sizeof(uint32_t), "this function is only for 4 byte data"); - c.v = data; - c.i = htobe32(c.i); - return out.write(reinterpret_cast(&c.i), sizeof(c.i)); + auto i = htobe32(std::bit_cast(data)); + return out.write(reinterpret_cast(&i), sizeof(i)); } template @@ -93,30 +89,22 @@ template std::ostream &marshall(std::ostream &out, T data) requires(sizeof(T) == sizeof(uint16_t)) { - union { - uint16_t i; - T v; - } c; static_assert(sizeof(T) == sizeof(uint16_t), "this function is only for 2 byte data"); - c.v = data; - c.i = htobe16(c.i); - return out.write(reinterpret_cast(&c.i), sizeof(c.i)); + auto i = htobe16(std::bit_cast(data)); + return out.write(reinterpret_cast(&i), sizeof(i)); } template std::istream &unmarshall(std::istream &in, T &data) requires(sizeof(T) == sizeof(uint32_t)) { - union { - uint32_t i; - T v; - } c; static_assert(sizeof(T) == sizeof(uint32_t), "this function is only for 4 byte data"); - if (in.read(reinterpret_cast(&c.i), sizeof(c.i))) { - c.i = be32toh(c.i); - data = c.v; + uint32_t i; + if (in.read(reinterpret_cast(&i), sizeof(i))) { + i = be32toh(i); + data = std::bit_cast(i); } return in; } @@ -132,15 +120,12 @@ template std::istream &unmarshall(std::istream &in, T &data) requires(sizeof(T) == sizeof(uint16_t)) { - union { - uint16_t i; - T v; - } c; static_assert(sizeof(T) == sizeof(uint16_t), "this function is only for 2 byte data"); - if (in.read(reinterpret_cast(&c.i), sizeof(c.i))) { - c.i = be16toh(c.i); - data = c.v; + uint16_t i; + if (in.read(reinterpret_cast(&i), sizeof(i))) { + i = be16toh(i); + data = std::bit_cast(i); } return in; }