1 /**
2  * @file   dimension.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  * This file implements class Dimension.
31  */
32 
33 #include "tiledb/sm/array_schema/dimension.h"
34 #include "tiledb/common/logger.h"
35 #include "tiledb/sm/buffer/buffer.h"
36 #include "tiledb/sm/enums/datatype.h"
37 #include "tiledb/sm/enums/filter_type.h"
38 #include "tiledb/sm/misc/utils.h"
39 
40 #include <bitset>
41 #include <cassert>
42 #include <cmath>
43 #include <iostream>
44 
45 using namespace tiledb::common;
46 
blank()47 tiledb::common::blank<tiledb::sm::Dimension>::blank()
48     : tiledb::sm::Dimension{"", tiledb::sm::Datatype::INT32} {
49 }
50 
51 namespace tiledb {
52 namespace sm {
53 
54 /* ********************************* */
55 /*     CONSTRUCTORS & DESTRUCTORS    */
56 /* ********************************* */
57 
Dimension(const std::string & name,Datatype type)58 Dimension::Dimension(const std::string& name, Datatype type)
59     : name_(name)
60     , type_(type) {
61   cell_val_num_ = (datatype_is_string(type)) ? constants::var_num : 1;
62   set_ceil_to_tile_func();
63   set_check_range_func();
64   set_adjust_range_oob_func();
65   set_coincides_with_tiles_func();
66   set_compute_mbr_func();
67   set_crop_range_func();
68   set_domain_range_func();
69   set_expand_range_func();
70   set_expand_range_v_func();
71   set_expand_to_tile_func();
72   set_oob_func();
73   set_covered_func();
74   set_overlap_func();
75   set_overlap_ratio_func();
76   set_split_range_func();
77   set_splitting_value_func();
78   set_tile_num_func();
79   set_map_to_uint64_func();
80   set_map_to_uint64_2_func();
81   set_map_to_uint64_3_func();
82   set_map_from_uint64_func();
83   set_smaller_than_func();
84 }
85 
Dimension(const Dimension * dim)86 Dimension::Dimension(const Dimension* dim) {
87   assert(dim != nullptr);
88 
89   cell_val_num_ = dim->cell_val_num_;
90   filters_ = dim->filters_;
91   name_ = dim->name();
92   type_ = dim->type_;
93 
94   // Set fuctions
95   adjust_range_oob_func_ = dim->adjust_range_oob_func_;
96   ceil_to_tile_func_ = dim->ceil_to_tile_func_;
97   check_range_func_ = dim->check_range_func_;
98   coincides_with_tiles_func_ = dim->coincides_with_tiles_func_;
99   compute_mbr_func_ = dim->compute_mbr_func_;
100   crop_range_func_ = dim->crop_range_func_;
101   domain_range_func_ = dim->domain_range_func_;
102   expand_range_v_func_ = dim->expand_range_v_func_;
103   expand_range_func_ = dim->expand_range_func_;
104   expand_to_tile_func_ = dim->expand_to_tile_func_;
105   oob_func_ = dim->oob_func_;
106   covered_func_ = dim->covered_func_;
107   overlap_func_ = dim->overlap_func_;
108   overlap_ratio_func_ = dim->overlap_ratio_func_;
109   split_range_func_ = dim->split_range_func_;
110   splitting_value_func_ = dim->splitting_value_func_;
111   tile_num_func_ = dim->tile_num_func_;
112   map_to_uint64_func_ = dim->map_to_uint64_func_;
113   map_to_uint64_2_func_ = dim->map_to_uint64_2_func_;
114   map_to_uint64_3_func_ = dim->map_to_uint64_3_func_;
115   map_from_uint64_func_ = dim->map_from_uint64_func_;
116   smaller_than_func_ = dim->smaller_than_func_;
117 
118   domain_ = dim->domain();
119   tile_extent_ = dim->tile_extent();
120 }
121 
122 /* ********************************* */
123 /*                API                */
124 /* ********************************* */
125 
cell_val_num() const126 unsigned int Dimension::cell_val_num() const {
127   return cell_val_num_;
128 }
129 
set_cell_val_num(unsigned int cell_val_num)130 Status Dimension::set_cell_val_num(unsigned int cell_val_num) {
131   // Error checkls
132   if (datatype_is_string(type_) && cell_val_num != constants::var_num)
133     return LOG_STATUS(
134         Status::DimensionError("Cannot set non-variable number of values per "
135                                "coordinate for a string dimension"));
136   if (!datatype_is_string(type_) && cell_val_num != 1)
137     return LOG_STATUS(Status::DimensionError(
138         "Cannot set number of values per coordinate; Currently only one value "
139         "per coordinate is supported"));
140 
141   cell_val_num_ = cell_val_num;
142 
143   return Status::Ok();
144 }
145 
coord_size() const146 uint64_t Dimension::coord_size() const {
147   return datatype_size(type_);
148 }
149 
coord_to_str(const QueryBuffer & buff,uint64_t i) const150 std::string Dimension::coord_to_str(const QueryBuffer& buff, uint64_t i) const {
151   std::stringstream ss;
152 
153   // Fixed sized
154   if (!var_size()) {
155     auto cbuff = (const unsigned char*)buff.buffer_;
156     auto coord = cbuff + i * coord_size();
157 
158     switch (type_) {
159       case Datatype::INT32:
160         ss << *((int32_t*)coord);
161         break;
162       case Datatype::INT64:
163         ss << *((int64_t*)coord);
164         break;
165       case Datatype::INT8:
166         ss << *((int8_t*)coord);
167         break;
168       case Datatype::UINT8:
169         ss << *((uint8_t*)coord);
170         break;
171       case Datatype::INT16:
172         ss << *((int16_t*)coord);
173         break;
174       case Datatype::UINT16:
175         ss << *((uint16_t*)coord);
176         break;
177       case Datatype::UINT32:
178         ss << *((uint32_t*)coord);
179         break;
180       case Datatype::UINT64:
181         ss << *((uint64_t*)coord);
182         break;
183       case Datatype::FLOAT32:
184         ss << *((float*)coord);
185         break;
186       case Datatype::FLOAT64:
187         ss << *((double*)coord);
188         break;
189       case Datatype::DATETIME_YEAR:
190       case Datatype::DATETIME_MONTH:
191       case Datatype::DATETIME_WEEK:
192       case Datatype::DATETIME_DAY:
193       case Datatype::DATETIME_HR:
194       case Datatype::DATETIME_MIN:
195       case Datatype::DATETIME_SEC:
196       case Datatype::DATETIME_MS:
197       case Datatype::DATETIME_US:
198       case Datatype::DATETIME_NS:
199       case Datatype::DATETIME_PS:
200       case Datatype::DATETIME_FS:
201       case Datatype::DATETIME_AS:
202       case Datatype::TIME_HR:
203       case Datatype::TIME_MIN:
204       case Datatype::TIME_SEC:
205       case Datatype::TIME_MS:
206       case Datatype::TIME_US:
207       case Datatype::TIME_NS:
208       case Datatype::TIME_PS:
209       case Datatype::TIME_FS:
210       case Datatype::TIME_AS:
211         ss << *((int64_t*)coord);
212         break;
213       default:
214         break;
215     }
216   } else {  // Var-sized
217     assert(type_ == Datatype::STRING_ASCII);
218     auto offs = (const uint64_t*)buff.buffer_;
219     auto offs_size = *(buff.buffer_size_);
220     auto var_size = *(buff.buffer_var_size_);
221     auto vars = (const char*)buff.buffer_var_;
222     auto coord = &vars[offs[i]];
223     auto next_off = ((i + 1) * constants::cell_var_offset_size == offs_size) ?
224                         var_size :
225                         offs[i + 1];
226     auto coord_size = next_off - offs[i];
227     auto coord_str = std::string(coord, coord_size);
228     ss << coord_str;
229   }
230 
231   return ss.str();
232 }
233 
deserialize(ConstBuffer * buff,uint32_t version,Datatype type)234 Status Dimension::deserialize(
235     ConstBuffer* buff, uint32_t version, Datatype type) {
236   // Load dimension name
237   uint32_t dimension_name_size;
238   RETURN_NOT_OK(buff->read(&dimension_name_size, sizeof(uint32_t)));
239   name_.resize(dimension_name_size);
240   RETURN_NOT_OK(buff->read(&name_[0], dimension_name_size));
241 
242   // Applicable only to version >= 5
243   if (version >= 5) {
244     // Load type
245     uint8_t type;
246     RETURN_NOT_OK(buff->read(&type, sizeof(uint8_t)));
247     type_ = (Datatype)type;
248 
249     // Load cell_val_num_
250     RETURN_NOT_OK(buff->read(&cell_val_num_, sizeof(uint32_t)));
251 
252     // Load filter pipeline
253     RETURN_NOT_OK(filters_.deserialize(buff));
254   } else {
255     type_ = type;
256   }
257 
258   // Load domain
259   uint64_t domain_size = 0;
260   if (version >= 5) {
261     RETURN_NOT_OK(buff->read(&domain_size, sizeof(uint64_t)));
262   } else {
263     domain_size = 2 * coord_size();
264   }
265   if (domain_size != 0) {
266     std::vector<uint8_t> tmp(domain_size);
267     RETURN_NOT_OK(buff->read(&tmp[0], domain_size));
268     domain_ = Range(&tmp[0], domain_size);
269   }
270 
271   // Load tile extent
272   tile_extent_.assign_as_void();
273   uint8_t null_tile_extent;
274   RETURN_NOT_OK(buff->read(&null_tile_extent, sizeof(uint8_t)));
275   if (null_tile_extent == 0) {
276     tile_extent_.resize(coord_size());
277     RETURN_NOT_OK(buff->read(tile_extent_.data(), coord_size()));
278   }
279 
280   set_ceil_to_tile_func();
281   set_check_range_func();
282   set_adjust_range_oob_func();
283   set_coincides_with_tiles_func();
284   set_compute_mbr_func();
285   set_crop_range_func();
286   set_domain_range_func();
287   set_expand_range_func();
288   set_expand_range_v_func();
289   set_expand_to_tile_func();
290   set_oob_func();
291   set_covered_func();
292   set_overlap_func();
293   set_overlap_ratio_func();
294   set_split_range_func();
295   set_splitting_value_func();
296   set_tile_num_func();
297   set_map_to_uint64_func();
298   set_map_to_uint64_2_func();
299   set_map_to_uint64_3_func();
300   set_map_from_uint64_func();
301   set_smaller_than_func();
302 
303   return Status::Ok();
304 }
305 
domain() const306 const Range& Dimension::domain() const {
307   return domain_;
308 }
309 
dump(FILE * out) const310 void Dimension::dump(FILE* out) const {
311   if (out == nullptr)
312     out = stdout;
313   // Retrieve domain and tile extent strings
314   std::string domain_s = domain_str();
315   std::string tile_extent_s = tile_extent_str();
316 
317   // Dump
318   fprintf(out, "### Dimension ###\n");
319   fprintf(out, "- Name: %s\n", name_.c_str());
320   fprintf(out, "- Type: %s\n", datatype_str(type_).c_str());
321   if (!var_size())
322     fprintf(out, "- Cell val num: %u\n", cell_val_num_);
323   else
324     fprintf(out, "- Cell val num: var\n");
325   fprintf(out, "- Domain: %s\n", domain_s.c_str());
326   fprintf(out, "- Tile extent: %s\n", tile_extent_s.c_str());
327   fprintf(out, "- Filters: %u", (unsigned)filters_.size());
328   filters_.dump(out);
329   fprintf(out, "\n");
330 }
331 
filters() const332 const FilterPipeline& Dimension::filters() const {
333   return filters_;
334 }
335 
name() const336 const std::string& Dimension::name() const {
337   return name_;
338 }
339 
340 template <class T>
ceil_to_tile(const Dimension * dim,const Range & r,uint64_t tile_num,ByteVecValue * v)341 void Dimension::ceil_to_tile(
342     const Dimension* dim, const Range& r, uint64_t tile_num, ByteVecValue* v) {
343   assert(dim != nullptr);
344   assert(!r.empty());
345   assert(dim->tile_extent());
346 
347   auto tile_extent = *(const T*)dim->tile_extent().data();
348   auto dim_dom = (const T*)dim->domain().data();
349   auto r_t = (const T*)r.data();
350 
351   T mid = tile_coord_low(tile_num + 1, r_t[0], tile_extent);
352   uint64_t div = tile_idx(mid, dim_dom[0], tile_extent);
353   T floored_mid = tile_coord_low(div, dim_dom[0], tile_extent);
354   assert(v != nullptr);
355   v->assign_as<T>(
356       (std::is_integral<T>::value) ?
357           floored_mid - 1 :
358           static_cast<T>(
359               std::nextafter(floored_mid, std::numeric_limits<T>::lowest())));
360 }
361 
ceil_to_tile(const Range & r,uint64_t tile_num,ByteVecValue * v) const362 void Dimension::ceil_to_tile(
363     const Range& r, uint64_t tile_num, ByteVecValue* v) const {
364   assert(ceil_to_tile_func_ != nullptr);
365   ceil_to_tile_func_(this, r, tile_num, v);
366 }
367 
check_range(const Range & range) const368 Status Dimension::check_range(const Range& range) const {
369   // Inapplicable to string domains
370   if (type_ == Datatype::STRING_ASCII)
371     return Status::Ok();
372 
373   assert(check_range_func_ != nullptr);
374   std::string err_msg;
375   auto ret = check_range_func_(this, range, &err_msg);
376   if (!ret)
377     return LOG_STATUS(Status::DimensionError(err_msg));
378   return Status::Ok();
379 }
380 
adjust_range_oob(Range * range) const381 Status Dimension::adjust_range_oob(Range* range) const {
382   // Inapplicable to string domains
383   if (type_ == Datatype::STRING_ASCII)
384     return Status::Ok();
385 
386   assert(adjust_range_oob_func_ != nullptr);
387   adjust_range_oob_func_(this, range);
388   return Status::Ok();
389 }
390 
391 template <class T>
coincides_with_tiles(const Dimension * dim,const Range & r)392 bool Dimension::coincides_with_tiles(const Dimension* dim, const Range& r) {
393   assert(dim != nullptr);
394   assert(!r.empty());
395   assert(dim->tile_extent());
396 
397   auto dim_domain = (const T*)dim->domain().data();
398   auto tile_extent = *(const T*)dim->tile_extent().data();
399   auto d = (const T*)r.data();
400   auto rounded_1 = Dimension::round_to_tile(d[0], dim_domain[0], tile_extent);
401   auto rounded_2 =
402       Dimension::round_to_tile(T(d[1] + 1), dim_domain[0], tile_extent);
403   return (rounded_1 == d[0]) && (rounded_2 == T(d[1] + 1));
404 }
405 
coincides_with_tiles(const Range & r) const406 bool Dimension::coincides_with_tiles(const Range& r) const {
407   assert(coincides_with_tiles_func_ != nullptr);
408   return coincides_with_tiles_func_(this, r);
409 }
410 
411 template <class T>
compute_mbr(const Tile & tile,Range * mbr)412 Status Dimension::compute_mbr(const Tile& tile, Range* mbr) {
413   assert(mbr != nullptr);
414   auto cell_num = tile.cell_num();
415   assert(cell_num > 0);
416 
417   void* tile_buffer = tile.buffer()->data();
418   assert(tile_buffer != nullptr);
419 
420   // Initialize MBR with the first tile values
421   const T* const data = static_cast<T*>(tile_buffer);
422   T res[] = {data[0], data[0]};
423   mbr->set_range(res, sizeof(res));
424 
425   // Expand the MBR with the rest tile values
426   for (uint64_t c = 1; c < cell_num; ++c)
427     expand_range_v<T>(&data[c], mbr);
428 
429   return Status::Ok();
430 }
431 
compute_mbr(const Tile & tile,Range * mbr) const432 Status Dimension::compute_mbr(const Tile& tile, Range* mbr) const {
433   assert(compute_mbr_func_ != nullptr);
434   return compute_mbr_func_(tile, mbr);
435 }
436 
437 template <>
compute_mbr_var(const Tile & tile_off,const Tile & tile_val,Range * mbr)438 Status Dimension::compute_mbr_var<char>(
439     const Tile& tile_off, const Tile& tile_val, Range* mbr) {
440   assert(mbr != nullptr);
441   auto d_val_size = tile_val.size();
442   auto cell_num = tile_off.cell_num();
443   assert(cell_num > 0);
444 
445   void* tile_buffer_off = tile_off.buffer()->data();
446   assert(tile_buffer_off != nullptr);
447 
448   void* tile_buffer_val = tile_val.buffer()->data();
449   assert(tile_buffer_val != nullptr);
450 
451   uint64_t* const d_off = static_cast<uint64_t*>(tile_buffer_off);
452   char* const d_val = static_cast<char*>(tile_buffer_val);
453 
454   // Initialize MBR with the first tile values
455   auto size_0 = (cell_num == 1) ? d_val_size : d_off[1];
456   mbr->set_range_var(d_val, size_0, d_val, size_0);
457 
458   // Expand the MBR with the rest tile values
459   for (uint64_t c = 1; c < cell_num; ++c) {
460     auto size =
461         (c == cell_num - 1) ? d_val_size - d_off[c] : d_off[c + 1] - d_off[c];
462     expand_range_var_v(&d_val[d_off[c]], size, mbr);
463   }
464 
465   return Status::Ok();
466 }
467 
compute_mbr_var(const Tile & tile_off,const Tile & tile_val,Range * mbr) const468 Status Dimension::compute_mbr_var(
469     const Tile& tile_off, const Tile& tile_val, Range* mbr) const {
470   assert(compute_mbr_var_func_ != nullptr);
471   return compute_mbr_var_func_(tile_off, tile_val, mbr);
472 }
473 
474 template <class T>
crop_range(const Dimension * dim,Range * range)475 void Dimension::crop_range(const Dimension* dim, Range* range) {
476   assert(dim != nullptr);
477   assert(!range->empty());
478   auto dim_dom = (const T*)dim->domain().data();
479   auto r = (const T*)range->data();
480   T res[2] = {std::max(r[0], dim_dom[0]), std::min(r[1], dim_dom[1])};
481   range->set_range(res, sizeof(res));
482 }
483 
crop_range(Range * range) const484 void Dimension::crop_range(Range* range) const {
485   assert(crop_range_func_ != nullptr);
486   crop_range_func_(this, range);
487 }
488 
489 template <class T>
domain_range(const Range & range)490 uint64_t Dimension::domain_range(const Range& range) {
491   assert(!range.empty());
492 
493   // Inapplicable to real domains
494   if (!std::is_integral<T>::value)
495     return std::numeric_limits<uint64_t>::max();
496 
497   auto r = (const T*)range.data();
498   uint64_t ret = r[1] - r[0];
499   if (ret == std::numeric_limits<uint64_t>::max())  // overflow
500     return ret;
501   ++ret;
502 
503   return ret;
504 }
505 
domain_range(const Range & range) const506 uint64_t Dimension::domain_range(const Range& range) const {
507   assert(domain_range_func_ != nullptr);
508   return domain_range_func_(range);
509 }
510 
511 template <class T>
expand_range_v(const void * v,Range * r)512 void Dimension::expand_range_v(const void* v, Range* r) {
513   assert(v != nullptr);
514   assert(r != nullptr);
515   assert(!r->empty());
516   auto rt = (const T*)r->data();
517   auto vt = (const T*)v;
518   T res[2] = {std::min(rt[0], *vt), std::max(rt[1], *vt)};
519   r->set_range(res, sizeof(res));
520 }
521 
expand_range_v(const void * v,Range * r) const522 void Dimension::expand_range_v(const void* v, Range* r) const {
523   assert(expand_range_v_func_ != nullptr);
524   expand_range_v_func_(v, r);
525 }
526 
expand_range_var_v(const char * v,uint64_t v_size,Range * r)527 void Dimension::expand_range_var_v(const char* v, uint64_t v_size, Range* r) {
528   assert(v != nullptr);
529   assert(r != nullptr);
530 
531   auto start = r->start_str();
532   auto end = r->end_str();
533   auto v_str = std::string(v, v_size);
534 
535   r->set_str_range(
536       (v_str < start) ? v_str : start, (v_str > end) ? v_str : end);
537 }
538 
539 template <class T>
expand_range(const Range & r1,Range * r2)540 void Dimension::expand_range(const Range& r1, Range* r2) {
541   assert(!r1.empty());
542   assert(!r2->empty());
543   auto d1 = (const T*)r1.data();
544   auto d2 = (const T*)r2->data();
545   T res[2] = {std::min(d1[0], d2[0]), std::max(d1[1], d2[1])};
546   r2->set_range(res, sizeof(res));
547 }
548 
expand_range(const Range & r1,Range * r2) const549 void Dimension::expand_range(const Range& r1, Range* r2) const {
550   assert(expand_range_func_ != nullptr);
551   expand_range_func_(r1, r2);
552 }
553 
expand_range_var(const Range & r1,Range * r2) const554 void Dimension::expand_range_var(const Range& r1, Range* r2) const {
555   assert(type_ == Datatype::STRING_ASCII);
556 
557   auto r1_start = r1.start_str();
558   auto r1_end = r1.end_str();
559 
560   auto r2_start = r2->start_str();
561   auto r2_end = r2->end_str();
562 
563   auto min = (r1_start < r2_start) ? r1_start : r2_start;
564   auto max = (r1_end < r2_end) ? r2_end : r1_end;
565 
566   r2->set_str_range(min, max);
567 }
568 
569 template <class T>
expand_to_tile(const Dimension * dim,Range * range)570 void Dimension::expand_to_tile(const Dimension* dim, Range* range) {
571   assert(dim != nullptr);
572   assert(!range->empty());
573 
574   // Applicable only to regular tiles and integral domains
575   if (!dim->tile_extent() || !std::is_integral<T>::value)
576     return;
577 
578   auto tile_extent = *(const T*)dim->tile_extent().data();
579   auto dim_dom = (const T*)dim->domain().data();
580   auto r = (const T*)range->data();
581   auto tile_idx1 = tile_idx(r[0], dim_dom[0], tile_extent);
582   auto tile_idx2 = tile_idx(r[1], dim_dom[0], tile_extent);
583 
584   T res[2];
585   res[0] = tile_coord_low(tile_idx1, dim_dom[0], tile_extent);
586   res[1] = tile_coord_high(tile_idx2, dim_dom[0], tile_extent);
587 
588   range->set_range(res, sizeof(res));
589 }
590 
expand_to_tile(Range * range) const591 void Dimension::expand_to_tile(Range* range) const {
592   assert(expand_to_tile_func_ != nullptr);
593   expand_to_tile_func_(this, range);
594 }
595 
596 template <class T>
oob(const Dimension * dim,const void * coord,std::string * err_msg)597 bool Dimension::oob(
598     const Dimension* dim, const void* coord, std::string* err_msg) {
599   auto domain = (const T*)dim->domain().data();
600   auto coord_t = (const T*)coord;
601   if (*coord_t < domain[0] || *coord_t > domain[1]) {
602     std::stringstream ss;
603     ss << "Coordinate " << *coord_t << " is out of domain bounds [" << domain[0]
604        << ", " << domain[1] << "] on dimension '" << dim->name() << "'";
605     *err_msg = ss.str();
606     return true;
607   }
608 
609   return false;
610 }
611 
oob(const void * coord) const612 Status Dimension::oob(const void* coord) const {
613   // Not applicable to string dimensions
614   if (datatype_is_string(type_))
615     return Status::Ok();
616 
617   assert(oob_func_ != nullptr);
618   std::string err_msg;
619   auto ret = oob_func_(this, coord, &err_msg);
620   if (ret)
621     return Status::DimensionError(err_msg);
622   return Status::Ok();
623 }
624 
625 template <>
covered(const Range & r1,const Range & r2)626 bool Dimension::covered<char>(const Range& r1, const Range& r2) {
627   auto r1_start = r1.start_str();
628   auto r1_end = r1.end_str();
629   auto r2_start = r2.start_str();
630   auto r2_end = r2.end_str();
631 
632   auto r1_after_r2 =
633       !r1_start.empty() && !r2_start.empty() && r1_start >= r2_start;
634   auto r2_after_r1 = !r1_end.empty() && !r2_end.empty() && r1_end <= r2_end;
635 
636   return r1_after_r2 && r2_after_r1;
637 }
638 
639 template <class T>
covered(const Range & r1,const Range & r2)640 bool Dimension::covered(const Range& r1, const Range& r2) {
641   assert(!r1.empty());
642   assert(!r2.empty());
643 
644   auto d1 = (const T*)r1.data();
645   auto d2 = (const T*)r2.data();
646   assert(d1[0] <= d1[1]);
647   assert(d2[0] <= d2[1]);
648 
649   return d1[0] >= d2[0] && d1[1] <= d2[1];
650 }
651 
covered(const Range & r1,const Range & r2) const652 bool Dimension::covered(const Range& r1, const Range& r2) const {
653   assert(covered_func_ != nullptr);
654   return covered_func_(r1, r2);
655 }
656 
657 template <>
overlap(const Range & r1,const Range & r2)658 bool Dimension::overlap<char>(const Range& r1, const Range& r2) {
659   auto r1_start = r1.start_str();
660   auto r1_end = r1.end_str();
661   auto r2_start = r2.start_str();
662   auto r2_end = r2.end_str();
663 
664   auto r1_after_r2 = !r1_start.empty() && !r2_end.empty() && r1_start > r2_end;
665   auto r2_after_r1 = !r2_start.empty() && !r1_end.empty() && r2_start > r1_end;
666 
667   return !r1_after_r2 && !r2_after_r1;
668 }
669 
670 template <class T>
overlap(const Range & r1,const Range & r2)671 bool Dimension::overlap(const Range& r1, const Range& r2) {
672   assert(!r1.empty());
673   assert(!r2.empty());
674 
675   auto d1 = (const T*)r1.data();
676   auto d2 = (const T*)r2.data();
677   return !(d1[0] > d2[1] || d1[1] < d2[0]);
678 }
679 
overlap(const Range & r1,const Range & r2) const680 bool Dimension::overlap(const Range& r1, const Range& r2) const {
681   assert(overlap_func_ != nullptr);
682   return overlap_func_(r1, r2);
683 }
684 
685 template <>
overlap_ratio(const Range & r1,const Range & r2)686 double Dimension::overlap_ratio<char>(const Range& r1, const Range& r2) {
687   // An empty range spans the whole domain
688   if (r1.empty() || r2.empty())
689     return 1.0;
690 
691   if (!overlap<char>(r1, r2))
692     return 0.0;
693 
694   auto r1_start = r1.start_str();
695   auto r1_end = r1.end_str();
696   auto r2_start = r2.start_str();
697   auto r2_end = r2.end_str();
698   assert(!r2_start.empty());
699   assert(!r2_end.empty());
700 
701   // Calculate the range of r2
702   uint64_t r2_range, pref_size = 0;
703   if (r2.unary()) {
704     r2_range = 1;
705   } else {
706     pref_size = utils::parse::common_prefix_size(r2_start, r2_end);
707     auto r2_start_c = (r2_start.size() == pref_size) ? 0 : r2_start[pref_size];
708     assert(r2_end.size() > pref_size);
709     r2_range = r2_end[pref_size] - r2_start_c + 1;
710   }
711 
712   // Calculate the overlap and its range
713   uint64_t o_range;
714   auto o_start =
715       (!r1_start.empty() && r1_start > r2_start) ? r1_start : r2_start;
716   auto o_end = (!r1_end.empty() && r1_end < r2_end) ? r1_end : r2_end;
717   if (o_start == o_end) {
718     o_range = 1;
719   } else {
720     assert(o_end.size() > pref_size);
721     auto o_start_c = (o_start.size() == pref_size) ? 0 : o_start[pref_size];
722     o_range = o_end[pref_size] - o_start_c + 1;
723   }
724 
725   // If the overlap is not equal to r2, then the ratio cannot be
726   // 1.0 - reduce it by epsilon
727   auto ratio = (double)o_range / r2_range;
728   if (ratio == 1.0 && (o_start != r2_start || o_end != r2_end))
729     ratio = std::nextafter(ratio, std::numeric_limits<double>::min());
730 
731   return ratio;
732 }
733 
734 template <class T>
overlap_ratio(const Range & r1,const Range & r2)735 double Dimension::overlap_ratio(const Range& r1, const Range& r2) {
736   // Verify that we have two intervals
737   assert(!r1.empty());
738   assert(!r2.empty());
739   auto d1 = (const T*)r1.data();
740   auto d2 = (const T*)r2.data();
741   const auto r1_low = d1[0];
742   const auto r1_high = d1[1];
743   auto r2_low = d2[0];
744   auto r2_high = d2[1];
745   assert(r1_low <= r1_high);
746   assert(r2_low <= r2_high);
747 
748   // Special case: No overlap, intervals are disjoint
749   if (r1_low > r2_high || r1_high < r2_low)
750     return 0.0;
751   // Special case: All overlap, interval r2 is a subset of interval r1
752   if (r1_low <= r2_low && r2_high <= r1_high)
753     return 1.0;
754   /*
755    * At this point we know that r2_low < r2_high, because we would have returned
756    * by now otherwise. Note that for floating point types, however, we cannot
757    * conclude that r2_high - r2_low > 0 because of the possibility of underflow.
758    */
759   auto intersection_low = std::max(r1_low, r2_low);
760   auto intersection_high = std::min(r1_high, r2_high);
761   /*
762    * The intersection is a proper subset of interval r1, either the upper bounds
763    * are distinct, or lower bounds are distinct, or both. This means that any
764    * result has to be strictly greater than zero and strictly less than 1.
765    */
766   /*
767    * Guard against overflow. If the outer interval has a bound with an absolute
768    * value that's "too large", meaning that it might lead to an overflow, we
769    * apply a shrinking transformation that preserves the ratio. We only need to
770    * check the outer interval because the intersection is strictly smaller. For
771    * unsigned types we only need to check the upper bound, since the lower bound
772    * is zero. For signed types we need to check both.
773    */
774   const T safe_upper = std::nextafter(std::numeric_limits<T>::max() / 2, 0);
775   bool unsafe = safe_upper < r2_high;
776   if (std::numeric_limits<T>::is_signed) {
777     const T safe_lower =
778         std::nextafter(std::numeric_limits<T>::lowest() / 2, 0);
779     unsafe = unsafe || r2_low < safe_lower;
780   }
781   if (unsafe) {
782     r2_low /= 2;
783     r2_high /= 2;
784     intersection_low /= 2;
785     intersection_high /= 2;
786   }
787 
788   // Compute ratio
789   auto numerator = intersection_high - intersection_low;
790   auto denominator = r2_high - r2_low;
791   if (std::numeric_limits<T>::is_integer) {
792     // integer types count elements; they don't measure length
793     numerator += 1;
794     denominator += 1;
795   } else {
796     if (denominator == 0) {
797       /*
798        * If the variable `denominator` is zero, it's the result of rounding,
799        * since checking the "disjoint" and "subset" cases above has ensured that
800        * the endpoints of the denominator interval are distinct. Thus we have no
801        * easy-to-access information about the true quotient value, but
802        * mathematically it must be between 0 and 1, so we need either to return
803        * some value between 0 and 1 or to throw an exception stating that we
804        * don't support this case.
805        *
806        * The variable `denominator` is larger than the variable `numerator`, so
807        * the numerator is also be zero. We could extract some information from
808        * the floating-point representation itself, but that's a lot of work that
809        * doesn't seem justified at present. Throwing an exception would be
810        * better on principle, but the code in its current state now would not
811        * deal with that gracefully. As a compromise, therefore, we return a
812        * valid but non-computed value. It's a defect, but one that will rarely
813        * if ever arise in practice.
814        */
815       return 0.5;
816     }
817     // The rounded-to-zero numerator is handled in the general case below.
818   }
819   auto ratio = (double)numerator / denominator;
820   // Round away from the endpoints if needed.
821   if (ratio == 0.0) {
822     ratio = std::nextafter(0, 1);
823   } else if (ratio == 1.0) {
824     ratio = std::nextafter(1, 0);
825   }
826   assert(0.0 < ratio && ratio < 1.0);
827   return ratio;
828 }
829 
overlap_ratio(const Range & r1,const Range & r2) const830 double Dimension::overlap_ratio(const Range& r1, const Range& r2) const {
831   assert(overlap_ratio_func_ != nullptr);
832   return overlap_ratio_func_(r1, r2);
833 }
834 
835 template <>
split_range(const Range & r,const ByteVecValue & v,Range * r1,Range * r2)836 void Dimension::split_range<char>(
837     const Range& r, const ByteVecValue& v, Range* r1, Range* r2) {
838   assert(v);
839   assert(r1 != nullptr);
840   assert(r2 != nullptr);
841 
842   // First range
843   auto min_string = std::string("\x0", 1);
844   auto new_r1_start = !r.start_str().empty() ? r.start_str() : min_string;
845   auto new_r1_end = v.rvalue_as<std::string>();
846   auto new_r1_end_size = (int)new_r1_end.size();
847   int pos;
848   for (pos = 0; pos < new_r1_end_size; ++pos) {
849     if ((int)(signed char)new_r1_end[pos] < 0) {
850       new_r1_end[pos] = 127;
851       new_r1_end.resize(pos + 1);
852       break;
853     }
854   }
855   assert(pos < new_r1_end_size);  // One negative char must be present
856   r1->set_str_range(new_r1_start, new_r1_end);
857 
858   // Second range
859   auto new_r2_start = v.rvalue_as<std::string>();
860   // The following will make "a b -1 -4 0" -> "a c"
861   for (pos = 0; pos < new_r1_end_size; ++pos) {
862     if ((int)(signed char)new_r2_start[pos] < 0)
863       break;
864   }
865   do {
866     assert(pos != 0);
867     new_r2_start[pos] = 0;
868     new_r2_start[--pos]++;
869   } while (pos >= 0 && (int)(signed char)new_r2_start[pos] < 0);
870   new_r2_start.resize(pos + 1);
871 
872   auto max_string = std::string("\x7F", 1);
873   auto new_r2_end = !r.end_str().empty() ? r.end_str() : max_string;
874 
875   assert(new_r2_start > new_r1_end);
876   assert(new_r2_start <= new_r2_end);
877   r2->set_str_range(new_r2_start, new_r2_end);
878 
879   // Set the depth of the split ranges to +1 the depth of
880   // the range they were split from.
881   r1->set_partition_depth(r.partition_depth() + 1);
882   r2->set_partition_depth(r.partition_depth() + 1);
883 }
884 
885 template <class T>
split_range(const Range & r,const ByteVecValue & v,Range * r1,Range * r2)886 void Dimension::split_range(
887     const Range& r, const ByteVecValue& v, Range* r1, Range* r2) {
888   assert(!r.empty());
889   assert(v);
890   assert(r1 != nullptr);
891   assert(r2 != nullptr);
892 
893   auto max = std::numeric_limits<T>::max();
894   bool int_domain = std::is_integral<T>::value;
895   auto r_t = (const T*)r.data();
896   auto v_t = *(const T*)(v.data());
897   assert(v_t >= r_t[0]);
898   assert(v_t < r_t[1]);
899 
900   T ret[2];
901   ret[0] = r_t[0];
902   ret[1] = v_t;
903   r1->set_range(ret, sizeof(ret));
904   ret[0] = int_domain ? (v_t + 1) : static_cast<T>(std::nextafter(v_t, max));
905   ret[1] = r_t[1];
906   r2->set_range(ret, sizeof(ret));
907 
908   // Set the depth of the split ranges to +1 the depth of
909   // the range they were split from.
910   r1->set_partition_depth(r.partition_depth() + 1);
911   r2->set_partition_depth(r.partition_depth() + 1);
912 }
913 
split_range(const Range & r,const ByteVecValue & v,Range * r1,Range * r2) const914 void Dimension::split_range(
915     const Range& r, const ByteVecValue& v, Range* r1, Range* r2) const {
916   assert(split_range_func_ != nullptr);
917   split_range_func_(r, v, r1, r2);
918 }
919 
920 template <>
splitting_value(const Range & r,ByteVecValue * v,bool * unsplittable)921 void Dimension::splitting_value<char>(
922     const Range& r, ByteVecValue* v, bool* unsplittable) {
923   assert(!r.empty());
924   assert(v != nullptr);
925   assert(unsplittable != nullptr);
926 
927   // Check unsplittable
928   if (!r.empty() && r.unary()) {
929     *unsplittable = true;
930     return;
931   }
932 
933   *unsplittable = false;
934 
935   // Find position to split
936   auto start = r.start_str();
937   auto end = r.end_str();
938   auto pref_size = utils::parse::common_prefix_size(start, end);
939 
940   // String ranges are infinitely splittable. We define a fixed
941   // limit on how deep we will split a user-given range. If we
942   // reach this limit, we will treat the range as unsplittable.
943   if (r.partition_depth() >= constants::max_string_dim_split_depth) {
944     *unsplittable = true;
945     return;
946   }
947 
948   // Check unsplittable
949   if (!end.empty() && end[pref_size] == 0) {
950     *unsplittable = true;
951     return;
952   }
953 
954   // 127 is the maximum ascii number
955   uint8_t end_pref = end.empty() ? 127 : (uint8_t)end[pref_size];
956   auto start_c = (start.size() == pref_size) ? 0 : start[pref_size];
957   auto split_v = (end_pref - start_c) / 2;
958   auto split_str =
959       start.substr(0, pref_size) + (char)(start_c + split_v) + "\x80";
960   assert(split_str >= start);
961 
962   v->resize(split_str.size());
963   std::memcpy(v->data(), split_str.data(), split_str.size());
964 }
965 
966 template <class T>
splitting_value(const Range & r,ByteVecValue * v,bool * unsplittable)967 void Dimension::splitting_value(
968     const Range& r, ByteVecValue* v, bool* unsplittable) {
969   assert(!r.empty());
970   assert(v != nullptr);
971   assert(unsplittable != nullptr);
972 
973   auto r_t = (const T*)r.data();
974 
975   // Floating-point template specializations for this routine exist below.
976   // All remaining template types are handled in this implementation,
977   // where all template types are integers. We will calculate the split value
978   // with the following expression: `r_t[0] + (r_t[1] - r_t[0]) / 2`. To
979   // prevent overflow in the `(r_t[1] - r_t[0]) / 2` sub-expression, we will
980   // perform this entire sub-expression with a 65-bit bitset.
981   std::bitset<65> r_t0(r_t[0]);
982   std::bitset<65> r_t1(r_t[1]);
983 
984   // If `T` is signed, respect two's complement on the high bit.
985   if (std::is_signed<T>::value) {
986     r_t0[64] = r_t0[63];
987     r_t1[64] = r_t1[63];
988   }
989 
990   // Subtract `r_t0` from `r_t1`.
991   while (r_t0 != 0) {
992     const std::bitset<65> carry = (~r_t1) & r_t0;
993     r_t1 = r_t1 ^ r_t0;
994     r_t0 = carry << 1;
995   }
996 
997   // Divide by 2.
998   r_t1 = r_t1 >> 1;
999 
1000   // Truncate the overflow bit. This will only occur if `T` is
1001   // a signed integer and the result of `(r_t[1] - r_t[0]) / 2`
1002   // is negative. This preserves signed representation when
1003   // converting back to 64-bits in the following invocation
1004   // of `std::bitset<65>::to_ulong`.
1005   r_t1 = r_t1 & std::bitset<65>(UINT64_MAX);
1006 
1007   // Cast the intermediate result back to type `T` to calculate
1008   // the split value.
1009   const T sp = r_t[0] + static_cast<T>(r_t1.to_ullong());
1010 
1011   v->assign_as<T>(sp);
1012   *unsplittable = !std::memcmp(&sp, &r_t[1], sizeof(T));
1013 }
1014 
1015 template <>
splitting_value(const Range & r,ByteVecValue * v,bool * unsplittable)1016 void Dimension::splitting_value<float>(
1017     const Range& r, ByteVecValue* v, bool* unsplittable) {
1018   assert(!r.empty());
1019   assert(v != nullptr);
1020   assert(unsplittable != nullptr);
1021 
1022   auto r_t = (const float*)r.data();
1023 
1024   // Cast `r_t` elements to `double` to prevent overflow before
1025   // dividing by 2.
1026   const float sp = r_t[0] + ((double)r_t[1] - (double)r_t[0]) / 2;
1027 
1028   v->assign_as<float>(sp);
1029   *unsplittable = !std::memcmp(&sp, &r_t[1], sizeof(float));
1030 }
1031 
1032 template <>
splitting_value(const Range & r,ByteVecValue * v,bool * unsplittable)1033 void Dimension::splitting_value<double>(
1034     const Range& r, ByteVecValue* v, bool* unsplittable) {
1035   assert(!r.empty());
1036   assert(v != nullptr);
1037   assert(unsplittable != nullptr);
1038 
1039   auto r_t = (const double*)r.data();
1040 
1041   // Cast `r_t` elements to `long double` to prevent overflow
1042   // before dividing by 2.
1043   const double sp = r_t[0] + ((long double)r_t[1] - (long double)r_t[0]) / 2;
1044 
1045   v->assign_as<double>(sp);
1046   *unsplittable = !std::memcmp(&sp, &r_t[1], sizeof(double));
1047 }
1048 
splitting_value(const Range & r,ByteVecValue * v,bool * unsplittable) const1049 void Dimension::splitting_value(
1050     const Range& r, ByteVecValue* v, bool* unsplittable) const {
1051   assert(splitting_value_func_ != nullptr);
1052   splitting_value_func_(r, v, unsplittable);
1053 }
1054 
1055 template <>
tile_num(const Dimension * dim,const Range & range)1056 uint64_t Dimension::tile_num<char>(const Dimension* dim, const Range& range) {
1057   (void)dim;
1058   (void)range;
1059 
1060   return 1;
1061 }
1062 
1063 template <class T>
tile_num(const Dimension * dim,const Range & range)1064 uint64_t Dimension::tile_num(const Dimension* dim, const Range& range) {
1065   assert(dim != nullptr);
1066   assert(!range.empty());
1067 
1068   // Trivial cases
1069   if (!dim->tile_extent())
1070     return 1;
1071 
1072   auto tile_extent = *(const T*)dim->tile_extent().data();
1073   auto dim_dom = (const T*)dim->domain().data();
1074   auto r = (const T*)range.data();
1075 
1076   uint64_t start = tile_idx(r[0], dim_dom[0], tile_extent);
1077   uint64_t end = tile_idx(r[1], dim_dom[0], tile_extent);
1078   return end - start + 1;
1079 }
1080 
tile_num(const Range & range) const1081 uint64_t Dimension::tile_num(const Range& range) const {
1082   assert(tile_num_func_ != nullptr);
1083   return tile_num_func_(this, range);
1084 }
1085 
map_to_uint64(const QueryBuffer * buff,uint64_t c,uint64_t coords_num,int bits,uint64_t max_bucket_val) const1086 uint64_t Dimension::map_to_uint64(
1087     const QueryBuffer* buff,
1088     uint64_t c,
1089     uint64_t coords_num,
1090     int bits,
1091     uint64_t max_bucket_val) const {
1092   assert(map_to_uint64_func_ != nullptr);
1093   return map_to_uint64_func_(this, buff, c, coords_num, bits, max_bucket_val);
1094 }
1095 
1096 template <class T>
map_to_uint64(const Dimension * dim,const QueryBuffer * buff,uint64_t c,uint64_t coords_num,int bits,uint64_t max_bucket_val)1097 uint64_t Dimension::map_to_uint64(
1098     const Dimension* dim,
1099     const QueryBuffer* buff,
1100     uint64_t c,
1101     uint64_t coords_num,
1102     int bits,
1103     uint64_t max_bucket_val) {
1104   assert(dim != nullptr);
1105   assert(buff != nullptr);
1106   assert(!dim->domain().empty());
1107   (void)coords_num;  // Not used here
1108   (void)bits;        // Not used here
1109 
1110   double dom_start_T = *(const T*)dim->domain().start();
1111   double dom_end_T = *(const T*)dim->domain().end();
1112   auto dom_range_T = dom_end_T - dom_start_T;
1113   auto norm_coord_T = ((const T*)buff->buffer_)[c] - dom_start_T;
1114   return (norm_coord_T / dom_range_T) * max_bucket_val;
1115 }
1116 
1117 template <>
map_to_uint64(const Dimension * dim,const QueryBuffer * buff,uint64_t c,uint64_t coords_num,int bits,uint64_t max_bucket_val)1118 uint64_t Dimension::map_to_uint64<char>(
1119     const Dimension* dim,
1120     const QueryBuffer* buff,
1121     uint64_t c,
1122     uint64_t coords_num,
1123     int bits,
1124     uint64_t max_bucket_val) {
1125   assert(dim != nullptr);
1126   assert(buff != nullptr);
1127   assert(buff->buffer_ != nullptr);
1128   assert(buff->buffer_var_ != nullptr);
1129   assert(buff->buffer_var_size_ != nullptr);
1130   (void)max_bucket_val;  // Not needed here
1131   (void)dim;
1132 
1133   auto offsets = (const uint64_t*)buff->buffer_;
1134   auto v_str = &((const char*)(buff->buffer_var_))[offsets[c]];
1135   auto v_str_size =
1136       ((c == coords_num - 1) ? *(buff->buffer_var_size_) : offsets[c + 1]) -
1137       offsets[c];
1138 
1139   // The following will place up to the first 8 characters of the string
1140   // in the uint64 value to be returned. For instance, "cat" will be
1141   // "cat\0\0\0\0\0" inside the 8-byte uint64 value `ret`.
1142   uint64_t ret = 0;
1143   for (uint64_t i = 0; i < 8; ++i) {
1144     ret <<= 8;  // Shift by one byte
1145     if (i < v_str_size)
1146       ret |= (uint64_t)v_str[i];  // Add next character (if exists)
1147   }
1148 
1149   // Shift to fits in given number of bits
1150   return ret >> (64 - bits);
1151 }
1152 
map_to_uint64(const void * coord,uint64_t coord_size,int bits,uint64_t max_bucket_val) const1153 uint64_t Dimension::map_to_uint64(
1154     const void* coord,
1155     uint64_t coord_size,
1156     int bits,
1157     uint64_t max_bucket_val) const {
1158   assert(map_to_uint64_2_func_ != nullptr);
1159   return map_to_uint64_2_func_(this, coord, coord_size, bits, max_bucket_val);
1160 }
1161 
1162 template <class T>
map_to_uint64_2(const Dimension * dim,const void * coord,uint64_t coord_size,int bits,uint64_t max_bucket_val)1163 uint64_t Dimension::map_to_uint64_2(
1164     const Dimension* dim,
1165     const void* coord,
1166     uint64_t coord_size,
1167     int bits,
1168     uint64_t max_bucket_val) {
1169   assert(dim != nullptr);
1170   assert(coord != nullptr);
1171   assert(!dim->domain().empty());
1172   (void)coord_size;  // Not needed here
1173   (void)bits;        // Not needed here
1174 
1175   double dom_start_T = *(const T*)dim->domain().start();
1176   double dom_end_T = *(const T*)dim->domain().end();
1177   auto dom_range_T = dom_end_T - dom_start_T;
1178   auto norm_coord_T = *(const T*)coord - dom_start_T;
1179   return (norm_coord_T / dom_range_T) * max_bucket_val;
1180 }
1181 
1182 template <>
map_to_uint64_2(const Dimension * dim,const void * coord,uint64_t coord_size,int bits,uint64_t max_bucket_val)1183 uint64_t Dimension::map_to_uint64_2<char>(
1184     const Dimension* dim,
1185     const void* coord,
1186     uint64_t coord_size,
1187     int bits,
1188     uint64_t max_bucket_val) {
1189   assert(dim != nullptr);
1190   assert(coord != nullptr);
1191   (void)max_bucket_val;
1192   (void)dim;
1193 
1194   auto v_str = (const char*)coord;
1195   auto v_str_size = coord_size;
1196 
1197   // The following will place up to the first 8 characters of the string
1198   // in the uint64 value to be returned. For instance, "cat" will be
1199   // "cat\0\0\0\0\0" inside the 8-byte uint64 value `ret`.
1200   uint64_t ret = 0;
1201   for (uint64_t i = 0; i < 8; ++i) {
1202     ret <<= 8;  // Shift by one byte
1203     if (i < v_str_size)
1204       ret |= (uint64_t)v_str[i];  // Add next character (if exists)
1205   }
1206 
1207   // Shift to fit in given number of bits
1208   return ret >> (64 - bits);
1209 }
1210 
map_to_uint64(const ResultCoords & coord,uint32_t dim_idx,int bits,uint64_t max_bucket_val) const1211 uint64_t Dimension::map_to_uint64(
1212     const ResultCoords& coord,
1213     uint32_t dim_idx,
1214     int bits,
1215     uint64_t max_bucket_val) const {
1216   assert(map_to_uint64_3_func_ != nullptr);
1217   return map_to_uint64_3_func_(this, coord, dim_idx, bits, max_bucket_val);
1218 }
1219 
1220 template <class T>
map_to_uint64_3(const Dimension * dim,const ResultCoords & coord,uint32_t dim_idx,int bits,uint64_t max_bucket_val)1221 uint64_t Dimension::map_to_uint64_3(
1222     const Dimension* dim,
1223     const ResultCoords& coord,
1224     uint32_t dim_idx,
1225     int bits,
1226     uint64_t max_bucket_val) {
1227   assert(dim != nullptr);
1228   assert(!dim->domain().empty());
1229   (void)bits;  // Not needed here
1230 
1231   double dom_start_T = *(const T*)dim->domain().start();
1232   double dom_end_T = *(const T*)dim->domain().end();
1233   auto dom_range_T = dom_end_T - dom_start_T;
1234   auto norm_coord_T = *((const T*)coord.coord(dim_idx)) - dom_start_T;
1235   return (norm_coord_T / dom_range_T) * max_bucket_val;
1236 }
1237 
1238 template <>
map_to_uint64_3(const Dimension * dim,const ResultCoords & coord,uint32_t dim_idx,int bits,uint64_t max_bucket_val)1239 uint64_t Dimension::map_to_uint64_3<char>(
1240     const Dimension* dim,
1241     const ResultCoords& coord,
1242     uint32_t dim_idx,
1243     int bits,
1244     uint64_t max_bucket_val) {
1245   assert(dim != nullptr);
1246   (void)max_bucket_val;  // Not needed here
1247   (void)dim;
1248 
1249   auto v_str = coord.coord_string(dim_idx);
1250   auto v_str_size = v_str.size();
1251 
1252   // The following will place up to the first 8 characters of the string
1253   // in the uint64 value to be returned. For instance, "cat" will be
1254   // "cat\0\0\0\0\0" inside the 8-byte uint64 value `ret`.
1255   uint64_t ret = 0;
1256   for (uint64_t i = 0; i < 8; ++i) {
1257     ret <<= 8;  // Shift by one byte
1258     if (i < v_str_size)
1259       ret |= (uint64_t)v_str[i];  // Add next character (if exists)
1260   }
1261 
1262   // Shift to fit in given number of bits
1263   return ret >> (64 - bits);
1264 }
1265 
map_from_uint64(uint64_t value,int bits,uint64_t max_bucket_val) const1266 ByteVecValue Dimension::map_from_uint64(
1267     uint64_t value, int bits, uint64_t max_bucket_val) const {
1268   assert(map_from_uint64_func_ != nullptr);
1269   return map_from_uint64_func_(this, value, bits, max_bucket_val);
1270 }
1271 
1272 template <class T>
map_from_uint64(const Dimension * dim,uint64_t value,int bits,uint64_t max_bucket_val)1273 ByteVecValue Dimension::map_from_uint64(
1274     const Dimension* dim, uint64_t value, int bits, uint64_t max_bucket_val) {
1275   assert(dim != nullptr);
1276   assert(!dim->domain().empty());
1277   (void)bits;  // Not needed here
1278 
1279   ByteVecValue ret(sizeof(T));
1280 
1281   // Add domain start
1282   auto value_T = static_cast<T>(value);
1283   value_T += *(const T*)dim->domain().start();
1284 
1285   auto dom_start_T = *(const T*)dim->domain().start();
1286   auto dom_end_T = *(const T*)dim->domain().end();
1287   double dom_range_T = dom_end_T - dom_start_T;
1288 
1289   // Essentially take the largest value in the bucket
1290   if (std::is_integral<T>::value) {  // Integers
1291     T norm_coord_T =
1292         std::ceil(((value + 1) / (double)max_bucket_val) * dom_range_T - 1);
1293     T coord_T = norm_coord_T + dom_start_T;
1294     std::memcpy(ret.data(), &coord_T, sizeof(T));
1295   } else {  // Floating point types
1296     T norm_coord_T = ((value + 1) / (double)max_bucket_val) * dom_range_T;
1297     norm_coord_T =
1298         std::nextafter(norm_coord_T, std::numeric_limits<T>::lowest());
1299     T coord_T = norm_coord_T + dom_start_T;
1300     std::memcpy(ret.data(), &coord_T, sizeof(T));
1301   }
1302 
1303   return ret;
1304 }
1305 
1306 template <>
map_from_uint64(const Dimension * dim,uint64_t value,int bits,uint64_t max_bucket_val)1307 ByteVecValue Dimension::map_from_uint64<char>(
1308     const Dimension* dim, uint64_t value, int bits, uint64_t max_bucket_val) {
1309   assert(dim != nullptr);
1310   (void)dim;
1311   (void)max_bucket_val;  // Not needed here
1312 
1313   std::vector<uint8_t> ret(sizeof(uint64_t));  // 8 bytes
1314 
1315   uint64_t ret_uint64 = (value << (64 - bits));
1316   int ret_c;
1317   for (size_t i = 0; i < 8; ++i) {  // Reverse ret_uint64
1318     ret_c = (int)((const char*)&ret_uint64)[7 - i];
1319     if (ret_c < 0) {
1320       ret[i] = 128;
1321       ret.resize(i + 1);
1322       break;
1323     } else {
1324       ret[i] = ret_c;
1325     }
1326   }
1327   if (ret.back() != 128)
1328     ret.push_back(128);
1329 
1330   return ByteVecValue(std::move(ret));
1331 }
1332 
smaller_than(const ByteVecValue & value,const Range & range) const1333 bool Dimension::smaller_than(
1334     const ByteVecValue& value, const Range& range) const {
1335   assert(smaller_than_func_ != nullptr);
1336   return smaller_than_func_(this, value, range);
1337 }
1338 
1339 template <class T>
smaller_than(const Dimension * dim,const ByteVecValue & value,const Range & range)1340 bool Dimension::smaller_than(
1341     const Dimension* dim, const ByteVecValue& value, const Range& range) {
1342   assert(dim != nullptr);
1343   (void)dim;
1344   assert(value);
1345 
1346   auto value_T = *(const T*)(value.data());
1347   auto range_start_T = *(const T*)range.start();
1348   return value_T < range_start_T;
1349 }
1350 
1351 template <>
smaller_than(const Dimension * dim,const ByteVecValue & value,const Range & range)1352 bool Dimension::smaller_than<char>(
1353     const Dimension* dim, const ByteVecValue& value, const Range& range) {
1354   assert(dim != nullptr);
1355   assert(value);
1356   (void)dim;
1357 
1358   auto value_str = value.rvalue_as<std::string>();
1359   auto range_start_str = range.start_str();
1360   auto range_end_str = range.end_str();
1361 
1362   // If the range start is empty, then it is essentially -inf
1363   if (range_start_str.empty())
1364     return false;
1365 
1366   return value_str < range_start_str;
1367 }
1368 
1369 // ===== FORMAT =====
1370 // dimension_name_size (uint32_t)
1371 // dimension_name (string)
1372 // type (uint8_t)
1373 // cell_val_num (uint32_t)
1374 // filter_pipeline (see FilterPipeline::serialize)
1375 // domain_size (uint64_t)
1376 // domain (void* - domain_size)
1377 // null_tile_extent (uint8_t)
1378 // tile_extent (void* - type_size)
serialize(Buffer * buff,uint32_t version)1379 Status Dimension::serialize(Buffer* buff, uint32_t version) {
1380   // Sanity check
1381   auto is_str = datatype_is_string(type_);
1382   assert(is_str || !domain_.empty());
1383 
1384   // Write dimension name
1385   auto dimension_name_size = (uint32_t)name_.size();
1386   RETURN_NOT_OK(buff->write(&dimension_name_size, sizeof(uint32_t)));
1387   RETURN_NOT_OK(buff->write(name_.c_str(), dimension_name_size));
1388 
1389   // Applicable only to version >= 5
1390   if (version >= 5) {
1391     // Write type
1392     auto type = (uint8_t)type_;
1393     RETURN_NOT_OK(buff->write(&type, sizeof(uint8_t)));
1394 
1395     // Write cell_val_num_
1396     RETURN_NOT_OK(buff->write(&cell_val_num_, sizeof(uint32_t)));
1397 
1398     // Write filter pipeline
1399     RETURN_NOT_OK(filters_.serialize(buff));
1400   }
1401 
1402   // Write domain and tile extent
1403   uint64_t domain_size = (is_str) ? 0 : 2 * coord_size();
1404   RETURN_NOT_OK(buff->write(&domain_size, sizeof(uint64_t)));
1405   RETURN_NOT_OK(buff->write(domain_.data(), domain_size));
1406 
1407   auto null_tile_extent = (uint8_t)(tile_extent_ ? 0 : 1);
1408   RETURN_NOT_OK(buff->write(&null_tile_extent, sizeof(uint8_t)));
1409   if (tile_extent_)
1410     RETURN_NOT_OK(buff->write(tile_extent_.data(), tile_extent_.size()));
1411 
1412   return Status::Ok();
1413 }
1414 
set_domain(const void * domain)1415 Status Dimension::set_domain(const void* domain) {
1416   if (type_ == Datatype::STRING_ASCII) {
1417     if (domain == nullptr)
1418       return Status::Ok();
1419     return LOG_STATUS(Status::DimensionError(
1420         std::string("Setting the domain to a dimension with type '") +
1421         datatype_str(type_) + "' is not supported"));
1422   }
1423 
1424   if (domain == nullptr)
1425     return Status::Ok();
1426   return set_domain(Range(domain, 2 * coord_size()));
1427 }
1428 
set_domain(const Range & domain)1429 Status Dimension::set_domain(const Range& domain) {
1430   if (domain.empty())
1431     return Status::Ok();
1432 
1433   domain_ = domain;
1434   RETURN_NOT_OK_ELSE(check_domain(), domain_.clear());
1435 
1436   return Status::Ok();
1437 }
1438 
set_domain_unsafe(const void * domain)1439 Status Dimension::set_domain_unsafe(const void* domain) {
1440   domain_ = Range(domain, 2 * coord_size());
1441 
1442   return Status::Ok();
1443 }
1444 
set_filter_pipeline(const FilterPipeline * pipeline)1445 Status Dimension::set_filter_pipeline(const FilterPipeline* pipeline) {
1446   if (pipeline == nullptr)
1447     return LOG_STATUS(Status::DimensionError(
1448         "Cannot set filter pipeline to dimension; Pipeline cannot be null"));
1449 
1450   for (unsigned i = 0; i < pipeline->size(); ++i) {
1451     if (datatype_is_real(type_) &&
1452         pipeline->get_filter(i)->type() == FilterType::FILTER_DOUBLE_DELTA)
1453       return LOG_STATUS(
1454           Status::DimensionError("Cannot set DOUBLE DELTA filter to a "
1455                                  "dimension with a real datatype"));
1456   }
1457 
1458   filters_ = *pipeline;
1459 
1460   return Status::Ok();
1461 }
1462 
set_tile_extent(const void * tile_extent)1463 Status Dimension::set_tile_extent(const void* tile_extent) {
1464   if (type_ == Datatype::STRING_ASCII) {
1465     if (tile_extent == nullptr)
1466       return Status::Ok();
1467     return LOG_STATUS(Status::DimensionError(
1468         std::string("Setting the tile extent to a dimension with type '") +
1469         datatype_str(type_) + "' is not supported"));
1470   }
1471 
1472   ByteVecValue te;
1473   if (tile_extent != nullptr) {
1474     auto size = coord_size();
1475     te.resize(size);
1476     std::memcpy(te.data(), tile_extent, size);
1477   }
1478 
1479   return set_tile_extent(te);
1480 }
1481 
set_tile_extent(const ByteVecValue & tile_extent)1482 Status Dimension::set_tile_extent(const ByteVecValue& tile_extent) {
1483   if (type_ == Datatype::STRING_ASCII) {
1484     if (!tile_extent)
1485       return Status::Ok();
1486     return LOG_STATUS(Status::DimensionError(
1487         std::string("Setting the tile extent to a dimension with type '") +
1488         datatype_str(type_) + "' is not supported"));
1489   }
1490   if (domain_.empty())
1491     return LOG_STATUS(Status::DimensionError(
1492         "Cannot set tile extent; Domain must be set first"));
1493 
1494   tile_extent_ = tile_extent;
1495 
1496   return check_tile_extent();
1497 }
1498 
set_null_tile_extent_to_range()1499 Status Dimension::set_null_tile_extent_to_range() {
1500   switch (type_) {
1501     case Datatype::INT8:
1502       return set_null_tile_extent_to_range<int8_t>();
1503     case Datatype::UINT8:
1504       return set_null_tile_extent_to_range<uint8_t>();
1505     case Datatype::INT16:
1506       return set_null_tile_extent_to_range<int16_t>();
1507     case Datatype::UINT16:
1508       return set_null_tile_extent_to_range<uint16_t>();
1509     case Datatype::INT32:
1510       return set_null_tile_extent_to_range<int32_t>();
1511     case Datatype::UINT32:
1512       return set_null_tile_extent_to_range<uint32_t>();
1513     case Datatype::INT64:
1514       return set_null_tile_extent_to_range<int64_t>();
1515     case Datatype::UINT64:
1516       return set_null_tile_extent_to_range<uint64_t>();
1517     case Datatype::FLOAT32:
1518       return set_null_tile_extent_to_range<float>();
1519     case Datatype::FLOAT64:
1520       return set_null_tile_extent_to_range<double>();
1521     case Datatype::DATETIME_YEAR:
1522     case Datatype::DATETIME_MONTH:
1523     case Datatype::DATETIME_WEEK:
1524     case Datatype::DATETIME_DAY:
1525     case Datatype::DATETIME_HR:
1526     case Datatype::DATETIME_MIN:
1527     case Datatype::DATETIME_SEC:
1528     case Datatype::DATETIME_MS:
1529     case Datatype::DATETIME_US:
1530     case Datatype::DATETIME_NS:
1531     case Datatype::DATETIME_PS:
1532     case Datatype::DATETIME_FS:
1533     case Datatype::DATETIME_AS:
1534     case Datatype::TIME_HR:
1535     case Datatype::TIME_MIN:
1536     case Datatype::TIME_SEC:
1537     case Datatype::TIME_MS:
1538     case Datatype::TIME_US:
1539     case Datatype::TIME_NS:
1540     case Datatype::TIME_PS:
1541     case Datatype::TIME_FS:
1542     case Datatype::TIME_AS:
1543       return set_null_tile_extent_to_range<int64_t>();
1544     case Datatype::STRING_ASCII:
1545       return Status::Ok();  // Do nothing for strings
1546     default:
1547       return LOG_STATUS(
1548           Status::DimensionError("Cannot set null tile extent to domain range; "
1549                                  "Invalid dimension domain type"));
1550   }
1551 
1552   assert(false);
1553   return LOG_STATUS(
1554       Status::DimensionError("Cannot set null tile extent to domain range; "
1555                              "Unsupported dimension type"));
1556 }
1557 
1558 template <class T>
set_null_tile_extent_to_range()1559 Status Dimension::set_null_tile_extent_to_range() {
1560   // Applicable only to null extents
1561   if (tile_extent_)
1562     return Status::Ok();
1563 
1564   // Check empty domain
1565   if (domain_.empty())
1566     return LOG_STATUS(Status::DimensionError(
1567         "Cannot set tile extent to domain range; Domain not set"));
1568 
1569   // Calculate new tile extent equal to domain range
1570   auto domain = (const T*)domain_.data();
1571 
1572   // For integral domain, we need to add 1, check for overflow before doing
1573   // anything
1574   if (std::is_integral<T>::value) {
1575     if (domain[0] == std::numeric_limits<T>::min() &&
1576         domain[1] == std::numeric_limits<T>::max()) {
1577       return LOG_STATUS(Status::DimensionError(
1578           "Cannot set null tile extent to domain range; "
1579           "Domain range exceeds domain type max numeric limit"));
1580     }
1581   }
1582 
1583   T tile_extent = domain[1] - domain[0];
1584 
1585   // We need to add 1 for integral domains
1586   if (std::is_integral<T>::value) {
1587     ++tile_extent;
1588     // After this, tile_extent = domain[1] - domain[0] + 1, which is the correct
1589     // domain range
1590   }
1591 
1592   tile_extent_.assign_as<T>(tile_extent);
1593   return Status::Ok();
1594 }
1595 
tile_extent() const1596 const ByteVecValue& Dimension::tile_extent() const {
1597   return tile_extent_;
1598 }
1599 
type() const1600 Datatype Dimension::type() const {
1601   return type_;
1602 }
1603 
var_size() const1604 bool Dimension::var_size() const {
1605   return cell_val_num_ == constants::var_num;
1606 }
1607 
1608 /* ********************************* */
1609 /*          PRIVATE METHODS          */
1610 /* ********************************* */
1611 
check_domain() const1612 Status Dimension::check_domain() const {
1613   switch (type_) {
1614     case Datatype::INT32:
1615       return check_domain<int>();
1616     case Datatype::INT64:
1617       return check_domain<int64_t>();
1618     case Datatype::INT8:
1619       return check_domain<int8_t>();
1620     case Datatype::UINT8:
1621       return check_domain<uint8_t>();
1622     case Datatype::INT16:
1623       return check_domain<int16_t>();
1624     case Datatype::UINT16:
1625       return check_domain<uint16_t>();
1626     case Datatype::UINT32:
1627       return check_domain<uint32_t>();
1628     case Datatype::UINT64:
1629       return check_domain<uint64_t>();
1630     case Datatype::FLOAT32:
1631       return check_domain<float>();
1632     case Datatype::FLOAT64:
1633       return check_domain<double>();
1634     case Datatype::DATETIME_YEAR:
1635     case Datatype::DATETIME_MONTH:
1636     case Datatype::DATETIME_WEEK:
1637     case Datatype::DATETIME_DAY:
1638     case Datatype::DATETIME_HR:
1639     case Datatype::DATETIME_MIN:
1640     case Datatype::DATETIME_SEC:
1641     case Datatype::DATETIME_MS:
1642     case Datatype::DATETIME_US:
1643     case Datatype::DATETIME_NS:
1644     case Datatype::DATETIME_PS:
1645     case Datatype::DATETIME_FS:
1646     case Datatype::DATETIME_AS:
1647     case Datatype::TIME_HR:
1648     case Datatype::TIME_MIN:
1649     case Datatype::TIME_SEC:
1650     case Datatype::TIME_MS:
1651     case Datatype::TIME_US:
1652     case Datatype::TIME_NS:
1653     case Datatype::TIME_PS:
1654     case Datatype::TIME_FS:
1655     case Datatype::TIME_AS:
1656       return check_domain<int64_t>();
1657     default:
1658       return LOG_STATUS(Status::DimensionError(
1659           "Domain check failed; Invalid dimension domain type"));
1660   }
1661 }
1662 
check_tile_extent() const1663 Status Dimension::check_tile_extent() const {
1664   switch (type_) {
1665     case Datatype::INT32:
1666       return check_tile_extent<int>();
1667     case Datatype::INT64:
1668       return check_tile_extent<int64_t>();
1669     case Datatype::INT8:
1670       return check_tile_extent<int8_t>();
1671     case Datatype::UINT8:
1672       return check_tile_extent<uint8_t>();
1673     case Datatype::INT16:
1674       return check_tile_extent<int16_t>();
1675     case Datatype::UINT16:
1676       return check_tile_extent<uint16_t>();
1677     case Datatype::UINT32:
1678       return check_tile_extent<uint32_t>();
1679     case Datatype::UINT64:
1680       return check_tile_extent<uint64_t>();
1681     case Datatype::FLOAT32:
1682       return check_tile_extent<float>();
1683     case Datatype::FLOAT64:
1684       return check_tile_extent<double>();
1685     case Datatype::DATETIME_YEAR:
1686     case Datatype::DATETIME_MONTH:
1687     case Datatype::DATETIME_WEEK:
1688     case Datatype::DATETIME_DAY:
1689     case Datatype::DATETIME_HR:
1690     case Datatype::DATETIME_MIN:
1691     case Datatype::DATETIME_SEC:
1692     case Datatype::DATETIME_MS:
1693     case Datatype::DATETIME_US:
1694     case Datatype::DATETIME_NS:
1695     case Datatype::DATETIME_PS:
1696     case Datatype::DATETIME_FS:
1697     case Datatype::DATETIME_AS:
1698     case Datatype::TIME_HR:
1699     case Datatype::TIME_MIN:
1700     case Datatype::TIME_SEC:
1701     case Datatype::TIME_MS:
1702     case Datatype::TIME_US:
1703     case Datatype::TIME_NS:
1704     case Datatype::TIME_PS:
1705     case Datatype::TIME_FS:
1706     case Datatype::TIME_AS:
1707       return check_tile_extent<int64_t>();
1708     default:
1709       return LOG_STATUS(Status::DimensionError(
1710           "Tile extent check failed; Invalid dimension domain type"));
1711   }
1712 }
1713 
1714 template <class T>
check_tile_extent() const1715 Status Dimension::check_tile_extent() const {
1716   if (domain_.empty())
1717     return LOG_STATUS(
1718         Status::DimensionError("Tile extent check failed; Domain not set"));
1719 
1720   if (!tile_extent_)
1721     return Status::Ok();
1722 
1723   auto tile_extent = (const T*)tile_extent_.data();
1724   auto domain = (const T*)domain_.data();
1725   bool is_int = std::is_integral<T>::value;
1726 
1727   // Check if tile extent exceeds domain
1728   if (!is_int) {
1729     // Check if tile extent is negative or 0
1730     if (*tile_extent <= 0)
1731       return LOG_STATUS(Status::DimensionError(
1732           "Tile extent check failed; Tile extent must be greater than 0"));
1733 
1734     if (*tile_extent > (domain[1] - domain[0] + 1))
1735       return LOG_STATUS(
1736           Status::DimensionError("Tile extent check failed; Tile extent "
1737                                  "exceeds dimension domain range"));
1738   } else {
1739     // Check if tile extent is 0
1740     if (*tile_extent == 0)
1741       return LOG_STATUS(Status::DimensionError(
1742           "Tile extent check failed; Tile extent must not be 0"));
1743 
1744     // Check if tile extent exceeds domain
1745     uint64_t range = (uint64_t)domain[1] - (uint64_t)domain[0] + 1;
1746     if (uint64_t(*tile_extent) > range)
1747       return LOG_STATUS(
1748           Status::DimensionError("Tile extent check failed; Tile extent "
1749                                  "exceeds dimension domain range"));
1750 
1751     // In the worst case one tile extent will be added to the upper domain
1752     // for the dense case, so check if the expanded domain will exceed type
1753     // T's max limit.
1754     if (range % uint64_t(*tile_extent))
1755       RETURN_NOT_OK(check_tile_extent_upper_floor(domain, *tile_extent));
1756   }
1757 
1758   return Status::Ok();
1759 }
1760 
1761 template <typename T>
check_tile_extent_upper_floor(const T * const domain,const T tile_extent) const1762 Status Dimension::check_tile_extent_upper_floor(
1763     const T* const domain, const T tile_extent) const {
1764   // The type of the upper floor must match the sign of the extent
1765   // type.
1766   return std::is_signed<T>::value ?
1767              check_tile_extent_upper_floor_internal<T, int64_t>(
1768                  domain, tile_extent) :
1769              check_tile_extent_upper_floor_internal<T, uint64_t>(
1770                  domain, tile_extent);
1771 }
1772 
1773 template <typename T_EXTENT, typename T_FLOOR>
check_tile_extent_upper_floor_internal(const T_EXTENT * const domain,const T_EXTENT tile_extent) const1774 Status Dimension::check_tile_extent_upper_floor_internal(
1775     const T_EXTENT* const domain, const T_EXTENT tile_extent) const {
1776   const uint64_t range = domain[1] - domain[0] + 1;
1777   const T_FLOOR upper_floor =
1778       ((range - 1) / (tile_extent)) * (tile_extent) + domain[0];
1779   const T_FLOOR upper_floor_max =
1780       std::numeric_limits<T_FLOOR>::max() - (tile_extent - 1);
1781   const T_FLOOR extent_max =
1782       static_cast<T_FLOOR>(std::numeric_limits<T_EXTENT>::max());
1783   const bool exceeds =
1784       upper_floor > upper_floor_max || upper_floor > extent_max;
1785   if (exceeds) {
1786     return LOG_STATUS(Status::DimensionError(
1787         "Tile extent check failed; domain max expanded to multiple of tile "
1788         "extent exceeds max value representable by domain type. Reduce "
1789         "domain max by 1 tile extent to allow for expansion."));
1790   }
1791 
1792   return Status::Ok();
1793 }
1794 
domain_str() const1795 std::string Dimension::domain_str() const {
1796   std::stringstream ss;
1797 
1798   if (domain_.empty())
1799     return constants::null_str;
1800 
1801   const int* domain_int32;
1802   const int64_t* domain_int64;
1803   const float* domain_float32;
1804   const double* domain_float64;
1805   const int8_t* domain_int8;
1806   const uint8_t* domain_uint8;
1807   const int16_t* domain_int16;
1808   const uint16_t* domain_uint16;
1809   const uint32_t* domain_uint32;
1810   const uint64_t* domain_uint64;
1811 
1812   switch (type_) {
1813     case Datatype::INT32:
1814       domain_int32 = (const int32_t*)domain_.data();
1815       ss << "[" << domain_int32[0] << "," << domain_int32[1] << "]";
1816       return ss.str();
1817     case Datatype::INT64:
1818       domain_int64 = (const int64_t*)domain_.data();
1819       ss << "[" << domain_int64[0] << "," << domain_int64[1] << "]";
1820       return ss.str();
1821     case Datatype::FLOAT32:
1822       domain_float32 = (const float*)domain_.data();
1823       ss << "[" << domain_float32[0] << "," << domain_float32[1] << "]";
1824       return ss.str();
1825     case Datatype::FLOAT64:
1826       domain_float64 = (const double*)domain_.data();
1827       ss << "[" << domain_float64[0] << "," << domain_float64[1] << "]";
1828       return ss.str();
1829     case Datatype::INT8:
1830       domain_int8 = (const int8_t*)domain_.data();
1831       ss << "[" << int(domain_int8[0]) << "," << int(domain_int8[1]) << "]";
1832       return ss.str();
1833     case Datatype::UINT8:
1834       domain_uint8 = (const uint8_t*)domain_.data();
1835       ss << "[" << int(domain_uint8[0]) << "," << int(domain_uint8[1]) << "]";
1836       return ss.str();
1837     case Datatype::INT16:
1838       domain_int16 = (const int16_t*)domain_.data();
1839       ss << "[" << domain_int16[0] << "," << domain_int16[1] << "]";
1840       return ss.str();
1841     case Datatype::UINT16:
1842       domain_uint16 = (const uint16_t*)domain_.data();
1843       ss << "[" << domain_uint16[0] << "," << domain_uint16[1] << "]";
1844       return ss.str();
1845     case Datatype::UINT32:
1846       domain_uint32 = (const uint32_t*)domain_.data();
1847       ss << "[" << domain_uint32[0] << "," << domain_uint32[1] << "]";
1848       return ss.str();
1849     case Datatype::UINT64:
1850       domain_uint64 = (const uint64_t*)domain_.data();
1851       ss << "[" << domain_uint64[0] << "," << domain_uint64[1] << "]";
1852       return ss.str();
1853     case Datatype::DATETIME_YEAR:
1854     case Datatype::DATETIME_MONTH:
1855     case Datatype::DATETIME_WEEK:
1856     case Datatype::DATETIME_DAY:
1857     case Datatype::DATETIME_HR:
1858     case Datatype::DATETIME_MIN:
1859     case Datatype::DATETIME_SEC:
1860     case Datatype::DATETIME_MS:
1861     case Datatype::DATETIME_US:
1862     case Datatype::DATETIME_NS:
1863     case Datatype::DATETIME_PS:
1864     case Datatype::DATETIME_FS:
1865     case Datatype::DATETIME_AS:
1866     case Datatype::TIME_HR:
1867     case Datatype::TIME_MIN:
1868     case Datatype::TIME_SEC:
1869     case Datatype::TIME_MS:
1870     case Datatype::TIME_US:
1871     case Datatype::TIME_NS:
1872     case Datatype::TIME_PS:
1873     case Datatype::TIME_FS:
1874     case Datatype::TIME_AS:
1875       domain_int64 = (const int64_t*)domain_.data();
1876       ss << "[" << domain_int64[0] << "," << domain_int64[1] << "]";
1877       return ss.str();
1878 
1879     case Datatype::CHAR:
1880     case Datatype::STRING_ASCII:
1881     case Datatype::STRING_UTF8:
1882     case Datatype::STRING_UTF16:
1883     case Datatype::STRING_UTF32:
1884     case Datatype::STRING_UCS2:
1885     case Datatype::STRING_UCS4:
1886     case Datatype::ANY:
1887       // Not supported domain type
1888       assert(false);
1889       return "";
1890   }
1891 
1892   assert(false);
1893   return "";
1894 }
1895 
tile_extent_str() const1896 std::string Dimension::tile_extent_str() const {
1897   std::stringstream ss;
1898 
1899   if (!tile_extent_)
1900     return constants::null_str;
1901 
1902   const float* tile_extent_float32;
1903   const double* tile_extent_float64;
1904   const uint8_t* tile_extent_uint8;
1905   const uint16_t* tile_extent_uint16;
1906   const uint32_t* tile_extent_uint32;
1907   const uint64_t* tile_extent_uint64;
1908 
1909   switch (type_) {
1910     case Datatype::INT32:
1911       tile_extent_uint32 = (const uint32_t*)tile_extent_.data();
1912       ss << *tile_extent_uint32;
1913       return ss.str();
1914     case Datatype::INT64:
1915       tile_extent_uint64 = (const uint64_t*)tile_extent_.data();
1916       ss << *tile_extent_uint64;
1917       return ss.str();
1918     case Datatype::FLOAT32:
1919       tile_extent_float32 = (const float*)tile_extent_.data();
1920       ss << *tile_extent_float32;
1921       return ss.str();
1922     case Datatype::FLOAT64:
1923       tile_extent_float64 = (const double*)tile_extent_.data();
1924       ss << *tile_extent_float64;
1925       return ss.str();
1926     case Datatype::INT8:
1927       tile_extent_uint8 = (const uint8_t*)tile_extent_.data();
1928       ss << int(*tile_extent_uint8);
1929       return ss.str();
1930     case Datatype::UINT8:
1931       tile_extent_uint8 = (const uint8_t*)tile_extent_.data();
1932       ss << int(*tile_extent_uint8);
1933       return ss.str();
1934     case Datatype::INT16:
1935       tile_extent_uint16 = (const uint16_t*)tile_extent_.data();
1936       ss << *tile_extent_uint16;
1937       return ss.str();
1938     case Datatype::UINT16:
1939       tile_extent_uint16 = (const uint16_t*)tile_extent_.data();
1940       ss << *tile_extent_uint16;
1941       return ss.str();
1942     case Datatype::UINT32:
1943       tile_extent_uint32 = (const uint32_t*)tile_extent_.data();
1944       ss << *tile_extent_uint32;
1945       return ss.str();
1946     case Datatype::UINT64:
1947       tile_extent_uint64 = (const uint64_t*)tile_extent_.data();
1948       ss << *tile_extent_uint64;
1949       return ss.str();
1950     case Datatype::DATETIME_YEAR:
1951     case Datatype::DATETIME_MONTH:
1952     case Datatype::DATETIME_WEEK:
1953     case Datatype::DATETIME_DAY:
1954     case Datatype::DATETIME_HR:
1955     case Datatype::DATETIME_MIN:
1956     case Datatype::DATETIME_SEC:
1957     case Datatype::DATETIME_MS:
1958     case Datatype::DATETIME_US:
1959     case Datatype::DATETIME_NS:
1960     case Datatype::DATETIME_PS:
1961     case Datatype::DATETIME_FS:
1962     case Datatype::DATETIME_AS:
1963     case Datatype::TIME_HR:
1964     case Datatype::TIME_MIN:
1965     case Datatype::TIME_SEC:
1966     case Datatype::TIME_MS:
1967     case Datatype::TIME_US:
1968     case Datatype::TIME_NS:
1969     case Datatype::TIME_PS:
1970     case Datatype::TIME_FS:
1971     case Datatype::TIME_AS:
1972       tile_extent_uint64 = (const uint64_t*)tile_extent_.data();
1973       ss << *tile_extent_uint64;
1974       return ss.str();
1975 
1976     case Datatype::CHAR:
1977     case Datatype::STRING_ASCII:
1978     case Datatype::STRING_UTF8:
1979     case Datatype::STRING_UTF16:
1980     case Datatype::STRING_UTF32:
1981     case Datatype::STRING_UCS2:
1982     case Datatype::STRING_UCS4:
1983     case Datatype::ANY:
1984       // Not supported domain type
1985       assert(false);
1986       return "";
1987   }
1988 
1989   assert(false);
1990   return "";
1991 }
1992 
set_crop_range_func()1993 void Dimension::set_crop_range_func() {
1994   switch (type_) {
1995     case Datatype::INT32:
1996       crop_range_func_ = crop_range<int32_t>;
1997       break;
1998     case Datatype::INT64:
1999       crop_range_func_ = crop_range<int64_t>;
2000       break;
2001     case Datatype::INT8:
2002       crop_range_func_ = crop_range<int8_t>;
2003       break;
2004     case Datatype::UINT8:
2005       crop_range_func_ = crop_range<uint8_t>;
2006       break;
2007     case Datatype::INT16:
2008       crop_range_func_ = crop_range<int16_t>;
2009       break;
2010     case Datatype::UINT16:
2011       crop_range_func_ = crop_range<uint16_t>;
2012       break;
2013     case Datatype::UINT32:
2014       crop_range_func_ = crop_range<uint32_t>;
2015       break;
2016     case Datatype::UINT64:
2017       crop_range_func_ = crop_range<uint64_t>;
2018       break;
2019     case Datatype::FLOAT32:
2020       crop_range_func_ = crop_range<float>;
2021       break;
2022     case Datatype::FLOAT64:
2023       crop_range_func_ = crop_range<double>;
2024       break;
2025     case Datatype::DATETIME_YEAR:
2026     case Datatype::DATETIME_MONTH:
2027     case Datatype::DATETIME_WEEK:
2028     case Datatype::DATETIME_DAY:
2029     case Datatype::DATETIME_HR:
2030     case Datatype::DATETIME_MIN:
2031     case Datatype::DATETIME_SEC:
2032     case Datatype::DATETIME_MS:
2033     case Datatype::DATETIME_US:
2034     case Datatype::DATETIME_NS:
2035     case Datatype::DATETIME_PS:
2036     case Datatype::DATETIME_FS:
2037     case Datatype::DATETIME_AS:
2038     case Datatype::TIME_HR:
2039     case Datatype::TIME_MIN:
2040     case Datatype::TIME_SEC:
2041     case Datatype::TIME_MS:
2042     case Datatype::TIME_US:
2043     case Datatype::TIME_NS:
2044     case Datatype::TIME_PS:
2045     case Datatype::TIME_FS:
2046     case Datatype::TIME_AS:
2047       crop_range_func_ = crop_range<int64_t>;
2048       break;
2049     default:
2050       crop_range_func_ = nullptr;
2051       break;
2052   }
2053 }
2054 
set_domain_range_func()2055 void Dimension::set_domain_range_func() {
2056   switch (type_) {
2057     case Datatype::INT32:
2058       domain_range_func_ = domain_range<int32_t>;
2059       break;
2060     case Datatype::INT64:
2061       domain_range_func_ = domain_range<int64_t>;
2062       break;
2063     case Datatype::INT8:
2064       domain_range_func_ = domain_range<int8_t>;
2065       break;
2066     case Datatype::UINT8:
2067       domain_range_func_ = domain_range<uint8_t>;
2068       break;
2069     case Datatype::INT16:
2070       domain_range_func_ = domain_range<int16_t>;
2071       break;
2072     case Datatype::UINT16:
2073       domain_range_func_ = domain_range<uint16_t>;
2074       break;
2075     case Datatype::UINT32:
2076       domain_range_func_ = domain_range<uint32_t>;
2077       break;
2078     case Datatype::UINT64:
2079       domain_range_func_ = domain_range<uint64_t>;
2080       break;
2081     case Datatype::FLOAT32:
2082       domain_range_func_ = domain_range<float>;
2083       break;
2084     case Datatype::FLOAT64:
2085       domain_range_func_ = domain_range<double>;
2086       break;
2087     case Datatype::DATETIME_YEAR:
2088     case Datatype::DATETIME_MONTH:
2089     case Datatype::DATETIME_WEEK:
2090     case Datatype::DATETIME_DAY:
2091     case Datatype::DATETIME_HR:
2092     case Datatype::DATETIME_MIN:
2093     case Datatype::DATETIME_SEC:
2094     case Datatype::DATETIME_MS:
2095     case Datatype::DATETIME_US:
2096     case Datatype::DATETIME_NS:
2097     case Datatype::DATETIME_PS:
2098     case Datatype::DATETIME_FS:
2099     case Datatype::DATETIME_AS:
2100     case Datatype::TIME_HR:
2101     case Datatype::TIME_MIN:
2102     case Datatype::TIME_SEC:
2103     case Datatype::TIME_MS:
2104     case Datatype::TIME_US:
2105     case Datatype::TIME_NS:
2106     case Datatype::TIME_PS:
2107     case Datatype::TIME_FS:
2108     case Datatype::TIME_AS:
2109       domain_range_func_ = domain_range<int64_t>;
2110       break;
2111     default:
2112       domain_range_func_ = nullptr;
2113       break;
2114   }
2115 }
2116 
set_ceil_to_tile_func()2117 void Dimension::set_ceil_to_tile_func() {
2118   switch (type_) {
2119     case Datatype::INT32:
2120       ceil_to_tile_func_ = ceil_to_tile<int32_t>;
2121       break;
2122     case Datatype::INT64:
2123       ceil_to_tile_func_ = ceil_to_tile<int64_t>;
2124       break;
2125     case Datatype::INT8:
2126       ceil_to_tile_func_ = ceil_to_tile<int8_t>;
2127       break;
2128     case Datatype::UINT8:
2129       ceil_to_tile_func_ = ceil_to_tile<uint8_t>;
2130       break;
2131     case Datatype::INT16:
2132       ceil_to_tile_func_ = ceil_to_tile<int16_t>;
2133       break;
2134     case Datatype::UINT16:
2135       ceil_to_tile_func_ = ceil_to_tile<uint16_t>;
2136       break;
2137     case Datatype::UINT32:
2138       ceil_to_tile_func_ = ceil_to_tile<uint32_t>;
2139       break;
2140     case Datatype::UINT64:
2141       ceil_to_tile_func_ = ceil_to_tile<uint64_t>;
2142       break;
2143     case Datatype::FLOAT32:
2144       ceil_to_tile_func_ = ceil_to_tile<float>;
2145       break;
2146     case Datatype::FLOAT64:
2147       ceil_to_tile_func_ = ceil_to_tile<double>;
2148       break;
2149     case Datatype::DATETIME_YEAR:
2150     case Datatype::DATETIME_MONTH:
2151     case Datatype::DATETIME_WEEK:
2152     case Datatype::DATETIME_DAY:
2153     case Datatype::DATETIME_HR:
2154     case Datatype::DATETIME_MIN:
2155     case Datatype::DATETIME_SEC:
2156     case Datatype::DATETIME_MS:
2157     case Datatype::DATETIME_US:
2158     case Datatype::DATETIME_NS:
2159     case Datatype::DATETIME_PS:
2160     case Datatype::DATETIME_FS:
2161     case Datatype::DATETIME_AS:
2162     case Datatype::TIME_HR:
2163     case Datatype::TIME_MIN:
2164     case Datatype::TIME_SEC:
2165     case Datatype::TIME_MS:
2166     case Datatype::TIME_US:
2167     case Datatype::TIME_NS:
2168     case Datatype::TIME_PS:
2169     case Datatype::TIME_FS:
2170     case Datatype::TIME_AS:
2171       ceil_to_tile_func_ = ceil_to_tile<int64_t>;
2172       break;
2173     default:
2174       ceil_to_tile_func_ = nullptr;
2175       break;
2176   }
2177 }
2178 
set_check_range_func()2179 void Dimension::set_check_range_func() {
2180   switch (type_) {
2181     case Datatype::INT32:
2182       check_range_func_ = check_range<int32_t>;
2183       break;
2184     case Datatype::INT64:
2185       check_range_func_ = check_range<int64_t>;
2186       break;
2187     case Datatype::INT8:
2188       check_range_func_ = check_range<int8_t>;
2189       break;
2190     case Datatype::UINT8:
2191       check_range_func_ = check_range<uint8_t>;
2192       break;
2193     case Datatype::INT16:
2194       check_range_func_ = check_range<int16_t>;
2195       break;
2196     case Datatype::UINT16:
2197       check_range_func_ = check_range<uint16_t>;
2198       break;
2199     case Datatype::UINT32:
2200       check_range_func_ = check_range<uint32_t>;
2201       break;
2202     case Datatype::UINT64:
2203       check_range_func_ = check_range<uint64_t>;
2204       break;
2205     case Datatype::FLOAT32:
2206       check_range_func_ = check_range<float>;
2207       break;
2208     case Datatype::FLOAT64:
2209       check_range_func_ = check_range<double>;
2210       break;
2211     case Datatype::DATETIME_YEAR:
2212     case Datatype::DATETIME_MONTH:
2213     case Datatype::DATETIME_WEEK:
2214     case Datatype::DATETIME_DAY:
2215     case Datatype::DATETIME_HR:
2216     case Datatype::DATETIME_MIN:
2217     case Datatype::DATETIME_SEC:
2218     case Datatype::DATETIME_MS:
2219     case Datatype::DATETIME_US:
2220     case Datatype::DATETIME_NS:
2221     case Datatype::DATETIME_PS:
2222     case Datatype::DATETIME_FS:
2223     case Datatype::DATETIME_AS:
2224     case Datatype::TIME_HR:
2225     case Datatype::TIME_MIN:
2226     case Datatype::TIME_SEC:
2227     case Datatype::TIME_MS:
2228     case Datatype::TIME_US:
2229     case Datatype::TIME_NS:
2230     case Datatype::TIME_PS:
2231     case Datatype::TIME_FS:
2232     case Datatype::TIME_AS:
2233       check_range_func_ = check_range<int64_t>;
2234       break;
2235     default:
2236       check_range_func_ = nullptr;
2237       break;
2238   }
2239 }
2240 
set_adjust_range_oob_func()2241 void Dimension::set_adjust_range_oob_func() {
2242   switch (type_) {
2243     case Datatype::INT32:
2244       adjust_range_oob_func_ = adjust_range_oob<int32_t>;
2245       break;
2246     case Datatype::INT64:
2247       adjust_range_oob_func_ = adjust_range_oob<int64_t>;
2248       break;
2249     case Datatype::INT8:
2250       adjust_range_oob_func_ = adjust_range_oob<int8_t>;
2251       break;
2252     case Datatype::UINT8:
2253       adjust_range_oob_func_ = adjust_range_oob<uint8_t>;
2254       break;
2255     case Datatype::INT16:
2256       adjust_range_oob_func_ = adjust_range_oob<int16_t>;
2257       break;
2258     case Datatype::UINT16:
2259       adjust_range_oob_func_ = adjust_range_oob<uint16_t>;
2260       break;
2261     case Datatype::UINT32:
2262       adjust_range_oob_func_ = adjust_range_oob<uint32_t>;
2263       break;
2264     case Datatype::UINT64:
2265       adjust_range_oob_func_ = adjust_range_oob<uint64_t>;
2266       break;
2267     case Datatype::FLOAT32:
2268       adjust_range_oob_func_ = adjust_range_oob<float>;
2269       break;
2270     case Datatype::FLOAT64:
2271       adjust_range_oob_func_ = adjust_range_oob<double>;
2272       break;
2273     case Datatype::DATETIME_YEAR:
2274     case Datatype::DATETIME_MONTH:
2275     case Datatype::DATETIME_WEEK:
2276     case Datatype::DATETIME_DAY:
2277     case Datatype::DATETIME_HR:
2278     case Datatype::DATETIME_MIN:
2279     case Datatype::DATETIME_SEC:
2280     case Datatype::DATETIME_MS:
2281     case Datatype::DATETIME_US:
2282     case Datatype::DATETIME_NS:
2283     case Datatype::DATETIME_PS:
2284     case Datatype::DATETIME_FS:
2285     case Datatype::DATETIME_AS:
2286     case Datatype::TIME_HR:
2287     case Datatype::TIME_MIN:
2288     case Datatype::TIME_SEC:
2289     case Datatype::TIME_MS:
2290     case Datatype::TIME_US:
2291     case Datatype::TIME_NS:
2292     case Datatype::TIME_PS:
2293     case Datatype::TIME_FS:
2294     case Datatype::TIME_AS:
2295       adjust_range_oob_func_ = adjust_range_oob<int64_t>;
2296       break;
2297     default:
2298       adjust_range_oob_func_ = nullptr;
2299       break;
2300   }
2301 }
2302 
set_coincides_with_tiles_func()2303 void Dimension::set_coincides_with_tiles_func() {
2304   switch (type_) {
2305     case Datatype::INT32:
2306       coincides_with_tiles_func_ = coincides_with_tiles<int32_t>;
2307       break;
2308     case Datatype::INT64:
2309       coincides_with_tiles_func_ = coincides_with_tiles<int64_t>;
2310       break;
2311     case Datatype::INT8:
2312       coincides_with_tiles_func_ = coincides_with_tiles<int8_t>;
2313       break;
2314     case Datatype::UINT8:
2315       coincides_with_tiles_func_ = coincides_with_tiles<uint8_t>;
2316       break;
2317     case Datatype::INT16:
2318       coincides_with_tiles_func_ = coincides_with_tiles<int16_t>;
2319       break;
2320     case Datatype::UINT16:
2321       coincides_with_tiles_func_ = coincides_with_tiles<uint16_t>;
2322       break;
2323     case Datatype::UINT32:
2324       coincides_with_tiles_func_ = coincides_with_tiles<uint32_t>;
2325       break;
2326     case Datatype::UINT64:
2327       coincides_with_tiles_func_ = coincides_with_tiles<uint64_t>;
2328       break;
2329     case Datatype::FLOAT32:
2330       coincides_with_tiles_func_ = coincides_with_tiles<float>;
2331       break;
2332     case Datatype::FLOAT64:
2333       coincides_with_tiles_func_ = coincides_with_tiles<double>;
2334       break;
2335     case Datatype::DATETIME_YEAR:
2336     case Datatype::DATETIME_MONTH:
2337     case Datatype::DATETIME_WEEK:
2338     case Datatype::DATETIME_DAY:
2339     case Datatype::DATETIME_HR:
2340     case Datatype::DATETIME_MIN:
2341     case Datatype::DATETIME_SEC:
2342     case Datatype::DATETIME_MS:
2343     case Datatype::DATETIME_US:
2344     case Datatype::DATETIME_NS:
2345     case Datatype::DATETIME_PS:
2346     case Datatype::DATETIME_FS:
2347     case Datatype::DATETIME_AS:
2348     case Datatype::TIME_HR:
2349     case Datatype::TIME_MIN:
2350     case Datatype::TIME_SEC:
2351     case Datatype::TIME_MS:
2352     case Datatype::TIME_US:
2353     case Datatype::TIME_NS:
2354     case Datatype::TIME_PS:
2355     case Datatype::TIME_FS:
2356     case Datatype::TIME_AS:
2357       coincides_with_tiles_func_ = coincides_with_tiles<int64_t>;
2358       break;
2359     default:
2360       coincides_with_tiles_func_ = nullptr;
2361       break;
2362   }
2363 }
2364 
set_compute_mbr_func()2365 void Dimension::set_compute_mbr_func() {
2366   if (!var_size()) {  // Fixed-sized
2367     compute_mbr_var_func_ = nullptr;
2368     switch (type_) {
2369       case Datatype::INT32:
2370         compute_mbr_func_ = compute_mbr<int32_t>;
2371         break;
2372       case Datatype::INT64:
2373         compute_mbr_func_ = compute_mbr<int64_t>;
2374         break;
2375       case Datatype::INT8:
2376         compute_mbr_func_ = compute_mbr<int8_t>;
2377         break;
2378       case Datatype::UINT8:
2379         compute_mbr_func_ = compute_mbr<uint8_t>;
2380         break;
2381       case Datatype::INT16:
2382         compute_mbr_func_ = compute_mbr<int16_t>;
2383         break;
2384       case Datatype::UINT16:
2385         compute_mbr_func_ = compute_mbr<uint16_t>;
2386         break;
2387       case Datatype::UINT32:
2388         compute_mbr_func_ = compute_mbr<uint32_t>;
2389         break;
2390       case Datatype::UINT64:
2391         compute_mbr_func_ = compute_mbr<uint64_t>;
2392         break;
2393       case Datatype::FLOAT32:
2394         compute_mbr_func_ = compute_mbr<float>;
2395         break;
2396       case Datatype::FLOAT64:
2397         compute_mbr_func_ = compute_mbr<double>;
2398         break;
2399       case Datatype::DATETIME_YEAR:
2400       case Datatype::DATETIME_MONTH:
2401       case Datatype::DATETIME_WEEK:
2402       case Datatype::DATETIME_DAY:
2403       case Datatype::DATETIME_HR:
2404       case Datatype::DATETIME_MIN:
2405       case Datatype::DATETIME_SEC:
2406       case Datatype::DATETIME_MS:
2407       case Datatype::DATETIME_US:
2408       case Datatype::DATETIME_NS:
2409       case Datatype::DATETIME_PS:
2410       case Datatype::DATETIME_FS:
2411       case Datatype::DATETIME_AS:
2412       case Datatype::TIME_HR:
2413       case Datatype::TIME_MIN:
2414       case Datatype::TIME_SEC:
2415       case Datatype::TIME_MS:
2416       case Datatype::TIME_US:
2417       case Datatype::TIME_NS:
2418       case Datatype::TIME_PS:
2419       case Datatype::TIME_FS:
2420       case Datatype::TIME_AS:
2421         compute_mbr_func_ = compute_mbr<int64_t>;
2422         break;
2423       default:
2424         compute_mbr_func_ = nullptr;
2425         break;
2426     }
2427   } else {  // Var-sized
2428     assert(type_ == Datatype::STRING_ASCII);
2429     compute_mbr_func_ = nullptr;
2430     compute_mbr_var_func_ = compute_mbr_var<char>;
2431   }
2432 }
2433 
set_expand_range_func()2434 void Dimension::set_expand_range_func() {
2435   switch (type_) {
2436     case Datatype::INT32:
2437       expand_range_func_ = expand_range<int32_t>;
2438       break;
2439     case Datatype::INT64:
2440       expand_range_func_ = expand_range<int64_t>;
2441       break;
2442     case Datatype::INT8:
2443       expand_range_func_ = expand_range<int8_t>;
2444       break;
2445     case Datatype::UINT8:
2446       expand_range_func_ = expand_range<uint8_t>;
2447       break;
2448     case Datatype::INT16:
2449       expand_range_func_ = expand_range<int16_t>;
2450       break;
2451     case Datatype::UINT16:
2452       expand_range_func_ = expand_range<uint16_t>;
2453       break;
2454     case Datatype::UINT32:
2455       expand_range_func_ = expand_range<uint32_t>;
2456       break;
2457     case Datatype::UINT64:
2458       expand_range_func_ = expand_range<uint64_t>;
2459       break;
2460     case Datatype::FLOAT32:
2461       expand_range_func_ = expand_range<float>;
2462       break;
2463     case Datatype::FLOAT64:
2464       expand_range_func_ = expand_range<double>;
2465       break;
2466     case Datatype::DATETIME_YEAR:
2467     case Datatype::DATETIME_MONTH:
2468     case Datatype::DATETIME_WEEK:
2469     case Datatype::DATETIME_DAY:
2470     case Datatype::DATETIME_HR:
2471     case Datatype::DATETIME_MIN:
2472     case Datatype::DATETIME_SEC:
2473     case Datatype::DATETIME_MS:
2474     case Datatype::DATETIME_US:
2475     case Datatype::DATETIME_NS:
2476     case Datatype::DATETIME_PS:
2477     case Datatype::DATETIME_FS:
2478     case Datatype::DATETIME_AS:
2479     case Datatype::TIME_HR:
2480     case Datatype::TIME_MIN:
2481     case Datatype::TIME_SEC:
2482     case Datatype::TIME_MS:
2483     case Datatype::TIME_US:
2484     case Datatype::TIME_NS:
2485     case Datatype::TIME_PS:
2486     case Datatype::TIME_FS:
2487     case Datatype::TIME_AS:
2488       expand_range_func_ = expand_range<int64_t>;
2489       break;
2490     default:
2491       expand_range_func_ = nullptr;
2492       break;
2493   }
2494 }
2495 
set_expand_range_v_func()2496 void Dimension::set_expand_range_v_func() {
2497   switch (type_) {
2498     case Datatype::INT32:
2499       expand_range_v_func_ = expand_range_v<int32_t>;
2500       break;
2501     case Datatype::INT64:
2502       expand_range_v_func_ = expand_range_v<int64_t>;
2503       break;
2504     case Datatype::INT8:
2505       expand_range_v_func_ = expand_range_v<int8_t>;
2506       break;
2507     case Datatype::UINT8:
2508       expand_range_v_func_ = expand_range_v<uint8_t>;
2509       break;
2510     case Datatype::INT16:
2511       expand_range_v_func_ = expand_range_v<int16_t>;
2512       break;
2513     case Datatype::UINT16:
2514       expand_range_v_func_ = expand_range_v<uint16_t>;
2515       break;
2516     case Datatype::UINT32:
2517       expand_range_v_func_ = expand_range_v<uint32_t>;
2518       break;
2519     case Datatype::UINT64:
2520       expand_range_v_func_ = expand_range_v<uint64_t>;
2521       break;
2522     case Datatype::FLOAT32:
2523       expand_range_v_func_ = expand_range_v<float>;
2524       break;
2525     case Datatype::FLOAT64:
2526       expand_range_v_func_ = expand_range_v<double>;
2527       break;
2528     case Datatype::DATETIME_YEAR:
2529     case Datatype::DATETIME_MONTH:
2530     case Datatype::DATETIME_WEEK:
2531     case Datatype::DATETIME_DAY:
2532     case Datatype::DATETIME_HR:
2533     case Datatype::DATETIME_MIN:
2534     case Datatype::DATETIME_SEC:
2535     case Datatype::DATETIME_MS:
2536     case Datatype::DATETIME_US:
2537     case Datatype::DATETIME_NS:
2538     case Datatype::DATETIME_PS:
2539     case Datatype::DATETIME_FS:
2540     case Datatype::DATETIME_AS:
2541     case Datatype::TIME_HR:
2542     case Datatype::TIME_MIN:
2543     case Datatype::TIME_SEC:
2544     case Datatype::TIME_MS:
2545     case Datatype::TIME_US:
2546     case Datatype::TIME_NS:
2547     case Datatype::TIME_PS:
2548     case Datatype::TIME_FS:
2549     case Datatype::TIME_AS:
2550       expand_range_v_func_ = expand_range_v<int64_t>;
2551       break;
2552     default:
2553       expand_range_v_func_ = nullptr;
2554       break;
2555   }
2556 }
2557 
set_expand_to_tile_func()2558 void Dimension::set_expand_to_tile_func() {
2559   switch (type_) {
2560     case Datatype::INT32:
2561       expand_to_tile_func_ = expand_to_tile<int32_t>;
2562       break;
2563     case Datatype::INT64:
2564       expand_to_tile_func_ = expand_to_tile<int64_t>;
2565       break;
2566     case Datatype::INT8:
2567       expand_to_tile_func_ = expand_to_tile<int8_t>;
2568       break;
2569     case Datatype::UINT8:
2570       expand_to_tile_func_ = expand_to_tile<uint8_t>;
2571       break;
2572     case Datatype::INT16:
2573       expand_to_tile_func_ = expand_to_tile<int16_t>;
2574       break;
2575     case Datatype::UINT16:
2576       expand_to_tile_func_ = expand_to_tile<uint16_t>;
2577       break;
2578     case Datatype::UINT32:
2579       expand_to_tile_func_ = expand_to_tile<uint32_t>;
2580       break;
2581     case Datatype::UINT64:
2582       expand_to_tile_func_ = expand_to_tile<uint64_t>;
2583       break;
2584     case Datatype::FLOAT32:
2585       expand_to_tile_func_ = expand_to_tile<float>;
2586       break;
2587     case Datatype::FLOAT64:
2588       expand_to_tile_func_ = expand_to_tile<double>;
2589       break;
2590     case Datatype::DATETIME_YEAR:
2591     case Datatype::DATETIME_MONTH:
2592     case Datatype::DATETIME_WEEK:
2593     case Datatype::DATETIME_DAY:
2594     case Datatype::DATETIME_HR:
2595     case Datatype::DATETIME_MIN:
2596     case Datatype::DATETIME_SEC:
2597     case Datatype::DATETIME_MS:
2598     case Datatype::DATETIME_US:
2599     case Datatype::DATETIME_NS:
2600     case Datatype::DATETIME_PS:
2601     case Datatype::DATETIME_FS:
2602     case Datatype::DATETIME_AS:
2603     case Datatype::TIME_HR:
2604     case Datatype::TIME_MIN:
2605     case Datatype::TIME_SEC:
2606     case Datatype::TIME_MS:
2607     case Datatype::TIME_US:
2608     case Datatype::TIME_NS:
2609     case Datatype::TIME_PS:
2610     case Datatype::TIME_FS:
2611     case Datatype::TIME_AS:
2612       expand_to_tile_func_ = expand_to_tile<int64_t>;
2613       break;
2614     default:
2615       expand_to_tile_func_ = nullptr;
2616       break;
2617   }
2618 }
2619 
set_oob_func()2620 void Dimension::set_oob_func() {
2621   switch (type_) {
2622     case Datatype::INT32:
2623       oob_func_ = oob<int32_t>;
2624       break;
2625     case Datatype::INT64:
2626       oob_func_ = oob<int64_t>;
2627       break;
2628     case Datatype::INT8:
2629       oob_func_ = oob<int8_t>;
2630       break;
2631     case Datatype::UINT8:
2632       oob_func_ = oob<uint8_t>;
2633       break;
2634     case Datatype::INT16:
2635       oob_func_ = oob<int16_t>;
2636       break;
2637     case Datatype::UINT16:
2638       oob_func_ = oob<uint16_t>;
2639       break;
2640     case Datatype::UINT32:
2641       oob_func_ = oob<uint32_t>;
2642       break;
2643     case Datatype::UINT64:
2644       oob_func_ = oob<uint64_t>;
2645       break;
2646     case Datatype::FLOAT32:
2647       oob_func_ = oob<float>;
2648       break;
2649     case Datatype::FLOAT64:
2650       oob_func_ = oob<double>;
2651       break;
2652     case Datatype::DATETIME_YEAR:
2653     case Datatype::DATETIME_MONTH:
2654     case Datatype::DATETIME_WEEK:
2655     case Datatype::DATETIME_DAY:
2656     case Datatype::DATETIME_HR:
2657     case Datatype::DATETIME_MIN:
2658     case Datatype::DATETIME_SEC:
2659     case Datatype::DATETIME_MS:
2660     case Datatype::DATETIME_US:
2661     case Datatype::DATETIME_NS:
2662     case Datatype::DATETIME_PS:
2663     case Datatype::DATETIME_FS:
2664     case Datatype::DATETIME_AS:
2665     case Datatype::TIME_HR:
2666     case Datatype::TIME_MIN:
2667     case Datatype::TIME_SEC:
2668     case Datatype::TIME_MS:
2669     case Datatype::TIME_US:
2670     case Datatype::TIME_NS:
2671     case Datatype::TIME_PS:
2672     case Datatype::TIME_FS:
2673     case Datatype::TIME_AS:
2674       oob_func_ = oob<int64_t>;
2675       break;
2676     default:
2677       oob_func_ = nullptr;
2678       break;
2679   }
2680 }
2681 
set_covered_func()2682 void Dimension::set_covered_func() {
2683   switch (type_) {
2684     case Datatype::INT32:
2685       covered_func_ = covered<int32_t>;
2686       break;
2687     case Datatype::INT64:
2688       covered_func_ = covered<int64_t>;
2689       break;
2690     case Datatype::INT8:
2691       covered_func_ = covered<int8_t>;
2692       break;
2693     case Datatype::UINT8:
2694       covered_func_ = covered<uint8_t>;
2695       break;
2696     case Datatype::INT16:
2697       covered_func_ = covered<int16_t>;
2698       break;
2699     case Datatype::UINT16:
2700       covered_func_ = covered<uint16_t>;
2701       break;
2702     case Datatype::UINT32:
2703       covered_func_ = covered<uint32_t>;
2704       break;
2705     case Datatype::UINT64:
2706       covered_func_ = covered<uint64_t>;
2707       break;
2708     case Datatype::FLOAT32:
2709       covered_func_ = covered<float>;
2710       break;
2711     case Datatype::FLOAT64:
2712       covered_func_ = covered<double>;
2713       break;
2714     case Datatype::DATETIME_YEAR:
2715     case Datatype::DATETIME_MONTH:
2716     case Datatype::DATETIME_WEEK:
2717     case Datatype::DATETIME_DAY:
2718     case Datatype::DATETIME_HR:
2719     case Datatype::DATETIME_MIN:
2720     case Datatype::DATETIME_SEC:
2721     case Datatype::DATETIME_MS:
2722     case Datatype::DATETIME_US:
2723     case Datatype::DATETIME_NS:
2724     case Datatype::DATETIME_PS:
2725     case Datatype::DATETIME_FS:
2726     case Datatype::DATETIME_AS:
2727     case Datatype::TIME_HR:
2728     case Datatype::TIME_MIN:
2729     case Datatype::TIME_SEC:
2730     case Datatype::TIME_MS:
2731     case Datatype::TIME_US:
2732     case Datatype::TIME_NS:
2733     case Datatype::TIME_PS:
2734     case Datatype::TIME_FS:
2735     case Datatype::TIME_AS:
2736       covered_func_ = covered<int64_t>;
2737       break;
2738     case Datatype::STRING_ASCII:
2739       assert(var_size());
2740       covered_func_ = covered<char>;
2741       break;
2742     default:
2743       covered_func_ = nullptr;
2744       break;
2745   }
2746 }
2747 
set_overlap_func()2748 void Dimension::set_overlap_func() {
2749   switch (type_) {
2750     case Datatype::INT32:
2751       overlap_func_ = overlap<int32_t>;
2752       break;
2753     case Datatype::INT64:
2754       overlap_func_ = overlap<int64_t>;
2755       break;
2756     case Datatype::INT8:
2757       overlap_func_ = overlap<int8_t>;
2758       break;
2759     case Datatype::UINT8:
2760       overlap_func_ = overlap<uint8_t>;
2761       break;
2762     case Datatype::INT16:
2763       overlap_func_ = overlap<int16_t>;
2764       break;
2765     case Datatype::UINT16:
2766       overlap_func_ = overlap<uint16_t>;
2767       break;
2768     case Datatype::UINT32:
2769       overlap_func_ = overlap<uint32_t>;
2770       break;
2771     case Datatype::UINT64:
2772       overlap_func_ = overlap<uint64_t>;
2773       break;
2774     case Datatype::FLOAT32:
2775       overlap_func_ = overlap<float>;
2776       break;
2777     case Datatype::FLOAT64:
2778       overlap_func_ = overlap<double>;
2779       break;
2780     case Datatype::DATETIME_YEAR:
2781     case Datatype::DATETIME_MONTH:
2782     case Datatype::DATETIME_WEEK:
2783     case Datatype::DATETIME_DAY:
2784     case Datatype::DATETIME_HR:
2785     case Datatype::DATETIME_MIN:
2786     case Datatype::DATETIME_SEC:
2787     case Datatype::DATETIME_MS:
2788     case Datatype::DATETIME_US:
2789     case Datatype::DATETIME_NS:
2790     case Datatype::DATETIME_PS:
2791     case Datatype::DATETIME_FS:
2792     case Datatype::DATETIME_AS:
2793     case Datatype::TIME_HR:
2794     case Datatype::TIME_MIN:
2795     case Datatype::TIME_SEC:
2796     case Datatype::TIME_MS:
2797     case Datatype::TIME_US:
2798     case Datatype::TIME_NS:
2799     case Datatype::TIME_PS:
2800     case Datatype::TIME_FS:
2801     case Datatype::TIME_AS:
2802       overlap_func_ = overlap<int64_t>;
2803       break;
2804     case Datatype::STRING_ASCII:
2805       assert(var_size());
2806       overlap_func_ = overlap<char>;
2807       break;
2808     default:
2809       overlap_func_ = nullptr;
2810       break;
2811   }
2812 }
2813 
set_overlap_ratio_func()2814 void Dimension::set_overlap_ratio_func() {
2815   switch (type_) {
2816     case Datatype::INT32:
2817       overlap_ratio_func_ = overlap_ratio<int32_t>;
2818       break;
2819     case Datatype::INT64:
2820       overlap_ratio_func_ = overlap_ratio<int64_t>;
2821       break;
2822     case Datatype::INT8:
2823       overlap_ratio_func_ = overlap_ratio<int8_t>;
2824       break;
2825     case Datatype::UINT8:
2826       overlap_ratio_func_ = overlap_ratio<uint8_t>;
2827       break;
2828     case Datatype::INT16:
2829       overlap_ratio_func_ = overlap_ratio<int16_t>;
2830       break;
2831     case Datatype::UINT16:
2832       overlap_ratio_func_ = overlap_ratio<uint16_t>;
2833       break;
2834     case Datatype::UINT32:
2835       overlap_ratio_func_ = overlap_ratio<uint32_t>;
2836       break;
2837     case Datatype::UINT64:
2838       overlap_ratio_func_ = overlap_ratio<uint64_t>;
2839       break;
2840     case Datatype::FLOAT32:
2841       overlap_ratio_func_ = overlap_ratio<float>;
2842       break;
2843     case Datatype::FLOAT64:
2844       overlap_ratio_func_ = overlap_ratio<double>;
2845       break;
2846     case Datatype::DATETIME_YEAR:
2847     case Datatype::DATETIME_MONTH:
2848     case Datatype::DATETIME_WEEK:
2849     case Datatype::DATETIME_DAY:
2850     case Datatype::DATETIME_HR:
2851     case Datatype::DATETIME_MIN:
2852     case Datatype::DATETIME_SEC:
2853     case Datatype::DATETIME_MS:
2854     case Datatype::DATETIME_US:
2855     case Datatype::DATETIME_NS:
2856     case Datatype::DATETIME_PS:
2857     case Datatype::DATETIME_FS:
2858     case Datatype::DATETIME_AS:
2859     case Datatype::TIME_HR:
2860     case Datatype::TIME_MIN:
2861     case Datatype::TIME_SEC:
2862     case Datatype::TIME_MS:
2863     case Datatype::TIME_US:
2864     case Datatype::TIME_NS:
2865     case Datatype::TIME_PS:
2866     case Datatype::TIME_FS:
2867     case Datatype::TIME_AS:
2868       overlap_ratio_func_ = overlap_ratio<int64_t>;
2869       break;
2870     case Datatype::STRING_ASCII:
2871       assert(var_size());
2872       overlap_ratio_func_ = overlap_ratio<char>;
2873       break;
2874     default:
2875       overlap_ratio_func_ = nullptr;
2876       break;
2877   }
2878 }
2879 
set_split_range_func()2880 void Dimension::set_split_range_func() {
2881   switch (type_) {
2882     case Datatype::INT32:
2883       split_range_func_ = split_range<int32_t>;
2884       break;
2885     case Datatype::INT64:
2886       split_range_func_ = split_range<int64_t>;
2887       break;
2888     case Datatype::INT8:
2889       split_range_func_ = split_range<int8_t>;
2890       break;
2891     case Datatype::UINT8:
2892       split_range_func_ = split_range<uint8_t>;
2893       break;
2894     case Datatype::INT16:
2895       split_range_func_ = split_range<int16_t>;
2896       break;
2897     case Datatype::UINT16:
2898       split_range_func_ = split_range<uint16_t>;
2899       break;
2900     case Datatype::UINT32:
2901       split_range_func_ = split_range<uint32_t>;
2902       break;
2903     case Datatype::UINT64:
2904       split_range_func_ = split_range<uint64_t>;
2905       break;
2906     case Datatype::FLOAT32:
2907       split_range_func_ = split_range<float>;
2908       break;
2909     case Datatype::FLOAT64:
2910       split_range_func_ = split_range<double>;
2911       break;
2912     case Datatype::DATETIME_YEAR:
2913     case Datatype::DATETIME_MONTH:
2914     case Datatype::DATETIME_WEEK:
2915     case Datatype::DATETIME_DAY:
2916     case Datatype::DATETIME_HR:
2917     case Datatype::DATETIME_MIN:
2918     case Datatype::DATETIME_SEC:
2919     case Datatype::DATETIME_MS:
2920     case Datatype::DATETIME_US:
2921     case Datatype::DATETIME_NS:
2922     case Datatype::DATETIME_PS:
2923     case Datatype::DATETIME_FS:
2924     case Datatype::DATETIME_AS:
2925     case Datatype::TIME_HR:
2926     case Datatype::TIME_MIN:
2927     case Datatype::TIME_SEC:
2928     case Datatype::TIME_MS:
2929     case Datatype::TIME_US:
2930     case Datatype::TIME_NS:
2931     case Datatype::TIME_PS:
2932     case Datatype::TIME_FS:
2933     case Datatype::TIME_AS:
2934       split_range_func_ = split_range<int64_t>;
2935       break;
2936     case Datatype::STRING_ASCII:
2937       split_range_func_ = split_range<char>;
2938       break;
2939     default:
2940       split_range_func_ = nullptr;
2941       break;
2942   }
2943 }
2944 
set_splitting_value_func()2945 void Dimension::set_splitting_value_func() {
2946   switch (type_) {
2947     case Datatype::INT32:
2948       splitting_value_func_ = splitting_value<int32_t>;
2949       break;
2950     case Datatype::INT64:
2951       splitting_value_func_ = splitting_value<int64_t>;
2952       break;
2953     case Datatype::INT8:
2954       splitting_value_func_ = splitting_value<int8_t>;
2955       break;
2956     case Datatype::UINT8:
2957       splitting_value_func_ = splitting_value<uint8_t>;
2958       break;
2959     case Datatype::INT16:
2960       splitting_value_func_ = splitting_value<int16_t>;
2961       break;
2962     case Datatype::UINT16:
2963       splitting_value_func_ = splitting_value<uint16_t>;
2964       break;
2965     case Datatype::UINT32:
2966       splitting_value_func_ = splitting_value<uint32_t>;
2967       break;
2968     case Datatype::UINT64:
2969       splitting_value_func_ = splitting_value<uint64_t>;
2970       break;
2971     case Datatype::FLOAT32:
2972       splitting_value_func_ = splitting_value<float>;
2973       break;
2974     case Datatype::FLOAT64:
2975       splitting_value_func_ = splitting_value<double>;
2976       break;
2977     case Datatype::DATETIME_YEAR:
2978     case Datatype::DATETIME_MONTH:
2979     case Datatype::DATETIME_WEEK:
2980     case Datatype::DATETIME_DAY:
2981     case Datatype::DATETIME_HR:
2982     case Datatype::DATETIME_MIN:
2983     case Datatype::DATETIME_SEC:
2984     case Datatype::DATETIME_MS:
2985     case Datatype::DATETIME_US:
2986     case Datatype::DATETIME_NS:
2987     case Datatype::DATETIME_PS:
2988     case Datatype::DATETIME_FS:
2989     case Datatype::DATETIME_AS:
2990     case Datatype::TIME_HR:
2991     case Datatype::TIME_MIN:
2992     case Datatype::TIME_SEC:
2993     case Datatype::TIME_MS:
2994     case Datatype::TIME_US:
2995     case Datatype::TIME_NS:
2996     case Datatype::TIME_PS:
2997     case Datatype::TIME_FS:
2998     case Datatype::TIME_AS:
2999       splitting_value_func_ = splitting_value<int64_t>;
3000       break;
3001     case Datatype::STRING_ASCII:
3002       assert(var_size());
3003       splitting_value_func_ = splitting_value<char>;
3004       break;
3005     default:
3006       splitting_value_func_ = nullptr;
3007       break;
3008   }
3009 }
3010 
set_tile_num_func()3011 void Dimension::set_tile_num_func() {
3012   switch (type_) {
3013     case Datatype::INT32:
3014       tile_num_func_ = tile_num<int32_t>;
3015       break;
3016     case Datatype::INT64:
3017       tile_num_func_ = tile_num<int64_t>;
3018       break;
3019     case Datatype::INT8:
3020       tile_num_func_ = tile_num<int8_t>;
3021       break;
3022     case Datatype::UINT8:
3023       tile_num_func_ = tile_num<uint8_t>;
3024       break;
3025     case Datatype::INT16:
3026       tile_num_func_ = tile_num<int16_t>;
3027       break;
3028     case Datatype::UINT16:
3029       tile_num_func_ = tile_num<uint16_t>;
3030       break;
3031     case Datatype::UINT32:
3032       tile_num_func_ = tile_num<uint32_t>;
3033       break;
3034     case Datatype::UINT64:
3035       tile_num_func_ = tile_num<uint64_t>;
3036       break;
3037     case Datatype::FLOAT32:
3038       tile_num_func_ = tile_num<float>;
3039       break;
3040     case Datatype::FLOAT64:
3041       tile_num_func_ = tile_num<double>;
3042       break;
3043     case Datatype::DATETIME_YEAR:
3044     case Datatype::DATETIME_MONTH:
3045     case Datatype::DATETIME_WEEK:
3046     case Datatype::DATETIME_DAY:
3047     case Datatype::DATETIME_HR:
3048     case Datatype::DATETIME_MIN:
3049     case Datatype::DATETIME_SEC:
3050     case Datatype::DATETIME_MS:
3051     case Datatype::DATETIME_US:
3052     case Datatype::DATETIME_NS:
3053     case Datatype::DATETIME_PS:
3054     case Datatype::DATETIME_FS:
3055     case Datatype::DATETIME_AS:
3056     case Datatype::TIME_HR:
3057     case Datatype::TIME_MIN:
3058     case Datatype::TIME_SEC:
3059     case Datatype::TIME_MS:
3060     case Datatype::TIME_US:
3061     case Datatype::TIME_NS:
3062     case Datatype::TIME_PS:
3063     case Datatype::TIME_FS:
3064     case Datatype::TIME_AS:
3065       tile_num_func_ = tile_num<int64_t>;
3066       break;
3067     case Datatype::STRING_ASCII:
3068       tile_num_func_ = tile_num<char>;
3069       break;
3070     default:
3071       tile_num_func_ = nullptr;
3072       break;
3073   }
3074 }
3075 
set_map_to_uint64_func()3076 void Dimension::set_map_to_uint64_func() {
3077   switch (type_) {
3078     case Datatype::INT32:
3079       map_to_uint64_func_ = map_to_uint64<int32_t>;
3080       break;
3081     case Datatype::INT64:
3082       map_to_uint64_func_ = map_to_uint64<int64_t>;
3083       break;
3084     case Datatype::INT8:
3085       map_to_uint64_func_ = map_to_uint64<int8_t>;
3086       break;
3087     case Datatype::UINT8:
3088       map_to_uint64_func_ = map_to_uint64<uint8_t>;
3089       break;
3090     case Datatype::INT16:
3091       map_to_uint64_func_ = map_to_uint64<int16_t>;
3092       break;
3093     case Datatype::UINT16:
3094       map_to_uint64_func_ = map_to_uint64<uint16_t>;
3095       break;
3096     case Datatype::UINT32:
3097       map_to_uint64_func_ = map_to_uint64<uint32_t>;
3098       break;
3099     case Datatype::UINT64:
3100       map_to_uint64_func_ = map_to_uint64<uint64_t>;
3101       break;
3102     case Datatype::FLOAT32:
3103       map_to_uint64_func_ = map_to_uint64<float>;
3104       break;
3105     case Datatype::FLOAT64:
3106       map_to_uint64_func_ = map_to_uint64<double>;
3107       break;
3108     case Datatype::DATETIME_YEAR:
3109     case Datatype::DATETIME_MONTH:
3110     case Datatype::DATETIME_WEEK:
3111     case Datatype::DATETIME_DAY:
3112     case Datatype::DATETIME_HR:
3113     case Datatype::DATETIME_MIN:
3114     case Datatype::DATETIME_SEC:
3115     case Datatype::DATETIME_MS:
3116     case Datatype::DATETIME_US:
3117     case Datatype::DATETIME_NS:
3118     case Datatype::DATETIME_PS:
3119     case Datatype::DATETIME_FS:
3120     case Datatype::DATETIME_AS:
3121     case Datatype::TIME_HR:
3122     case Datatype::TIME_MIN:
3123     case Datatype::TIME_SEC:
3124     case Datatype::TIME_MS:
3125     case Datatype::TIME_US:
3126     case Datatype::TIME_NS:
3127     case Datatype::TIME_PS:
3128     case Datatype::TIME_FS:
3129     case Datatype::TIME_AS:
3130       map_to_uint64_func_ = map_to_uint64<int64_t>;
3131       break;
3132     case Datatype::STRING_ASCII:
3133       map_to_uint64_func_ = map_to_uint64<char>;
3134       break;
3135     default:
3136       map_to_uint64_func_ = nullptr;
3137       break;
3138   }
3139 }
3140 
set_map_to_uint64_2_func()3141 void Dimension::set_map_to_uint64_2_func() {
3142   switch (type_) {
3143     case Datatype::INT32:
3144       map_to_uint64_2_func_ = map_to_uint64_2<int32_t>;
3145       break;
3146     case Datatype::INT64:
3147       map_to_uint64_2_func_ = map_to_uint64_2<int64_t>;
3148       break;
3149     case Datatype::INT8:
3150       map_to_uint64_2_func_ = map_to_uint64_2<int8_t>;
3151       break;
3152     case Datatype::UINT8:
3153       map_to_uint64_2_func_ = map_to_uint64_2<uint8_t>;
3154       break;
3155     case Datatype::INT16:
3156       map_to_uint64_2_func_ = map_to_uint64_2<int16_t>;
3157       break;
3158     case Datatype::UINT16:
3159       map_to_uint64_2_func_ = map_to_uint64_2<uint16_t>;
3160       break;
3161     case Datatype::UINT32:
3162       map_to_uint64_2_func_ = map_to_uint64_2<uint32_t>;
3163       break;
3164     case Datatype::UINT64:
3165       map_to_uint64_2_func_ = map_to_uint64_2<uint64_t>;
3166       break;
3167     case Datatype::FLOAT32:
3168       map_to_uint64_2_func_ = map_to_uint64_2<float>;
3169       break;
3170     case Datatype::FLOAT64:
3171       map_to_uint64_2_func_ = map_to_uint64_2<double>;
3172       break;
3173     case Datatype::DATETIME_YEAR:
3174     case Datatype::DATETIME_MONTH:
3175     case Datatype::DATETIME_WEEK:
3176     case Datatype::DATETIME_DAY:
3177     case Datatype::DATETIME_HR:
3178     case Datatype::DATETIME_MIN:
3179     case Datatype::DATETIME_SEC:
3180     case Datatype::DATETIME_MS:
3181     case Datatype::DATETIME_US:
3182     case Datatype::DATETIME_NS:
3183     case Datatype::DATETIME_PS:
3184     case Datatype::DATETIME_FS:
3185     case Datatype::DATETIME_AS:
3186     case Datatype::TIME_HR:
3187     case Datatype::TIME_MIN:
3188     case Datatype::TIME_SEC:
3189     case Datatype::TIME_MS:
3190     case Datatype::TIME_US:
3191     case Datatype::TIME_NS:
3192     case Datatype::TIME_PS:
3193     case Datatype::TIME_FS:
3194     case Datatype::TIME_AS:
3195       map_to_uint64_2_func_ = map_to_uint64_2<int64_t>;
3196       break;
3197     case Datatype::STRING_ASCII:
3198       map_to_uint64_2_func_ = map_to_uint64_2<char>;
3199       break;
3200     default:
3201       map_to_uint64_2_func_ = nullptr;
3202       break;
3203   }
3204 }
3205 
set_map_to_uint64_3_func()3206 void Dimension::set_map_to_uint64_3_func() {
3207   switch (type_) {
3208     case Datatype::INT32:
3209       map_to_uint64_3_func_ = map_to_uint64_3<int32_t>;
3210       break;
3211     case Datatype::INT64:
3212       map_to_uint64_3_func_ = map_to_uint64_3<int64_t>;
3213       break;
3214     case Datatype::INT8:
3215       map_to_uint64_3_func_ = map_to_uint64_3<int8_t>;
3216       break;
3217     case Datatype::UINT8:
3218       map_to_uint64_3_func_ = map_to_uint64_3<uint8_t>;
3219       break;
3220     case Datatype::INT16:
3221       map_to_uint64_3_func_ = map_to_uint64_3<int16_t>;
3222       break;
3223     case Datatype::UINT16:
3224       map_to_uint64_3_func_ = map_to_uint64_3<uint16_t>;
3225       break;
3226     case Datatype::UINT32:
3227       map_to_uint64_3_func_ = map_to_uint64_3<uint32_t>;
3228       break;
3229     case Datatype::UINT64:
3230       map_to_uint64_3_func_ = map_to_uint64_3<uint64_t>;
3231       break;
3232     case Datatype::FLOAT32:
3233       map_to_uint64_3_func_ = map_to_uint64_3<float>;
3234       break;
3235     case Datatype::FLOAT64:
3236       map_to_uint64_3_func_ = map_to_uint64_3<double>;
3237       break;
3238     case Datatype::DATETIME_YEAR:
3239     case Datatype::DATETIME_MONTH:
3240     case Datatype::DATETIME_WEEK:
3241     case Datatype::DATETIME_DAY:
3242     case Datatype::DATETIME_HR:
3243     case Datatype::DATETIME_MIN:
3244     case Datatype::DATETIME_SEC:
3245     case Datatype::DATETIME_MS:
3246     case Datatype::DATETIME_US:
3247     case Datatype::DATETIME_NS:
3248     case Datatype::DATETIME_PS:
3249     case Datatype::DATETIME_FS:
3250     case Datatype::DATETIME_AS:
3251     case Datatype::TIME_HR:
3252     case Datatype::TIME_MIN:
3253     case Datatype::TIME_SEC:
3254     case Datatype::TIME_MS:
3255     case Datatype::TIME_US:
3256     case Datatype::TIME_NS:
3257     case Datatype::TIME_PS:
3258     case Datatype::TIME_FS:
3259     case Datatype::TIME_AS:
3260       map_to_uint64_3_func_ = map_to_uint64_3<int64_t>;
3261       break;
3262     case Datatype::STRING_ASCII:
3263       map_to_uint64_3_func_ = map_to_uint64_3<char>;
3264       break;
3265     default:
3266       map_to_uint64_3_func_ = nullptr;
3267       break;
3268   }
3269 }
3270 
set_map_from_uint64_func()3271 void Dimension::set_map_from_uint64_func() {
3272   switch (type_) {
3273     case Datatype::INT32:
3274       map_from_uint64_func_ = map_from_uint64<int32_t>;
3275       break;
3276     case Datatype::INT64:
3277       map_from_uint64_func_ = map_from_uint64<int64_t>;
3278       break;
3279     case Datatype::INT8:
3280       map_from_uint64_func_ = map_from_uint64<int8_t>;
3281       break;
3282     case Datatype::UINT8:
3283       map_from_uint64_func_ = map_from_uint64<uint8_t>;
3284       break;
3285     case Datatype::INT16:
3286       map_from_uint64_func_ = map_from_uint64<int16_t>;
3287       break;
3288     case Datatype::UINT16:
3289       map_from_uint64_func_ = map_from_uint64<uint16_t>;
3290       break;
3291     case Datatype::UINT32:
3292       map_from_uint64_func_ = map_from_uint64<uint32_t>;
3293       break;
3294     case Datatype::UINT64:
3295       map_from_uint64_func_ = map_from_uint64<uint64_t>;
3296       break;
3297     case Datatype::FLOAT32:
3298       map_from_uint64_func_ = map_from_uint64<float>;
3299       break;
3300     case Datatype::FLOAT64:
3301       map_from_uint64_func_ = map_from_uint64<double>;
3302       break;
3303     case Datatype::DATETIME_YEAR:
3304     case Datatype::DATETIME_MONTH:
3305     case Datatype::DATETIME_WEEK:
3306     case Datatype::DATETIME_DAY:
3307     case Datatype::DATETIME_HR:
3308     case Datatype::DATETIME_MIN:
3309     case Datatype::DATETIME_SEC:
3310     case Datatype::DATETIME_MS:
3311     case Datatype::DATETIME_US:
3312     case Datatype::DATETIME_NS:
3313     case Datatype::DATETIME_PS:
3314     case Datatype::DATETIME_FS:
3315     case Datatype::DATETIME_AS:
3316     case Datatype::TIME_HR:
3317     case Datatype::TIME_MIN:
3318     case Datatype::TIME_SEC:
3319     case Datatype::TIME_MS:
3320     case Datatype::TIME_US:
3321     case Datatype::TIME_NS:
3322     case Datatype::TIME_PS:
3323     case Datatype::TIME_FS:
3324     case Datatype::TIME_AS:
3325       map_from_uint64_func_ = map_from_uint64<int64_t>;
3326       break;
3327     case Datatype::STRING_ASCII:
3328       map_from_uint64_func_ = map_from_uint64<char>;
3329       break;
3330     default:
3331       map_from_uint64_func_ = nullptr;
3332       break;
3333   }
3334 }
3335 
set_smaller_than_func()3336 void Dimension::set_smaller_than_func() {
3337   switch (type_) {
3338     case Datatype::INT32:
3339       smaller_than_func_ = smaller_than<int32_t>;
3340       break;
3341     case Datatype::INT64:
3342       smaller_than_func_ = smaller_than<int64_t>;
3343       break;
3344     case Datatype::INT8:
3345       smaller_than_func_ = smaller_than<int8_t>;
3346       break;
3347     case Datatype::UINT8:
3348       smaller_than_func_ = smaller_than<uint8_t>;
3349       break;
3350     case Datatype::INT16:
3351       smaller_than_func_ = smaller_than<int16_t>;
3352       break;
3353     case Datatype::UINT16:
3354       smaller_than_func_ = smaller_than<uint16_t>;
3355       break;
3356     case Datatype::UINT32:
3357       smaller_than_func_ = smaller_than<uint32_t>;
3358       break;
3359     case Datatype::UINT64:
3360       smaller_than_func_ = smaller_than<uint64_t>;
3361       break;
3362     case Datatype::FLOAT32:
3363       smaller_than_func_ = smaller_than<float>;
3364       break;
3365     case Datatype::FLOAT64:
3366       smaller_than_func_ = smaller_than<double>;
3367       break;
3368     case Datatype::DATETIME_YEAR:
3369     case Datatype::DATETIME_MONTH:
3370     case Datatype::DATETIME_WEEK:
3371     case Datatype::DATETIME_DAY:
3372     case Datatype::DATETIME_HR:
3373     case Datatype::DATETIME_MIN:
3374     case Datatype::DATETIME_SEC:
3375     case Datatype::DATETIME_MS:
3376     case Datatype::DATETIME_US:
3377     case Datatype::DATETIME_NS:
3378     case Datatype::DATETIME_PS:
3379     case Datatype::DATETIME_FS:
3380     case Datatype::DATETIME_AS:
3381     case Datatype::TIME_HR:
3382     case Datatype::TIME_MIN:
3383     case Datatype::TIME_SEC:
3384     case Datatype::TIME_MS:
3385     case Datatype::TIME_US:
3386     case Datatype::TIME_NS:
3387     case Datatype::TIME_PS:
3388     case Datatype::TIME_FS:
3389     case Datatype::TIME_AS:
3390       smaller_than_func_ = smaller_than<int64_t>;
3391       break;
3392     case Datatype::STRING_ASCII:
3393       smaller_than_func_ = smaller_than<char>;
3394       break;
3395     default:
3396       smaller_than_func_ = nullptr;
3397       break;
3398   }
3399 }
3400 
3401 }  // namespace sm
3402 }  // namespace tiledb
3403