Copilot commented on code in PR #7750:
URL: https://github.com/apache/ignite-3/pull/7750#discussion_r2918133259


##########
modules/platforms/cpp/ignite/common/detail/hash_utils.h:
##########
@@ -0,0 +1,120 @@
+// 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 "Murmur3Hash.h"
+
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace ignite::detail {
+constexpr std::uint64_t C1 = 0x87'C3'7B'91'11'42'53'D5L;
+constexpr std::uint64_t C2 = 0x4C'F5'AD'43'27'45'93'7FL;
+constexpr int R1 = 31;
+constexpr int R2 = 27;
+constexpr int R3 = 33;
+constexpr int M = 5;
+constexpr int N1 = 0x52dce729;
+constexpr int N2 = 0x38495ab5;
+
+inline std::uint64_t murmur_original( const void * key, const int len, 
std::uint64_t seed) {
+    std::uint64_t res[2];
+    MurmurHash3_x64_128(key, len, seed, res);
+
+    return res[0];
+}
+
+inline std::uint64_t hash64(std::int8_t data, std::uint64_t seed) {
+
+    return murmur_original(&data, sizeof(data), seed);
+}
+
+inline std::uint64_t hash64(std::uint8_t data, std::uint64_t seed) {
+    return murmur_original(&data, sizeof(data), seed);
+}
+
+inline std::uint64_t hash64(std::int16_t data, std::uint64_t seed) {
+    return murmur_original(&data, sizeof(data), seed);
+}
+
+inline std::uint64_t hash64(std::uint16_t data, std::uint64_t seed) {
+    return murmur_original(&data, sizeof(data), seed);
+}
+
+inline std::uint64_t hash64(std::int32_t data, std::uint64_t seed) {
+    return murmur_original(&data, sizeof(data), seed);
+}
+
+inline std::uint64_t hash64(std::uint32_t data, std::uint64_t seed) {
+    return murmur_original(&data, sizeof(data), seed);
+}
+
+inline std::uint64_t hash64(std::int64_t data, std::uint64_t seed) {
+    return murmur_original(&data, sizeof(data), seed);
+}
+
+inline std::uint64_t hash64(std::uint64_t data, std::uint64_t seed) {
+    return murmur_original(&data, sizeof(data), seed);
+}
+
+inline std::uint64_t hash64(const std::uint8_t *data, size_t off, size_t len, 
std::uint64_t seed) {
+    return murmur_original(data + off, len, seed);
+}

Review Comment:
   `hash64(const std::uint8_t*, size_t, size_t, ...)` forwards `len` (a 
`size_t`) into `murmur_original(..., const int len, ...)` via implicit 
conversion. For large strings/byte arrays this can truncate/overflow `int` and 
produce incorrect hashes or UB. Consider changing 
`murmur_original`/`MurmurHash3_x64_128` wrapper to accept `size_t` and 
explicitly validate/cast to `int` only after checking `len <= INT_MAX`.



##########
modules/platforms/cpp/ignite/common/detail/hash_utils.h:
##########
@@ -0,0 +1,120 @@
+// 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 "Murmur3Hash.h"
+
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace ignite::detail {
+constexpr std::uint64_t C1 = 0x87'C3'7B'91'11'42'53'D5L;
+constexpr std::uint64_t C2 = 0x4C'F5'AD'43'27'45'93'7FL;

Review Comment:
   `C1`/`C2` are declared as `std::uint64_t` but the literals use the `L` 
suffix. On LLP64 platforms (e.g., MSVC) `long` is 32-bit, so these literals are 
ill-formed and can fail compilation. Use a 64-bit suffix (`ULL`) / 
`UINT64_C(...)`, or drop the suffix entirely.
   ```suggestion
   constexpr std::uint64_t C1 = UINT64_C(0x87'C3'7B'91'11'42'53'D5);
   constexpr std::uint64_t C2 = UINT64_C(0x4C'F5'AD'43'27'45'93'7F);
   ```



##########
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>());

Review Comment:
   In the `DATETIME` branch, `hash(val.get<ignite_date_time>())` calls 
`hash(...)` without the required `precision` argument. `hash_utils.h` only 
declares `hash(const ignite_date_time&, std::int32_t precision)`, so this does 
not compile. Pass `precision` here (or add the missing overload if intentional).
   ```suggestion
               return hash(val.get<ignite_date_time>(), precision);
   ```



##########
modules/platforms/cpp/ignite/common/primitive_test.cpp:
##########
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+#include "detail/hash_calculator.h"
+#include "ignite/client/table/ignite_tuple.h"
 #include "ignite/common/primitive.h"

Review Comment:
   `primitive_test.cpp` adds `detail/hash_calculator.h` and `ignite_tuple.h` 
includes, but neither is referenced anywhere in this file (search shows only 
the include lines). Please remove these unused includes to avoid unnecessary 
dependencies and extra compile time.



##########
modules/platforms/cpp/ignite/common/ignite_time.h:
##########
@@ -162,4 +163,32 @@ constexpr bool operator>=(const ignite_time &lhs, const 
ignite_time &rhs) noexce
     return lhs.compare(rhs) >= 0;
 }
 
+
+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:
+            return nanos; // 1ns precision
+        default:
+            throw std::runtime_error("Unsupported fractional seconds 
precision: " + std::to_string(precision));
+    }

Review Comment:
   `normalize_nanos` throws `std::runtime_error` from a public common header. 
The rest of this module consistently throws `ignite_error` for invalid input 
(e.g., `detail/string_utils.cpp`), so this introduces an inconsistent exception 
type and message format. Consider switching this to `ignite_error` (or 
validating `precision` at the call site and making `normalize_nanos` 
non-throwing).



##########
modules/platforms/cpp/ignite/common/ignite_time.h:
##########
@@ -18,6 +18,7 @@
 #pragma once
 
 #include <cstdint>
+#include <stdexcept>

Review Comment:
   `ignite_time.h` now calls `std::to_string(precision)` inside 
`normalize_nanos`, but the header does not include `<string>`. Please add the 
missing standard header so this file is self-contained and doesn't rely on 
indirect includes.
   ```suggestion
   #include <stdexcept>
   #include <string>
   ```



##########
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>());
+        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,

Review Comment:
   The default branch throws `ignite_error(error::code::INTERNAL, "")` with an 
empty message. Please provide a non-empty message that includes the unsupported 
`ignite_type` value to make debugging easier if this is ever hit.



##########
modules/platforms/cpp/ignite/common/detail/hash_utils_test.cpp:
##########
@@ -0,0 +1,451 @@
+// 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 <cmath>
+
+#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}

Review Comment:
   This test instantiation contains commented-out test cases and a trailing 
`//,` marker. Please either enable these cases (if they are valid) or remove 
the commented code to keep the test suite clean and avoid leaving 
dead/ambiguous expectations in the codebase.
   ```suggestion
           test_case<ignite_date>{ignite_date{1970, 1, 1}, -1730003579}
   ```



##########
modules/platforms/cpp/ignite/common/detail/hash_utils_test.cpp:
##########
@@ -0,0 +1,451 @@
+// 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 <cmath>
+
+#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 << "Ox" << static_cast<uint32_t>(b) << ",";

Review Comment:
   `PrintTo` for byte vectors prints the hex prefix as `"Ox"`, which looks like 
a typo and makes the output confusing. Use the conventional `"0x"` prefix 
instead.
   ```suggestion
            *os << "0x" << static_cast<uint32_t>(b) << ",";
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to