1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements.  See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership.  The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License.  You may obtain a copy of the License at
8 //
9 //   http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied.  See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17 
18 #include <algorithm>
19 #include <cstdint>
20 #include <limits>
21 #include <memory>
22 #include <new>
23 #include <string>
24 #include <vector>
25 
26 #include <gtest/gtest.h>
27 
28 #include "arrow/memory_pool.h"
29 #include "arrow/stl.h"
30 #include "arrow/stl_allocator.h"
31 #include "arrow/table.h"
32 #include "arrow/testing/gtest_util.h"
33 #include "arrow/type.h"
34 #include "arrow/type_fwd.h"
35 #include "arrow/util/optional.h"
36 
37 using primitive_types_tuple = std::tuple<int8_t, int16_t, int32_t, int64_t, uint8_t,
38                                          uint16_t, uint32_t, uint64_t, bool, std::string>;
39 
40 using raw_pointer_optional_types_tuple =
41     std::tuple<int8_t*, int16_t*, int32_t*, int64_t*, uint8_t*, uint16_t*, uint32_t*,
42                uint64_t*, bool*, std::string*>;
43 
44 struct CustomType {
45   int8_t i8;
46   int16_t i16;
47   int32_t i32;
48   int64_t i64;
49   uint8_t u8;
50   uint16_t u16;
51   uint32_t u32;
52   uint64_t u64;
53   bool b;
54   std::string s;
55 
56 #define ARROW_CUSTOM_TYPE_TIED std::tie(i8, i16, i32, i64, u8, u16, u32, u64, b, s)
tieCustomType57   auto tie() const -> decltype(ARROW_CUSTOM_TYPE_TIED) { return ARROW_CUSTOM_TYPE_TIED; }
58 #undef ARROW_CUSTOM_TYPE_TIED
59 };
60 
61 // Mock optional object returning null, "yes", "no", null, "yes", "no", ...
62 // Note: This mock optional object will advance its state every time it's casted
63 // to bool. Successive castings to bool may give inconsistent results. It
64 // doesn't mock entire optional logic. It is used only for ensuring user
65 // specialization isn't broken with templated Optionals.
66 struct CustomOptionalTypeMock {
67   static int counter;
68   mutable bool was_casted_once_ = false;
69 
70   CustomOptionalTypeMock() = default;
operator boolCustomOptionalTypeMock71   explicit operator bool() const {
72     if (!was_casted_once_) {
73       was_casted_once_ = true;
74       counter++;
75       return counter % 3 != 0;
76     }
77     ADD_FAILURE() << "A CustomOptionalTypeMock should be casted to bool only once.";
78     return false;
79   }
operator *CustomOptionalTypeMock80   std::string operator*() const {
81     switch (counter % 3) {
82       case 0:
83         ADD_FAILURE() << "Optional dereferenced in null value";
84         break;
85       case 1:
86         return "yes";
87       case 2:
88         return "no";
89     }
90     return "error";
91   }
92 };
93 
94 int CustomOptionalTypeMock::counter = -1;
95 
96 // This is for testing appending list values with custom types
97 struct TestInt32Type {
98   int32_t value;
99 };
100 
101 namespace arrow {
102 
103 using optional_types_tuple =
104     std::tuple<util::optional<int8_t>, util::optional<int16_t>, util::optional<int32_t>,
105                util::optional<int64_t>, util::optional<uint8_t>, util::optional<uint16_t>,
106                util::optional<uint32_t>, util::optional<uint64_t>, util::optional<bool>,
107                util::optional<std::string>>;
108 
109 template <>
110 struct CTypeTraits<CustomOptionalTypeMock> {
111   using ArrowType = ::arrow::StringType;
112 
type_singletonarrow::CTypeTraits113   static std::shared_ptr<::arrow::DataType> type_singleton() { return ::arrow::utf8(); }
114 };
115 
116 template <>
117 struct CTypeTraits<TestInt32Type> {
118   using ArrowType = ::arrow::Int32Type;
119 
type_singletonarrow::CTypeTraits120   static std::shared_ptr<::arrow::DataType> type_singleton() { return ::arrow::int32(); }
121 };
122 
123 namespace stl {
124 
125 template <>
126 struct ConversionTraits<CustomOptionalTypeMock>
127     : public CTypeTraits<CustomOptionalTypeMock> {
AppendRowarrow::stl::ConversionTraits128   static Status AppendRow(typename TypeTraits<ArrowType>::BuilderType& builder,
129                           const CustomOptionalTypeMock& cell) {
130     if (cell) {
131       return builder.Append("mock " + *cell);
132     } else {
133       return builder.AppendNull();
134     }
135   }
136 };
137 
138 template <>
139 struct ConversionTraits<TestInt32Type> : public CTypeTraits<TestInt32Type> {
140   // AppendRow is not needed, explicitly elide an implementation
141 };
142 
143 template <>
AppendListValues(Int32Builder & value_builder,const std::vector<TestInt32Type> & cell_range)144 Status AppendListValues<TestInt32Type, const std::vector<TestInt32Type>&>(
145     Int32Builder& value_builder, const std::vector<TestInt32Type>& cell_range) {
146   return value_builder.AppendValues(reinterpret_cast<const int32_t*>(cell_range.data()),
147                                     cell_range.size());
148 }
149 
TEST(TestSchemaFromTuple,PrimitiveTypesVector)150 TEST(TestSchemaFromTuple, PrimitiveTypesVector) {
151   Schema expected_schema(
152       {field("column1", int8(), false), field("column2", int16(), false),
153        field("column3", int32(), false), field("column4", int64(), false),
154        field("column5", uint8(), false), field("column6", uint16(), false),
155        field("column7", uint32(), false), field("column8", uint64(), false),
156        field("column9", boolean(), false), field("column10", utf8(), false)});
157 
158   std::shared_ptr<Schema> schema = SchemaFromTuple<primitive_types_tuple>::MakeSchema(
159       std::vector<std::string>({"column1", "column2", "column3", "column4", "column5",
160                                 "column6", "column7", "column8", "column9", "column10"}));
161   ASSERT_TRUE(expected_schema.Equals(*schema));
162 }
163 
TEST(TestSchemaFromTuple,PrimitiveTypesTuple)164 TEST(TestSchemaFromTuple, PrimitiveTypesTuple) {
165   Schema expected_schema(
166       {field("column1", int8(), false), field("column2", int16(), false),
167        field("column3", int32(), false), field("column4", int64(), false),
168        field("column5", uint8(), false), field("column6", uint16(), false),
169        field("column7", uint32(), false), field("column8", uint64(), false),
170        field("column9", boolean(), false), field("column10", utf8(), false)});
171 
172   std::shared_ptr<Schema> schema = SchemaFromTuple<primitive_types_tuple>::MakeSchema(
173       std::make_tuple("column1", "column2", "column3", "column4", "column5", "column6",
174                       "column7", "column8", "column9", "column10"));
175   ASSERT_TRUE(expected_schema.Equals(*schema));
176 }
177 
TEST(TestSchemaFromTuple,SimpleList)178 TEST(TestSchemaFromTuple, SimpleList) {
179   Schema expected_schema({field("column1", list(utf8()), false)});
180   std::shared_ptr<Schema> schema =
181       SchemaFromTuple<std::tuple<std::vector<std::string>>>::MakeSchema({"column1"});
182 
183   ASSERT_TRUE(expected_schema.Equals(*schema));
184 }
185 
TEST(TestSchemaFromTuple,NestedList)186 TEST(TestSchemaFromTuple, NestedList) {
187   Schema expected_schema({field("column1", list(list(boolean())), false)});
188   std::shared_ptr<Schema> schema =
189       SchemaFromTuple<std::tuple<std::vector<std::vector<bool>>>>::MakeSchema(
190           {"column1"});
191 
192   ASSERT_TRUE(expected_schema.Equals(*schema));
193 }
194 
TEST(TestTableFromTupleVector,PrimitiveTypes)195 TEST(TestTableFromTupleVector, PrimitiveTypes) {
196   std::vector<std::string> names{"column1", "column2", "column3", "column4", "column5",
197                                  "column6", "column7", "column8", "column9", "column10"};
198   std::vector<primitive_types_tuple> rows{
199       primitive_types_tuple(-1, -2, -3, -4, 1, 2, 3, 4, true, "Tests"),
200       primitive_types_tuple(-10, -20, -30, -40, 10, 20, 30, 40, false, "Other")};
201   std::shared_ptr<Table> table;
202   ASSERT_OK(TableFromTupleRange(default_memory_pool(), rows, names, &table));
203 
204   std::shared_ptr<Schema> expected_schema =
205       schema({field("column1", int8(), false), field("column2", int16(), false),
206               field("column3", int32(), false), field("column4", int64(), false),
207               field("column5", uint8(), false), field("column6", uint16(), false),
208               field("column7", uint32(), false), field("column8", uint64(), false),
209               field("column9", boolean(), false), field("column10", utf8(), false)});
210 
211   // Construct expected arrays
212   std::shared_ptr<Array> int8_array = ArrayFromJSON(int8(), "[-1, -10]");
213   std::shared_ptr<Array> int16_array = ArrayFromJSON(int16(), "[-2, -20]");
214   std::shared_ptr<Array> int32_array = ArrayFromJSON(int32(), "[-3, -30]");
215   std::shared_ptr<Array> int64_array = ArrayFromJSON(int64(), "[-4, -40]");
216   std::shared_ptr<Array> uint8_array = ArrayFromJSON(uint8(), "[1, 10]");
217   std::shared_ptr<Array> uint16_array = ArrayFromJSON(uint16(), "[2, 20]");
218   std::shared_ptr<Array> uint32_array = ArrayFromJSON(uint32(), "[3, 30]");
219   std::shared_ptr<Array> uint64_array = ArrayFromJSON(uint64(), "[4, 40]");
220   std::shared_ptr<Array> bool_array = ArrayFromJSON(boolean(), "[true, false]");
221   std::shared_ptr<Array> string_array = ArrayFromJSON(utf8(), R"(["Tests", "Other"])");
222   auto expected_table =
223       Table::Make(expected_schema,
224                   {int8_array, int16_array, int32_array, int64_array, uint8_array,
225                    uint16_array, uint32_array, uint64_array, bool_array, string_array});
226 
227   ASSERT_TRUE(expected_table->Equals(*table));
228 }
229 
TEST(TestTableFromTupleVector,ListType)230 TEST(TestTableFromTupleVector, ListType) {
231   using tuple_type = std::tuple<std::vector<int64_t>>;
232 
233   auto expected_schema =
234       std::shared_ptr<Schema>(new Schema({field("column1", list(int64()), false)}));
235   std::shared_ptr<Array> expected_array =
236       ArrayFromJSON(list(int64()), "[[1, 1, 2, 34], [2, -4]]");
237   std::shared_ptr<Table> expected_table = Table::Make(expected_schema, {expected_array});
238 
239   std::vector<tuple_type> rows{tuple_type(std::vector<int64_t>{1, 1, 2, 34}),
240                                tuple_type(std::vector<int64_t>{2, -4})};
241   std::vector<std::string> names{"column1"};
242 
243   std::shared_ptr<Table> table;
244   ASSERT_OK(TableFromTupleRange(default_memory_pool(), rows, names, &table));
245   ASSERT_TRUE(expected_table->Equals(*table));
246 }
247 
TEST(TestTableFromTupleVector,ReferenceTuple)248 TEST(TestTableFromTupleVector, ReferenceTuple) {
249   std::vector<std::string> names{"column1", "column2", "column3", "column4", "column5",
250                                  "column6", "column7", "column8", "column9", "column10"};
251   std::vector<CustomType> rows{
252       {-1, -2, -3, -4, 1, 2, 3, 4, true, std::string("Tests")},
253       {-10, -20, -30, -40, 10, 20, 30, 40, false, std::string("Other")}};
254   std::vector<decltype(rows[0].tie())> rng_rows{
255       rows[0].tie(),
256       rows[1].tie(),
257   };
258   std::shared_ptr<Table> table;
259   ASSERT_OK(TableFromTupleRange(default_memory_pool(), rng_rows, names, &table));
260 
261   std::shared_ptr<Schema> expected_schema =
262       schema({field("column1", int8(), false), field("column2", int16(), false),
263               field("column3", int32(), false), field("column4", int64(), false),
264               field("column5", uint8(), false), field("column6", uint16(), false),
265               field("column7", uint32(), false), field("column8", uint64(), false),
266               field("column9", boolean(), false), field("column10", utf8(), false)});
267 
268   // Construct expected arrays
269   std::shared_ptr<Array> int8_array = ArrayFromJSON(int8(), "[-1, -10]");
270   std::shared_ptr<Array> int16_array = ArrayFromJSON(int16(), "[-2, -20]");
271   std::shared_ptr<Array> int32_array = ArrayFromJSON(int32(), "[-3, -30]");
272   std::shared_ptr<Array> int64_array = ArrayFromJSON(int64(), "[-4, -40]");
273   std::shared_ptr<Array> uint8_array = ArrayFromJSON(uint8(), "[1, 10]");
274   std::shared_ptr<Array> uint16_array = ArrayFromJSON(uint16(), "[2, 20]");
275   std::shared_ptr<Array> uint32_array = ArrayFromJSON(uint32(), "[3, 30]");
276   std::shared_ptr<Array> uint64_array = ArrayFromJSON(uint64(), "[4, 40]");
277   std::shared_ptr<Array> bool_array = ArrayFromJSON(boolean(), "[true, false]");
278   std::shared_ptr<Array> string_array = ArrayFromJSON(utf8(), R"(["Tests", "Other"])");
279   auto expected_table =
280       Table::Make(expected_schema,
281                   {int8_array, int16_array, int32_array, int64_array, uint8_array,
282                    uint16_array, uint32_array, uint64_array, bool_array, string_array});
283 
284   ASSERT_TRUE(expected_table->Equals(*table));
285 }
286 
TEST(TestTableFromTupleVector,NullableTypesWithBoostOptional)287 TEST(TestTableFromTupleVector, NullableTypesWithBoostOptional) {
288   std::vector<std::string> names{"column1", "column2", "column3", "column4", "column5",
289                                  "column6", "column7", "column8", "column9", "column10"};
290   using types_tuple = optional_types_tuple;
291   std::vector<types_tuple> rows{
292       types_tuple(-1, -2, -3, -4, 1, 2, 3, 4, true, std::string("Tests")),
293       types_tuple(-10, -20, -30, -40, 10, 20, 30, 40, false, std::string("Other")),
294       types_tuple(util::nullopt, util::nullopt, util::nullopt, util::nullopt,
295                   util::nullopt, util::nullopt, util::nullopt, util::nullopt,
296                   util::nullopt, util::nullopt),
297   };
298   std::shared_ptr<Table> table;
299   ASSERT_OK(TableFromTupleRange(default_memory_pool(), rows, names, &table));
300 
301   std::shared_ptr<Schema> expected_schema =
302       schema({field("column1", int8(), true), field("column2", int16(), true),
303               field("column3", int32(), true), field("column4", int64(), true),
304               field("column5", uint8(), true), field("column6", uint16(), true),
305               field("column7", uint32(), true), field("column8", uint64(), true),
306               field("column9", boolean(), true), field("column10", utf8(), true)});
307 
308   // Construct expected arrays
309   std::shared_ptr<Array> int8_array = ArrayFromJSON(int8(), "[-1, -10, null]");
310   std::shared_ptr<Array> int16_array = ArrayFromJSON(int16(), "[-2, -20, null]");
311   std::shared_ptr<Array> int32_array = ArrayFromJSON(int32(), "[-3, -30, null]");
312   std::shared_ptr<Array> int64_array = ArrayFromJSON(int64(), "[-4, -40, null]");
313   std::shared_ptr<Array> uint8_array = ArrayFromJSON(uint8(), "[1, 10, null]");
314   std::shared_ptr<Array> uint16_array = ArrayFromJSON(uint16(), "[2, 20, null]");
315   std::shared_ptr<Array> uint32_array = ArrayFromJSON(uint32(), "[3, 30, null]");
316   std::shared_ptr<Array> uint64_array = ArrayFromJSON(uint64(), "[4, 40, null]");
317   std::shared_ptr<Array> bool_array = ArrayFromJSON(boolean(), "[true, false, null]");
318   std::shared_ptr<Array> string_array =
319       ArrayFromJSON(utf8(), R"(["Tests", "Other", null])");
320   auto expected_table =
321       Table::Make(expected_schema,
322                   {int8_array, int16_array, int32_array, int64_array, uint8_array,
323                    uint16_array, uint32_array, uint64_array, bool_array, string_array});
324 
325   ASSERT_TRUE(expected_table->Equals(*table));
326 }
327 
TEST(TestTableFromTupleVector,NullableTypesWithRawPointer)328 TEST(TestTableFromTupleVector, NullableTypesWithRawPointer) {
329   std::vector<std::string> names{"column1", "column2", "column3", "column4", "column5",
330                                  "column6", "column7", "column8", "column9", "column10"};
331   std::vector<primitive_types_tuple> data_rows{
332       primitive_types_tuple(-1, -2, -3, -4, 1, 2, 3, 4, true, std::string("Tests")),
333       primitive_types_tuple(-10, -20, -30, -40, 10, 20, 30, 40, false,
334                             std::string("Other")),
335   };
336   std::vector<raw_pointer_optional_types_tuple> pointer_rows;
337   for (auto& row : data_rows) {
338     pointer_rows.emplace_back(
339         std::addressof(std::get<0>(row)), std::addressof(std::get<1>(row)),
340         std::addressof(std::get<2>(row)), std::addressof(std::get<3>(row)),
341         std::addressof(std::get<4>(row)), std::addressof(std::get<5>(row)),
342         std::addressof(std::get<6>(row)), std::addressof(std::get<7>(row)),
343         std::addressof(std::get<8>(row)), std::addressof(std::get<9>(row)));
344   }
345   pointer_rows.emplace_back(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
346                             nullptr, nullptr, nullptr);
347   std::shared_ptr<Table> table;
348   ASSERT_OK(TableFromTupleRange(default_memory_pool(), pointer_rows, names, &table));
349 
350   std::shared_ptr<Schema> expected_schema =
351       schema({field("column1", int8(), true), field("column2", int16(), true),
352               field("column3", int32(), true), field("column4", int64(), true),
353               field("column5", uint8(), true), field("column6", uint16(), true),
354               field("column7", uint32(), true), field("column8", uint64(), true),
355               field("column9", boolean(), true), field("column10", utf8(), true)});
356 
357   // Construct expected arrays
358   std::shared_ptr<Array> int8_array = ArrayFromJSON(int8(), "[-1, -10, null]");
359   std::shared_ptr<Array> int16_array = ArrayFromJSON(int16(), "[-2, -20, null]");
360   std::shared_ptr<Array> int32_array = ArrayFromJSON(int32(), "[-3, -30, null]");
361   std::shared_ptr<Array> int64_array = ArrayFromJSON(int64(), "[-4, -40, null]");
362   std::shared_ptr<Array> uint8_array = ArrayFromJSON(uint8(), "[1, 10, null]");
363   std::shared_ptr<Array> uint16_array = ArrayFromJSON(uint16(), "[2, 20, null]");
364   std::shared_ptr<Array> uint32_array = ArrayFromJSON(uint32(), "[3, 30, null]");
365   std::shared_ptr<Array> uint64_array = ArrayFromJSON(uint64(), "[4, 40, null]");
366   std::shared_ptr<Array> bool_array = ArrayFromJSON(boolean(), "[true, false, null]");
367   std::shared_ptr<Array> string_array =
368       ArrayFromJSON(utf8(), R"(["Tests", "Other", null])");
369   auto expected_table =
370       Table::Make(expected_schema,
371                   {int8_array, int16_array, int32_array, int64_array, uint8_array,
372                    uint16_array, uint32_array, uint64_array, bool_array, string_array});
373 
374   ASSERT_TRUE(expected_table->Equals(*table));
375 }
376 
TEST(TestTableFromTupleVector,NullableTypesDoNotBreakUserSpecialization)377 TEST(TestTableFromTupleVector, NullableTypesDoNotBreakUserSpecialization) {
378   std::vector<std::string> names{"column1"};
379   std::vector<std::tuple<CustomOptionalTypeMock>> rows(3);
380   std::shared_ptr<Table> table;
381   ASSERT_OK(TableFromTupleRange(default_memory_pool(), rows, names, &table));
382 
383   std::shared_ptr<Schema> expected_schema = schema({field("column1", utf8(), true)});
384   std::shared_ptr<Array> string_array =
385       ArrayFromJSON(utf8(), R"([null, "mock yes", "mock no"])");
386   auto expected_table = Table::Make(expected_schema, {string_array});
387 
388   ASSERT_TRUE(expected_table->Equals(*table));
389 }
390 
TEST(TestTableFromTupleVector,AppendingMultipleRows)391 TEST(TestTableFromTupleVector, AppendingMultipleRows) {
392   using row_type = std::tuple<std::vector<TestInt32Type>>;
393   std::vector<std::string> names{"column1"};
394   std::vector<row_type> rows = {
395       row_type{{{1}, {2}, {3}}},    //
396       row_type{{{10}, {20}, {30}}}  //
397   };
398   std::shared_ptr<Table> table;
399   ASSERT_OK(TableFromTupleRange(default_memory_pool(), rows, names, &table));
400 
401   std::shared_ptr<Schema> expected_schema =
402       schema({field("column1", list(int32()), false)});
403   std::shared_ptr<Array> int_array =
404       ArrayFromJSON(list(int32()), "[[1, 2, 3], [10, 20, 30]]");
405   auto expected_table = Table::Make(expected_schema, {int_array});
406 
407   ASSERT_TRUE(expected_table->Equals(*table));
408 }
409 
TEST(TestTupleVectorFromTable,PrimitiveTypes)410 TEST(TestTupleVectorFromTable, PrimitiveTypes) {
411   compute::ExecContext ctx;
412   compute::CastOptions cast_options;
413 
414   std::vector<primitive_types_tuple> expected_rows{
415       primitive_types_tuple(-1, -2, -3, -4, 1, 2, 3, 4, true, "Tests"),
416       primitive_types_tuple(-10, -20, -30, -40, 10, 20, 30, 40, false, "Other")};
417 
418   std::shared_ptr<Schema> schema = std::shared_ptr<Schema>(
419       new Schema({field("column1", int8(), false), field("column2", int16(), false),
420                   field("column3", int32(), false), field("column4", int64(), false),
421                   field("column5", uint8(), false), field("column6", uint16(), false),
422                   field("column7", uint32(), false), field("column8", uint64(), false),
423                   field("column9", boolean(), false), field("column10", utf8(), false)}));
424 
425   // Construct expected arrays
426   std::shared_ptr<Array> int8_array;
427   ArrayFromVector<Int8Type, int8_t>({-1, -10}, &int8_array);
428   std::shared_ptr<Array> int16_array;
429   ArrayFromVector<Int16Type, int16_t>({-2, -20}, &int16_array);
430   std::shared_ptr<Array> int32_array;
431   ArrayFromVector<Int32Type, int32_t>({-3, -30}, &int32_array);
432   std::shared_ptr<Array> int64_array;
433   ArrayFromVector<Int64Type, int64_t>({-4, -40}, &int64_array);
434   std::shared_ptr<Array> uint8_array;
435   ArrayFromVector<UInt8Type, uint8_t>({1, 10}, &uint8_array);
436   std::shared_ptr<Array> uint16_array;
437   ArrayFromVector<UInt16Type, uint16_t>({2, 20}, &uint16_array);
438   std::shared_ptr<Array> uint32_array;
439   ArrayFromVector<UInt32Type, uint32_t>({3, 30}, &uint32_array);
440   std::shared_ptr<Array> uint64_array;
441   ArrayFromVector<UInt64Type, uint64_t>({4, 40}, &uint64_array);
442   std::shared_ptr<Array> bool_array;
443   ArrayFromVector<BooleanType, bool>({true, false}, &bool_array);
444   std::shared_ptr<Array> string_array;
445   ArrayFromVector<StringType, std::string>({"Tests", "Other"}, &string_array);
446   auto table = Table::Make(
447       schema, {int8_array, int16_array, int32_array, int64_array, uint8_array,
448                uint16_array, uint32_array, uint64_array, bool_array, string_array});
449 
450   std::vector<primitive_types_tuple> rows(2);
451   ASSERT_OK(TupleRangeFromTable(*table, cast_options, &ctx, &rows));
452   ASSERT_EQ(rows, expected_rows);
453 
454   // The number of rows must match
455   std::vector<primitive_types_tuple> too_few_rows(1);
456   ASSERT_RAISES(Invalid, TupleRangeFromTable(*table, cast_options, &ctx, &too_few_rows));
457 
458   // The number of columns must match
459   ASSERT_OK_AND_ASSIGN(auto corrupt_table, table->RemoveColumn(0));
460   ASSERT_RAISES(Invalid, TupleRangeFromTable(*corrupt_table, cast_options, &ctx, &rows));
461 }
462 
TEST(TestTupleVectorFromTable,ListType)463 TEST(TestTupleVectorFromTable, ListType) {
464   using tuple_type = std::tuple<std::vector<int64_t>>;
465 
466   compute::ExecContext ctx;
467   compute::CastOptions cast_options;
468   auto expected_schema =
469       std::shared_ptr<Schema>(new Schema({field("column1", list(int64()), false)}));
470   std::shared_ptr<Array> expected_array =
471       ArrayFromJSON(list(int64()), "[[1, 1, 2, 34], [2, -4]]");
472   std::shared_ptr<Table> table = Table::Make(expected_schema, {expected_array});
473 
474   std::vector<tuple_type> expected_rows{tuple_type(std::vector<int64_t>{1, 1, 2, 34}),
475                                         tuple_type(std::vector<int64_t>{2, -4})};
476 
477   std::vector<tuple_type> rows(2);
478   ASSERT_OK(TupleRangeFromTable(*table, cast_options, &ctx, &rows));
479   ASSERT_EQ(rows, expected_rows);
480 }
481 
TEST(TestTupleVectorFromTable,CastingNeeded)482 TEST(TestTupleVectorFromTable, CastingNeeded) {
483   using tuple_type = std::tuple<std::vector<int64_t>>;
484 
485   compute::ExecContext ctx;
486   compute::CastOptions cast_options;
487   auto expected_schema =
488       std::shared_ptr<Schema>(new Schema({field("column1", list(int16()), false)}));
489   std::shared_ptr<Array> expected_array =
490       ArrayFromJSON(list(int16()), "[[1, 1, 2, 34], [2, -4]]");
491   std::shared_ptr<Table> table = Table::Make(expected_schema, {expected_array});
492 
493   std::vector<tuple_type> expected_rows{tuple_type(std::vector<int64_t>{1, 1, 2, 34}),
494                                         tuple_type(std::vector<int64_t>{2, -4})};
495 
496   std::vector<tuple_type> rows(2);
497   ASSERT_OK(TupleRangeFromTable(*table, cast_options, &ctx, &rows));
498   ASSERT_EQ(rows, expected_rows);
499 }
500 
TEST(STLMemoryPool,Base)501 TEST(STLMemoryPool, Base) {
502   std::allocator<uint8_t> allocator;
503   STLMemoryPool<std::allocator<uint8_t>> pool(allocator);
504 
505   uint8_t* data = nullptr;
506   ASSERT_OK(pool.Allocate(100, &data));
507   ASSERT_EQ(pool.max_memory(), 100);
508   ASSERT_EQ(pool.bytes_allocated(), 100);
509   ASSERT_NE(data, nullptr);
510 
511   ASSERT_OK(pool.Reallocate(100, 150, &data));
512   ASSERT_EQ(pool.max_memory(), 150);
513   ASSERT_EQ(pool.bytes_allocated(), 150);
514 
515   pool.Free(data, 150);
516 
517   ASSERT_EQ(pool.max_memory(), 150);
518   ASSERT_EQ(pool.bytes_allocated(), 0);
519 }
520 
TEST(allocator,MemoryTracking)521 TEST(allocator, MemoryTracking) {
522   auto pool = default_memory_pool();
523   allocator<uint64_t> alloc;
524   uint64_t* data = alloc.allocate(100);
525 
526   ASSERT_EQ(100 * sizeof(uint64_t), pool->bytes_allocated());
527 
528   alloc.deallocate(data, 100);
529   ASSERT_EQ(0, pool->bytes_allocated());
530 }
531 
532 #if !(defined(ARROW_VALGRIND) || defined(ADDRESS_SANITIZER) || defined(ARROW_JEMALLOC))
533 
TEST(allocator,TestOOM)534 TEST(allocator, TestOOM) {
535   allocator<uint64_t> alloc;
536   uint64_t to_alloc = std::numeric_limits<uint64_t>::max() / 2;
537   ASSERT_THROW(alloc.allocate(to_alloc), std::bad_alloc);
538 }
539 
TEST(stl_allocator,MaxMemory)540 TEST(stl_allocator, MaxMemory) {
541   auto pool = MemoryPool::CreateDefault();
542 
543   allocator<uint8_t> alloc(pool.get());
544   uint8_t* data = alloc.allocate(1000);
545   uint8_t* data2 = alloc.allocate(1000);
546 
547   alloc.deallocate(data, 1000);
548   alloc.deallocate(data2, 1000);
549 
550   ASSERT_EQ(2000, pool->max_memory());
551 }
552 
553 #endif  // !(defined(ARROW_VALGRIND) || defined(ADDRESS_SANITIZER)
554         // || defined(ARROW_JEMALLOC))
555 
556 }  // namespace stl
557 
558 }  // namespace arrow
559