Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
SharafMohamed committed Nov 13, 2023
2 parents 120342a + 2b884bd commit 8ec7713
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 112 deletions.
4 changes: 3 additions & 1 deletion components/core/src/ffi/encoding_methods.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ eight_byte_encoded_variable_t encode_four_byte_float_as_eight_byte(
);

/**
* Encodes a float value with the given properties into an encoded variable
* Encodes a float value with the given properties into an encoded variable.
* NOTE: It's the caller's responsibility to validate that the input is a
* representable float.
* @tparam encoded_variable_t Type of the encoded variable
* @param is_negative
* @param digits The digits of the float, ignoring the decimal, as an
Expand Down
10 changes: 6 additions & 4 deletions components/core/src/ffi/encoding_methods.inc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ bool encode_float_string(std::string_view str, encoded_variable_t& encoded_var)
// digits found
return false;
}
if constexpr (std::is_same_v<encoded_variable_t, four_byte_encoded_variable_t>) {
if (cFourByteEncodedFloatDigitsBitMask < digits) {
// digits is larger than maximum representable
return false;
}
}

encoded_var = encode_float_properties<encoded_variable_t>(
is_negative,
Expand Down Expand Up @@ -127,10 +133,6 @@ encoded_variable_t encode_float_properties(
return bit_cast<encoded_variable_t>(encoded_float);
} else {
// std::is_same_v<encoded_variable_t, four_byte_encoded_variable_t>
if (digits > cFourByteEncodedFloatDigitsBitMask) {
// digits is larger than maximum representable
return false;
}

// Encode into 32 bits with the following format (from MSB to LSB):
// - 1 bit : is negative
Expand Down
43 changes: 40 additions & 3 deletions components/core/src/ffi/ir_stream/decoding_methods.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "decoding_methods.hpp"

#include <regex>

#include "byteswap.hpp"
#include "protocol_constants.hpp"

Expand Down Expand Up @@ -251,6 +253,12 @@ parse_timestamp(ReaderInterface& reader, encoded_tag_t encoded_tag, epoch_time_m
return IRErrorCode_Incomplete_IR;
}
ts = ts_delta;
} else if (cProtocol::Payload::TimestampDeltaLong == encoded_tag) {
int64_t ts_delta;
if (false == decode_int(reader, ts_delta)) {
return IRErrorCode_Incomplete_IR;
}
ts = ts_delta;
} else {
return IRErrorCode_Corrupted_IR;
}
Expand All @@ -277,9 +285,8 @@ generic_decode_next_message(ReaderInterface& reader, string& message, epoch_time
message.append(value, begin_pos, length);
};

auto encoded_int_handler = [&](encoded_variable_t value) {
message.append(decode_integer_var(value));
};
auto encoded_int_handler
= [&](encoded_variable_t value) { message.append(decode_integer_var(value)); };

auto encoded_float_handler = [&](encoded_variable_t encoded_float) {
message.append(decode_float_var(encoded_float));
Expand Down Expand Up @@ -458,6 +465,36 @@ IRErrorCode decode_preamble(
return IRErrorCode_Success;
}

IRProtocolErrorCode validate_protocol_version(std::string_view protocol_version) {
if ("v0.0.0" == protocol_version) {
// This version is hardcoded to support the oldest IR protocol version.
// When this version is no longer supported, this branch should be
// removed.
return IRProtocolErrorCode_Supported;
}
std::regex const protocol_version_regex{cProtocol::Metadata::VersionRegex};
if (false
== std::regex_match(
protocol_version.begin(),
protocol_version.end(),
protocol_version_regex
))
{
return IRProtocolErrorCode_Invalid;
}
std::string_view current_build_protocol_version{cProtocol::Metadata::VersionValue};
auto get_major_version{[](std::string_view version) {
return version.substr(0, version.find('.'));
}};
if (current_build_protocol_version < protocol_version) {
return IRProtocolErrorCode_Too_New;
}
if (get_major_version(current_build_protocol_version) > get_major_version(protocol_version)) {
return IRProtocolErrorCode_Too_Old;
}
return IRProtocolErrorCode_Supported;
}

namespace four_byte_encoding {
IRErrorCode decode_next_message(
ReaderInterface& reader,
Expand Down
21 changes: 21 additions & 0 deletions components/core/src/ffi/ir_stream/decoding_methods.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ typedef enum {
IRErrorCode_Incomplete_IR,
} IRErrorCode;

typedef enum {
IRProtocolErrorCode_Supported,
IRProtocolErrorCode_Too_Old,
IRProtocolErrorCode_Too_New,
IRProtocolErrorCode_Invalid,
} IRProtocolErrorCode;

class DecodingException : public TraceableException {
public:
// Constructors
Expand Down Expand Up @@ -142,6 +149,20 @@ IRErrorCode decode_preamble(
std::vector<int8_t>& metadata
);

/**
* Validates whether the given protocol version can be supported by the current
* build.
* @param protocol_version
* @return IRProtocolErrorCode_Supported if the protocol version is supported.
* @return IRProtocolErrorCode_Too_Old if the protocol version is no longer
* supported by this build's protocol version.
* @return IRProtocolErrorCode_Too_New if the protocol version is newer than this
* build's protocol version.
* @return IRProtocolErrorCode_Invalid if the protocol version does not follow
* the SemVer specification.
*/
IRProtocolErrorCode validate_protocol_version(std::string_view protocol_version);

