Skip to content

Commit

Permalink
[#1] Add BitStreamWriter and BitStreamReader from Zserio C++ runtime
Browse files Browse the repository at this point in the history
* add also BitSizeOfCalculator
  • Loading branch information
Mi-La committed Sep 3, 2024
1 parent 6caeab8 commit 946d913
Show file tree
Hide file tree
Showing 14 changed files with 4,162 additions and 2 deletions.
4 changes: 2 additions & 2 deletions runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ if (${ZSERIO_CODE_COVERAGE_ENABLE})
if (${ZSERIO_CODE_COVERAGE_FAIL_ON_INCOMPLETE})
list(APPEND COV_PARAMS "INCOMPLETE_COVERAGE_FAIL")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
list(APPEND COV_PARAMS "99.3")
list(APPEND COV_PARAMS "99.5")
else ()
list(APPEND COV_PARAMS "99.3")
list(APPEND COV_PARAMS "99.5")
endif ()
endif ()
#list(APPEND COV_PARAMS "EXCLUDE_SOURCES")
Expand Down
18 changes: 18 additions & 0 deletions runtime/ClangTidySuppressions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ cppcoreguidelines-pro-bounds-array-to-pointer-decay:src/zserio/Span.h:113
# This is necessary for convenient usage of CppRuntimeException
cppcoreguidelines-pro-bounds-array-to-pointer-decay:src/zserio/CppRuntimeException.h:193

# The following is filtered out because bounds are checked naturally by implementation. Therefore method 'at'
# would only bring the performance drop.
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamReader.cpp:301
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamReader.cpp:315
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:357
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:368
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:379
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:380
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:386
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:391
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:392
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:398
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:594
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/BitStreamWriter.cpp:662

# The following is filtered out because bounds are checked naturally by implementation. Therefore method 'at'
# would only bring the performance drop.
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/StringConvertUtil.h:43
Expand All @@ -22,6 +37,9 @@ cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/StringConvertUtil.h
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/StringConvertUtil.h:54
cppcoreguidelines-pro-bounds-constant-array-index:src/zserio/StringConvertUtil.h:55

# This is false positive, the member is initialized.
cppcoreguidelines-pro-type-member-init:src/zserio/BitStreamWriter.h:71

# This is necessary for implementation of reading and writing to the file.
cppcoreguidelines-pro-type-reinterpret-cast:src/zserio/FileUtil.cpp:18
cppcoreguidelines-pro-type-reinterpret-cast:src/zserio/FileUtil.cpp:48
Expand Down
6 changes: 6 additions & 0 deletions runtime/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ set(ZSERIO_CPP17_RUNTIME_LIB_SRCS
zserio/BitFieldUtil.cpp
zserio/BitPositionUtil.h
zserio/BitFieldUtil.h
zserio/BitSizeOfCalculator.cpp
zserio/BitSizeOfCalculator.h
zserio/BitStreamReader.cpp
zserio/BitStreamReader.h
zserio/BitStreamWriter.cpp
zserio/BitStreamWriter.h
zserio/BuiltInOperators.cpp
zserio/BuiltInOperators.h
zserio/CppRuntimeException.cpp
Expand Down
183 changes: 183 additions & 0 deletions runtime/src/zserio/BitSizeOfCalculator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#include <array>
#include <limits>

#include "zserio/BitSizeOfCalculator.h"
#include "zserio/CppRuntimeException.h"

namespace zserio
{

static const std::array<uint64_t, 2> VARIN16_MAX_VALUES = {
(UINT64_C(1) << (6)) - 1,
(UINT64_C(1) << (6 + 8)) - 1,
};

static const std::array<uint64_t, 4> VARINT32_MAX_VALUES = {
(UINT64_C(1) << (6)) - 1,
(UINT64_C(1) << (6 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 8)) - 1,
};

static const std::array<uint64_t, 8> VARINT64_MAX_VALUES = {
(UINT64_C(1) << (6)) - 1,
(UINT64_C(1) << (6 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7 + 7 + 7 + 7 + 8)) - 1,
};

static const std::array<uint64_t, 2> VARUINT16_MAX_VALUES = {
(UINT64_C(1) << (7)) - 1,
(UINT64_C(1) << (7 + 8)) - 1,
};

static const std::array<uint64_t, 4> VARUINT32_MAX_VALUES = {
(UINT64_C(1) << (7)) - 1,
(UINT64_C(1) << (7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 8)) - 1,
};

static const std::array<uint64_t, 8> VARUINT64_MAX_VALUES = {
(UINT64_C(1) << (7)) - 1,
(UINT64_C(1) << (7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7 + 7 + 7 + 7 + 8)) - 1,
};

static const std::array<uint64_t, 9> VARINT_MAX_VALUES = {
(UINT64_C(1) << (6)) - 1,
(UINT64_C(1) << (6 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (6 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 8)) - 1,
};

static const std::array<uint64_t, 9> VARUINT_MAX_VALUES = {
(UINT64_C(1) << (7)) - 1,
(UINT64_C(1) << (7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7 + 7 + 7 + 7 + 7)) - 1,
UINT64_MAX,
};

static const std::array<uint64_t, 5> VARSIZE_MAX_VALUES = {
(UINT64_C(1) << (7)) - 1,
(UINT64_C(1) << (7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7)) - 1,
(UINT64_C(1) << (7 + 7 + 7 + 7)) - 1,
(UINT64_C(1) << (2 + 7 + 7 + 7 + 8)) - 1,
};

template <std::size_t SIZE>
static size_t bitSizeOfVarIntImpl(
uint64_t value, const std::array<uint64_t, SIZE>& maxValues, const char* varIntName)
{
size_t byteSize = 1;
for (uint64_t maxValue : maxValues)
{
if (value <= maxValue)
{
break;
}
byteSize++;
}

if (byteSize > maxValues.size())
{
throw CppRuntimeException("BitSizeOfCalculator: Value '")
<< value << "' is out of range for " << varIntName << "!";
}

return byteSize * 8;
}

template <typename T>
static uint64_t convertToAbsValue(T value)
{
return static_cast<uint64_t>((value < 0) ? -value : value);
}

size_t bitSizeOfVarInt16(int16_t value)
{
return bitSizeOfVarIntImpl(convertToAbsValue(value), VARIN16_MAX_VALUES, "varint16");
}

size_t bitSizeOfVarInt32(int32_t value)
{
return bitSizeOfVarIntImpl(convertToAbsValue(value), VARINT32_MAX_VALUES, "varint32");
}

size_t bitSizeOfVarInt64(int64_t value)
{
return bitSizeOfVarIntImpl(convertToAbsValue(value), VARINT64_MAX_VALUES, "varint64");
}

size_t bitSizeOfVarUInt16(uint16_t value)
{
return bitSizeOfVarIntImpl(value, VARUINT16_MAX_VALUES, "varuint16");
}

size_t bitSizeOfVarUInt32(uint32_t value)
{
return bitSizeOfVarIntImpl(value, VARUINT32_MAX_VALUES, "varuint32");
}

size_t bitSizeOfVarUInt64(uint64_t value)
{
return bitSizeOfVarIntImpl(value, VARUINT64_MAX_VALUES, "varuint64");
}

size_t bitSizeOfVarInt(int64_t value)
{
if (value == INT64_MIN)
{
return 8; // INT64_MIN is stored as -0
}

return bitSizeOfVarIntImpl(convertToAbsValue(value), VARINT_MAX_VALUES, "varint");
}

size_t bitSizeOfVarUInt(uint64_t value)
{
return bitSizeOfVarIntImpl(value, VARUINT_MAX_VALUES, "varuint");
}

size_t bitSizeOfVarSize(uint32_t value)
{
return bitSizeOfVarIntImpl(value, VARSIZE_MAX_VALUES, "varsize");
}

size_t bitSizeOfBytes(Span<const uint8_t> bytesValue)
{
const size_t bytesSize = bytesValue.size();

// the bytes consists of varsize for size followed by the bytes
return bitSizeOfVarSize(convertSizeToUInt32(bytesSize)) + bytesSize * 8;
}

size_t bitSizeOfString(std::string_view stringValue)
{
const size_t stringSize = stringValue.size();

// the string consists of varsize for size followed by the UTF-8 encoded string
return bitSizeOfVarSize(convertSizeToUInt32(stringSize)) + stringSize * 8;
}

} // namespace zserio
134 changes: 134 additions & 0 deletions runtime/src/zserio/BitSizeOfCalculator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#ifndef ZSERIO_BITSIZEOF_CALCULATOR_H_INC
#define ZSERIO_BITSIZEOF_CALCULATOR_H_INC

#include <cstddef>
#include <string>
#include <string_view>

#include "zserio/BitBuffer.h"
#include "zserio/BitPositionUtil.h"
#include "zserio/SizeConvertUtil.h"
#include "zserio/Span.h"
#include "zserio/Types.h"

namespace zserio
{

/**
* Calculates bit size of Zserio varint16 type.
*
* \param value Varint16 value.
*
* \return Bit size of the current varint16 value.
*/
size_t bitSizeOfVarInt16(int16_t value);

/**
* Calculates bit size of Zserio varint32 type.
*
* \param value Varint32 value.
*
* \return Bit size of the current varint32 value.
*/
size_t bitSizeOfVarInt32(int32_t value);

/**
* Calculates bit size of Zserio varint64 type.
*
* \param value Varint64 value.
*
* \return Bit size of the current varint64 value.
*/
size_t bitSizeOfVarInt64(int64_t value);

/**
* Calculates bit size of Zserio varuint16 type.
*
* \param value Varuint16 value.
*
* \return Bit size of the current varuint16 value.
*/
size_t bitSizeOfVarUInt16(uint16_t value);

/**
* Calculates bit size of Zserio varuint32 type.
*
* \param value Varuint32 value.
*
* \return Bit size of the current varuint32 value.
*/
size_t bitSizeOfVarUInt32(uint32_t value);

/**
* Calculates bit size of Zserio varuint64 type.
*
* \param value Varuint64 value.
*
* \return Bit size of the current varuint64 value.
*/
size_t bitSizeOfVarUInt64(uint64_t value);

/**
* Calculates bit size of Zserio varint type.
*
* \param value Varint value.
*
* \return Bit size of the current varint value.
*/
size_t bitSizeOfVarInt(int64_t value);

/**
* Calculates bit size of Zserio varuint type.
*
* \param value Varuint value.
*
* \return Bit size of the current varuint value.
*/
size_t bitSizeOfVarUInt(uint64_t value);

/**
* Calculates bit size of Zserio varsize type.
*
* \param value Varsize value.
*
* \return Bit size of the current varsize value.
*/
size_t bitSizeOfVarSize(uint32_t value);

/**
* Calculates bit size of bytes.
*
* \param bytesValue Span representing the bytes value.
*
* \return Bit size of the given bytes value.
*/
size_t bitSizeOfBytes(Span<const uint8_t> bytesValue);

/**
* Calculates bit size of the string.
*
* \param stringValue String view for which to calculate bit size.
*
* \return Bit size of the given string.
*/
size_t bitSizeOfString(std::string_view stringValue);

/**
* Calculates bit size of the bit buffer.
*
* \param bitBuffer Bit buffer for which to calculate bit size.
*
* \return Bit size of the given bit buffer.
*/
template <typename ALLOC>
size_t bitSizeOfBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer)
{
const size_t bitBufferSize = bitBuffer.getBitSize();

// bit buffer consists of varsize for bit size followed by the bits
return bitSizeOfVarSize(convertSizeToUInt32(bitBufferSize)) + bitBufferSize;
}

} // namespace zserio

#endif // ifndef ZSERIO_BITSIZEOF_CALCULATOR_H_INC
Loading

0 comments on commit 946d913

Please sign in to comment.