1 /**
2  * @file unit-CellSlabIter.cc
3  *
4  * @section LICENSE
5  *
6  * The MIT License
7  *
8  * @copyright Copyright (c) 2017-2021 TileDB, Inc.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  * @section DESCRIPTION
29  *
30  * Tests the `CellSlabIter` class.
31  */
32 
33 #include "test/src/helpers.h"
34 #include "test/src/vfs_helpers.h"
35 #include "tiledb/sm/c_api/tiledb_struct_def.h"
36 #include "tiledb/sm/subarray/cell_slab_iter.h"
37 
38 #ifdef _WIN32
39 #include "tiledb/sm/filesystem/win.h"
40 #else
41 #include "tiledb/sm/filesystem/posix.h"
42 #endif
43 
44 #include <catch.hpp>
45 #include <iostream>
46 
47 using namespace tiledb::sm;
48 using namespace tiledb::test;
49 
50 /* ********************************* */
51 /*         STRUCT DEFINITION         */
52 /* ********************************* */
53 
54 struct CellSlabIterFx {
55   tiledb_ctx_t* ctx_;
56   tiledb_vfs_t* vfs_;
57 
58   const std::vector<std::unique_ptr<SupportedFs>> fs_vec_;
59 
60   std::string temp_dir_;
61   std::string array_name_;
62   const char* ARRAY_NAME = "cell_slab_iter";
63   tiledb_array_t* array_ = nullptr;
64 
65   CellSlabIterFx();
66   ~CellSlabIterFx();
67 
68   template <class T>
69   void check_iter(
70       const Subarray& subarray, const std::vector<CellSlab<T>>& c_cell_slabs);
71 };
72 
CellSlabIterFx()73 CellSlabIterFx::CellSlabIterFx()
74     : fs_vec_(vfs_test_get_fs_vec()) {
75   // Initialize vfs test
76   REQUIRE(vfs_test_init(fs_vec_, &ctx_, &vfs_).ok());
77 
78 // Create temporary directory based on the supported filesystem
79 #ifdef _WIN32
80   SupportedFsLocal windows_fs;
81   temp_dir_ = windows_fs.file_prefix() + windows_fs.temp_dir();
82 #else
83   SupportedFsLocal posix_fs;
84   temp_dir_ = posix_fs.file_prefix() + posix_fs.temp_dir();
85 #endif
86 
87   create_dir(temp_dir_, ctx_, vfs_);
88 
89   array_name_ = temp_dir_ + ARRAY_NAME;
90   int rc = tiledb_array_alloc(ctx_, array_name_.c_str(), &array_);
91   CHECK(rc == TILEDB_OK);
92 }
93 
~CellSlabIterFx()94 CellSlabIterFx::~CellSlabIterFx() {
95   tiledb_array_free(&array_);
96   remove_dir(temp_dir_, ctx_, vfs_);
97   tiledb_ctx_free(&ctx_);
98   tiledb_vfs_free(&vfs_);
99 }
100 
101 template <class T>
check_iter(const Subarray & subarray,const std::vector<CellSlab<T>> & c_cell_slabs)102 void CellSlabIterFx::check_iter(
103     const Subarray& subarray, const std::vector<CellSlab<T>>& c_cell_slabs) {
104   CellSlabIter<T> iter(&subarray);
105   CHECK(iter.end());
106   CHECK(iter.begin().ok());
107   auto cell_slab = iter.cell_slab();
108   CHECK(cell_slab == c_cell_slabs[0]);
109 
110   for (size_t i = 1; i < c_cell_slabs.size(); ++i) {
111     ++iter;
112     cell_slab = iter.cell_slab();
113     CHECK(cell_slab == c_cell_slabs[i]);
114     CHECK(!iter.end());
115   }
116 
117   ++iter;
118   CHECK(iter.end());
119 }
120 
121 /* ********************************* */
122 /*                TESTS              */
123 /* ********************************* */
124 
125 TEST_CASE_METHOD(
126     CellSlabIterFx, "CellSlabIter: Empty iterator", "[CellSlabIter][empty]") {
127   CellSlabIter<int32_t> iter;
128   CHECK(iter.end());
129   CHECK(iter.begin().ok());
130   CHECK(iter.end());
131 }
132 
133 TEST_CASE_METHOD(
134     CellSlabIterFx, "CellSlabIter: Error checks", "[CellSlabIter][error]") {
135   // Create array
136   uint64_t domain[] = {1, 100};
137   uint64_t tile_extent = 10;
138   create_array(
139       ctx_,
140       array_name_,
141       TILEDB_DENSE,
142       {"d"},
143       {TILEDB_UINT64},
144       {domain},
145       {&tile_extent},
146       {"a", "b"},
147       {TILEDB_INT32, TILEDB_INT32},
148       {1, TILEDB_VAR_NUM},
149       {tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1),
150        tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1)},
151       TILEDB_ROW_MAJOR,
152       TILEDB_ROW_MAJOR,
153       2);
154 
155   // Create subarray
156   open_array(ctx_, array_, TILEDB_READ);
157   Subarray subarray;
158   SubarrayRanges<uint64_t> ranges = {};
159   Layout subarray_layout = Layout::ROW_MAJOR;
160   create_subarray(array_->array_, ranges, subarray_layout, &subarray);
161 
162   // Datatype mismatch
163   CellSlabIter<int32_t> iter(&subarray);
164   CHECK(iter.end());
165   CHECK(!iter.begin().ok());
166 
167   // Create subarray
168   Subarray subarray_2;
169   subarray_layout = Layout::GLOBAL_ORDER;
170   create_subarray(array_->array_, ranges, subarray_layout, &subarray_2);
171 
172   // Invalid layout
173   CellSlabIter<uint64_t> iter2(&subarray_2);
174   CHECK(iter2.end());
175   CHECK(!iter2.begin().ok());
176 
177   close_array(ctx_, array_);
178 }
179 
180 TEST_CASE_METHOD(
181     CellSlabIterFx,
182     "CellSlabIter: Test 1D ranges",
183     "[CellSlabIter][ranges][1d]") {
184   // Create array
185   uint64_t domain[] = {1, 100};
186   uint64_t tile_extent = 10;
187   create_array(
188       ctx_,
189       array_name_,
190       TILEDB_DENSE,
191       {"d"},
192       {TILEDB_UINT64},
193       {domain},
194       {&tile_extent},
195       {"a", "b"},
196       {TILEDB_INT32, TILEDB_INT32},
197       {1, TILEDB_VAR_NUM},
198       {tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1),
199        tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1)},
200       TILEDB_ROW_MAJOR,
201       TILEDB_ROW_MAJOR,
202       2);
203 
204   // Create subarray
205   open_array(ctx_, array_, TILEDB_READ);
206   Subarray subarray;
207   SubarrayRanges<uint64_t> ranges = {{5, 15, 3, 5, 10, 20, 6, 36}};
208   Layout subarray_layout = Layout::ROW_MAJOR;
209   create_subarray(array_->array_, ranges, subarray_layout, &subarray);
210 
211   CellSlabIter<uint64_t> iter(&subarray);
212   CHECK(iter.end());
213   CHECK(iter.begin().ok());
214   auto iter_ranges = iter.ranges();
215 
216   std::vector<CellSlabIter<uint64_t>::Range> c_ranges = {{5, 10, 0},
217                                                          {11, 15, 1},
218                                                          {3, 5, 0},
219                                                          {10, 10, 0},
220                                                          {11, 20, 1},
221                                                          {6, 10, 0},
222                                                          {11, 20, 1},
223                                                          {21, 30, 2},
224                                                          {31, 36, 3}};
225   CHECK(iter_ranges.size() == 1);
226   CHECK(iter_ranges[0].size() == c_ranges.size());
227   CHECK(std::equal(
228       iter_ranges[0].begin(), iter_ranges[0].end(), c_ranges.begin()));
229 
230   close_array(ctx_, array_);
231 }
232 
233 TEST_CASE_METHOD(
234     CellSlabIterFx,
235     "CellSlabIter: Test 2D ranges",
236     "[CellSlabIter][ranges][2d]") {
237   // Create array
238   uint64_t domain[] = {1, 10};
239   uint64_t tile_extent_1 = 5;
240   uint64_t tile_extent_2 = 2;
241   create_array(
242       ctx_,
243       array_name_,
244       TILEDB_DENSE,
245       {"d1", "d2"},
246       {TILEDB_UINT64, TILEDB_UINT64},
247       {domain, domain},
248       {&tile_extent_1, &tile_extent_2},
249       {"a", "b"},
250       {TILEDB_INT32, TILEDB_INT32},
251       {1, TILEDB_VAR_NUM},
252       {tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1),
253        tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1)},
254       TILEDB_ROW_MAJOR,
255       TILEDB_ROW_MAJOR,
256       2);
257 
258   // Create subarray
259   open_array(ctx_, array_, TILEDB_READ);
260   Subarray subarray;
261   SubarrayRanges<uint64_t> ranges = {{5, 8, 3, 5}, {5, 8, 3, 5}};
262   Layout subarray_layout = Layout::ROW_MAJOR;
263   create_subarray(array_->array_, ranges, subarray_layout, &subarray);
264 
265   CellSlabIter<uint64_t> iter(&subarray);
266   CHECK(iter.end());
267   CHECK(iter.begin().ok());
268   auto iter_ranges = iter.ranges();
269 
270   CHECK(iter_ranges.size() == 2);
271   std::vector<CellSlabIter<uint64_t>::Range> c_ranges_1 = {
272       {5, 5, 0}, {6, 8, 1}, {3, 5, 0}};
273   CHECK(iter_ranges[0].size() == c_ranges_1.size());
274   CHECK(std::equal(
275       iter_ranges[0].begin(), iter_ranges[0].end(), c_ranges_1.begin()));
276 
277   std::vector<CellSlabIter<uint64_t>::Range> c_ranges_2 = {
278       {5, 6, 2}, {7, 8, 3}, {3, 4, 1}, {5, 5, 2}};
279   CHECK(iter_ranges[1].size() == c_ranges_2.size());
280   CHECK(std::equal(
281       iter_ranges[1].begin(), iter_ranges[1].end(), c_ranges_2.begin()));
282 
283   close_array(ctx_, array_);
284 }
285 
286 TEST_CASE_METHOD(
287     CellSlabIterFx,
288     "CellSlabIter: Test 1D slabs",
289     "[CellSlabIter][slabs][1d]") {
290   // Create array
291   uint64_t domain[] = {1, 100};
292   uint64_t tile_extent = 10;
293   create_array(
294       ctx_,
295       array_name_,
296       TILEDB_DENSE,
297       {"d"},
298       {TILEDB_UINT64},
299       {domain},
300       {&tile_extent},
301       {"a", "b"},
302       {TILEDB_INT32, TILEDB_INT32},
303       {1, TILEDB_VAR_NUM},
304       {tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1),
305        tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1)},
306       TILEDB_ROW_MAJOR,
307       TILEDB_ROW_MAJOR,
308       2);
309 
310   // Create subarray
311   open_array(ctx_, array_, TILEDB_READ);
312   Subarray subarray;
313   SubarrayRanges<uint64_t> ranges = {{5, 15, 3, 5, 11, 14}};
314   Layout subarray_layout = Layout::ROW_MAJOR;
315   create_subarray(array_->array_, ranges, subarray_layout, &subarray);
316   subarray.compute_tile_coords<uint64_t>();
317 
318   uint64_t tile_coords_0[] = {0};
319   uint64_t tile_coords_1[] = {1};
320 
321   // Check iterator
322   std::vector<CellSlab<uint64_t>> c_cell_slabs = {
323       CellSlab<uint64_t>(tile_coords_0, {5}, 6),
324       CellSlab<uint64_t>(tile_coords_1, {11}, 5),
325       CellSlab<uint64_t>(tile_coords_0, {3}, 3),
326       CellSlab<uint64_t>(tile_coords_1, {11}, 4),
327   };
328   check_iter<uint64_t>(subarray, c_cell_slabs);
329 
330   close_array(ctx_, array_);
331 }
332 
333 TEST_CASE_METHOD(
334     CellSlabIterFx,
335     "CellSlabIter: Test 2D slabs",
336     "[CellSlabIter][slabs][2d]") {
337   // Create array
338   uint64_t domain_1[] = {1, 10};
339   uint64_t domain_2[] = {1, 9};
340   uint64_t tile_extent_1 = 5;
341   uint64_t tile_extent_2 = 3;
342   create_array(
343       ctx_,
344       array_name_,
345       TILEDB_DENSE,
346       {"d1", "d2"},
347       {TILEDB_UINT64, TILEDB_UINT64},
348       {domain_1, domain_2},
349       {&tile_extent_1, &tile_extent_2},
350       {"a", "b"},
351       {TILEDB_INT32, TILEDB_INT32},
352       {1, TILEDB_VAR_NUM},
353       {tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1),
354        tiledb::test::Compressor(TILEDB_FILTER_LZ4, -1)},
355       TILEDB_ROW_MAJOR,
356       TILEDB_ROW_MAJOR,
357       2);
358 
359   Layout subarray_layout = Layout::ROW_MAJOR;
360   std::vector<CellSlab<uint64_t>> c_cell_slabs;
361   uint64_t tile_coords_0_0[] = {0, 0};
362   uint64_t tile_coords_0_1[] = {0, 1};
363   uint64_t tile_coords_0_2[] = {0, 2};
364   uint64_t tile_coords_1_0[] = {1, 0};
365   uint64_t tile_coords_1_1[] = {1, 1};
366   uint64_t tile_coords_1_2[] = {1, 2};
367 
368   SECTION("- row-major") {
369     subarray_layout = Layout::ROW_MAJOR;
370     c_cell_slabs = {
371         CellSlab<uint64_t>(tile_coords_0_0, {2, 1}, 2),
372         CellSlab<uint64_t>(tile_coords_0_1, {2, 5}, 2),
373         CellSlab<uint64_t>(tile_coords_0_2, {2, 7}, 2),
374         CellSlab<uint64_t>(tile_coords_0_0, {3, 1}, 2),
375         CellSlab<uint64_t>(tile_coords_0_1, {3, 5}, 2),
376         CellSlab<uint64_t>(tile_coords_0_2, {3, 7}, 2),
377         CellSlab<uint64_t>(tile_coords_0_0, {4, 1}, 2),
378         CellSlab<uint64_t>(tile_coords_0_1, {4, 5}, 2),
379         CellSlab<uint64_t>(tile_coords_0_2, {4, 7}, 2),
380         CellSlab<uint64_t>(tile_coords_0_0, {3, 1}, 2),
381         CellSlab<uint64_t>(tile_coords_0_1, {3, 5}, 2),
382         CellSlab<uint64_t>(tile_coords_0_2, {3, 7}, 2),
383         CellSlab<uint64_t>(tile_coords_0_0, {4, 1}, 2),
384         CellSlab<uint64_t>(tile_coords_0_1, {4, 5}, 2),
385         CellSlab<uint64_t>(tile_coords_0_2, {4, 7}, 2),
386         CellSlab<uint64_t>(tile_coords_0_0, {5, 1}, 2),
387         CellSlab<uint64_t>(tile_coords_0_1, {5, 5}, 2),
388         CellSlab<uint64_t>(tile_coords_0_2, {5, 7}, 2),
389         CellSlab<uint64_t>(tile_coords_1_0, {6, 1}, 2),
390         CellSlab<uint64_t>(tile_coords_1_1, {6, 5}, 2),
391         CellSlab<uint64_t>(tile_coords_1_2, {6, 7}, 2),
392         CellSlab<uint64_t>(tile_coords_1_0, {7, 1}, 2),
393         CellSlab<uint64_t>(tile_coords_1_1, {7, 5}, 2),
394         CellSlab<uint64_t>(tile_coords_1_2, {7, 7}, 2),
395         CellSlab<uint64_t>(tile_coords_1_0, {8, 1}, 2),
396         CellSlab<uint64_t>(tile_coords_1_1, {8, 5}, 2),
397         CellSlab<uint64_t>(tile_coords_1_2, {8, 7}, 2),
398         CellSlab<uint64_t>(tile_coords_1_0, {9, 1}, 2),
399         CellSlab<uint64_t>(tile_coords_1_1, {9, 5}, 2),
400         CellSlab<uint64_t>(tile_coords_1_2, {9, 7}, 2),
401     };
402   }
403 
404   SECTION("- col-major") {
405     subarray_layout = Layout::COL_MAJOR;
406     c_cell_slabs = {
407         CellSlab<uint64_t>(tile_coords_0_0, {2, 1}, 3),
408         CellSlab<uint64_t>(tile_coords_0_0, {3, 1}, 3),
409         CellSlab<uint64_t>(tile_coords_1_0, {6, 1}, 4),
410         CellSlab<uint64_t>(tile_coords_0_0, {2, 2}, 3),
411         CellSlab<uint64_t>(tile_coords_0_0, {3, 2}, 3),
412         CellSlab<uint64_t>(tile_coords_1_0, {6, 2}, 4),
413         CellSlab<uint64_t>(tile_coords_0_1, {2, 5}, 3),
414         CellSlab<uint64_t>(tile_coords_0_1, {3, 5}, 3),
415         CellSlab<uint64_t>(tile_coords_1_1, {6, 5}, 4),
416         CellSlab<uint64_t>(tile_coords_0_1, {2, 6}, 3),
417         CellSlab<uint64_t>(tile_coords_0_1, {3, 6}, 3),
418         CellSlab<uint64_t>(tile_coords_1_1, {6, 6}, 4),
419         CellSlab<uint64_t>(tile_coords_0_2, {2, 7}, 3),
420         CellSlab<uint64_t>(tile_coords_0_2, {3, 7}, 3),
421         CellSlab<uint64_t>(tile_coords_1_2, {6, 7}, 4),
422         CellSlab<uint64_t>(tile_coords_0_2, {2, 8}, 3),
423         CellSlab<uint64_t>(tile_coords_0_2, {3, 8}, 3),
424         CellSlab<uint64_t>(tile_coords_1_2, {6, 8}, 4),
425     };
426   }
427 
428   open_array(ctx_, array_, TILEDB_READ);
429 
430   Subarray subarray;
431   SubarrayRanges<uint64_t> ranges = {
432       {2, 4, 3, 9},
433       {1, 2, 5, 8},
434   };
435   create_subarray(array_->array_, ranges, subarray_layout, &subarray);
436   subarray.compute_tile_coords<uint64_t>();
437 
438   check_iter<uint64_t>(subarray, c_cell_slabs);
439 
440   close_array(ctx_, array_);
441 }
442