namespace eight_byte_encoding {
/**
* Decodes the next message for the eight-byte encoding IR stream.
Expand Down
10 changes: 5 additions & 5 deletions components/core/src/ffi/ir_stream/encoding_methods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,7 @@ static void add_base_metadata_fields(
* @param logtype
* @return true
*/
static bool append_constant_to_logtype(
string_view constant,
string& logtype
);
static bool append_constant_to_logtype(string_view constant, string& logtype);

/**
* A functor for encoding dictionary variables in a message
Expand Down Expand Up @@ -308,8 +305,11 @@ namespace four_byte_encoding {
} else if (INT32_MIN <= timestamp_delta && timestamp_delta <= INT32_MAX) {
ir_buf.push_back(cProtocol::Payload::TimestampDeltaInt);
encode_int(static_cast<int32_t>(timestamp_delta), ir_buf);
} else if (INT64_MIN <= timestamp_delta && timestamp_delta <= INT64_MAX) {
ir_buf.push_back(cProtocol::Payload::TimestampDeltaLong);
encode_int(static_cast<int64_t>(timestamp_delta), ir_buf);
} else {
// Delta exceeds maximum representable by an int (24.86 days)
// Delta exceeds maximum representable by a 64-bit int
return false;
}

Expand Down
10 changes: 9 additions & 1 deletion components/core/src/ffi/ir_stream/protocol_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ namespace Metadata {
constexpr int8_t LengthUShort = 0x12;

constexpr char VersionKey[] = "VERSION";
constexpr char VersionValue[] = "v0.0.0";
constexpr char VersionValue[] = "0.0.1";

// The following regex can be used to validate a Semantic Versioning string.
// The source of the regex can be found here: https://semver.org/
constexpr char VersionRegex[] = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)"
"(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)"
"(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?"
"(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$";

constexpr char TimestampPatternKey[] = "TIMESTAMP_PATTERN";
constexpr char TimestampPatternSyntaxKey[] = "TIMESTAMP_PATTERN_SYNTAX";
Expand All @@ -39,6 +46,7 @@ namespace Payload {
constexpr int8_t TimestampDeltaByte = 0x31;
constexpr int8_t TimestampDeltaShort = 0x32;
constexpr int8_t TimestampDeltaInt = 0x33;
constexpr int8_t TimestampDeltaLong = 0x34;
} // namespace Payload

constexpr int8_t FourByteEncodingMagicNumber[]
Expand Down
4 changes: 2 additions & 2 deletions components/core/src/ir/LogEventDeserializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ auto LogEventDeserializer<encoded_variable_t>::create(ReaderInterface& reader)
return std::errc::protocol_error;
}
auto metadata_version = version_iter->get_ref<nlohmann::json::string_t&>();
if (static_cast<char const*>(ffi::ir_stream::cProtocol::Metadata::VersionValue)
!= metadata_version)
if (ffi::ir_stream::IRProtocolErrorCode_Supported
!= ffi::ir_stream::validate_protocol_version(metadata_version))
{
return std::errc::protocol_not_supported;
}
Expand Down
91 changes: 37 additions & 54 deletions components/core/tests/test-encoding_methods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,61 +226,44 @@ TEMPLATE_TEST_CASE("Encoding floats", "[ffi][encode-float]", eight_byte_encoded_
decoded_value = decode_float_var(encoded_var);
REQUIRE(decoded_value == value);

// Test non-floats
value = "";
REQUIRE(!encode_float_string(value, encoded_var));

value = "a";
REQUIRE(!encode_float_string(value, encoded_var));

value = "-";
REQUIRE(!encode_float_string(value, encoded_var));

value = "+";
REQUIRE(!encode_float_string(value, encoded_var));

value = "-a";
REQUIRE(!encode_float_string(value, encoded_var));

value = "+a";
REQUIRE(!encode_float_string(value, encoded_var));

value = "--";
REQUIRE(!encode_float_string(value, encoded_var));

value = "++";
REQUIRE(!encode_float_string(value, encoded_var));

// Test unrepresentable values
value = ".";
REQUIRE(!encode_float_string(value, encoded_var));

value = "1.";
REQUIRE(!encode_float_string(value, encoded_var));

value = " 1.0";
REQUIRE(!encode_float_string(value, encoded_var));

value = "- 1.0";
REQUIRE(!encode_float_string(value, encoded_var));

value = "1.0 ";
REQUIRE(!encode_float_string(value, encoded_var));

value = "+1.0";
REQUIRE(!encode_float_string(value, encoded_var));

value = "1.0f";
REQUIRE(!encode_float_string(value, encoded_var));

value = "1.0F";
REQUIRE(!encode_float_string(value, encoded_var));

value = "1.0l";
REQUIRE(!encode_float_string(value, encoded_var));
SECTION("Test unrepresentable floats") {
if constexpr (std::is_same_v<TestType, four_byte_encoded_variable_t>) {
string const unrepresentable_values = GENERATE(
"0.33554431",
"-0.33554431",
"3.3554432",
"-3.3554432",
"60.000004",
"-60.000004"
);
REQUIRE(false == ffi::encode_float_string(unrepresentable_values, encoded_var));
}
}

value = "1.0L";
REQUIRE(!encode_float_string(value, encoded_var));
SECTION("Test non-floats") {
string const non_floating_values = GENERATE(
"",
"a",
"-",
"+",
"-a",
"+a",
"--",
"++",
".",
"1.",
" 1.0",
"1.0 ",
"- 1.0",
"+1.0",
"1.0f"
"1.0F",
"1.0l",
"1.0L",
"1.0.0"
);
REQUIRE(false == encode_float_string(non_floating_values, encoded_var));
}
}

TEMPLATE_TEST_CASE("encode_float_properties", "[ffi][encode-float]", eight_byte_encoded_variable_t,
Expand Down
Loading

0 comments on commit 8ec7713

Please sign in to comment.