array
C++ library for multi-dimensional arrays
z_order.h
Go to the documentation of this file.
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
18 #ifndef NDARRAY_Z_ORDER_H
19 #define NDARRAY_Z_ORDER_H
20 
21 #include "array.h"
22 
23 #include <algorithm>
24 #include <functional>
25 
26 namespace nda {
27 
28 namespace internal {
29 
30 inline index_t next_power_of_two(index_t x) {
31  index_t result = 1;
32  while (result < x) {
33  result <<= 1;
34  }
35  return result;
36 }
37 
38 // TODO: This probably doesn't need fn to be inlined, and it would reduce template instantiations
39 // to use std::function instead.
40 template <size_t Rank, class Fn>
41 NDARRAY_UNIQUE void for_each_index_in_z_order_impl(const std::array<index_t, Rank>& end,
42  std::array<index_t, Rank> z, index_t dim, index_t step, const Fn& fn) {
43  if (dim == 0 && step == 1) {
44  // We're at the innermost step of the traversal, call fn for the two neighboring points we have.
45  fn(z);
46  z[0] += 1;
47  if (z[0] < end[0]) {
48  fn(z);
49  }
50  } else if (dim == 0) {
51  // We're on the innermost dimension, but not the innermost step.
52  // Move to the next step for the outermost dimension.
53  for_each_index_in_z_order_impl(end, z, Rank - 1, step >> 1, fn);
54  z[0] += step;
55  if (z[0] < end[0]) {
56  for_each_index_in_z_order_impl(end, z, Rank - 1, step >> 1, fn);
57  }
58  } else {
59  // Move to the next dimension for the same step.
60  for_each_index_in_z_order_impl(end, z, dim - 1, step, fn);
61  z[dim] += step;
62  if (z[dim] < end[dim]) {
63  for_each_index_in_z_order_impl(end, z, dim - 1, step, fn);
64  }
65  }
66 }
67 
68 // TODO: If this conformed more to the rest of the array API, perhaps it could be
69 // exposed as a user API.
70 template <class Extents, class Fn>
71 NDARRAY_UNIQUE void for_each_index_in_z_order(const Extents& extents, const Fn& fn) {
72  constexpr index_t Rank = std::tuple_size<Extents>::value;
73  // Get the ends of the iteration space as an array.
74  const auto end = tuple_to_array<index_t>(extents, make_index_sequence<Rank>());
75  const index_t max_extent = *std::max_element(end.begin(), end.end());
76  const index_t step = std::max<index_t>(1, next_power_of_two(max_extent) >> 1);
77  std::array<index_t, Rank> z = {{0,}};
78  for_each_index_in_z_order_impl(end, z, Rank - 1, step, fn);
79 }
80 
81 template <class... Ranges, class Fn, size_t... Is>
82 NDARRAY_UNIQUE void for_each_in_z_order_impl(
83  const std::tuple<Ranges...>& ranges, const Fn& fn, index_sequence<Is...>) {
84  constexpr size_t Rank = sizeof...(Is);
85  std::array<index_t, Rank> extents = {
86  {(std::end(std::get<Is>(ranges)) - std::begin(std::get<Is>(ranges)))...}};
87  for_each_index_in_z_order(extents, [&](const std::array<index_t, Rank>& i) {
88  fn(std::make_tuple(*(std::begin(std::get<Is>(ranges)) + std::get<Is>(i))...));
89  });
90 }
91 
92 } // namespace internal
93 
98 template <class... Ranges, class Fn>
99 NDARRAY_UNIQUE void for_each_in_z_order(
100  const std::tuple<Ranges...>& ranges, const Fn& fn) {
101  internal::for_each_in_z_order_impl(
102  ranges, fn, internal::make_index_sequence<sizeof...(Ranges)>());
103 }
104 template <class Fn, class... Ranges>
105 NDARRAY_UNIQUE void for_all_in_z_order(
106  const std::tuple<Ranges...>& ranges, const Fn& fn) {
107  internal::for_each_in_z_order_impl(
108  ranges, [&](const auto& i) { internal::apply(fn, i); },
109  internal::make_index_sequence<sizeof...(Ranges)>());
110 }
111 
112 } // namespace nda
113 
114 #endif // NDARRAY_Z_ORDER_H
NDARRAY_UNIQUE void for_each_in_z_order(const std::tuple< Ranges... > &ranges, const Fn &fn)
Definition: z_order.h:99
Main header for array library.
Definition: absl.h:10
std::ptrdiff_t index_t
Definition: array.h:87