blob: f0c7a9c6cf7c566a05d775743c6b061021da454e [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* License); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef ENCODING_PLAIN_DECODER_H
#define ENCODING_PLAIN_DECODER_H
#include <algorithm>
#include <cstdint>
#include <cstring>
#if defined(_MSC_VER)
#include <intrin.h>
#include <stdlib.h>
#endif
#include "encoding/decoder.h"
namespace storage {
FORCE_INLINE uint32_t plain_bswap32(uint32_t v) {
#if defined(__GNUC__) || defined(__clang__)
return __builtin_bswap32(v);
#elif defined(_MSC_VER)
return _byteswap_ulong(v);
#else
return ((v & 0x000000FFu) << 24) | ((v & 0x0000FF00u) << 8) |
((v & 0x00FF0000u) >> 8) | ((v & 0xFF000000u) >> 24);
#endif
}
FORCE_INLINE uint64_t plain_bswap64(uint64_t v) {
#if defined(__GNUC__) || defined(__clang__)
return __builtin_bswap64(v);
#elif defined(_MSC_VER)
return _byteswap_uint64(v);
#else
return ((v & 0x00000000000000FFull) << 56) |
((v & 0x000000000000FF00ull) << 40) |
((v & 0x0000000000FF0000ull) << 24) |
((v & 0x00000000FF000000ull) << 8) |
((v & 0x000000FF00000000ull) >> 8) |
((v & 0x0000FF0000000000ull) >> 24) |
((v & 0x00FF000000000000ull) >> 40) |
((v & 0xFF00000000000000ull) >> 56);
#endif
}
class PlainDecoder : public Decoder {
public:
~PlainDecoder() override = default;
FORCE_INLINE void reset() override { /* do nothing */
}
FORCE_INLINE bool has_remaining(const common::ByteStream& buffer) override {
return buffer.has_remaining();
}
FORCE_INLINE int read_boolean(bool& ret_bool,
common::ByteStream& in) override {
return common::SerializationUtil::read_ui8((uint8_t&)ret_bool, in);
}
FORCE_INLINE int read_int32(int32_t& ret_int32,
common::ByteStream& in) override {
return common::SerializationUtil::read_var_int(ret_int32, in);
}
FORCE_INLINE int read_int64(int64_t& ret_int64,
common::ByteStream& in) override {
return common::SerializationUtil::read_i64(ret_int64, in);
}
FORCE_INLINE int read_float(float& ret_float,
common::ByteStream& in) override {
return common::SerializationUtil::read_float(ret_float, in);
}
FORCE_INLINE int read_double(double& ret_double,
common::ByteStream& in) override {
return common::SerializationUtil::read_double(ret_double, in);
}
FORCE_INLINE int read_String(common::String& ret_String,
common::PageArena& pa,
common::ByteStream& in) override {
return common::SerializationUtil::read_mystring(ret_String, &pa, in);
}
// ── Batch overrides ──────────────────────────────────────────────────────
//
// INT32: PLAIN encoding uses varint (variable stride). Override to avoid
// virtual dispatch per element; actual decode is still per-value.
// No PLAIN_READ_BATCH_FIXED macro: varint has no fixed stride.
int read_batch_int32(int32_t* out, int capacity, int& actual,
common::ByteStream& in) override {
actual = 0;
while (actual < capacity && in.has_remaining()) {
int ret = common::SerializationUtil::read_var_int(out[actual], in);
if (ret != common::E_OK) return ret;
++actual;
}
return common::E_OK;
}
// No PLAIN_SKIP_FIXED macro: varint has no fixed stride.
int skip_int32(int count, int& skipped, common::ByteStream& in) override {
skipped = 0;
int32_t dummy;
while (skipped < count && in.has_remaining()) {
int ret = common::SerializationUtil::read_var_int(dummy, in);
if (ret != common::E_OK) {
return ret;
}
++skipped;
}
return common::E_OK;
}
// Fixed-stride INT64 / FLOAT / DOUBLE share the same shape: when the
// ByteStream is wrapped (contiguous buf), advance the read pointer in one
// step and byte-swap in place; otherwise fall back to per-value reads.
// The macros below expand into one override per type.
#define PLAIN_SKIP_FIXED(NAME, T, STRIDE, READ_ONE) \
int NAME(int count, int& skipped, common::ByteStream& in) override { \
skipped = 0; \
if (!in.is_wrapped()) { \
T dummy; \
while (skipped < count && in.has_remaining()) { \
int ret = READ_ONE(dummy, in); \
if (ret != common::E_OK) { \
return ret; \
} \
++skipped; \
} \
return common::E_OK; \
} \
skipped = static_cast<int>(std::min<uint32_t>( \
in.remaining_size() / (STRIDE), static_cast<uint32_t>(count))); \
if (skipped <= 0) { \
skipped = 0; \
return common::E_OK; \
} \
in.wrapped_buf_advance_read_pos(static_cast<uint32_t>(skipped) * \
(STRIDE)); \
return common::E_OK; \
}
#define PLAIN_READ_BATCH_FIXED(NAME, T, U, STRIDE, READ_ONE, BSWAP) \
int NAME(T* out, int capacity, int& actual, common::ByteStream& in) \
override { \
actual = 0; \
if (!in.is_wrapped()) { \
while (actual < capacity && in.has_remaining()) { \
int ret = READ_ONE(out[actual], in); \
if (ret != common::E_OK) { \
return ret; \
} \
++actual; \
} \
return common::E_OK; \
} \
int n = static_cast<int>(std::min<uint32_t>( \
in.remaining_size() / (STRIDE), static_cast<uint32_t>(capacity))); \
if (n <= 0) { \
return common::E_OK; \
} \
const uint8_t* src = \
(const uint8_t*)in.get_wrapped_buf() + in.read_pos(); \
in.wrapped_buf_advance_read_pos(static_cast<uint32_t>(n) * (STRIDE)); \
actual = n; \
for (int i = 0; i < n; ++i) { \
U v; \
memcpy(&v, src + i * (STRIDE), (STRIDE)); \
v = BSWAP(v); \
memcpy(&out[i], &v, (STRIDE)); \
} \
return common::E_OK; \
}
PLAIN_SKIP_FIXED(skip_int64, int64_t, 8,
common::SerializationUtil::read_i64)
PLAIN_SKIP_FIXED(skip_float, float, 4,
common::SerializationUtil::read_float)
PLAIN_SKIP_FIXED(skip_double, double, 8,
common::SerializationUtil::read_double)
PLAIN_READ_BATCH_FIXED(read_batch_int64, int64_t, uint64_t, 8,
common::SerializationUtil::read_i64, plain_bswap64)
PLAIN_READ_BATCH_FIXED(read_batch_float, float, uint32_t, 4,
common::SerializationUtil::read_float, plain_bswap32)
PLAIN_READ_BATCH_FIXED(read_batch_double, double, uint64_t, 8,
common::SerializationUtil::read_double,
plain_bswap64)
#undef PLAIN_SKIP_FIXED
#undef PLAIN_READ_BATCH_FIXED
};
} // end namespace storage
#endif // ENCODING_PLAIN_DECODER_H