github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/query/algorithm_unittest.cu (about)

     1  //  Copyright (c) 2017-2018 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <thrust/transform.h>
    16  #include <cstdint>
    17  #include <cfloat>
    18  #include <algorithm>
    19  #include <cmath>
    20  #include <exception>
    21  #include <iterator>
    22  #include <iostream>
    23  #include <type_traits>
    24  #include "gtest/gtest.h"
    25  #include "query/algorithm.hpp"
    26  #include "query/iterator.hpp"
    27  #include "query/time_series_aggregate.h"
    28  #include "query/transform.hpp"
    29  #include "query/unittest_utils.hpp"
    30  
    31  namespace ares {
    32  
    33  template<typename TypeA, typename TypeB, typename ExpectedType>
    34  void checkCommonTypeAsExpected() {
    35    bool isSame = std::is_same<typename common_type<TypeA, TypeB>::type,
    36                               ExpectedType>::value;
    37    EXPECT_TRUE(isSame);
    38  }
    39  
    40  // cppcheck-suppress *
    41  TEST(CommonTypeTraitsTest, CheckCommonType) {
    42    checkCommonTypeAsExpected<float_t, float_t, float_t>();
    43    checkCommonTypeAsExpected<int16_t, float_t, float_t>();
    44    checkCommonTypeAsExpected<float_t, float_t, float_t>();
    45    checkCommonTypeAsExpected<float_t, uint32_t, float_t>();
    46    checkCommonTypeAsExpected<int16_t, uint32_t, int32_t>();
    47    checkCommonTypeAsExpected<int32_t, uint32_t, int32_t>();
    48    checkCommonTypeAsExpected<int32_t, bool, int32_t>();
    49    checkCommonTypeAsExpected<uint32_t, bool, uint32_t>();
    50    checkCommonTypeAsExpected<uint16_t, bool, uint32_t>();
    51  }
    52  
    53  // cppcheck-suppress *
    54  TEST(CGoCallResHandleTest, CheckCGoCallResHandle) {
    55    CGoCallResHandle resHandle = {0, nullptr};
    56    try {
    57      throw std::invalid_argument("test");
    58    }
    59    catch (std::exception &e) {
    60      resHandle.pStrErr = strdup(e.what());
    61    }
    62  
    63    EXPECT_STREQ(resHandle.pStrErr, "test");
    64    EXPECT_TRUE(resHandle.pStrErr != nullptr);
    65    free(const_cast<char *>(resHandle.pStrErr));
    66    CGoCallResHandle resHandle2 = {0, nullptr};
    67    try {
    68      printf("test CGoCallResHandle\n");
    69    }
    70    catch (std::exception &e) {
    71      resHandle2.pStrErr = strdup(e.what());
    72    }
    73  
    74    EXPECT_TRUE(resHandle2.pStrErr == nullptr);
    75  }
    76  
    77  // cppcheck-suppress *
    78  TEST(UnaryTransformTest, CheckInt) {
    79    const int size = 3;
    80    uint32_t indexVectorH[size * 2] = {0, 1, 2};
    81    int inputValuesH[size] = {-1, 1, 0};
    82    // T T F
    83    uint8_t inputNullsH[1 + ((size - 1) / 8)] = {0x03};
    84  
    85    int outputValuesH[size] = {0, 0, 0};
    86    bool outputNullsH[size] = {false, false, false};
    87  
    88    uint32_t *indexVector = allocate(&indexVectorH[0], size * 2);
    89    uint8_t *basePtr =
    90        allocate_column(nullptr, &inputNullsH[0], &inputValuesH[0], 0, 1, 12);
    91  
    92    uint8_t *outputBasePtr =
    93        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]),
    94                        &outputNullsH[0], 0, 12, 3);
    95  
    96    DefaultValue defaultValue = {false, {.Int32Val = 0}};
    97    VectorPartySlice inputVP = {basePtr, 0, 8, 0, Int32, defaultValue};
    98  
    99    ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Int32};
   100  
   101    InputVector input = {{.VP = inputVP}, VectorPartyInput};
   102    OutputVector output =
   103        {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput};
   104  
   105    UnaryTransform(input, output, indexVector, size, nullptr, 0,
   106                   Negate, 0, 0);
   107  
   108    int expectedValues[size] = {1, -1, 0};
   109    bool expectedNulls[size] = {true, true, false};
   110    int *outputValues = reinterpret_cast<int *>(outputBasePtr);
   111    bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16;
   112    EXPECT_TRUE(
   113        equal(outputValues, outputValues + size,
   114              &expectedValues[0]));
   115  
   116    EXPECT_TRUE(
   117        equal(outputNulls, outputNulls + size,
   118              &expectedNulls[0]));
   119  
   120    release(basePtr);
   121    release(outputBasePtr);
   122    release(indexVector);
   123  }
   124  
   125  // cppcheck-suppress *
   126  TEST(UnaryTransformTest, CheckConstant) {
   127    const int size = 3;
   128    uint32_t indexVectorH[size * 2] = {0, 1, 2};
   129    ConstantVector constant = {
   130        {.IntVal = 1}, true, ConstInt,
   131    };
   132  
   133    int outputValuesH[size] = {0, 0, 0};
   134    bool outputNullsH[size] = {false, false, false};
   135  
   136    uint32_t *indexVector = allocate(&indexVectorH[0], size * 2);
   137  
   138    uint8_t *outputBasePtr =
   139        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]),
   140                        &outputNullsH[0], 0, 12, 3);
   141    ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Int32};
   142  
   143    InputVector input = {{.Constant = constant}, ConstantInput};
   144    OutputVector output =
   145        {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput};
   146  
   147    UnaryTransform(input, output, &indexVector[0], size, nullptr, 0,
   148                   Negate, 0, 0);
   149    int expectedValues[3] = {-1, -1, -1};
   150    bool expectedNulls[3] = {true, true, true};
   151    int *outputValues = reinterpret_cast<int *>(outputBasePtr);
   152    bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16;
   153    EXPECT_TRUE(
   154        equal(outputValues, outputValues + size,
   155              &expectedValues[0]));
   156  
   157    EXPECT_TRUE(
   158        equal(outputNulls, outputNulls + size,
   159              &expectedNulls[0]));
   160  
   161    release(outputBasePtr);
   162    release(indexVector);
   163  }
   164  
   165  // cppcheck-suppress *
   166  TEST(UnaryTransformTest, CheckMeasureOutputIteratorForAvg) {
   167    const int size = 3;
   168    uint32_t indexVectorH[size * 2] = {0, 1, 2};
   169    uint32_t baseCountsH[size + 1] = {0, 3, 9, 12};
   170    int inputValuesH[size] = {-1, 1, 0};
   171    // T T F
   172    uint8_t inputNullsH[1 + ((size - 1) / 8)] = {0x03};
   173  
   174    int64_t outputValuesH[size] = {0, 0, 0};
   175  
   176    uint32_t *indexVector = allocate(&indexVectorH[0], size * 2);
   177    uint32_t *baseCounts = allocate(&baseCountsH[0], size + 1);
   178    uint8_t *basePtr =
   179        allocate_column(nullptr, &inputNullsH[0], &inputValuesH[0], 0, 1, 12);
   180    int64_t *outputValues = allocate(&outputValuesH[0], size);
   181  
   182    DefaultValue defaultValue = {false, {.Int32Val = 0}};
   183    VectorPartySlice inputVP = {basePtr, 0, 8, 0, Int32, defaultValue};
   184  
   185    MeasureOutputVector outputMeasure = {
   186        reinterpret_cast<uint32_t *>(outputValues), Int64,
   187        AGGR_SUM_SIGNED};
   188  
   189    InputVector input = {{.VP = inputVP}, VectorPartyInput};
   190    OutputVector output = {{.Measure = outputMeasure}, MeasureOutput};
   191  
   192    UnaryTransform(input, output, indexVector, size, baseCounts, 0,
   193                   Negate, 0, 0);
   194    int64_t expectedValues[3] = {3, -6, 0};
   195    EXPECT_TRUE(equal(outputValues, outputValues + size,
   196                      &expectedValues[0]));
   197  
   198    // Test NOOP functor
   199    UnaryTransform(input, output, indexVector, size, baseCounts, 0,
   200                   Noop, 0, 0);
   201    int64_t expectedValues2[3] = {-3, 6, 0};
   202    EXPECT_TRUE(equal(outputValues, outputValues + size,
   203                      &expectedValues2[0]));
   204  
   205    // Test avg aggregation.
   206    MeasureOutputVector outputMeasure2 = {
   207        reinterpret_cast<uint32_t *>(outputValues), Float64,
   208        AGGR_AVG_FLOAT};
   209  
   210    OutputVector output2 = {{.Measure = outputMeasure2}, MeasureOutput};
   211  
   212    UnaryTransform(input, output2, indexVector, size, baseCounts, 0,
   213                   Noop, 0, 0);
   214    float_t expectedValues3[6] = {-1.0, 0, 1.0, 0, 0, 0};
   215    *reinterpret_cast<uint32_t*>(&expectedValues3[1]) = 3;
   216    *reinterpret_cast<uint32_t*>(&expectedValues3[3]) = 6;
   217    EXPECT_TRUE(equal_print(outputValues, outputValues + size,
   218                      reinterpret_cast<int64_t*>(&expectedValues3[0])));
   219  
   220    release(basePtr);
   221    release(outputValues);
   222    release(indexVector);
   223    release(baseCounts);
   224  }
   225  
   226  // cppcheck-suppress *
   227  TEST(UnaryTransformTest, CheckDimensionOutputIterator) {
   228    const int size = 3;
   229    uint32_t indexVectorH[size * 2] = {0, 1, 2};
   230    int16_t inputValuesH[size] = {-1, 1, 0};
   231    // T T F
   232    uint8_t inputNullsH[1 + ((size - 1) / 8)] = {0x03};
   233  
   234    uint8_t outputValuesH[3 * 3];
   235    thrust::fill(std::begin(outputValuesH), std::end(outputValuesH), 0);
   236  
   237    uint8_t *basePtr =
   238        allocate_column(nullptr, &inputNullsH[0], &inputValuesH[0], 0, 1, 6);
   239    uint32_t *indexVector = allocate(&indexVectorH[0], size * 2);
   240    uint8_t *outputValues = allocate(&outputValuesH[0], 9);
   241  
   242    DefaultValue defaultValue = {false, {.Int32Val = 0}};
   243    VectorPartySlice inputVP = {basePtr, 0, 8, 0, Int16, defaultValue};
   244  
   245    DimensionOutputVector outputDimension = {
   246        outputValues, outputValues + 6, Int16};
   247  
   248    InputVector input = {{.VP = inputVP}, VectorPartyInput};
   249    OutputVector output =
   250        {{.Dimension = outputDimension}, DimensionOutput};
   251  
   252    UnaryTransform(input, output, indexVector, size, nullptr, 0,
   253                   Negate, 0, 0);
   254  
   255    uint8_t expectedValues[9] = {1, 0, 0xFF, 0xFF, 0, 0, 1, 1, 0};
   256    EXPECT_TRUE(equal(outputValues, outputValues + 9, &expectedValues[0]));
   257  
   258    // Test NOOP functor
   259    UnaryTransform(input, output, indexVector, size, nullptr, 0, Noop, 0, 0);
   260  
   261    uint8_t expectedValues2[9] = {0xFF, 0xFF, 1, 0, 0, 0, 1, 1, 0};
   262    EXPECT_TRUE(equal(outputValues, outputValues + 9, &expectedValues2[0]));
   263  
   264    release(basePtr);
   265    release(outputValues);
   266    release(indexVector);
   267  }
   268  
   269  // cppcheck-suppress *
   270  TEST(UnaryFilterTest, CheckFilter) {
   271    const int size = 3;
   272    uint32_t indexVectorH[size] = {0, 1, 2};
   273    RecordID recordIDVectorH[3];
   274    for (int i = 0; i < size; i++) {
   275      RecordID recordID = {(int32_t) 0, (uint32_t) i};
   276      recordIDVectorH[i] = recordID;
   277    }
   278    uint8_t boolVectorH[size] = {0, 0, 0};
   279  
   280    int inputValuesH[size] = {1, 0, 1};
   281    uint8_t inputNullsH[size] = {1, 0, 1};
   282  
   283    uint8_t *basePtr =
   284        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&inputValuesH[0]),
   285                        &inputNullsH[0], 0, 12, 3);
   286  
   287    uint32_t *indexVector = allocate(&indexVectorH[0], size);
   288    uint8_t *boolVector = allocate(&boolVectorH[0], size);
   289    RecordID *recordIDVector = allocate(&recordIDVectorH[0], size);
   290  
   291    ScratchSpaceVector inputVP = {basePtr, 16, Int32};
   292  
   293    InputVector input = {{.ScratchSpace = inputVP}, ScratchSpaceInput};
   294    RecordID *recordIDVectors[1] = {recordIDVector};
   295    CGoCallResHandle resHandle = UnaryFilter(input,
   296                                             indexVector,
   297                                             boolVector,
   298                                             size,
   299                                             recordIDVectors,
   300                                             1,
   301                                             nullptr,
   302                                             0,
   303                                             IsNotNull,
   304                                             0,
   305                                             0);
   306    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 2);
   307    EXPECT_EQ(resHandle.pStrErr, nullptr);
   308  
   309    int length = reinterpret_cast<int64_t>(resHandle.res);
   310  
   311    uint32_t expectedValues[2] = {0, 2};
   312    RecordID recordID0 = {(int32_t) 0, (int32_t) 0};
   313    RecordID recordID1 = {(int32_t) 0, (int32_t) 2};
   314    RecordID expectedRecordIDs[2] = {recordID0, recordID1};
   315    EXPECT_TRUE(equal(indexVector, indexVector + length, &expectedValues[0]));
   316    EXPECT_TRUE(equal(
   317        reinterpret_cast<uint8_t *>(recordIDVector),
   318        reinterpret_cast<uint8_t *>(recordIDVector) + sizeof(RecordID) * length,
   319        reinterpret_cast<uint8_t *>(&expectedRecordIDs[0])));
   320    release(basePtr);
   321    release(boolVector);
   322    release(indexVector);
   323    release(recordIDVector);
   324  }
   325  
   326  // cppcheck-suppress *
   327  TEST(UnaryFilterTest, AllEmpty) {
   328    const int size = 3;
   329    uint32_t indexVectorH[size] = {0, 1, 2};
   330    uint8_t boolVectorH[size] = {0, 0, 0};
   331  
   332    int inputValuesH[size] = {0, 0, 0};
   333    uint8_t inputNullsH[size] = {1, 1, 1};
   334  
   335    uint8_t *basePtr =
   336        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&inputValuesH[0]),
   337                        &inputNullsH[0], 0, 12, 3);
   338  
   339    uint32_t *indexVector = allocate(&indexVectorH[0], size);
   340    uint8_t *boolVector = allocate(&boolVectorH[0], size);
   341  
   342    ScratchSpaceVector inputVP = {basePtr, 16, Int32};
   343  
   344    InputVector input = {{.ScratchSpace = inputVP}, ScratchSpaceInput};
   345    CGoCallResHandle resHandle = UnaryFilter(input, indexVector, boolVector, size,
   346                                             nullptr, 0, nullptr,
   347                                             0, Negate, 0, 0);
   348    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 0);
   349    EXPECT_EQ(resHandle.pStrErr, nullptr);
   350    release(basePtr);
   351    release(indexVector);
   352  }
   353  
   354  // cppcheck-suppress *
   355  TEST(BinaryTransformTest, CheckInt) {
   356    const int size = 3;
   357    uint32_t indexVectorH[size * 2] = {0, 1, 2};
   358    int lhsValuesH[size] = {-1, 1, 0};
   359    // T T F
   360    uint8_t lhsNullsH[1 + ((size - 1) / 8)] = {0x03};
   361  
   362    uint8_t *lhsBasePtr =
   363        allocate_column(nullptr, &lhsNullsH[0], &lhsValuesH[0], 0, 1, 12);
   364  
   365    int rhsValuesH[size] = {0, 1, -1};
   366    // F T T
   367    uint8_t rhsNullsH[1 + ((size - 1) / 8)] = {0x06};
   368  
   369    uint8_t *rhsBasePtr =
   370        allocate_column(nullptr, &rhsNullsH[0], &rhsValuesH[0], 0, 1, 12);
   371  
   372    int outputValuesH[size] = {0, 0, 0};
   373    bool outputNullsH[size] = {false, false, false};
   374    uint8_t *outputBasePtr =
   375        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]),
   376                        &outputNullsH[0], 0, 12, 3);
   377  
   378    uint32_t *indexVector = allocate(&indexVectorH[0], size * 2);
   379  
   380    DefaultValue defaultValue = {false, {.Int32Val = 0}};
   381    VectorPartySlice
   382        lhsColumn = {lhsBasePtr, 0, 8, 0, Int32, defaultValue};
   383    VectorPartySlice
   384        rhsColumn = {rhsBasePtr, 0, 8, 0, Int32, defaultValue};
   385  
   386    ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Int32};
   387  
   388    InputVector lhs = {{.VP = lhsColumn}, VectorPartyInput};
   389    InputVector rhs = {{.VP = rhsColumn}, VectorPartyInput};
   390    OutputVector output = {{.ScratchSpace = outputScratchSpace},
   391                           ScratchSpaceOutput};
   392  
   393    BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0,
   394                    Plus, 0, 0);
   395  
   396    int expectedValues[3] = {0, 2, 0};
   397    bool expectedNulls[3] = {false, true, false};
   398  
   399    int *outputValues = reinterpret_cast<int *>(outputBasePtr);
   400    bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16;
   401  
   402    EXPECT_TRUE(
   403        equal(outputValues, outputValues + size,
   404              &expectedValues[0]));
   405  
   406    EXPECT_TRUE(
   407        equal(outputNulls, outputNulls + size,
   408              &expectedNulls[0]));
   409  
   410    release(lhsBasePtr);
   411    release(rhsBasePtr);
   412    release(outputBasePtr);
   413    release(indexVector);
   414  }
   415  
   416  // cppcheck-suppress *
   417  TEST(BinaryTransformTest, CheckGeoPoint) {
   418    const int size = 3;
   419    uint32_t indexVectorH[size * 2] = {0, 1, 2};
   420    GeoPointT lhsValuesH[size] = {{1, 1}, {1, 0}, {0, 0}};
   421    // T T F
   422    uint8_t lhsNullsH[1 + ((size - 1) / 8)] = {0x03};
   423  
   424    uint8_t *lhsBasePtr =
   425        allocate_column(nullptr, &lhsNullsH[0], &lhsValuesH[0], 0, 1, 24);
   426  
   427    ConstantVector rhsConstant = {{.GeoPointVal = {1, 1}}, true, ConstGeoPoint};
   428  
   429    uint32_t outputValuesH[size] = {false, false, false};
   430    bool outputNullsH[size] = {false, false, false};
   431    uint8_t *outputBasePtr =
   432        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]),
   433                        &outputNullsH[0], 0, 12, 3);
   434  
   435    uint32_t *indexVector = allocate(&indexVectorH[0], size * 2);
   436  
   437    DefaultValue defaultValue = {false, {.Int32Val = 0}};
   438    VectorPartySlice
   439        lhsColumn = {lhsBasePtr, 0, 8, 0, GeoPoint, defaultValue};
   440    ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Uint32};
   441  
   442    InputVector lhs = {{.VP = lhsColumn}, VectorPartyInput};
   443    InputVector rhs = {{.Constant = rhsConstant}, ConstantInput};
   444    OutputVector output = {{.ScratchSpace = outputScratchSpace},
   445                           ScratchSpaceOutput};
   446    BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0,
   447                    Equal, 0, 0);
   448  
   449    uint32_t expectedValues[3] = {true, false, false};
   450    bool expectedNulls[3] = {true, true, false};
   451  
   452    uint32_t *outputValues = reinterpret_cast<uint32_t *>(outputBasePtr);
   453    bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16;
   454  
   455    EXPECT_TRUE(
   456        equal(outputValues, outputValues + size,
   457              &expectedValues[0]));
   458  
   459    EXPECT_TRUE(
   460        equal(outputNulls, outputNulls + size,
   461              &expectedNulls[0]));
   462  
   463    int rhsValuesH[size] = {0, 1, -1};
   464    // F T T
   465    uint8_t rhsNullsH[1 + ((size - 1) / 8)] = {0x06};
   466  
   467    uint8_t *rhsBasePtr =
   468        allocate_column(nullptr, &rhsNullsH[0], &rhsValuesH[0], 0, 1, 12);
   469  
   470    VectorPartySlice
   471        rhsColumn = {rhsBasePtr, 0, 8, 0, Int32, defaultValue};
   472  
   473    InputVector rhsVector = {{.VP = rhsColumn}, VectorPartyInput};
   474  
   475    CGoCallResHandle resHandle = {0, nullptr};
   476    resHandle = BinaryTransform(lhs, rhsVector, output, indexVector, size,
   477        nullptr, 0, Equal, 0, 0);
   478    EXPECT_TRUE(resHandle.pStrErr != nullptr);
   479    free(const_cast<char *>(resHandle.pStrErr));
   480    release(lhsBasePtr);
   481    release(rhsBasePtr);
   482    release(outputBasePtr);
   483    release(indexVector);
   484  }
   485  
   486  // cppcheck-suppress *
   487  TEST(BinaryTransformTest, CheckFloatAndUnpackedBoolIter) {
   488    const int size = 3;
   489    uint32_t indexVectorH[size * 2] = {0, 1, 2};
   490    int lhsValuesH[size] = {-1, 1, 0};
   491    uint8_t lhsNullsH[size] = {1, 1, 1};
   492  
   493    uint8_t *lhsBasePtr =
   494        allocate_column(nullptr,
   495                        reinterpret_cast<uint8_t *>(&lhsValuesH[0]),
   496                        &lhsNullsH[0], 0, 12, 3);
   497  
   498    float rhsValuesH[size] = {1.1, -1.1, 0.1};
   499    uint8_t rhsNullsH[size] = {1, 1, 1};
   500  
   501    uint8_t *rhsBasePtr =
   502        allocate_column(nullptr,
   503                        reinterpret_cast<uint8_t *>(&rhsValuesH[0]),
   504                        &rhsNullsH[0], 0, 12, 3);
   505  
   506    float outputValuesH[size] = {200, 0, 0};
   507    bool outputNullsH[size] = {false, false, false};
   508    uint8_t *outputBasePtr =
   509        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]),
   510                        &outputNullsH[0], 0, 12, 3);
   511  
   512    uint32_t *indexVector = allocate(&indexVectorH[0], size * 2);
   513  
   514    ScratchSpaceVector lhsColumn = {lhsBasePtr, 16, Int32};
   515    ScratchSpaceVector rhsColumn = {rhsBasePtr, 16, Float32};
   516    ScratchSpaceVector outputScratchSpace = {
   517        outputBasePtr, 16, Float32};
   518  
   519    InputVector lhs = {{.ScratchSpace = lhsColumn}, ScratchSpaceInput};
   520    InputVector rhs = {{.ScratchSpace = rhsColumn}, ScratchSpaceInput};
   521    OutputVector output = {{.ScratchSpace = outputScratchSpace},
   522                           ScratchSpaceOutput};
   523  
   524    BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0, Minus, 0, 0);
   525  
   526    float expectedValues[3] = {-2.1, 2.1, -0.1};
   527    bool expectedNulls[3] = {true, true, true};
   528  
   529    float_t *outputValues = reinterpret_cast<float_t *>(outputBasePtr);
   530    bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16;
   531  
   532    EXPECT_TRUE(
   533        equal(outputValues, outputValues + size,
   534              &expectedValues[0]));
   535  
   536    EXPECT_TRUE(
   537        equal(outputNulls, outputNulls + size,
   538              &expectedNulls[0]));
   539  
   540    // transform using multiply functor.
   541    BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0,
   542                    Multiply, 0, 0);
   543    float expectedValues2[3] = {-1.1, -1.1, -0};
   544    bool expectedNulls2[3] = {true, true, true};
   545  
   546    EXPECT_TRUE(
   547        equal(outputValues, outputValues + size,
   548              &expectedValues2[0]));
   549  
   550    EXPECT_TRUE(
   551        equal(outputNulls, outputNulls + size,
   552              &expectedNulls2[0]));
   553  
   554    release(lhsBasePtr);
   555    release(rhsBasePtr);
   556    release(outputBasePtr);
   557    release(indexVector);
   558  }
   559  
   560  // cppcheck-suppress *
   561  TEST(BinaryTransformTest, CheckConstantIterator) {
   562    const int size = 3;
   563    uint32_t indexVectorH[size * 2] = {0, 1, 2};
   564    int columnValuesH[size] = {-1, 1, 0};
   565    uint8_t columnNullsH[size] = {1, 1, 1};
   566  
   567    uint8_t *columnBasePtr =
   568        allocate_column(nullptr,
   569                        reinterpret_cast<uint8_t *>(&columnValuesH[0]),
   570                        &columnNullsH[0], 0, 12, 3);
   571  
   572    float outputValuesH[size] = {0, 0, 0};
   573    uint8_t outputNullsH[size] = {false, false, false};
   574  
   575    uint8_t *outputBasePtr =
   576        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]),
   577                        &outputNullsH[0], 0, 12, 3);
   578  
   579    uint32_t *indexVector = allocate(&indexVectorH[0], size * 2);
   580  
   581    ScratchSpaceVector lhsColumn = {columnBasePtr, 16, Int32};
   582    ConstantVector rhsConstant = {{.FloatVal = 0.1}, true, ConstFloat};
   583    ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Float32};
   584  
   585    InputVector lhs = {{.ScratchSpace = lhsColumn}, ScratchSpaceInput};
   586    InputVector rhs = {{.Constant = rhsConstant}, ConstantInput};
   587    OutputVector output = {{.ScratchSpace = outputScratchSpace},
   588                           ScratchSpaceOutput};
   589  
   590    BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0,
   591                    Plus, 0, 0);
   592  
   593    float expectedValues[3] = {-0.9, 1.1, 0.1};
   594    bool expectedNulls[3] = {true, true, true};
   595  
   596    float_t *outputValues = reinterpret_cast<float_t *>(outputBasePtr);
   597    bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16;
   598  
   599    EXPECT_TRUE(
   600        equal(outputValues, outputValues + size,
   601              &expectedValues[0]));
   602  
   603    EXPECT_TRUE(
   604        equal(outputNulls, outputNulls + size,
   605              &expectedNulls[0]));
   606  
   607    release(columnBasePtr);
   608    release(outputBasePtr);
   609    release(indexVector);
   610  }
   611  
   612  // cppcheck-suppress *
   613  TEST(BinaryFilterTest, CheckFilter) {
   614    const int size = 3;
   615    int lhsValuesH[size] = {0, 1, 2};
   616    uint8_t lhsNullsH[size] = {1, 1, 1};
   617  
   618    uint8_t *lhsBasePtr =
   619        allocate_column(nullptr,
   620                        reinterpret_cast<uint8_t *>(&lhsValuesH[0]),
   621                        &lhsNullsH[0], 0, 12, 3);
   622  
   623    float rhsValuesH[size] = {0.1, 0.9, 1.9};
   624    uint8_t rhsNullsH[size] = {1, 1, 1};
   625  
   626    uint8_t *rhsBasePtr =
   627        allocate_column(nullptr,
   628                        reinterpret_cast<uint8_t *>(&rhsValuesH[0]),
   629                        &rhsNullsH[0], 0, 12, 3);
   630  
   631    uint32_t indexVectorH[size * 2] = {0, 1, 2};
   632    uint8_t boolVectorH[size] = {0, 0, 0};
   633  
   634    uint32_t *indexVector = allocate(&indexVectorH[0], size);
   635    uint8_t *boolVector = allocate(&boolVectorH[0], size);
   636  
   637    ScratchSpaceVector lhsColumn = {lhsBasePtr, 16, Int32};
   638    ScratchSpaceVector rhsColumn = {rhsBasePtr, 16, Float32};
   639  
   640    InputVector lhs = {{.ScratchSpace = lhsColumn}, ScratchSpaceInput};
   641    InputVector rhs = {{.ScratchSpace = rhsColumn}, ScratchSpaceInput};
   642  
   643    CGoCallResHandle resHandle = BinaryFilter(lhs, rhs, indexVector, boolVector,
   644                                              size, nullptr, 0, nullptr, 0,
   645                                              GreaterThan, 0, 0);
   646    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 2);
   647    EXPECT_EQ(resHandle.pStrErr, nullptr);
   648  
   649    int length = reinterpret_cast<int64_t>(resHandle.res);
   650  
   651    uint32_t expectedValues[2] = {1, 2};
   652    EXPECT_TRUE(
   653        equal(indexVector, indexVector + length,
   654              &expectedValues[0]));
   655  
   656    release(lhsBasePtr);
   657    release(rhsBasePtr);
   658    release(indexVector);
   659    release(boolVector);
   660  }
   661  
   662  // cppcheck-suppress *
   663  TEST(BinaryTransformTest, CheckMeasureOutputIterator) {
   664    const int size = 3;
   665    uint32_t indexVectorH[size * 2] = {0, 1, 2};
   666    uint32_t baseCountsH[size + 1] = {0, 3, 9, 10};
   667  
   668    int lhsValuesH[size] = {-1, 1, 0};
   669    uint8_t lhsNullsH[size] = {1, 1, 0};
   670  
   671    uint8_t *lhsBasePtr =
   672        allocate_column(nullptr,
   673                        reinterpret_cast<uint8_t *>(&lhsValuesH[0]),
   674                        &lhsNullsH[0], 0, 12, 3);
   675  
   676    float rhsValuesH[size] = {1.1, -1.1, 0.1};
   677    uint8_t rhsNullsH[size] = {1, 1, 1};
   678  
   679    uint8_t *rhsBasePtr =
   680        allocate_column(nullptr,
   681                        reinterpret_cast<uint8_t *>(&rhsValuesH[0]),
   682                        &rhsNullsH[0], 0, 12, 3);
   683  
   684    float outputValuesH[size] = {0, 0, 0};
   685  
   686    float *outputValues = allocate(&outputValuesH[0], size);
   687    uint32_t *indexVector = allocate(&indexVectorH[0], size);
   688    uint32_t *baseCounts = allocate(&baseCountsH[0], size);
   689  
   690    ScratchSpaceVector lhsColumn = {lhsBasePtr, 16, Int32};
   691  
   692    ScratchSpaceVector rhsColumn = {rhsBasePtr, 16, Float32};
   693  
   694    MeasureOutputVector outputMeasure = {
   695        reinterpret_cast<uint32_t *>(outputValues), Float32,
   696        AGGR_SUM_FLOAT};
   697  
   698    InputVector lhs = {{.ScratchSpace = lhsColumn}, ScratchSpaceInput};
   699    InputVector rhs = {{.ScratchSpace = rhsColumn}, ScratchSpaceInput};
   700    OutputVector output = {{.Measure = outputMeasure}, MeasureOutput};
   701  
   702    BinaryTransform(lhs, rhs, output, indexVector, size, baseCounts,
   703                    0, Minus, 0, 0);
   704    float expectedValues[3] = {-6.3, 12.6, 0.0};
   705  
   706    EXPECT_TRUE(
   707        equal(outputValues, outputValues + 3,
   708              &expectedValues[0]));
   709  
   710    release(lhsBasePtr);
   711    release(rhsBasePtr);
   712    release(outputValues);
   713    release(indexVector);
   714    release(baseCounts);
   715  }
   716  
   717  // cppcheck-suppress *
   718  TEST(InitIndexVectorTest, InitIndexVector) {
   719    const int size = 3;
   720    uint32_t indexVectorH[size * 2] = {0, 0, 0};
   721    uint32_t *indexVector = allocate(&indexVectorH[0], 3);
   722    InitIndexVector(indexVector, 0, 3, 0, 0);
   723    uint32_t expectedValues[3] = {0, 1, 2};
   724    EXPECT_TRUE(
   725        equal(indexVector, indexVector + size, &expectedValues[0]));
   726    release(indexVector);
   727  }
   728  
   729  // cppcheck-suppress *
   730  TEST(HashLookupTest, CheckLookup) {
   731    // hash index created in golang cuckoo_hash_index
   732    uint8_t bucketsH[312] = {
   733        0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0,
   734        0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0,
   735        0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 17,
   736        0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0,
   737        12, 0, 0, 0, 140, 236, 116, 56, 157, 195, 184, 133, 16, 0, 0,
   738        0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0,
   739        0, 0, 17, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 0,
   740        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
   741        0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0,
   742        0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0,
   743        0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 2,
   744        0, 0, 0, 121, 236, 209, 218, 160, 185, 109, 187, 0, 0, 0, 0,
   745        8, 0, 0, 0, 15, 0, 0, 0, 9, 0, 0, 0, 1, 0, 0,
   746        0, 10, 0, 0, 0, 14, 0, 0, 0, 2, 0, 0, 0, 0, 0,
   747        0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
   748        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   749        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   750        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   751        0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 7,
   752        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   753        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
   754  
   755    uint8_t *buckets = allocate(bucketsH, 312);
   756    CuckooHashIndex hashIndex = {
   757        buckets,
   758        {(uint32_t) 2596996162, (uint32_t) 4039455774, (uint32_t) 2854263694,
   759         (uint32_t) 1879968118},
   760        4,
   761        4,
   762        2};
   763    const int size = 18;
   764  
   765    uint32_t indexVectorH[size] = {0, 1, 2, 3, 4, 5, 6, 7, 8,
   766                                   9, 10, 11, 12, 13, 14, 15, 16, 17};
   767    uint32_t inputValuesH[size] = {0, 1, 2, 3, 4, 5, 6, 7, 8,
   768                                   9, 10, 11, 12, 13, 14, 15, 16, 17};
   769    uint8_t inputNullsH[3] = {0xFF, 0xFF, 0xFF};
   770  
   771    uint8_t *basePtr =
   772        allocate_column(nullptr,
   773                        &inputNullsH[0], &inputValuesH[0], 0, 3, size * 4);
   774  
   775    RecordID outputValuesH[18];
   776  
   777    uint32_t *indexVector = allocate(&indexVectorH[0], size);
   778  
   779    RecordID *outputValues = allocate(&outputValuesH[0], size);
   780  
   781    DefaultValue defaultValue = {false, {.Int32Val = 0}};
   782    VectorPartySlice inputVP = {basePtr, 0, 8, 0, Int32, defaultValue};
   783  
   784    InputVector input = {{.VP = inputVP}, VectorPartyInput};
   785    HashLookup(input, outputValues, indexVector,
   786               size, nullptr, 0, hashIndex, 0, 0);
   787  
   788    RecordID expectedOutputValues[18];
   789    for (int i = 0; i < size; i++) {
   790      RecordID recordID = {(int32_t) 0, (uint32_t) i};
   791      expectedOutputValues[i] = recordID;
   792    }
   793  
   794    EXPECT_TRUE(
   795        equal(reinterpret_cast<uint8_t *>(outputValues),
   796              reinterpret_cast<uint8_t *>(outputValues) + sizeof(RecordID) * size,
   797              reinterpret_cast<uint8_t *>(&expectedOutputValues[0])));
   798    release(buckets);
   799    release(indexVector);
   800    release(basePtr);
   801    release(outputValues);
   802  }
   803  
   804  // cppcheck-suppress *
   805  TEST(HashLookupTest, CheckUUID) {
   806    // hash index created in golang cuckoo_hash_index
   807    uint8_t bucketsH[600] = {
   808        0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   809        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   810        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 2, 0,
   811        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   812        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   813        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   814        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   815        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   816        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   817        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   818        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 22, 0, 0, 0, 0, 0, 0, 0,
   819        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   820        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   821        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   822        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   823        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   824        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   825        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   826        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   827        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   828        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   829        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   830        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   831        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   832        0, 0};
   833  
   834    uint8_t *buckets = allocate(bucketsH, 600);
   835    CuckooHashIndex hashIndex = {
   836        buckets,
   837        {(uint32_t) 1904795661, (uint32_t) 1908039658, (uint32_t) 3167437076,
   838         (uint32_t) 4232957548},
   839        16,
   840        4,
   841        2};
   842    const int size = 3;
   843  
   844    uint32_t indexVectorH[size] = {0, 1, 2};
   845    UUIDT inputValuesH[size] = {{0, 0}, {1, 0}, {2, 0}};
   846    uint8_t inputNullsH[1] = {0xFF};
   847  
   848    uint8_t *basePtr =
   849        allocate_column(nullptr,
   850                        &inputNullsH[0], &inputValuesH[0], 0, 1, size * 16);
   851  
   852    RecordID outputValuesH[3];
   853  
   854    uint32_t *indexVector = allocate(&indexVectorH[0], size);
   855  
   856    RecordID *outputValues = allocate(&outputValuesH[0], size);
   857  
   858    DefaultValue defaultValue = {false, {}};
   859    VectorPartySlice inputVP = {basePtr, 0, 8, 0, UUID, defaultValue};
   860  
   861    InputVector input = {{.VP = inputVP}, VectorPartyInput};
   862    HashLookup(input, outputValues, indexVector,
   863               size, nullptr, 0, hashIndex, 0, 0);
   864  
   865    RecordID expectedOutputValues[3];
   866    for (int i = 0; i < size; i++) {
   867      RecordID recordID = {(int32_t) 0, (uint32_t) i};
   868      expectedOutputValues[i] = recordID;
   869    }
   870  
   871    EXPECT_TRUE(
   872        equal(reinterpret_cast<uint8_t *>(outputValues),
   873              reinterpret_cast<uint8_t *>(outputValues) + sizeof(RecordID) * size,
   874              reinterpret_cast<uint8_t *>(&expectedOutputValues[0])));
   875    release(buckets);
   876    release(indexVector);
   877    release(basePtr);
   878    release(outputValues);
   879  }
   880  
   881  // cppcheck-suppress *
   882  TEST(ForeignTableColumnTransformTest, CheckTransform) {
   883    const int numBatches = 5;
   884    const int kNumRecords = 5;
   885    const int numRecordsInLastBatch = 5;
   886    int16_t* const timezoneLookup = nullptr;
   887    int16_t timezoneLookupSize = 0;
   888    int32_t baseBatchID = -2147483648;
   889    RecordID recordIDsH[kNumRecords];
   890    VectorPartySlice batches[kNumRecords];
   891    for (int i = 0; i < kNumRecords; i++) {
   892      RecordID recordID = {(int32_t) i + baseBatchID, (uint32_t) i};
   893      recordIDsH[i] = recordID;
   894    }
   895    RecordID *recordIDs = allocate(&recordIDsH[0], kNumRecords);
   896    int valuesH[5][5] = {{1, 0, 0, 0, 0},
   897                         {0, 2, 0, 0, 0},
   898                         {0, 0, 3, 0, 0},
   899                         {0, 0, 0, 4, 0},
   900                         {0, 0, 0, 0, 5}};
   901  
   902    uint8_t nullsH[1] = {0xFF};
   903  
   904    uint8_t *basePtrs[5];
   905    for (int i = 0; i < numBatches; i++) {
   906      uint8_t
   907          *basePtr = allocate_column(nullptr, nullsH, &valuesH[i][0], 0, 1, 20);
   908      VectorPartySlice foreignVP = {basePtr, 0, 8, 0, Int32};
   909      batches[i] = foreignVP;
   910      basePtrs[i] = basePtr;
   911    }
   912  
   913    DefaultValue defaultValue = {false, {.Int32Val = 0}};
   914    ForeignColumnVector foreignColumnVP = {recordIDs,
   915                                            batches,
   916                                            baseBatchID,
   917                                            (int32_t) numBatches,
   918                                            (int32_t) numRecordsInLastBatch,
   919                                            timezoneLookup,
   920                                            timezoneLookupSize,
   921                                            Int32,
   922                                            defaultValue};
   923    InputVector input = {{.ForeignVP = foreignColumnVP},
   924                         ForeignColumnInput};
   925    int outputValuesH[kNumRecords];
   926    bool outputNullsH[kNumRecords];
   927  
   928    uint8_t *outputBasePtr =
   929        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]),
   930                        &outputNullsH[0], 0, 20, 5);
   931  
   932    ScratchSpaceVector outputScratchSpace = {outputBasePtr, 24, Int32};
   933    OutputVector output = {{.ScratchSpace = outputScratchSpace},
   934                           ScratchSpaceOutput};
   935  
   936    int expectedValues[kNumRecords] = {-1, -2, -3, -4, -5};
   937    bool expectedNulls[kNumRecords] = {true, true, true, true, true};
   938  
   939    int *outputValues = reinterpret_cast<int *>(outputBasePtr);
   940    bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 24;
   941  
   942    UnaryTransform(input, output, nullptr, kNumRecords, nullptr, 0,
   943                   Negate, 0, 0);
   944  
   945    ForeignTableIterator<int> *vpIters = prepareForeignTableIterators(
   946        numBatches,
   947        batches,
   948        4,
   949        false,
   950        0, 0);
   951    RecordIDJoinIterator<int> inputIter(
   952        recordIDs,
   953        numBatches,
   954        baseBatchID,
   955        vpIters,
   956        numRecordsInLastBatch,
   957        timezoneLookup,
   958        timezoneLookupSize);
   959  
   960    outputValues = reinterpret_cast<int *>(outputBasePtr);
   961    outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 24;
   962  
   963    EXPECT_TRUE(
   964        equal(outputValues, outputValues + kNumRecords, &expectedValues[0]));
   965    EXPECT_TRUE(equal(outputNulls, outputNulls + kNumRecords, &expectedNulls[0]));
   966  
   967    release(recordIDs);
   968  
   969    for (int i = 0; i < numBatches; i++) {
   970      release(basePtrs[i]);
   971    }
   972    release(outputBasePtr);
   973  }
   974  
   975  // cppcheck-suppress *
   976  TEST(SortDimColumnVectorTest, CheckSort) {
   977    // test with 1 4-byte dim, 1 2-byte dim and 1 1-byte dim
   978    // with length = 3
   979    // numBytes=(4+2+1+3)*3=30
   980    uint8_t keysH[30] = {0};
   981    reinterpret_cast<uint32_t *>(keysH)[0] = 1;
   982    reinterpret_cast<uint32_t *>(keysH)[1] = 2;
   983    reinterpret_cast<uint32_t *>(keysH)[2] = 1;
   984    reinterpret_cast<uint16_t *>(keysH + 12)[0] = 1;
   985    reinterpret_cast<uint16_t *>(keysH + 12)[1] = 2;
   986    reinterpret_cast<uint16_t *>(keysH + 12)[2] = 1;
   987    (keysH + 18)[0] = 1;
   988    (keysH + 18)[1] = 2;
   989    (keysH + 18)[2] = 1;
   990  
   991    uint32_t indexH[3] = {0, 1, 2};
   992    uint64_t hashValuesH[3] = {0};
   993  
   994    uint8_t *keys = allocate(&keysH[0], 30);
   995    uint32_t *index = allocate(&indexH[0], 3);
   996    uint64_t *hashValues = allocate(&hashValuesH[0], 3);
   997  
   998    const int vectorCapacity = 3;
   999    const int length = 3;
  1000    DimensionColumnVector keyColVector = {
  1001        keys,
  1002        hashValues,
  1003        index,
  1004        vectorCapacity,
  1005        {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}};
  1006    Sort(keyColVector, length, 0, 0);
  1007  
  1008    uint32_t expectedIndex1[3] = {1, 0, 2};
  1009    uint32_t expectedIndex2[3] = {0, 2, 1};
  1010    EXPECT_TRUE(equal(index, index + 3, expectedIndex1) ||
  1011        equal(index, index + 3, expectedIndex2));
  1012  }
  1013  
  1014  // cppcheck-suppress *
  1015  TEST(ReduceDimColumnVectorTest, CheckReduce) {
  1016    // test with 3 dimensions (4-byte, 2-byte, 1-byte)
  1017    // each dimension vector has 6 elements with values assigned as [1,2,3,2,3,1]
  1018    uint8_t inputDimValuesH[60] = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0,
  1019                                   0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0, 3, 0,
  1020                                   2, 0, 3, 0, 1, 0, 1, 2, 3, 2, 3, 1, 1, 1, 1,
  1021                                   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
  1022    uint64_t inputHashValuesH[6] = {1, 1, 2, 2, 3, 3};
  1023    uint32_t inputIndexVectorH[6] = {1, 3, 2, 4, 0, 5};
  1024    uint32_t inputValuesH[6] = {5, 1, 3, 2, 4, 6};
  1025  
  1026    uint8_t outputDimValuesH[60] = {0};
  1027    uint64_t outputHashValuesH[6] = {0};
  1028    uint32_t outputIndexVectorH[6] = {0};
  1029    uint32_t outputValuesH[6] = {0};
  1030  
  1031    uint8_t *inputDimValues = allocate(inputDimValuesH, 60);
  1032    uint64_t *inputHashValues = allocate(inputHashValuesH, 6);
  1033    uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6);
  1034    uint32_t *inputValues = allocate(inputValuesH, 6);
  1035  
  1036    uint8_t *outputDimValues = allocate(outputDimValuesH, 60);
  1037    uint64_t *outputHashValues = allocate(outputHashValuesH, 6);
  1038    uint32_t *outputIndexVector = allocate(outputIndexVectorH, 6);
  1039    uint32_t *outputValues = allocate(outputValuesH, 6);
  1040  
  1041    uint32_t expectedValues[3] = {3, 7, 11};
  1042    uint32_t expectedIndex[3] = {1, 2, 0};
  1043    // output dimension values should be [2,3,1] for each dim vector
  1044    uint8_t expectedDimValues[60] = {
  1045        2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1046        0, 0, 0, 0, 2, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 3, 1, 0,
  1047        0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,
  1048    };
  1049    int length = 6;
  1050    int vectorCapacity = 6;
  1051    DimensionColumnVector inputKeys = {
  1052        inputDimValues,
  1053        inputHashValues,
  1054        inputIndexVector,
  1055        vectorCapacity,
  1056        {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}};
  1057  
  1058    DimensionColumnVector outputKeys = {
  1059        outputDimValues,
  1060        outputHashValues,
  1061        outputIndexVector,
  1062        vectorCapacity,
  1063        {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}};
  1064    CGoCallResHandle
  1065        resHandle = Reduce(inputKeys,
  1066                           reinterpret_cast<uint8_t *>(inputValues),
  1067                           outputKeys,
  1068                           reinterpret_cast<uint8_t *>(outputValues),
  1069                           4,
  1070                           length,
  1071                           AGGR_SUM_UNSIGNED,
  1072                           0,
  1073                           0);
  1074    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3);
  1075    EXPECT_EQ(resHandle.pStrErr, nullptr);
  1076  
  1077    EXPECT_TRUE(equal(outputValues, outputValues + 3, expectedValues));
  1078    EXPECT_TRUE(equal(outputIndexVector, outputIndexVector + 3, expectedIndex));
  1079    EXPECT_TRUE(equal(outputDimValues, outputDimValues + 60, expectedDimValues));
  1080  }
  1081  
  1082  TEST(SortAndReduceTest, CheckReduceByAvg) {
  1083    // 6 elements 1 2 3 2 3 1
  1084    uint8_t inputDimValuesH[30] = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0,
  1085                                   0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1};
  1086    uint64_t inputHashValuesH[6] = {1, 1, 2, 2, 3, 3};
  1087    uint32_t inputIndexVectorH[6] = {1, 3, 2, 4, 0, 5};
  1088    float_t inputValuesH[12] = {5.0, 0, 1.0, 0, 3.0, 0, 2.0, 0, 4.0, 0, 6.0, 0};
  1089    // set count to be 1.
  1090    for (int i = 0; i < 6; i++) {
  1091      *reinterpret_cast<uint32_t*>(&inputValuesH[i*2+1]) = uint32_t(1);
  1092    }
  1093  
  1094    uint8_t outputDimValuesH[30] = {0};
  1095    uint64_t outputHashValuesH[6] = {0};
  1096    uint32_t outputIndexVectorH[6] = {0};
  1097    uint64_t outputValuesH[6] = {0};
  1098  
  1099    uint8_t *inputDimValues = allocate(inputDimValuesH, 30);
  1100    uint64_t *inputHashValues = allocate(inputHashValuesH, 6);
  1101    uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6);
  1102    uint32_t *inputValues =
  1103        allocate(reinterpret_cast<uint32_t*>(&inputValuesH[0]), 12);
  1104  
  1105    uint8_t *outputDimValues = allocate(outputDimValuesH, 30);
  1106    uint64_t *outputHashValues = allocate(outputHashValuesH, 6);
  1107    uint32_t *outputIndexVector = allocate(outputIndexVectorH, 6);
  1108    uint64_t *outputValues = allocate(outputValuesH, 6);
  1109  
  1110    float_t expectedValuesF[6] = {1.5, 0, 3.5, 0, 5.5, 0};
  1111    uint64_t* expectedValues = reinterpret_cast<uint64_t*>(&expectedValuesF[0]);
  1112    for (int i = 0; i < 3; i++) {
  1113      *(reinterpret_cast<uint32_t *>(&expectedValues[i]) + 1) = 2;
  1114    }
  1115  
  1116    uint32_t expectedIndex[3] = {1, 2, 0};
  1117    // output dimension values should be [2,3,1] for each dim vector
  1118    uint8_t expectedDimValues[30] = {
  1119        2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
  1120        0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
  1121    };
  1122  
  1123    int length = 6;
  1124    int vectorCapacity = 6;
  1125    DimensionColumnVector inputKeys = {
  1126        inputDimValues,
  1127        inputHashValues,
  1128        inputIndexVector,
  1129        vectorCapacity,
  1130        {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)0, (uint8_t)0}};
  1131  
  1132    DimensionColumnVector outputKeys = {
  1133        outputDimValues,
  1134        outputHashValues,
  1135        outputIndexVector,
  1136        vectorCapacity,
  1137        {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)0, (uint8_t)0}};
  1138    CGoCallResHandle
  1139        resHandle = Reduce(inputKeys,
  1140                           reinterpret_cast<uint8_t *>(inputValues),
  1141                           outputKeys,
  1142                           reinterpret_cast<uint8_t *>(outputValues),
  1143                           8,
  1144                           length,
  1145                           AGGR_AVG_FLOAT, 0, 0);
  1146    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3);
  1147    EXPECT_EQ(resHandle.pStrErr, nullptr);
  1148  
  1149    EXPECT_TRUE(equal(outputValues, outputValues + 3, expectedValues));
  1150    EXPECT_TRUE(equal(outputIndexVector, outputIndexVector + 3, expectedIndex));
  1151    EXPECT_TRUE(equal(outputDimValues, outputDimValues + 30, expectedDimValues));
  1152  }
  1153  
  1154  // cppcheck-suppress *
  1155  TEST(SortAndReduceTest, CheckHash) {
  1156    int size = 8;
  1157  
  1158    uint8_t dimValuesH[16] = {2, 1, 0, 3, 0, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1};
  1159    uint32_t measureValuesH[8] = {1, 1, 1, 1, 1, 1, 1, 1};
  1160    uint64_t hashValuesH[8] = {0};
  1161    uint32_t indexValuesH[8] = {0};
  1162  
  1163    uint8_t dimValuesOutH[16] = {0};
  1164    uint32_t measureValuesOutH[8] = {0};
  1165    uint64_t hashValuesOutH[8] = {0};
  1166    uint32_t indexValuesOutH[8] = {0};
  1167  
  1168    uint8_t *dimValues = allocate(dimValuesH, 16);
  1169    uint32_t *measureValues = allocate(measureValuesH, 8);
  1170    uint64_t *hashValues = allocate(hashValuesH, 8);
  1171    uint32_t *indexValues = allocate(indexValuesH, 8);
  1172  
  1173    uint8_t *dimValuesOut = allocate(dimValuesOutH, 16);
  1174    uint32_t *measureValuesOut = allocate(measureValuesOutH, 8);
  1175    uint64_t *hashValuesOut = allocate(hashValuesOutH, 8);
  1176    uint32_t *indexValuesOut = allocate(indexValuesOutH, 8);
  1177  
  1178    InitIndexVector(indexValues, 0, size, 0, 0);
  1179  
  1180    const int length = 8;
  1181    const int vectorCapacity = 8;
  1182    DimensionColumnVector inputKeyColVector = {
  1183        dimValues,
  1184        hashValues,
  1185        indexValues,
  1186        vectorCapacity,
  1187        {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}};
  1188  
  1189    DimensionColumnVector outputKeyColVector = {
  1190        dimValuesOut,
  1191        hashValuesOut,
  1192        indexValuesOut,
  1193        vectorCapacity,
  1194        {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}};
  1195  
  1196    Sort(inputKeyColVector, length, 0, 0);
  1197    CGoCallResHandle resHandle =
  1198        Reduce(inputKeyColVector, reinterpret_cast<uint8_t *>(measureValues),
  1199               outputKeyColVector, reinterpret_cast<uint8_t *>(measureValuesOut),
  1200               4, length, AGGR_SUM_UNSIGNED, nullptr, 0);
  1201  
  1202    uint8_t expectedDims[16] = {2, 0, 3, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0};
  1203    uint32_t expectedMeasures[8] = {2, 2, 2, 2, 0, 0, 0, 0};
  1204    uint32_t expectedIndexes[8] = {0, 2, 3, 1, 0, 0, 0, 0};
  1205  
  1206    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 4);
  1207    EXPECT_EQ(resHandle.pStrErr, nullptr);
  1208  
  1209    EXPECT_TRUE(equal(dimValuesOut, dimValuesOut + 16, &expectedDims[0]));
  1210    EXPECT_TRUE(
  1211        equal(measureValuesOut, measureValuesOut + 8, &expectedMeasures[0]));
  1212    EXPECT_TRUE(equal(indexValuesOut, indexValuesOut + 8, &expectedIndexes[0]));
  1213    release(dimValues);
  1214    release(measureValues);
  1215    release(hashValues);
  1216    release(indexValues);
  1217    release(dimValuesOut);
  1218    release(measureValuesOut);
  1219    release(hashValuesOut);
  1220    release(indexValuesOut);
  1221  }
  1222  
  1223  // cppcheck-suppress *
  1224  TEST(HyperLogLogTest, CheckSparseMode) {
  1225    int prevResultSize = 0;
  1226    int curBatchSize = 8;
  1227    const int vectorCapacity = 8;
  1228  
  1229    uint8_t prevDimH[16] = {1, 1, 2, 2, 3, 3, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1};
  1230    uint32_t prevValuesH[8] = {0};
  1231    uint64_t prevHashH[8] = {0};
  1232    uint32_t prevIndexH[8] = {0};
  1233  
  1234    uint8_t curDimH[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  1235    uint32_t curValuesH[8] = {0x010001, 0x020002, 0x010002, 0x020002,
  1236                              0x010003, 0x020003, 0x010004, 0x020004};
  1237    uint32_t curIndexH[8] = {0, 1, 2, 3, 4, 5, 6, 7};
  1238    uint64_t curHashH[8] = {0};
  1239  
  1240    uint8_t *prevDim = allocate(prevDimH, 16);
  1241    uint32_t *prevValues = allocate(prevValuesH, 8);
  1242    uint64_t *prevHash = allocate(prevHashH, 8);
  1243    uint32_t *prevIndex = allocate(prevIndexH, 8);
  1244  
  1245    uint8_t *curDim = allocate(curDimH, 16);
  1246    uint32_t *curValues = allocate(curValuesH, 8);
  1247    uint64_t *curHash = allocate(curHashH, 8);
  1248    uint32_t *curIndex = allocate(curIndexH, 8);
  1249  
  1250    DimensionColumnVector prevDimOut = {
  1251        prevDim,
  1252        prevHash,
  1253        prevIndex,
  1254        vectorCapacity,
  1255        {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}};
  1256  
  1257    DimensionColumnVector curDimOut = {
  1258        curDim,
  1259        curHash,
  1260        curIndex,
  1261        vectorCapacity,
  1262        {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}};
  1263  
  1264    uint8_t *hllVector;
  1265    size_t hllVectorSize;
  1266    uint16_t *hllDimRegIDCount;
  1267    CGoCallResHandle
  1268        resHandle = HyperLogLog(prevDimOut, curDimOut, prevValues, curValues,
  1269                                prevResultSize, curBatchSize, true, &hllVector,
  1270                                &hllVectorSize, &hllDimRegIDCount, 0, 0);
  1271  
  1272    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 4);
  1273    EXPECT_EQ(resHandle.pStrErr, nullptr);
  1274  
  1275    int resSize = reinterpret_cast<int64_t>(resHandle.res);
  1276  
  1277    EXPECT_EQ(resSize, 4);
  1278    EXPECT_EQ(hllVectorSize, 20);
  1279    uint8_t expectedDims[16] = {2, 4, 3, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0};
  1280    uint8_t expectedHLL[20] = {2, 0, 3, 0, 4, 0, 3, 0, 3, 0,
  1281                               3, 0, 1, 0, 2, 0, 2, 0, 3, 0};
  1282    uint16_t expectedDimRegIDCount[4] = {1, 1, 1, 2};
  1283    EXPECT_TRUE(equal(curDim, curDim + 16, &expectedDims[0]));
  1284    EXPECT_TRUE(equal(hllVector, hllVector + hllVectorSize, &expectedHLL[0]));
  1285    EXPECT_TRUE(equal(hllDimRegIDCount, hllDimRegIDCount + resSize,
  1286                      &expectedDimRegIDCount[0]));
  1287    release(prevDim);
  1288    release(curDim);
  1289    release(prevValues);
  1290    release(prevHash);
  1291    release(prevIndex);
  1292    release(curValues);
  1293    release(curHash);
  1294    release(curIndex);
  1295    release(hllVector);
  1296    release(hllDimRegIDCount);
  1297  }
  1298  
  1299  // cppcheck-suppress *
  1300  TEST(HyperLogLogTest, CheckDenseMode) {
  1301    int prevResultSize = 0;
  1302    int curBatchSize = 5000;
  1303    const int vectorCapacity = 5000;
  1304  
  1305    uint8_t prevDimH[10000] = {0};
  1306    // {1,1,2,2,0,0, ... }
  1307    prevDimH[0] = 1;
  1308    prevDimH[1] = 1;
  1309    prevDimH[2] = 2;
  1310    prevDimH[3] = 2;
  1311    for (int i = 5000; i < 10000; i++) {
  1312      prevDimH[i] = 1;
  1313    }
  1314    uint32_t prevValuesH[5000] = {0};
  1315    uint64_t prevHashH[5000] = {0};
  1316    uint32_t prevIndexH[5000] = {0};
  1317  
  1318    uint8_t curDimH[10000] = {0};
  1319    uint32_t curValuesH[5000] = {0};
  1320    curValuesH[0] = 0x010001;
  1321    curValuesH[1] = 0x020002;
  1322    curValuesH[2] = 0x010002;
  1323    curValuesH[3] = 0x020002;
  1324    for (int i = 4; i < 5000; i++) {
  1325      // 4996 registers
  1326      curValuesH[i] = (0x010000 | (i - 4));
  1327    }
  1328    uint32_t curIndexH[5000] = {0};
  1329    for (int i = 0; i < 5000; i++) {
  1330      curIndexH[i] = i;
  1331    }
  1332    uint64_t curHashH[5000] = {0};
  1333  
  1334    uint8_t *prevDim = allocate(prevDimH, 10000);
  1335    uint32_t *prevValues = allocate(prevValuesH, 5000);
  1336    uint64_t *prevHash = allocate(prevHashH, 5000);
  1337    uint32_t *prevIndex = allocate(prevIndexH, 5000);
  1338  
  1339    uint8_t *curDim = allocate(curDimH, 10000);
  1340    uint32_t *curValues = allocate(curValuesH, 5000);
  1341    uint64_t *curHash = allocate(curHashH, 5000);
  1342    uint32_t *curIndex = allocate(curIndexH, 5000);
  1343  
  1344    DimensionColumnVector prevDimOut = {
  1345        prevDim,
  1346        prevHash,
  1347        prevIndex,
  1348        vectorCapacity,
  1349        {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}};
  1350  
  1351    DimensionColumnVector curDimOut = {
  1352        curDim,
  1353        curHash,
  1354        curIndex,
  1355        vectorCapacity,
  1356        {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}};
  1357  
  1358    uint8_t *hllVector;
  1359    size_t hllVectorSize;
  1360    uint16_t *hllDimRegIDCount;
  1361    CGoCallResHandle
  1362        resHandle = HyperLogLog(prevDimOut, curDimOut, prevValues, curValues,
  1363                                prevResultSize, curBatchSize, true, &hllVector,
  1364                                &hllVectorSize, &hllDimRegIDCount, 0, 0);
  1365  
  1366    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3);
  1367    EXPECT_EQ(resHandle.pStrErr, nullptr);
  1368  
  1369    int resSize = reinterpret_cast<int64_t>(resHandle.res);
  1370  
  1371    EXPECT_EQ(resSize, 3);
  1372    EXPECT_EQ(hllVectorSize, 16396);
  1373    uint8_t expectedDims[10000] = {0};
  1374    expectedDims[0] = 2;
  1375    expectedDims[1] = 0;
  1376    expectedDims[2] = 1;
  1377    expectedDims[5000] = 1;
  1378    expectedDims[5001] = 1;
  1379    expectedDims[5002] = 1;
  1380    uint8_t expectedHLL[16396] = {0};
  1381    expectedHLL[0] = 2;
  1382    expectedHLL[1] = 0;
  1383    expectedHLL[2] = 3;
  1384    expectedHLL[3] = 0;
  1385    for (int i = 4; i < 5000; i++) {
  1386      expectedHLL[i] = 2;
  1387    }
  1388    expectedHLL[16388] = 1;
  1389    expectedHLL[16389] = 0;
  1390    expectedHLL[16390] = 2;
  1391    expectedHLL[16391] = 0;
  1392    expectedHLL[16392] = 2;
  1393    expectedHLL[16393] = 0;
  1394    expectedHLL[16394] = 3;
  1395    expectedHLL[16395] = 0;
  1396  
  1397    uint16_t expectedDimRegIDCount[3] = {1, 4996, 2};
  1398    EXPECT_TRUE(equal(curDim, curDim + 10000, &expectedDims[0]));
  1399    EXPECT_TRUE(equal(hllVector, hllVector + hllVectorSize, &expectedHLL[0]));
  1400    EXPECT_TRUE(equal(hllDimRegIDCount, hllDimRegIDCount + resSize,
  1401                      &expectedDimRegIDCount[0]));
  1402    release(prevDim);
  1403    release(curDim);
  1404    release(prevValues);
  1405    release(prevHash);
  1406    release(prevIndex);
  1407    release(curValues);
  1408    release(curHash);
  1409    release(curIndex);
  1410    release(hllVector);
  1411    release(hllDimRegIDCount);
  1412  }
  1413  
  1414  // cppcheck-suppress *
  1415  TEST(DateFunctorsTest, CheckGetStarts) {
  1416    // First ensure the constant memory is properly initialized.
  1417    BootstrapDevice();
  1418  
  1419    const int size = 3;
  1420    uint32_t indexVectorH[size * 2] = {0, 1, 2};
  1421    uint32_t *indexVector = allocate(&indexVectorH[0], size * 2);
  1422  
  1423    uint32_t inputValuesH[size] = {0, get_ts(2018, 6, 11), get_ts(1970, 1, 1)};
  1424    bool inputNullsH[size] = {false, true, true};
  1425    uint8_t *basePtr =
  1426        allocate_column(nullptr,
  1427                        reinterpret_cast<uint8_t *>(&inputValuesH[0]),
  1428                        &inputNullsH[0], 0, 12, 3);
  1429  
  1430    uint32_t outputValuesH[size] = {0, 0, 0};
  1431    bool outputNullsH[size] = {false, false, false};
  1432    uint8_t *outputBasePtr =
  1433        allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]),
  1434                        &outputNullsH[0], 0, 12, 3);
  1435  
  1436    ScratchSpaceVector inputScratchSpace = {basePtr, 16, Int32};
  1437    ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Int32};
  1438  
  1439    InputVector
  1440        input = {{.ScratchSpace = inputScratchSpace}, ScratchSpaceInput};
  1441    OutputVector output = {{.ScratchSpace = outputScratchSpace},
  1442                           ScratchSpaceOutput};
  1443  
  1444    UnaryTransform(input, output, indexVector, size, nullptr, 0,
  1445                   GetMonthStart, 0, 0);
  1446  
  1447    uint32_t *outputValues = reinterpret_cast<uint32_t *>(outputBasePtr);
  1448    bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16;
  1449  
  1450    uint32_t expectedValues[3] = {0, get_ts(2018, 6, 1), get_ts(1970, 1, 1)};
  1451    bool expectedNulls[3] = {false, true, true};
  1452  
  1453    EXPECT_TRUE(
  1454        equal(outputValues, outputValues + size,
  1455                    &expectedValues[0]));
  1456  
  1457    EXPECT_TRUE(
  1458        equal(outputNulls, outputNulls + size,
  1459                    &expectedNulls[0]));
  1460  
  1461    // Check get quarter start.
  1462    UnaryTransform(input, output, indexVector, size, nullptr, 0,
  1463                   GetQuarterStart, 0, 0);
  1464  
  1465    uint32_t expectedValues2[3] = {0, get_ts(2018, 4, 1), get_ts(1970, 1, 1)};
  1466    bool expectedNulls2[3] = {false, true, true};
  1467  
  1468    EXPECT_TRUE(
  1469        equal(outputValues, outputValues + size,
  1470                    &expectedValues2[0]));
  1471  
  1472    EXPECT_TRUE(
  1473        equal(outputNulls, outputNulls + size,
  1474                    &expectedNulls2[0]));
  1475  
  1476    // Check get year start.
  1477    UnaryTransform(input, output, indexVector, size, nullptr, 0,
  1478                   GetYearStart, 0, 0);
  1479  
  1480    uint32_t expectedValues3[3] = {0, get_ts(2018, 1, 1), get_ts(1970, 1, 1)};
  1481    bool expectedNulls3[3] = {false, true, true};
  1482  
  1483    EXPECT_TRUE(
  1484        equal(outputValues, outputValues + size,
  1485              &expectedValues3[0]));
  1486  
  1487    EXPECT_TRUE(
  1488        equal(outputNulls, outputNulls + size,
  1489              &expectedNulls3[0]));
  1490  
  1491    release(basePtr);
  1492    release(outputBasePtr);
  1493    release(indexVector);
  1494  }
  1495  
  1496  // cppcheck-suppress *
  1497  TEST(GeoBatchIntersectTest, CheckInShape) {
  1498    // 3 shapes
  1499    // 1. Square with (1,1), (1,-1), (-1,-1), (-1, 1)
  1500    // 2. Triangle with (3,3),(2,2),(4,2)
  1501    // 3. Square with a hole (0,6),(3,6),(3,3),(0,3), hole (1,5),(2,5),(2,4),(1,4)
  1502    float shapeLatsH[20] = {1, 1, -1, -1, 1,       3, 2, 4, 3, 0,
  1503                             3, 3, 0,  0,  FLT_MAX, 1, 2, 2, 1, 1};
  1504    float shapeLongsH[20] = {1, -1, -1, 1, 1,       3, 2, 2, 3, 6,
  1505                              6, 3,  3,  6, FLT_MAX, 5, 5, 4, 4, 5};
  1506    uint8_t shapeIndexsH[20] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
  1507                                2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
  1508    GeoShapeBatch geoShapes =
  1509        get_geo_shape_batch(shapeLatsH, shapeLongsH, shapeIndexsH, 3, 20);
  1510  
  1511    uint32_t indexVectorH[5] = {0, 1, 2, 3, 4};
  1512    uint32_t *indexVector = allocate(indexVectorH, 5);
  1513  
  1514    // 5 points (0,0),(3,2.5),(1.5, 3.5),(1.5,4.5),null
  1515    //           in 1   in 2    in 3       out      out
  1516    GeoPointT pointsH[5] = {{0, 0}, {3, 2.5}, {1.5, 3.5}, {1.5, 4.5}, {0, 0}};
  1517    uint8_t nullsH[1] = {0x0F};
  1518  
  1519    uint32_t outputPredicateH[5] = {0};
  1520    uint32_t *outputPredicate = allocate(outputPredicateH, 5);
  1521  
  1522    // in.
  1523    bool inOrOut = true;
  1524  
  1525    uint8_t *basePtr =
  1526        allocate_column(nullptr, &nullsH[0], &pointsH[0], 0, 1, 40);
  1527  
  1528    DefaultValue defaultValue = {false};
  1529    VectorPartySlice inputVP = {basePtr, 0, 8, 0, GeoPoint, defaultValue, 5};
  1530    InputVector points = {{.VP = inputVP}, VectorPartyInput};
  1531  
  1532    CGoCallResHandle resHandle =
  1533        GeoBatchIntersects(geoShapes, points, indexVector, 5, 0, nullptr, 0,
  1534                           outputPredicate, inOrOut, 0, 0);
  1535  
  1536    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3);
  1537    EXPECT_EQ(resHandle.pStrErr, nullptr);
  1538    uint32_t expectedOutputPredicate[5] = {1, 2, 4, 0, 0};
  1539    EXPECT_TRUE(
  1540        equal(outputPredicate, outputPredicate + 5, expectedOutputPredicate));
  1541  
  1542    release(outputPredicate);
  1543    release(indexVector);
  1544    release(basePtr);
  1545    release(geoShapes);
  1546  }
  1547  
  1548  // cppcheck-suppress *
  1549  TEST(GeoBatchIntersectTest, CheckRecordIDJoinIterator) {
  1550    // 3 shapes
  1551    // 1. Square with (1,1), (1,-1), (-1,-1), (-1, 1)
  1552    // 2. Triangle with (3,3),(2,2),(4,2)
  1553    // 3. Square with a hole (0,6),(3,6),(3,3),(0,3), hole (1,5),(2,5),(2,4),(1,4)
  1554    float shapeLatsH[20] = {1, 1, -1, -1, 1,       3, 2, 4, 3, 0,
  1555                             3, 3, 0,  0,  FLT_MAX, 1, 2, 2, 1, 1};
  1556    float shapeLongsH[20] = {1, -1, -1, 1, 1,       3, 2, 2, 3, 6,
  1557                              6, 3,  3,  6, FLT_MAX, 5, 5, 4, 4, 5};
  1558    uint8_t shapeIndexsH[20] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
  1559                                2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
  1560    GeoShapeBatch geoShapes =
  1561        get_geo_shape_batch(shapeLatsH, shapeLongsH, shapeIndexsH, 3, 20);
  1562  
  1563    uint32_t indexVectorH[5] = {0, 1, 2, 3, 4};
  1564    uint32_t *indexVector = allocate(indexVectorH, 5);
  1565  
  1566    // 5 points (0,0),(3,2.5),(1.5, 3.5),(1.5,4.5),null
  1567    //           in 1   in 2    in 3       out      out
  1568    const int numBatches = 5;
  1569    const int kNumRecords = 5;
  1570    const int numRecordsInLastBatch = 5;
  1571    int32_t baseBatchID = -2147483648;
  1572    RecordID recordIDsH[kNumRecords];
  1573    VectorPartySlice batches[kNumRecords];
  1574    for (int i = 0; i < kNumRecords; i++) {
  1575      RecordID recordID = {(int32_t) i + baseBatchID, (uint32_t) i};
  1576      recordIDsH[i] = recordID;
  1577    }
  1578    RecordID *recordIDs = allocate(&recordIDsH[0], kNumRecords);
  1579    GeoPointT valuesH[5][5];
  1580    GeoPointT pointsH[5] = {{0, 0}, {3, 2.5}, {1.5, 3.5}, {1.5, 4.5}, {0, 0}};
  1581    for (int i = 0; i < kNumRecords; i++) {
  1582      valuesH[i][i] = pointsH[i];
  1583    }
  1584    uint8_t nullsH[1] = {0x0F};
  1585  
  1586    uint8_t *basePtrs[5];
  1587    for (int i = 0; i < numBatches; i++) {
  1588      uint8_t *basePtr =
  1589          allocate_column(nullptr, nullsH, &valuesH[i][0], 0, 1, 40);
  1590      VectorPartySlice foreignVP = {basePtr, 0, 8, 0, GeoPoint};
  1591      batches[i] = foreignVP;
  1592      basePtrs[i] = basePtr;
  1593    }
  1594  
  1595    DefaultValue defaultValue = {false, {}};
  1596    ForeignColumnVector foreignColumnVP = {recordIDs,
  1597                                           batches,
  1598                                           baseBatchID,
  1599                                           (int32_t) numBatches,
  1600                                           (int32_t) numRecordsInLastBatch,
  1601                                           nullptr,
  1602                                           0,
  1603                                           GeoPoint,
  1604                                           defaultValue};
  1605    InputVector points = {{.ForeignVP = foreignColumnVP},
  1606                         ForeignColumnInput};
  1607  
  1608    uint32_t outputPredicateH[5] = {0};
  1609    uint32_t *outputPredicate = allocate(outputPredicateH, 5);
  1610  
  1611    CGoCallResHandle resHandle =
  1612        GeoBatchIntersects(geoShapes, points, indexVector, 5, 0, nullptr, 0,
  1613                           outputPredicate, true, 0, 0);
  1614  
  1615    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3);
  1616    EXPECT_EQ(resHandle.pStrErr, nullptr);
  1617    uint32_t expectedOutputPredicate[5] = {1, 2, 4, 0, 0};
  1618    EXPECT_TRUE(
  1619        equal(outputPredicate, outputPredicate + 5, expectedOutputPredicate));
  1620  
  1621    release(outputPredicate);
  1622    release(indexVector);
  1623    release(recordIDs);
  1624    release(geoShapes);
  1625    for (int i = 0; i < numBatches; i++) {
  1626      release(basePtrs[i]);
  1627    }
  1628  }
  1629  
  1630  // cppcheck-suppress *
  1631  TEST(GeoBatchIntersectTest, CheckNotInShape) {
  1632    // 3 shapes
  1633    // 1. Square with (1,1), (1,-1), (-1,-1), (-1, 1)
  1634    // 2. Triangle with (3,3),(2,2),(4,2)
  1635    // 3. Square with a hole (0,6),(3,6),(3,3),(0,3), hole (1,5),(2,5),(2,4),(1,4)
  1636    float shapeLatsH[20] = {1, 1, -1, -1, 1,       3, 2, 4, 3, 0,
  1637                            3, 3, 0,  0,  FLT_MAX, 1, 2, 2, 1, 1};
  1638    float shapeLongsH[20] = {1, -1, -1, 1, 1,       3, 2, 2, 3, 6,
  1639                             6, 3,  3,  6, FLT_MAX, 5, 5, 4, 4, 5};
  1640    uint8_t shapeIndexsH[20] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
  1641                                2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
  1642    GeoShapeBatch geoShapes =
  1643        get_geo_shape_batch(shapeLatsH, shapeLongsH, shapeIndexsH, 3, 20);
  1644  
  1645    uint32_t indexVectorH[5] = {0, 1, 2, 3, 4};
  1646    uint32_t *indexVector = allocate(indexVectorH, 5);
  1647  
  1648    // 5 points (0,0),(3,2.5),(1.5, 3.5),(1.5,4.5),null
  1649    //           in 1   in 2    in 3       out      out
  1650    GeoPointT pointsH[5] = {{0, 0}, {3, 2.5}, {1.5, 3.5}, {1.5, 4.5}, {0, 0}};
  1651    uint8_t nullsH[1] = {0x0F};
  1652  
  1653    uint32_t outputPredicateH[5] = {0};
  1654    uint32_t *outputPredicate = allocate(outputPredicateH, 5);
  1655  
  1656    // in.
  1657    bool inOrOut = false;
  1658  
  1659    uint8_t *basePtr =
  1660        allocate_column(nullptr, &nullsH[0], &pointsH[0], 0, 1, 40);
  1661  
  1662    DefaultValue defaultValue = {false};
  1663    VectorPartySlice inputVP = {basePtr, 0, 8, 0, GeoPoint, defaultValue, 5};
  1664    InputVector points = {{.VP = inputVP}, VectorPartyInput};
  1665    CGoCallResHandle resHandle =
  1666        GeoBatchIntersects(geoShapes, points, indexVector, 5, 0, nullptr, 0,
  1667                           outputPredicate, inOrOut, 0, 0);
  1668  
  1669    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 1);
  1670    EXPECT_EQ(resHandle.pStrErr, nullptr);
  1671    uint32_t expectedOutputPredicate[5] = {1, 2, 4, 0, 1};
  1672    EXPECT_TRUE(
  1673        equal(outputPredicate, outputPredicate + 5, expectedOutputPredicate));
  1674  
  1675    release(outputPredicate);
  1676    release(indexVector);
  1677    release(basePtr);
  1678    release(geoShapes);
  1679  }
  1680  
  1681  // cppcheck-suppress *
  1682  TEST(GeoBatchIntersectionJoinTest, DimensionWriting) {
  1683    float shapeLatsH[15] = {
  1684        1,  1, -1,        -1,        1,         2,         2,        -2,
  1685        -2, 2, 1.5 + 0.1, 1.5 + 0.1, 1.5 - 0.1, 1.5 - 0.1, 1.5 + 0.1};
  1686    float shapeLongsH[15] = {
  1687        1, -1, -1,        1,         1,         2,         -2,       -2,
  1688        2, 2,  3.5 + 0.1, 3.5 - 0.1, 3.5 + 0.1, 3.5 - 0.1, 3.5 + 0.1};
  1689    uint8_t shapeIndexsH[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2};
  1690    GeoShapeBatch geoShapes =
  1691        get_geo_shape_batch(shapeLatsH, shapeLongsH, shapeIndexsH, 3, 15);
  1692    uint32_t indexVectorH[5] = {0, 1, 2, 3, 4};
  1693    uint32_t *indexVector = allocate(indexVectorH, 5);
  1694  
  1695    // 5 points  (1.5,1.5) (0,0) (1.5,4.5) (1.5, 3.5)   null
  1696    //             in2     in1,2  out            in3        out
  1697    GeoPointT pointsH[5] = {{1.5, 1.5}, {0, 0}, {1.5, 4.5}, {1.5, 3.5}, {0, 0}};
  1698    uint8_t nullsH[1] = {0x0F};
  1699  
  1700    uint32_t outputPredicateH[5] = {0};
  1701    uint32_t *outputPredicate = allocate(outputPredicateH, 5);
  1702  
  1703    uint8_t *basePtr =
  1704        allocate_column(nullptr, &nullsH[0], &pointsH[0], 0, 1, 40);
  1705  
  1706    DefaultValue defaultValue = {false};
  1707    VectorPartySlice inputVP = {basePtr, 0, 8, 0, GeoPoint, defaultValue, 5};
  1708  
  1709    uint8_t outputValuesH[10];
  1710    thrust::fill(std::begin(outputValuesH), std::end(outputValuesH), 0);
  1711    uint8_t *outputValues = allocate(&outputValuesH[0], 10);
  1712    DimensionOutputVector outputDimension = {outputValues, outputValues + 5,
  1713                                             Uint8};
  1714  
  1715    InputVector points = {{.VP = inputVP}, VectorPartyInput};
  1716    CGoCallResHandle resHandle =
  1717        GeoBatchIntersects(geoShapes, points, indexVector, 5,
  1718                           0, nullptr, 0, outputPredicate, true, 0, 0);
  1719  
  1720    EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3);
  1721    EXPECT_EQ(resHandle.pStrErr, nullptr);
  1722  
  1723    resHandle = WriteGeoShapeDim(1, outputDimension, 5, outputPredicate, 0, 0);
  1724  
  1725    uint32_t expectedOutputPredicate[5] = {2, 3, 0, 4, 0};
  1726    GeoPredicateIterator geoIter(expectedOutputPredicate, 1);
  1727    EXPECT_TRUE(
  1728        equal(outputPredicate, outputPredicate + 5, expectedOutputPredicate));
  1729    uint8_t expectedDimValues[5] = {1, 0, 2, 0, 0};
  1730    uint8_t expectedDimNulls[5] = {1, 1, 1, 0, 0};
  1731    EXPECT_TRUE(equal(outputDimension.DimValues,
  1732        outputDimension.DimValues + 5, expectedDimValues));
  1733    EXPECT_TRUE(equal(outputDimension.DimNulls,
  1734        outputDimension.DimNulls + 5, expectedDimNulls));
  1735  
  1736    release(outputPredicate);
  1737    release(indexVector);
  1738    release(basePtr);
  1739    release(geoShapes);
  1740  }
  1741  
  1742  TEST(ExpandTest, testOverFill) {
  1743      // test with 3 dimensions (4-byte, 2-byte, 1-byte)
  1744      // each dimension vector has 6 elements with values assigned as
  1745      // [1,2,3,2,3,1]
  1746      uint8_t inputDimValuesH[60] = {
  1747          1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0,
  1748          1, 0, 2, 0, 3, 0, 2, 0, 3, 0, 1, 0,
  1749          1, 2, 3, 2, 3, 1, 1,
  1750          1, 1, 1, 1, 1, 1,
  1751          1, 1, 1, 1, 1, 1,
  1752          1, 1, 1, 1, 1
  1753      };
  1754      uint32_t inputIndexVectorH[6] = {1, 2, 4, 7, 9, 12};
  1755      uint32_t baseCountVectorH[16] = {
  1756          0, 0, 1, 3, 4, 7, 8, 10, 13, 14, 16, 19, 22, 23, 26, 30
  1757      };
  1758      // => counts{1, 2, 3, 3, 2, 1}
  1759      // so normal result will be {1, 2, 2, 3, 3, 3, 2, 2, 2, 3, 3, 1}
  1760      // and only cut first 10 elem
  1761  
  1762      uint8_t outputDimValuesH[100] = {0};
  1763      uint8_t expectedDimValues[100] = {
  1764          1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,
  1765          3, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0,
  1766          1, 0, 2, 0, 2, 0, 3, 0, 3, 0, 3, 0, 2, 0, 2, 0, 2, 0, 3, 0,
  1767          1, 2, 2, 3, 3, 3, 2, 2, 2, 3,
  1768          1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1769          1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1770          1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
  1771      };
  1772  
  1773      uint8_t *inputDimValues = allocate(inputDimValuesH, 60);
  1774      uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6);
  1775      uint32_t *baseCountVector = allocate(baseCountVectorH, 16);
  1776  
  1777      uint8_t *outputDimValues = allocate(outputDimValuesH, 100);
  1778  
  1779      int length = 6;
  1780      int vectorCapacity = 6;
  1781      DimensionColumnVector inputKeys = {
  1782          inputDimValues,
  1783          NULL,
  1784          NULL,
  1785          vectorCapacity,
  1786          {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}};
  1787      int outCapacity =  10;
  1788  
  1789      DimensionColumnVector outputKeys = {
  1790          outputDimValues,
  1791          NULL,
  1792          NULL,
  1793          outCapacity,
  1794          {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}};
  1795      CGoCallResHandle
  1796          resHandle = Expand(inputKeys,
  1797                             outputKeys,
  1798                             baseCountVector,
  1799                             inputIndexVector,
  1800                             length,
  1801                             0,
  1802                             0,
  1803                             0);
  1804      EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 10);
  1805      EXPECT_EQ(resHandle.pStrErr, nullptr);
  1806      EXPECT_TRUE(equal(outputDimValues, outputDimValues + 100,
  1807                          expectedDimValues));
  1808  }
  1809  
  1810  TEST(ExpandTest, testAppend) {
  1811      // test with 3 dimensions (4-byte, 2-byte, 1-byte)
  1812      // each dimension vector has 6 elements with values assigned as
  1813      // [1,2,3,2,3,1]
  1814      uint8_t inputDimValuesH[60] = {
  1815          1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0,
  1816          1, 0, 2, 0, 3, 0, 2, 0, 3, 0, 1, 0,
  1817          1, 2, 3, 2, 3, 1, 1,
  1818          1, 1, 1, 1, 1, 1,
  1819          1, 1, 1, 1, 1, 1,
  1820          1, 1, 1, 1, 1
  1821      };
  1822      uint32_t inputIndexVectorH[6] = {1, 2, 4, 7, 9, 12};
  1823      uint32_t baseCountVectorH[16] = {
  1824          0, 0, 1, 3, 4, 7, 8, 10, 13, 14, 16, 19, 22, 23, 26, 30
  1825      };
  1826      // => counts{1, 2, 3, 3, 2, 1}
  1827      // so normal result will be {1, 2, 2, 3, 3, 3, 2, 2, 2, 3, 3, 1}
  1828      // and only append the first 5 elem to the last 5 elem of output
  1829  
  1830      uint8_t outputDimValuesH[100] = {0};
  1831      uint8_t expectedDimValues[100] = {
  1832          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1833          1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,
  1834          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 0, 3, 0, 3, 0,
  1835          0, 0, 0, 0, 0, 1, 2, 2, 3, 3,
  1836          0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
  1837          0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
  1838          0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
  1839      };
  1840  
  1841      uint8_t *inputDimValues = allocate(inputDimValuesH, 60);
  1842      uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6);
  1843      uint32_t *baseCountVector = allocate(baseCountVectorH, 16);
  1844  
  1845      uint8_t *outputDimValues = allocate(outputDimValuesH, 100);
  1846  
  1847      int length = 6;
  1848      int vectorCapacity = 6;
  1849      int outCapacity =  10;
  1850  
  1851      DimensionColumnVector inputKeys = {
  1852          inputDimValues,
  1853          NULL,
  1854          NULL,
  1855          vectorCapacity,
  1856          {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}};
  1857  
  1858      DimensionColumnVector outputKeys = {
  1859          outputDimValues,
  1860          NULL,
  1861          NULL,
  1862          outCapacity,
  1863          {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}};
  1864      CGoCallResHandle
  1865          resHandle = Expand(inputKeys,
  1866                             outputKeys,
  1867                             baseCountVector,
  1868                             inputIndexVector,
  1869                             length,
  1870                             5,
  1871                             0,
  1872                             0);
  1873      EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 10);
  1874      EXPECT_EQ(resHandle.pStrErr, nullptr);
  1875      EXPECT_TRUE(equal(outputDimValues, outputDimValues + 100,
  1876                          expectedDimValues));
  1877  }
  1878  
  1879  TEST(ExpandTest, testFillPartial) {
  1880      // test with 3 dimensions (4-byte, 2-byte, 1-byte)
  1881      // each dimension vector has 6 elements with values assigned as
  1882      // [1,2,3,2,3,1]
  1883      uint8_t inputDimValuesH[60] = {
  1884          1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0,
  1885          1, 0, 2, 0, 3, 0, 2, 0, 3, 0, 1, 0,
  1886          1, 2, 3, 2, 3, 1, 1,
  1887          1, 1, 1, 1, 1, 1,
  1888          1, 1, 1, 1, 1, 1,
  1889          1, 1, 1, 1, 1
  1890      };
  1891      uint32_t inputIndexVectorH[6] = {1, 2, 4};
  1892      uint32_t baseCountVectorH[16] = {
  1893          0, 0, 1, 3, 4, 7, 8, 10, 13, 14, 16, 19, 22, 23, 26, 30
  1894      };
  1895      // => counts{1, 2, 3}
  1896      // so normal result will be {1, 2, 2, 3, 3, 3}
  1897      // and only cut first 10 elem
  1898  
  1899      uint8_t outputDimValuesH[100] = {0};
  1900      uint8_t expectedDimValues[100] = {
  1901          1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,
  1902          3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1903          1, 0, 2, 0, 2, 0, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1904          1, 2, 2, 3, 3, 3, 0, 0, 0, 0,
  1905          1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
  1906          1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
  1907          1, 1, 1, 1, 1, 1, 0, 0, 0, 0
  1908      };
  1909  
  1910      uint8_t *inputDimValues = allocate(inputDimValuesH, 60);
  1911      uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6);
  1912      uint32_t *baseCountVector = allocate(baseCountVectorH, 16);
  1913  
  1914      uint8_t *outputDimValues = allocate(outputDimValuesH, 100);
  1915  
  1916      int length = 3;
  1917      int vectorCapacity = 6;
  1918      DimensionColumnVector inputKeys = {
  1919          inputDimValues,
  1920          NULL,
  1921          NULL,
  1922          vectorCapacity,
  1923          {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}};
  1924      int outCapacity =  10;
  1925  
  1926      DimensionColumnVector outputKeys = {
  1927          outputDimValues,
  1928          NULL,
  1929          NULL,
  1930          outCapacity,
  1931          {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}};
  1932      CGoCallResHandle
  1933          resHandle = Expand(inputKeys,
  1934                             outputKeys,
  1935                             baseCountVector,
  1936                             inputIndexVector,
  1937                             length,
  1938                             0,
  1939                             0,
  1940                             0);
  1941      EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 6);
  1942      EXPECT_EQ(resHandle.pStrErr, nullptr);
  1943      EXPECT_TRUE(equal(outputDimValues, outputDimValues + 100,
  1944                          expectedDimValues));
  1945  }
  1946  
  1947  }  // namespace ares