include/native/dxapi/data_writer.h (401 lines of code) (raw):

/* * Copyright 2021 EPAM Systems, Inc * * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. Licensed 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. */ #pragma once #include "dxcommon.h" #include "dxconstants.h" // PUBLIC API namespace DxApi { class DataWriter { public: /********************************************************************** * Non-nullable types, have special value if actually null */ // Integers void writeByte(uint8_t); void writeInt8(int8_t); void writeUInt16(uint16_t); void writeInt16(int16_t); void writeUInt32(uint32_t); void writeInt32(int32_t); void writeUInt40(uint64_t); void writeInt48(int64_t); void writeUInt64(uint64_t); void writeInt64(int64_t); // Compressed unsigned integers void writePUInt30(uint32_t); void writePUInt61(uint64_t); void writeInterval(uint32_t); void writeCompressedTime(int64_t); // Milliseconds void writeCompressedNanoTime(int64_t); // Nanoseconds // Floating point types void writeFloat64(double); void writeFloat32(float); // Compressed floating point void writeDecimal(double); void writeDecimal(double value, unsigned precision); // Timestamp void writeTimestamp(int64_t); // Timestamp void writeTimeOfDay(int32_t); // Enum types void writeEnum8(int); void writeEnum16(int); void writeEnum32(int); void writeEnum64(int64_t); // Other types void writeBoolean(bool); void writeWChar(wchar_t); // Binary array, data pointer can't be null, use writeBinaryArrayNull to write NULL void writeBinaryArray(const uint8_t *data, size_t size); void writeBinaryArrayNull(); // Arrays // Start writing array. Parameter is the number of items array will contain. We can write less items than specified here. void writeArrayStart(size_t nItems); // Stop writing array void writeArrayEnd(); // Write NULL array void writeArrayNull(); // Objects // Start writing nested object. Parameter is the number of items void writeObjectStart(uint8_t typeIndex); // Stop writing nested object void writeObjectEnd(); // Write NULL object void writeObjectNull(); // Not nullable (s != NULL) void writeUTF8(const char * s, size_t length); // Not nullable (s != NULL) void writeUTF8(const wchar_t * s, size_t length); // Not nullable (s != NULL) void writeAscii(const char * s, size_t length); // Not nullable (s != NULL) void writeAscii(const wchar_t * s, size_t length); void writeAlphanumericNull(uint32_t size); void writeAlphanumeric(uint32_t fieldSize, const char *str, size_t stringLength); void writeAlphanumeric(uint32_t fieldSize, const wchar_t *str, size_t stringLength); void writeAlphanumeric(uint32_t fieldSize, const std::string &value); void writeAlphanumeric(uint32_t fieldSize, const std::string *value); // bool writeAlphanumeric(char value[], size_t size); // TODO: Later template <typename T> void writeAlphanumericInt(uint32_t fieldSize, T value); INLINE void writeUTF8(const std::string &s) { writeUTF8(s.data(), s.length()); } INLINE void writeUTF8(const std::wstring &s) { writeUTF8(s.data(), s.length()); } template<class T> INLINE void writeUTF8(const T *s) { if (NULL == s) { putUInt16(0xFFFF); } else { writeUTF8(*s); } } INLINE void writeAscii(const std::string &s) { writeAscii(s.data(), s.length()); } INLINE void writeAscii(const std::wstring &s) { writeAscii(s.data(), s.length()); } template<class T> INLINE void writeAscii(const T *s) { if (NULL == s) { putUInt16(0xFFFF); } else { writeAscii(*s); } } /********************************************************************** * Nullable types, write null if bool or pointer parameter is false. */ // Integers void writeInt8(const int8_t value, bool isNull); void writeInt16(const int16_t value, bool isNull); void writeInt32(const int32_t value, bool isNull); void writeInt48(const int64_t value, bool isNull); void writeInt64(const int64_t value, bool isNull); // Compressed unsigned integers void writePUInt30(uint32_t value, bool isNull); void writePUInt61(uint64_t value, bool isNull); void writeInterval(uint32_t value, bool isNull); // Floating point types void writeFloat64(double value, bool isNull); void writeFloat32(float value, bool isNull); // Compressed floating point void writeDecimal(double value, bool isNull); // Timestamp void writeTimestamp(int64_t value, bool isNull); // Enum types void writeEnum8(int value, bool isNull); void writeEnum16(int value, bool isNull); void writeEnum32(int value, bool isNull); void writeEnum64(int64_t value, bool isNull); // Other types void writeNullableBoolean(bool value, bool isNull); void writeWChar(wchar_t value, bool isNull); void writeNullableUTF8(const char *srcString, size_t length); void writeNullableUTF8(const wchar_t *srcString, size_t length); // Misc protected: void putByte(uint8_t value); void putUInt16(uint16_t value); void putUInt32(uint32_t value); void putUInt64(uint64_t value); void putFloat64(double value); void putFloat32(float value); void checkNull(bool isNull); void setNotNull(); void wroteNull(); // Arbitrary sequence of bytes (RAW data), can not be NULL void putBytes(const uint8_t *srcData, size_t size); template <typename P, typename Q> static const P& as(const Q &x); template <typename T> static void storeBE(void * ptr, T x); template <typename T> void putBE(const T x, size_t size); template <typename T> void putBE(const T x); DataWriter(); DISALLOW_COPY_AND_ASSIGN(DataWriter); protected: uint8_t *dataPtr; // Current write pointer const uint8_t *dataEnd; // Written data end pointer (including written NULL values) uint8_t *dataEndNotNull; // Written data end pointer (ignoring trailing NULL values) protected: uint8_t* onOverflow(); }; /************************************************************************* * Internal inline methods implementation */ INLINE void DataWriter::putByte(uint8_t value) { putBE<uint8_t>(value); } INLINE void DataWriter::putUInt16(uint16_t value) { putBE<uint16_t>(value); } INLINE void DataWriter::putUInt32(uint32_t value) { putBE<uint32_t>(value); } INLINE void DataWriter::putUInt64(uint64_t value) { putBE<uint64_t>(value); } INLINE void DataWriter::putFloat64(double value) { putBE<double>(value); } INLINE void DataWriter::putFloat32(float value) { putBE<float>(value); } INLINE void DataWriter::checkNull(bool isNull) { // I'm deliberately using these temp vars. Don't remove, if you don't know why uint8_t *dataEndNotNullCopy = dataEndNotNull; uint8_t *dataPtrCopy = dataPtr; dataEndNotNull = isNull ? dataEndNotNullCopy : dataPtrCopy; } INLINE void DataWriter::setNotNull() { dataEndNotNull = dataPtr; } // Dummy function. Called after writing NULL value INLINE void DataWriter::wroteNull() { } /************************************************************************* * DataReader inline methods implementation */ INLINE void DataWriter::writeByte(uint8_t value) { putByte(value); } INLINE void DataWriter::writeInt8(int8_t value) { putByte(value); checkNull(INT8_NULL == value); } INLINE void DataWriter::writeUInt16(uint16_t value) { putUInt16(value); } INLINE void DataWriter::writeInt16(int16_t value) { putUInt16(value); checkNull(INT16_NULL == value); } INLINE void DataWriter::writeUInt32(uint32_t value) { putUInt32(value); } INLINE void DataWriter::writeInt32(int32_t value) { putUInt32(value); checkNull(INT32_NULL == value); } INLINE void DataWriter::writeUInt40(uint64_t value) { assert(value < (1ULL << 40)); putBE<uint64_t>(value << 24, 5); } INLINE void DataWriter::writeInt48(int64_t value) { assert(value < (1LL << 47) && value >= (int64_t)((uint64_t)-1LL << 47)); putBE<uint64_t>(value << 16, 6); checkNull(INT48_NULL == value); } INLINE void DataWriter::writeUInt64(uint64_t value) { putUInt64(value); } INLINE void DataWriter::writeInt64(int64_t value) { putUInt64(value); checkNull(INT64_NULL == value); } INLINE void DataWriter::writeFloat64(double value) { putFloat64(value); checkNull(std::isnan(value)); } INLINE void DataWriter::writeFloat32(float value) { putFloat32(value); checkNull(std::isnan(value)); } INLINE void DataWriter::writeTimestamp(int64_t value) { putUInt64(value); checkNull(TIMESTAMP_NULL == value); } INLINE void DataWriter::writeTimeOfDay(int32_t value) { putUInt32(value); checkNull(TIMEOFDAY_NULL == value); } INLINE void DataWriter::writeEnum8(int value) { putByte((uint8_t)value); checkNull(ENUM_NULL == value); } INLINE void DataWriter::writeEnum16(int value) { putUInt16((uint16_t)value); checkNull(ENUM_NULL == value); } INLINE void DataWriter::writeEnum32(int value) { putUInt32((uint32_t)value); checkNull(ENUM_NULL == value); } INLINE void DataWriter::writeEnum64(int64_t value) { putUInt64(value); checkNull(ENUM_NULL == value); } INLINE void DataWriter::writeBoolean(bool value) { putByte(value); setNotNull(); } INLINE void DataWriter::writeWChar(wchar_t value) { putUInt16(value); checkNull(CHAR_NULL == value); } INLINE void DataWriter::writeBinaryArrayNull() { putByte(1); wroteNull(); } INLINE void DataWriter::writeArrayNull() { putByte(0); wroteNull(); } INLINE void DataWriter::writeObjectNull() { putByte(0); wroteNull(); } /********************************************************************** * Nullable types, return false if null */ INLINE void DataWriter::writeInt8(int8_t value, bool isNull) { putByte(isNull ? INT8_NULL : value); checkNull(isNull); } INLINE void DataWriter::writeInt16(int16_t value, bool isNull) { putUInt16(isNull ? INT16_NULL : value); checkNull(isNull); } INLINE void DataWriter::writeInt32(int32_t value, bool isNull) { putUInt32(isNull ? INT32_NULL : value); checkNull(isNull); } INLINE void DataWriter::writeInt48(int64_t value, bool isNull) { //put(isNull ? 0x80 : _byteswap_uint64(value) >> 16, 6); putBE<uint64_t>(isNull ? (uint64_t)INT48_NULL << 16 : (uint64_t)value << 16, 6); checkNull(isNull); } INLINE void DataWriter::writeInt64(int64_t value, bool isNull) { //put(isNull ? 0x80 : _byteswap_uint64(value), 8); putBE<uint64_t>(isNull ? INT64_NULL : value); checkNull(isNull); } // Compressed integers INLINE void DataWriter::writePUInt30(uint32_t value, bool isNull) { writePUInt30(isNull ? UINT30_NULL : value); checkNull(isNull); } INLINE void DataWriter::writePUInt61(uint64_t value, bool isNull) { writePUInt61(isNull ? UINT61_NULL : value); checkNull(isNull); } INLINE void DataWriter::writeInterval(uint32_t value, bool isNull) { writeInterval(isNull ? INTERVAL_NULL : value); checkNull(isNull); } // Floating point types INLINE void DataWriter::writeFloat64(double value, bool isNull) { putBE<uint64_t>(isNull ? float64null.u : as<uint64_t>(value)); // Should be done better checkNull(isNull); } INLINE void DataWriter::writeFloat32(float value, bool isNull) { putBE<uint32_t>(isNull ? float32null.u : as<uint32_t>(value)); // Should be done better checkNull(isNull); } // Enum types INLINE void DataWriter::writeEnum8(int value, bool isNull) { putByte(isNull ? ENUM_NULL : (uint8_t)value); checkNull(isNull); } INLINE void DataWriter::writeEnum16(int value, bool isNull) { putUInt16(isNull ? ENUM_NULL : (uint16_t)value); checkNull(isNull); } INLINE void DataWriter::writeEnum32(int value, bool isNull) { putUInt32(isNull ? ENUM_NULL : (uint32_t)value); checkNull(isNull); } INLINE void DataWriter::writeEnum64(int64_t value, bool isNull) { putUInt64(isNull ? ENUM_NULL : (uint64_t)value); checkNull(isNull); } INLINE void DataWriter::writeTimestamp(int64_t value, bool isNull) { putUInt64(isNull ? TIMESTAMP_NULL : value); checkNull(isNull); } INLINE void DataWriter::writeNullableBoolean(bool value, bool isNull) { putByte(isNull ? BOOL_NULL : value); checkNull(isNull); } INLINE void DataWriter::writeWChar(wchar_t value, bool isNull) { putUInt16(isNull ? CHAR_NULL : value); checkNull(isNull); } INLINE void DataWriter::writeAlphanumeric(uint32_t size, const std::string &value) { writeAlphanumeric(size, value.c_str(), value.size()); setNotNull(); } INLINE void DataWriter::writeAlphanumeric(uint32_t size, const std::string *value) { if (NULL == value) { writeAlphanumericNull(size); } else { writeAlphanumeric(size, value->c_str(), value->size()); setNotNull(); } } /********************************************************************* * Private functions */ template <typename P, typename Q> INLINE const P& DataWriter::as(const Q &x) { return DxApiImpl::_as<P, Q>(x); } template <typename T> INLINE void DataWriter::storeBE(void *ptr, T x) { return DxApiImpl::_storeBE<T>(ptr, x); } template <typename T> INLINE void DataWriter::putBE(const T value, size_t size) { uint8_t * p; assert(size <= 8); storeBE(p = dataPtr, value); if ((dataPtr = p + size) > dataEnd) { onOverflow(); } } INLINE void DataWriter::putBytes(const uint8_t *data, size_t size) { assert(NULL != data); uint8_t * p = dataPtr; // TODO: Check correctness if ((dataPtr = p + size) > dataEnd) { memcpy(p, data, dataEnd - p); onOverflow(); } else { memcpy(p, data, size); } } template <typename T> INLINE void DataWriter::putBE(const T value) { putBE(value, sizeof(T)); } } // namespace DxApi