This is an automated email from the ASF dual-hosted git repository.
isapego pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 35d0692e3e2 IGNITE-28081 C++ Client: Add hashing functions (#7750)
35d0692e3e2 is described below
commit 35d0692e3e26378cd8efebd44f92aeac0ccb4859
Author: Ed Rakhmankulov <[email protected]>
AuthorDate: Tue Mar 17 18:26:22 2026 +0300
IGNITE-28081 C++ Client: Add hashing functions (#7750)
---
modules/platforms/cpp/ignite/common/CMakeLists.txt | 5 +
.../platforms/cpp/ignite/common/big_decimal.cpp | 24 +-
modules/platforms/cpp/ignite/common/big_decimal.h | 19 +-
.../platforms/cpp/ignite/common/bignum_test.cpp | 33 ++
.../cpp/ignite/common/detail/hash_calculator.cpp | 77 ++++
.../cpp/ignite/common/detail/hash_calculator.h | 60 +++
.../cpp/ignite/common/detail/hash_utils.cpp | 131 ++++++
.../cpp/ignite/common/detail/hash_utils.h | 234 +++++++++++
.../cpp/ignite/common/detail/hash_utils_test.cpp | 455 +++++++++++++++++++++
.../cpp/ignite/common/detail/murmur3_hash.cpp | 176 ++++++++
.../cpp/ignite/common/detail/murmur3_hash.h | 22 +
.../cpp/ignite/common/detail/string_extensions.cpp | 83 ++++
.../cpp/ignite/common/detail/string_extensions.h | 43 ++
modules/platforms/cpp/ignite/common/detail/utils.h | 35 +-
modules/platforms/cpp/ignite/common/ignite_time.h | 1 +
15 files changed, 1393 insertions(+), 5 deletions(-)
diff --git a/modules/platforms/cpp/ignite/common/CMakeLists.txt
b/modules/platforms/cpp/ignite/common/CMakeLists.txt
index afd0a609dc7..1988441b7d3 100644
--- a/modules/platforms/cpp/ignite/common/CMakeLists.txt
+++ b/modules/platforms/cpp/ignite/common/CMakeLists.txt
@@ -47,8 +47,12 @@ set(SOURCES
big_integer.cpp
detail/mpi.cpp
detail/string_utils.cpp
+ detail/string_extensions.cpp
detail/thread_timer.cpp
uuid.cpp
+ detail/hash_calculator.cpp
+ detail/hash_utils.cpp
+ detail/murmur3_hash.cpp
)
add_library(${TARGET} STATIC ${SOURCES})
@@ -71,3 +75,4 @@ ignite_test(thread_timer_test DISCOVER SOURCES
detail/thread_timer_test.cpp LIBS
ignite_test(uuid_test DISCOVER SOURCES uuid_test.cpp LIBS ${TARGET})
ignite_test(bignum_test DISCOVER SOURCES bignum_test.cpp LIBS ${TARGET})
ignite_test(primitive_test DISCOVER SOURCES primitive_test.cpp LIBS ${TARGET})
+ignite_test(hash_utils_test DISCOVER SOURCES detail/hash_utils_test.cpp LIBS
${TARGET})
diff --git a/modules/platforms/cpp/ignite/common/big_decimal.cpp
b/modules/platforms/cpp/ignite/common/big_decimal.cpp
index def7aa28054..30fe02df67a 100644
--- a/modules/platforms/cpp/ignite/common/big_decimal.cpp
+++ b/modules/platforms/cpp/ignite/common/big_decimal.cpp
@@ -40,9 +40,14 @@ big_decimal::big_decimal(const std::byte *data, std::size_t
size) {
m_magnitude = big_integer(data + sizeof(m_scale), size - sizeof(m_scale));
}
-void big_decimal::set_scale(std::int16_t new_scale, big_decimal &res) const {
- if (m_scale == new_scale)
+void big_decimal::set_scale(std::int16_t new_scale, big_decimal &res,
rounding_mode r_mode) const {
+ if (m_scale == new_scale) {
+ if (&res != this) {
+ res = *this;
+ }
return;
+ }
+
auto diff = std::int16_t(m_scale - new_scale);
@@ -50,8 +55,21 @@ void big_decimal::set_scale(std::int16_t new_scale,
big_decimal &res) const {
if (diff > 0) {
big_integer::get_power_of_ten(diff, adjustment);
+ big_integer rem;
+
+ m_magnitude.divide(adjustment, res.m_magnitude, &rem);
- m_magnitude.divide(adjustment, res.m_magnitude);
+ if (r_mode == rounding_mode::HALF_UP) {
+ rem.add(rem, rem);
+ if (rem.compare(adjustment, true) >= 0) {
+ static const big_integer plus_one{1};
+ static const big_integer minus_one{-1};
+
+ auto& fix = rem.get_sign() == 1 ? plus_one : minus_one;
+
+ res.m_magnitude.add(fix, res.m_magnitude);
+ }
+ }
} else {
big_integer::get_power_of_ten(-diff, adjustment);
diff --git a/modules/platforms/cpp/ignite/common/big_decimal.h
b/modules/platforms/cpp/ignite/common/big_decimal.h
index fef514e4dbd..b71adac69b5 100644
--- a/modules/platforms/cpp/ignite/common/big_decimal.h
+++ b/modules/platforms/cpp/ignite/common/big_decimal.h
@@ -34,6 +34,13 @@ namespace ignite {
*/
class big_decimal {
public:
+
+ enum class rounding_mode {
+ // TODO IGNITE-28198 support other rounding modes
+ DOWN,
+ HALF_UP
+ };
+
// Default
big_decimal() = default;
@@ -212,7 +219,17 @@ public:
* @param scale Scale to set.
* @param res Result is placed here. Can be *this.
*/
- void set_scale(std::int16_t new_scale, big_decimal &res) const;
+ void set_scale(std::int16_t new_scale, big_decimal &res) const {
+ set_scale(new_scale, res, rounding_mode::DOWN);
+ }
+
+ /**
+ * Set scale.
+ *
+ * @param scale Scale to set.
+ * @param res Result is placed here. Can be *this.
+ */
+ void set_scale(std::int16_t new_scale, big_decimal &res, rounding_mode
r_mode) const;
/**
* Get precision of the Decimal.
diff --git a/modules/platforms/cpp/ignite/common/bignum_test.cpp
b/modules/platforms/cpp/ignite/common/bignum_test.cpp
index 45eb4f61663..8f8c60d247e 100644
--- a/modules/platforms/cpp/ignite/common/bignum_test.cpp
+++ b/modules/platforms/cpp/ignite/common/bignum_test.cpp
@@ -1290,3 +1290,36 @@ TEST(bignum, TestDoubleCast) {
CheckDoubleCast(-0.00000000000001);
CheckDoubleCast(-0.000000000000001);
}
+
+struct big_decimal_rounding_tc {
+ big_decimal initial;
+ int16_t new_scale;
+ big_decimal expected;
+};
+
+class big_decimal_rounding_test : public
::testing::TestWithParam<big_decimal_rounding_tc> {};
+
+TEST_P(big_decimal_rounding_test, TestScaleWithRoundHalfUp) {
+ auto [initial, new_scale, expected] = GetParam();
+
+ big_decimal actual;
+ initial.set_scale(new_scale, actual, big_decimal::rounding_mode::HALF_UP);
+
+ ASSERT_EQ(expected, actual);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ ScaleWithRoundHalfUp,
+ big_decimal_rounding_test,
+ ::testing::Values(
+ big_decimal_rounding_tc{big_decimal{0}, 0, big_decimal{0}},
+ big_decimal_rounding_tc{big_decimal{1}, 0, big_decimal{1}},
+ big_decimal_rounding_tc{big_decimal{-1}, 0, big_decimal{-1}},
+ big_decimal_rounding_tc{big_decimal{"1.5"}, 0, big_decimal{2}},
+ big_decimal_rounding_tc{big_decimal{"-1.5"}, 0, big_decimal{-2}},
+ big_decimal_rounding_tc{big_decimal{"3.64586"}, 2,
big_decimal{"3.65"}},
+ big_decimal_rounding_tc{big_decimal{"3.64586"}, 1, big_decimal{"3.6"}},
+ big_decimal_rounding_tc{big_decimal{"-3.64586"}, 2,
big_decimal{"-3.65"}},
+ big_decimal_rounding_tc{big_decimal{"-3.64586"}, 1,
big_decimal{"-3.6"}}
+ )
+);
diff --git a/modules/platforms/cpp/ignite/common/detail/hash_calculator.cpp
b/modules/platforms/cpp/ignite/common/detail/hash_calculator.cpp
new file mode 100644
index 00000000000..9419ddcf68c
--- /dev/null
+++ b/modules/platforms/cpp/ignite/common/detail/hash_calculator.cpp
@@ -0,0 +1,77 @@
+// 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.
+//
+
+//
+
+#include "hash_calculator.h"
+
+#include "hash_utils.h"
+
+namespace ignite::detail {
+
+std::int32_t hash_calculator::calc_hash(const primitive& val, std::int32_t
scale, std::int32_t precision) {
+ auto type = val.get_type();
+
+ switch (type) {
+ case ignite_type::BOOLEAN:
+ return hash(val.get<bool>());
+ case ignite_type::NIL:
+ return hash(static_cast<std::int8_t>(0));
+ case ignite_type::INT8:
+ return hash(val.get<std::int8_t>());
+ case ignite_type::INT16:
+ return hash(val.get<std::int16_t>());
+ case ignite_type::INT32:
+ return hash(val.get<std::int32_t>());
+ case ignite_type::INT64:
+ return hash(val.get<std::int64_t>());
+ case ignite_type::FLOAT:
+ return hash(val.get<float>());
+ case ignite_type::DOUBLE:
+ return hash(val.get<double>());
+ case ignite_type::DECIMAL:
+ return hash(val.get<big_decimal>(), scale);
+ case ignite_type::DATE:
+ return hash(val.get<ignite_date>());
+ case ignite_type::TIME:
+ return hash(val.get<ignite_time>(), precision);
+ case ignite_type::DATETIME:
+ return hash(val.get<ignite_date_time>(), precision);
+ case ignite_type::TIMESTAMP:
+ return hash(val.get<ignite_timestamp>(), precision);
+ case ignite_type::UUID:
+ return hash(val.get<uuid>());
+ case ignite_type::STRING:
+ return hash(val.get<std::string>());
+ case ignite_type::BYTE_ARRAY:
+ return hash(val.get<std::vector<std::byte>>());
+ case ignite_type::PERIOD:
+ case ignite_type::DURATION:
+ case ignite_type::UNDEFINED:
+ default:
+ throw ignite_error(
+ error::code::INTERNAL,
+ "Can't calculate hash value for type = " +
std::to_string(static_cast<int>(type))
+ );
+ }
+}
+
+void hash_calculator::append(const primitive &val, std::int32_t scale,
std::int32_t precision) {
+ auto h = calc_hash(val, scale, precision);
+
+ m_state = hash32(m_state, h);
+}
+} // namespace ignite::detail
\ No newline at end of file
diff --git a/modules/platforms/cpp/ignite/common/detail/hash_calculator.h
b/modules/platforms/cpp/ignite/common/detail/hash_calculator.h
new file mode 100644
index 00000000000..80a2d64b721
--- /dev/null
+++ b/modules/platforms/cpp/ignite/common/detail/hash_calculator.h
@@ -0,0 +1,60 @@
+// 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.
+//
+
+//
+
+#pragma once
+
+#include "primitive.h"
+
+namespace ignite::detail {
+
+/**
+ * Calculator of hashes for all basic types.
+ */
+class hash_calculator {
+public:
+ /**
+ * Calculates hash.
+ * @param val Value of basic type.
+ * @param scale Scale applies to some types (e.g. big_decimal), value
ignored by other types.
+ * @param precision Precision applies to some type (e.g. ignite_time)
value ignored by other types.
+ * @return Hash value.
+ */
+ static std::int32_t calc_hash(const primitive& val, std::int32_t scale,
std::int32_t precision);
+
+ /**
+ * Appends hash of provided value into internal state.
+ * @param val Value of basic type.
+ * @param scale Scale applies to some types (e.g. big_decimal), value
ignored by other types.
+ * @param precision Precision applies to some type (e.g. ignite_time)
value ignored by other types.
+ */
+ void append(const primitive& val, std::int32_t scale, std::int32_t
precision);
+
+ /**
+ * Retrieves accumulated hash from internal state.
+ * @return hash from internal state.
+ */
+ [[nodiscard]] std::int32_t result_hash() const {
+ return m_state;
+ }
+
+private:
+ /** Internal state. */
+ std::int32_t m_state{0};
+};
+
+} // namespace ignite::detail
diff --git a/modules/platforms/cpp/ignite/common/detail/hash_utils.cpp
b/modules/platforms/cpp/ignite/common/detail/hash_utils.cpp
new file mode 100644
index 00000000000..04648f5aa24
--- /dev/null
+++ b/modules/platforms/cpp/ignite/common/detail/hash_utils.cpp
@@ -0,0 +1,131 @@
+// 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.
+//
+
+//
+
+#include "hash_utils.h"
+#include "utils.h"
+
+namespace ignite::detail {
+
+std::int32_t hash(bool val) {
+ return hash32<std::uint8_t>(val ? 1 : 0);
+}
+
+std::int32_t hash(std::int8_t val) {
+ return hash32(val);
+}
+
+std::int32_t hash(std::uint8_t val) {
+ return hash32(val);
+}
+
+std::int32_t hash(std::int16_t val) {
+ return hash32(val);
+}
+
+std::int32_t hash(std::uint16_t val) {
+ return hash32(val);
+}
+
+std::int32_t hash(std::int32_t val) {
+ return hash32(val);
+}
+
+std::int32_t hash(std::uint32_t val) {
+ return hash32(val);
+}
+
+std::int32_t hash(std::int64_t val) {
+ return hash32(val);
+}
+
+std::int32_t hash(std::uint64_t val) {
+ return hash32(val);
+}
+
+std::int32_t hash(float val) {
+ std::uint32_t v;
+
+ static_assert(sizeof(v) == sizeof(val));
+
+ std::memcpy(&v, &val, sizeof(val));
+
+ return hash32(v);
+}
+
+std::int32_t hash(double val) {
+ std::uint64_t v;
+
+ static_assert(sizeof(v) == sizeof(val));
+
+ std::memcpy(&v, &val, sizeof(val));
+
+ return hash32(v);
+}
+
+std::int32_t hash(const big_decimal &val, std::int16_t scale) {
+ big_decimal copy;
+ val.set_scale(scale, copy, big_decimal::rounding_mode::HALF_UP);
+
+ // TODO IGNITE-28278 optimize unnecessary allocation
+ auto bytes = copy.get_unscaled_value().to_bytes();
+
+ return hash32(bytes.data(), bytes.size(), 0);
+}
+
+std::int32_t hash(const uuid &val) {
+ return hash32(val.get_least_significant_bits(),
hash32(val.get_most_significant_bits()));
+}
+
+std::int32_t hash(const ignite_date &val) {
+ auto h_year = hash32(val.get_year());
+ auto h_month = hash32<uint32_t>(val.get_month(), h_year);
+ return hash32<uint32_t>(val.get_day_of_month(), h_month);
+}
+
+std::int32_t hash(const ignite_date_time &val, std::int32_t precision) {
+ auto h_date = hash(val.date());
+ auto h_time = hash(val.time(), precision);
+
+ return hash32(h_date, h_time);
+}
+
+std::int32_t hash(const ignite_time &val, std::int32_t precision) {
+ auto h_hour = hash32<std::uint32_t>(val.get_hour());
+ auto h_min = hash32<std::uint32_t>(val.get_minute(), h_hour);
+ auto h_sec = hash32<std::uint32_t>(val.get_second(), h_min);
+
+ auto norm_nanos = normalize_nanos(val.get_nano(), precision);
+
+ return hash32<std::uint32_t>(norm_nanos, h_sec);
+}
+
+std::int32_t hash(const ignite_timestamp &val, std::int32_t precision) {
+ auto norm_nanos = normalize_nanos(val.get_nano(), precision);
+ auto h_epoch = hash32(val.get_epoch_second());
+
+ return hash32(norm_nanos, h_epoch);
+}
+
+std::int32_t hash(const std::string &val) {
+ return hash32(val.data(), val.length(), 0);
+}
+
+std::int32_t hash(const std::vector<std::byte> &val) {
+ return hash32(val.data(),val.size(), 0);
+}
+} // namespace ignite::detail
\ No newline at end of file
diff --git a/modules/platforms/cpp/ignite/common/detail/hash_utils.h
b/modules/platforms/cpp/ignite/common/detail/hash_utils.h
new file mode 100644
index 00000000000..7c9d81cc7f0
--- /dev/null
+++ b/modules/platforms/cpp/ignite/common/detail/hash_utils.h
@@ -0,0 +1,234 @@
+// 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.
+//
+
+//
+
+#pragma once
+#include "big_decimal.h"
+#include "ignite_date_time.h"
+#include "ignite_time.h"
+#include "ignite_timestamp.h"
+#include "uuid.h"
+
+#include "murmur3_hash.h"
+
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace ignite::detail {
+
+/**
+ * Adapter to original murmur3 hash function
+ * @param key Pointer to begin of data.
+ * @param len Data length
+ * @param seed Seed.
+ * @return Hash value.
+ */
+inline std::uint64_t murmur_original( const void * key, std::size_t len,
std::uint64_t seed) {
+ std::uint64_t res[2];
+ MurmurHash3_x64_128(key, len, seed, res);
+
+ return res[0];
+}
+
+/**
+ * Calculates hash.
+ * @param data Data.
+ * @param seed Seed.
+ * @return Hash value.
+ */
+template<typename T>
+std::uint64_t hash64(T data, std::uint64_t seed) {
+ return murmur_original(&data, sizeof(data), seed);
+}
+
+/**
+ * Calculates hash.
+ * @param data Pointer to begin of data.
+ * @param len Data length.
+ * @param seed Seed.
+ * @return Hash value.
+ */
+inline std::uint64_t hash64(const void *data, size_t len, std::uint64_t seed) {
+ return murmur_original(data, len, seed);
+}
+
+/**
+ * Calculates hash.
+ * @param data Data.
+ * @param seed Seed.
+ * @return Hash value.
+ */
+template<typename T>
+std::int32_t hash32(T data, std::uint64_t seed = 0) {
+ auto hash = hash64<T>(data, seed);
+
+ return static_cast<std::int32_t>(hash ^ hash >> 32);
+}
+
+/**
+ * Calculates hash.
+ * @param data Pointer to begin of data.
+ * @param len Data length.
+ * @param seed Seed.
+ * @return Hash value.
+ */
+inline std::int32_t hash32(const void *data, size_t len, std::uint64_t seed) {
+ auto hash = hash64(data, len, seed);
+
+ return static_cast<std::int32_t>(hash ^ hash >> 32);
+}
+
+/**
+ * Calculation hash of @code bool value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(bool val);
+
+/**
+ * Calculation hash of @code int8_t value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(std::int8_t val);
+
+/**
+ * Calculation hash of @code uint8_t value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(std::uint8_t val);
+
+/**
+ * Calculation hash of @code int16_t value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(std::int16_t val);
+
+/**
+ * Calculation hash of @code uint16_t value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(std::uint16_t val);
+
+/**
+ * Calculation hash of @code int32_t value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(std::int32_t val);
+
+/**
+ * Calculation hash of @code uint32_t value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(std::uint32_t val);
+
+/**
+ * Calculation hash of @code int64_t value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(std::int64_t val);
+
+/**
+ * Calculation hash of @code uint64_t value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(std::uint64_t val);
+
+/**
+ * Calculation hash of @code float value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(float val);
+
+/**
+ * Calculation hash of @code double value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(double val);
+
+/**
+ * Calculation hash of @code ignite::big_decimal value.
+ * @param val Value
+ * @param scale Required scale.
+ * @return Hash.
+ */
+std::int32_t hash(const big_decimal &val, std::int16_t scale);
+
+/**
+ * Calculation hash of @code ignite::uuid value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(const uuid &val);
+
+/**
+ * Calculation hash of @code ignite_date value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(const ignite_date &val);
+
+/**
+ * Calculation hash of @code ignite_date_time value.
+ * @param val Value
+ * @param precision Required precision.
+ * @return Hash.
+ */
+std::int32_t hash(const ignite_date_time &val, std::int32_t precision);
+
+/**
+ * Calculation hash of @code ignite_time value.
+ * @param val Value
+ * @param precision Required precision.
+ * @return Hash.
+ */
+std::int32_t hash(const ignite_time &val, std::int32_t precision);
+
+/**
+ * Calculation hash of @code ignite_timestamp value.
+ * @param val Value
+ * @param precision Required precision.
+ * @return Hash.
+ */
+std::int32_t hash(const ignite_timestamp &val, std::int32_t precision);
+
+/**
+ * Calculation hash of @code std::string value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(const std::string &val);
+
+/**
+ * Calculation hash of @code std::vector<std::byte> value.
+ * @param val Value
+ * @return Hash.
+ */
+std::int32_t hash(const std::vector<std::byte> &val);
+
+} // namespace ignite::detail
\ No newline at end of file
diff --git a/modules/platforms/cpp/ignite/common/detail/hash_utils_test.cpp
b/modules/platforms/cpp/ignite/common/detail/hash_utils_test.cpp
new file mode 100644
index 00000000000..9742e40960b
--- /dev/null
+++ b/modules/platforms/cpp/ignite/common/detail/hash_utils_test.cpp
@@ -0,0 +1,455 @@
+// 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.
+//
+
+#include <ignite/common/detail/hash_utils.h>
+#include <ignite/common/detail/string_extensions.h>
+
+#include <algorithm>
+#define _USE_MATH_DEFINES
+#include <cmath>
+#include <iterator>
+#include <limits>
+
+#include <gtest/gtest.h>
+
+using namespace ignite;
+using namespace ignite::detail;
+
+class hash_utils_bool_test : public ::testing::Test {};
+
+TEST_F(hash_utils_bool_test, true_value) {
+ ASSERT_EQ(-105209210, hash(true));
+}
+
+
+TEST_F(hash_utils_bool_test, false_value) {
+ ASSERT_EQ(686815056, hash(false));
+}
+
+template<typename T>
+struct test_case {
+ T arg;
+ std::int32_t expected;
+};
+
+template<typename T>
+void PrintTo(const test_case<T>& tc, std::ostream* os) {
+ using std::to_string;
+ using ignite::detail::to_string;
+
+ *os << "arg = " << to_string(tc.arg);
+}
+
+class hash_utils_uint8_t_test: public
::testing::TestWithParam<test_case<std::uint8_t>> {};
+
+TEST_P(hash_utils_uint8_t_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_uint8_t_test,
+ ::testing::Values(
+ test_case<uint8_t>{0, 686815056},
+ test_case<uint8_t>{1, -105209210},
+ test_case<uint8_t>{255, -482826348},
+ test_case<uint8_t>{127, -2036967051},
+ test_case<uint8_t>{128, 49585133},
+ test_case<uint8_t>{42, 1990634712}
+ )
+);
+
+class hash_utils_int8_t_test: public
::testing::TestWithParam<test_case<std::int8_t>> {};
+
+TEST_P(hash_utils_int8_t_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_int8_t_test,
+ ::testing::Values(
+ test_case<std::int8_t>{0, 686815056},
+ test_case<std::int8_t>{1, -105209210},
+ test_case<std::int8_t>{-1, -482826348},
+ test_case<std::int8_t>{127, -2036967051},
+ test_case<std::int8_t>{-128, 49585133},
+ test_case<std::int8_t>{42, 1990634712}
+ )
+);
+
+class hash_utils_uint16_t_test: public
::testing::TestWithParam<test_case<std::uint16_t>> {};
+
+TEST_P(hash_utils_uint16_t_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_uint16_t_test,
+ ::testing::Values(
+ test_case<std::uint16_t>{0,1076422130},
+ test_case<std::uint16_t>{1, 1765994081},
+ test_case<std::uint16_t>{std::numeric_limits<std::uint16_t>::max(),
22229479},
+ test_case<std::uint16_t>{42,-461853154}
+ )
+);
+
+class hash_utils_int16_t_test: public
::testing::TestWithParam<test_case<std::int16_t>> {};
+
+TEST_P(hash_utils_int16_t_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_int16_t_test,
+ ::testing::Values(
+ test_case<std::int16_t>{0,1076422130},
+ test_case<std::int16_t>{1, 1765994081},
+ test_case<std::int16_t>{-1, 22229479},
+ test_case<std::int16_t>{std::numeric_limits<std::int16_t>::max(),
-1586500059},
+ test_case<std::int16_t>{std::numeric_limits<std::int16_t>::min(),
-667322922},
+ test_case<std::int16_t>{42,-461853154}
+ )
+);
+
+class hash_utils_uint32_t_test: public
::testing::TestWithParam<test_case<std::uint32_t>> {};
+
+TEST_P(hash_utils_uint32_t_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_uint32_t_test,
+ ::testing::Values(
+ test_case<std::uint32_t>{0,401375585},
+ test_case<std::uint32_t>{1, 666724619},
+ test_case<std::uint32_t>{std::numeric_limits<std::uint32_t>::max(),
2008810410},
+ test_case<std::uint32_t>{42,872512553}
+ )
+);
+
+class hash_utils_int32_t_test: public
::testing::TestWithParam<test_case<std::int32_t>> {};
+
+TEST_P(hash_utils_int32_t_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_int32_t_test,
+ ::testing::Values(
+ test_case<std::int32_t>{0, 401375585},
+ test_case<std::int32_t>{1,666724619},
+ test_case<std::int32_t>{-1,2008810410},
+ test_case<std::int32_t>{std::numeric_limits<std::int32_t>::max(),
-1452754491},
+ test_case<std::int32_t>{std::numeric_limits<std::int32_t>::min(),
694163409},
+ test_case<std::int32_t>{42,872512553}
+ )
+);
+
+class hash_utils_uint64_t_test: public
::testing::TestWithParam<test_case<std::uint64_t>> {};
+
+TEST_P(hash_utils_uint64_t_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_uint64_t_test,
+ ::testing::Values(
+ test_case<std::uint64_t>{0,-460808068},
+ test_case<std::uint64_t>{1, -79575043},
+ test_case<std::uint64_t>{std::numeric_limits<std::uint64_t>::max(),
-1168220407},
+ test_case<std::uint64_t>{42,1065270881}
+ )
+);
+
+class hash_utils_int64_t_test: public
::testing::TestWithParam<test_case<std::int64_t>> {};
+
+TEST_P(hash_utils_int64_t_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_int64_t_test,
+ ::testing::Values(
+ test_case<std::int64_t>{0, -460808068},
+ test_case<std::int64_t>{1,-79575043},
+ test_case<std::int64_t>{-1,-1168220407},
+ test_case<std::int64_t>{std::numeric_limits<std::int64_t>::max(),
-1230994913},
+ test_case<std::int64_t>{std::numeric_limits<std::int64_t>::min(),
-1253265447},
+ test_case<std::int64_t>{42,1065270881}
+ )
+);
+
+class hash_utils_float_test: public ::testing::TestWithParam<test_case<float>>
{};
+
+TEST_P(hash_utils_float_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_float_test,
+ ::testing::Values(
+ test_case<float>{0.0, 401375585},
+ test_case<float>{1.0,-132467364},
+ test_case<float>{-1.0,-2101035902},
+ test_case<float>{std::numeric_limits<float>::max(), 1780074225},
+ test_case<float>{42.0F,1227011061},
+ test_case<float>{float{M_PI},-2142471555}
+ )
+);
+
+class hash_utils_double_test: public
::testing::TestWithParam<test_case<double>> {};
+
+TEST_P(hash_utils_double_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_double_test,
+ ::testing::Values(
+ test_case<double>{0.0, -460808068},
+ test_case<double>{1.0,-2124529649},
+ test_case<double>{-1.0,210701226},
+ test_case<double>{std::numeric_limits<double>::max(), -1921889547},
+ test_case<double>{42.0F,2109601987},
+ test_case<double>{double{M_PI},-521675661}
+ )
+);
+
+class hash_utils_big_decimal_test: public
::testing::TestWithParam<test_case<big_decimal>> {};
+
+TEST_P(hash_utils_big_decimal_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg, 10));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_big_decimal_test,
+ ::testing::Values(
+ test_case<big_decimal>{big_decimal{0}, 686815056},
+ test_case<big_decimal>{big_decimal{1},904832652},
+ test_case<big_decimal>{big_decimal{-1},-1497790521},
+ test_case<big_decimal>{big_decimal{42},1347451647},
+ test_case<big_decimal>{big_decimal::from_double(M_PI),572053262},
+ test_case<big_decimal>{big_decimal::from_double(M_PI*-1),-2078930604}
+ )
+);
+
+class hash_utils_uuid_test: public ::testing::TestWithParam<test_case<uuid>>
{};
+
+TEST_P(hash_utils_uuid_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_uuid_test,
+ ::testing::Values(
+ test_case<uuid>{uuid{0,0}, -177475040},
+ test_case<uuid>{uuid{420000042, 420042}, -2034825191}
+ )
+);
+
+class hash_utils_date_test: public
::testing::TestWithParam<test_case<ignite_date>> {};
+
+TEST_P(hash_utils_date_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_date_test,
+ ::testing::Values(
+ test_case<ignite_date>{ignite_date{1970, 1, 1}, -1730003579},
+ test_case<ignite_date>{ignite_date{1905, 9, 26}, -1268080282},
+ test_case<ignite_date>{ignite_date{2036, 3, 17}, 435798353}
+ )
+);
+
+class hash_utils_time_test: public
::testing::TestWithParam<test_case<ignite_time>> {};
+
+TEST_P(hash_utils_time_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg, 5));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_time_test,
+ ::testing::Values(
+ test_case<ignite_time>{ignite_time{0, 0}, -1321305871},
+ test_case<ignite_time>{ignite_time{0,0, 1}, -975644488},
+ test_case<ignite_time>{ignite_time{0, 0, 0, 1}, -1321305871},
+ test_case<ignite_time>{ignite_time{0, 0, 0, 10'000}, -1417871408},
+ test_case<ignite_time>{ignite_time{0, 0, 0, 10'001}, -1417871408},
+ test_case<ignite_time>{ignite_time{19, 42, 21, 42'042}, 57055814}
+ )
+);
+
+class hash_utils_date_time_test: public
::testing::TestWithParam<test_case<ignite_date_time>> {};
+
+TEST_P(hash_utils_date_time_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg, 5));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_date_time_test,
+ ::testing::Values(
+ test_case<ignite_date_time>{ignite_date_time{{1970, 1, 1}, {0,0}},
-986160737},
+ test_case<ignite_date_time>{ignite_date_time{{1905, 9, 26}, {19, 42,
21}}, -1487071575},
+ test_case<ignite_date_time>{ignite_date_time{{2036, 3, 17}, {21, 21,
21, 12'000}}, 1007809846},
+ test_case<ignite_date_time>{ignite_date_time{{2036, 3, 17}, {21, 21,
21, 12'001}}, 1007809846}
+ )
+);
+
+class hash_utils_timestamp_test: public
::testing::TestWithParam<test_case<ignite_timestamp>> {};
+
+TEST_P(hash_utils_timestamp_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg, 5));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_timestamp_test,
+ ::testing::Values(
+ test_case<ignite_timestamp>{{0,0}, -1028348915},
+ test_case<ignite_timestamp>{{0, 420'000}, 789406184},
+ test_case<ignite_timestamp>{{1773221571, 21'123}, 670786278},
+ test_case<ignite_timestamp>{{1773221571, 21'000}, 670786278}
+ )
+);
+
+
+template<>
+void PrintTo(const test_case<std::string>& tc, std::ostream* os) {
+ *os << "arg = " << tc.arg;
+}
+
+class hash_utils_string_test: public
::testing::TestWithParam<test_case<std::string>> {};
+
+TEST_P(hash_utils_string_test, simple) {
+ auto param = GetParam();
+
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_string_test,
+ ::testing::Values(
+ test_case<std::string>{"", 0},
+ test_case<std::string>{" ", -2039187927},
+ test_case<std::string>{"foo", -477838538},
+ test_case<std::string>{"foo ", 1516292748},
+ test_case<std::string>{" foo", -1406774036},
+ test_case<std::string>{"Foo", 2010420341},
+ test_case<std::string>{"bar", 1863106271},
+ test_case<std::string>{"baR", -1753335891},
+ test_case<std::string>{"the quick brown fox jumped over the lazy dog",
1452923692},
+ test_case<std::string>{"Карл у Клары украл кораллы", -1909478343}
+ )
+);
+
+
+template<>
+void PrintTo(const test_case<std::vector<std::byte>>& tc, std::ostream* os) {
+ *os << "arg = " << "[";
+ *os << std::hex;
+ for (auto b : tc.arg) {
+ *os << "0x" << static_cast<uint32_t>(b) << ",";
+ }
+
+ *os << "]";
+}
+
+class hash_utils_bytes_test: public
::testing::TestWithParam<test_case<std::vector<std::byte>>> {};
+
+TEST_P(hash_utils_bytes_test, simple) {
+ auto param = GetParam();
+ ASSERT_EQ(param.expected, hash(param.arg));
+}
+
+std::vector<std::byte> from_ints(std::vector<int> ints) {
+ std::vector<std::byte> res;
+ res.reserve(ints.size());
+
+ std::transform(
+ ints.begin(),
+ ints.end(),
+ std::back_inserter(res),
+ [](int src) {
+ return static_cast<std::byte>(src);
+ }
+ );
+
+ return res;
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ simple,
+ hash_utils_bytes_test,
+ ::testing::Values(
+ test_case<std::vector<std::byte>>{{},0},
+ test_case<std::vector<std::byte>>{from_ints({1,2,3}),343345478},
+ test_case<std::vector<std::byte>>{from_ints({3,2,1}),-1822332709},
+ test_case<std::vector<std::byte>>{from_ints({42,42,42}),246686034},
+ test_case<std::vector<std::byte>>{from_ints({-1,1}),-1645252459},
+ test_case<std::vector<std::byte>>{std::vector(4,
std::byte{0}),401375585},
+ test_case<std::vector<std::byte>>{std::vector(5,
std::byte{0}),65263045},
+ test_case<std::vector<std::byte>>{std::vector(8,
std::byte{0}),-460808068},
+ test_case<std::vector<std::byte>>{std::vector(1000,
std::byte{0x20}),838145700}
+ )
+);
\ No newline at end of file
diff --git a/modules/platforms/cpp/ignite/common/detail/murmur3_hash.cpp
b/modules/platforms/cpp/ignite/common/detail/murmur3_hash.cpp
new file mode 100644
index 00000000000..72df941ff8e
--- /dev/null
+++ b/modules/platforms/cpp/ignite/common/detail/murmur3_hash.cpp
@@ -0,0 +1,176 @@
+// 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.
+//
+
+#include "bytes.h"
+#include "murmur3_hash.h"
+
+//-----------------------------------------------------------------------------
+// MurmurHash3 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code.
+
+// Note - The x86 and x64 versions do _not_ produce the same results, as the
+// algorithms are optimized for their respective platforms. You can still
+// compile and run any of them on any platform, but your performance with the
+// non-native version will be less than optimal.
+
+#if defined(_MSC_VER)
+
+#define FORCE_INLINE __forceinline
+
+#include <stdlib.h>
+
+#define ROTL32(x,y) _rotl(x,y)
+#define ROTL64(x,y) _rotl64(x,y)
+
+#define BIG_CONSTANT(x) (x)
+
+// Other compilers
+
+#else // defined(_MSC_VER)
+
+#define FORCE_INLINE inline __attribute__((always_inline))
+
+inline uint32_t rotl32 ( uint32_t x, int8_t r )
+{
+ return (x << r) | (x >> (32 - r));
+}
+
+inline uint64_t rotl64 ( uint64_t x, int8_t r )
+{
+ return (x << r) | (x >> (64 - r));
+}
+
+#define ROTL32(x,y) rotl32(x,y)
+#define ROTL64(x,y) rotl64(x,y)
+
+#define BIG_CONSTANT(x) (x##LLU)
+
+#endif // !defined(_MSC_VER)
+
+//-----------------------------------------------------------------------------
+// Block read - if your platform needs to do endian-swapping or can only
+// handle aligned reads, do the conversion here
+
+FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, int i )
+{
+ return ignite::detail::bytes::htol<std::uint64_t>(p[i]);
+}
+
+//-----------------------------------------------------------------------------
+// Finalization mix - force all bits of a hash block to avalanche
+
+FORCE_INLINE uint32_t fmix32 ( uint32_t h )
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+
+ return h;
+}
+
+//----------
+
+FORCE_INLINE uint64_t fmix64 ( uint64_t k )
+{
+ k ^= k >> 33;
+ k *= BIG_CONSTANT(0xff51afd7ed558ccd);
+ k ^= k >> 33;
+ k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
+ k ^= k >> 33;
+
+ return k;
+}
+
+void MurmurHash3_x64_128 ( const void * key, std::size_t len,
+ const uint64_t seed, void * out )
+{
+ const uint8_t * data = (const uint8_t*)key;
+ const int nblocks = len / 16;
+
+ uint64_t h1 = seed;
+ uint64_t h2 = seed;
+
+ const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
+ const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
+
+ //----------
+ // body
+
+ const uint64_t * blocks = (const uint64_t *)(data);
+
+ for(int i = 0; i < nblocks; i++)
+ {
+ uint64_t k1 = getblock64(blocks,i*2+0);
+ uint64_t k2 = getblock64(blocks,i*2+1);
+
+ k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
+
+ h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
+
+ k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
+
+ h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
+ }
+
+ //----------
+ // tail
+
+ const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
+
+ uint64_t k1 = 0;
+ uint64_t k2 = 0;
+
+ switch(len & 15)
+ {
+ case 15: k2 ^= ((uint64_t)tail[14]) << 48; [[fallthrough]];
+ case 14: k2 ^= ((uint64_t)tail[13]) << 40; [[fallthrough]];
+ case 13: k2 ^= ((uint64_t)tail[12]) << 32; [[fallthrough]];
+ case 12: k2 ^= ((uint64_t)tail[11]) << 24; [[fallthrough]];
+ case 11: k2 ^= ((uint64_t)tail[10]) << 16; [[fallthrough]];
+ case 10: k2 ^= ((uint64_t)tail[ 9]) << 8; [[fallthrough]];
+ case 9: k2 ^= ((uint64_t)tail[ 8]) << 0;
+ k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
+ [[fallthrough]];
+ case 8: k1 ^= ((uint64_t)tail[ 7]) << 56; [[fallthrough]];
+ case 7: k1 ^= ((uint64_t)tail[ 6]) << 48; [[fallthrough]];
+ case 6: k1 ^= ((uint64_t)tail[ 5]) << 40; [[fallthrough]];
+ case 5: k1 ^= ((uint64_t)tail[ 4]) << 32; [[fallthrough]];
+ case 4: k1 ^= ((uint64_t)tail[ 3]) << 24; [[fallthrough]];
+ case 3: k1 ^= ((uint64_t)tail[ 2]) << 16; [[fallthrough]];
+ case 2: k1 ^= ((uint64_t)tail[ 1]) << 8; [[fallthrough]];
+ case 1: k1 ^= ((uint64_t)tail[ 0]) << 0;
+ k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
+ };
+
+ //----------
+ // finalization
+
+ h1 ^= len; h2 ^= len;
+
+ h1 += h2;
+ h2 += h1;
+
+ h1 = fmix64(h1);
+ h2 = fmix64(h2);
+
+ h1 += h2;
+ h2 += h1;
+
+ ((uint64_t*)out)[0] = h1;
+ ((uint64_t*)out)[1] = h2;
+}
diff --git a/modules/platforms/cpp/ignite/common/detail/murmur3_hash.h
b/modules/platforms/cpp/ignite/common/detail/murmur3_hash.h
new file mode 100644
index 00000000000..03f174de1c1
--- /dev/null
+++ b/modules/platforms/cpp/ignite/common/detail/murmur3_hash.h
@@ -0,0 +1,22 @@
+// 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.
+//
+
+#pragma once
+#include <cstdint>
+#include <cstddef>
+
+void MurmurHash3_x64_128 ( const void * key, std::size_t len,
+ std::uint64_t seed, void * out );
\ No newline at end of file
diff --git a/modules/platforms/cpp/ignite/common/detail/string_extensions.cpp
b/modules/platforms/cpp/ignite/common/detail/string_extensions.cpp
new file mode 100644
index 00000000000..b3da28ccff4
--- /dev/null
+++ b/modules/platforms/cpp/ignite/common/detail/string_extensions.cpp
@@ -0,0 +1,83 @@
+// 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.
+//
+
+#include "string_extensions.h"
+
+#include <sstream>
+#include <iomanip>
+
+namespace ignite::detail {
+
+std::string to_string(const big_decimal &bd) {
+ std::stringstream ss;
+ ss << bd;
+
+ return ss.str();
+}
+
+std::string to_string(const uuid& uuid) {
+ std::stringstream ss;
+
+ ss << uuid;
+
+ return ss.str();
+}
+
+std::string to_string(const ignite_date &date) {
+ std::stringstream ss;
+
+ ss << date.get_year()
+ << '-'
+ << std::setfill('0') << std::setw(2) << std::to_string(date.get_month())
+ << '-'
+ << std::setfill('0') << std::setw(2) <<
std::to_string(date.get_day_of_month());
+
+ return ss.str();
+}
+
+std::string to_string(const ignite_time &time) {
+ std::stringstream ss;
+
+ ss << std::setfill('0') << std::setw(2) << std::to_string(time.get_hour())
+ << ':'
+ << std::setfill('0') << std::setw(2) <<
std::to_string(time.get_minute())
+ << ':'
+ << std::setfill('0') << std::setw(2) <<
std::to_string(time.get_second())
+ << '.'
+ << std::setfill('0') << std::setw(9) << std::to_string(time.get_nano());
+
+ return ss.str();
+}
+
+std::string to_string(const ignite_date_time &dt) {
+ std::stringstream ss;
+
+ ss << to_string(dt.date()) << 'T' << to_string(dt.time());
+
+ return ss.str();
+}
+
+std::string to_string(const ignite_timestamp &ts) {
+ std::stringstream ss;
+
+ ss << std::to_string(ts.get_epoch_second())
+ << '.'
+ << std::setfill('0') << std::setw(9) << std::to_string(ts.get_nano());
+
+ return ss.str();
+}
+
+} // namespace ignite::detail
\ No newline at end of file
diff --git a/modules/platforms/cpp/ignite/common/detail/string_extensions.h
b/modules/platforms/cpp/ignite/common/detail/string_extensions.h
new file mode 100644
index 00000000000..9c341828559
--- /dev/null
+++ b/modules/platforms/cpp/ignite/common/detail/string_extensions.h
@@ -0,0 +1,43 @@
+// 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.
+//
+
+#pragma once
+
+#include <big_decimal.h>
+#include <ignite_date.h>
+#include <ignite_date_time.h>
+#include <ignite_time.h>
+#include <ignite_timestamp.h>
+#include <uuid.h>
+
+#include <string>
+
+// TODO IGNITE-28196 functions should be moved to header files for
corresponding types.
+namespace ignite::detail {
+
+std::string to_string(const big_decimal &bd);
+
+std::string to_string(const uuid &uuid);
+
+std::string to_string(const ignite_date &date);
+
+std::string to_string(const ignite_time &time);
+
+std::string to_string(const ignite_date_time &dt);
+
+std::string to_string(const ignite_timestamp &ts);
+
+} // namespace ignite::detail
\ No newline at end of file
diff --git a/modules/platforms/cpp/ignite/common/detail/utils.h
b/modules/platforms/cpp/ignite/common/detail/utils.h
index f044346a9a5..ffc61ca09ac 100644
--- a/modules/platforms/cpp/ignite/common/detail/utils.h
+++ b/modules/platforms/cpp/ignite/common/detail/utils.h
@@ -17,7 +17,7 @@
#pragma once
-#include <ignite/common/ignite_error.h>
+#include <ignite_error.h>
#include <future>
#include <memory>
@@ -71,4 +71,37 @@ inline std::optional<std::string> get_env(const std::string
&name) {
return env;
}
+/**
+ * Normalizes nanosecond portion of temporal type according to chosen
precision.
+ *
+ * @param nanos Nanoseconds.
+ * @param precision Precision, 0 means one-second precision 9 means nanosecond
precision.
+ * @return Truncated nanoseconds.
+ */
+inline std::int_least32_t normalize_nanos(std::int32_t nanos, std::int32_t
precision) {
+ switch (precision) {
+ case 0:
+ return 0;
+ case 1:
+ return nanos / 100'000'000 * 100'000'000; // 100ms precision
+ case 2:
+ return nanos / 10'000'000 * 10'000'000; // 10ms precision
+ case 3:
+ return nanos / 1'000'000 * 1'000'000; // 1ms precision
+ case 4:
+ return nanos / 100'000 * 100'000; // 100us precision
+ case 5:
+ return nanos / 10'000 * 10'000; // 10us precision
+ case 6:
+ return nanos / 1'000 * 1'000; // 1us precision
+ case 7:
+ return nanos / 100 * 100; // 100ns precision
+ case 8:
+ return nanos / 10 * 10; // 10ns precision
+ case 9:
+ default:
+ return nanos; // 1ns precision
+ }
+}
+
} // namespace ignite::detail
diff --git a/modules/platforms/cpp/ignite/common/ignite_time.h
b/modules/platforms/cpp/ignite/common/ignite_time.h
index b6df81b603c..13df3713807 100644
--- a/modules/platforms/cpp/ignite/common/ignite_time.h
+++ b/modules/platforms/cpp/ignite/common/ignite_time.h
@@ -18,6 +18,7 @@
#pragma once
#include <cstdint>
+#include <stdexcept>
namespace ignite {