Skip to content

Commit 4586fc7

Browse files
committed
cleanup helpers
1 parent c1ee145 commit 4586fc7

File tree

1 file changed

+76
-78
lines changed

1 file changed

+76
-78
lines changed

src/bin_dots.cpp

Lines changed: 76 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ constexpr R_xlen_t operator""_rz(unsigned long long n) {
3535
return n;
3636
}
3737

38-
// helpers ---------------------------------------------------------------------------
38+
// container helpers ---------------------------------------------------------------------------
3939

4040
/// Signed size of a container (from C++20)
4141
template<class C>
@@ -89,7 +89,50 @@ Rcpp::IntegerVector wilkinson_bin_to_right_(const Rcpp::NumericVector& x, const
8989
return bins;
9090
}
9191

92-
// grid_swarm ------------------------------------------------------------
92+
// reversible sequence helpers ------------------------------------------------------
93+
// These helpers allow us to write the core grid swarm placement methods in a way that
94+
// is agnostic to whether we are iterating forward or backward through the candidate dots.
95+
96+
/// const begin iterator for forward or reverse iteration
97+
/// @tparam reverse iterate in reverse?
98+
/// @tparam C container type
99+
/// @param container object to iterate over
100+
template<bool reverse, typename C>
101+
inline auto cbegin(const C& container) {
102+
if constexpr (reverse) {
103+
return container.crbegin();
104+
} else {
105+
return container.cbegin();
106+
}
107+
}
108+
109+
/// const end iterator for forward or reverse iteration
110+
/// @tparam reverse iterate in reverse?
111+
/// @tparam C container type
112+
/// @param container object to iterate over
113+
template<bool reverse, typename C>
114+
inline auto cend(const C& container) {
115+
if constexpr (reverse) {
116+
return container.crend();
117+
} else {
118+
return container.cend();
119+
}
120+
}
121+
122+
/// Erase an element from a container via a (possibly reversed) iterator
123+
/// @tparam reverse is the iterator reversed?
124+
/// @tparam C container type
125+
/// @tparam It iterator type
126+
/// @param container object to erase from
127+
/// @param it iterator pointing at element to erase
128+
template<bool reverse, typename C, typename It>
129+
inline auto erase(C& container, const It& it) -> It {
130+
if constexpr (reverse) {
131+
return std::reverse_iterator(container.erase(std::next(it).base()));
132+
} else {
133+
return container.erase(it);
134+
}
135+
}
93136

94137
/// Add distance to a value, possibly in reverse direction
95138
/// @tparam reverse add in reverse direction?
@@ -119,6 +162,27 @@ inline auto min_candidate(const double a, const double b) -> double {
119162
}
120163
}
121164

165+
/// Advance an iterator on a set of candidates to at least `min_next_candidate`
166+
/// @tparam reverse is the iterator reversed?
167+
/// @tparam Candidates container type
168+
/// @param candidates set of candidates
169+
/// @param it current iterator position
170+
/// @param min_next_candidate minimum candidate value to advance to
171+
template<bool reverse, typename Iterator, typename Candidates>
172+
inline auto advance_to_at_least(
173+
const Candidates& candidates, const Iterator it, const double min_next_candidate
174+
) {
175+
if constexpr (reverse) {
176+
auto next_it = std::reverse_iterator(upper_bound(candidates, min_next_candidate));
177+
return std::max(it, next_it);
178+
} else {
179+
auto next_it = lower_bound(candidates, min_next_candidate);
180+
return std::max(it, next_it);
181+
}
182+
}
183+
184+
// core grid swarm placement methods ------------------------------------------------------
185+
122186
/// Attempt to place a candidate dot in a target row
123187
/// @tparam Row container type for rows of already-placed dots
124188
/// @param candidate candidate x position
@@ -185,79 +249,6 @@ inline auto place_candidate(
185249
return true;
186250
}
187251

188-
/// const begin iterator for forward or reverse s
189-
/// @tparam reverse iterate in reverse?
190-
/// @tparam C container type
191-
/// @param container object to iterate over
192-
template<bool reverse, typename C>
193-
inline auto cbegin(const C& container) {
194-
if constexpr (reverse) {
195-
return container.crbegin();
196-
} else {
197-
return container.cbegin();
198-
}
199-
}
200-
201-
/// const end iterator for forward or reverse iteration
202-
/// @tparam reverse iterate in reverse?
203-
/// @tparam C container type
204-
/// @param container object to iterate over
205-
template<bool reverse, typename C>
206-
inline auto cend(const C& container) {
207-
if constexpr (reverse) {
208-
return container.crend();
209-
} else {
210-
return container.cend();
211-
}
212-
}
213-
214-
/// push onto front or back of a container
215-
/// @tparam front push onto front?
216-
/// @tparam C container type
217-
/// @param container object to push onto
218-
template<bool front, typename C, typename V>
219-
inline void push(C& container, V&& value) {
220-
if constexpr (front) {
221-
container.push_front(std::forward<V>(value));
222-
} else {
223-
container.push_back(std::forward<V>(value));
224-
}
225-
}
226-
227-
/// Erase an element from a container via a (possibly reversed) iterator
228-
/// @tparam reverse is the iterator reversed?
229-
/// @tparam C container type
230-
/// @tparam It iterator type
231-
/// @param container object to erase from
232-
/// @param it iterator pointing at element to erase
233-
template<bool reverse, typename C, typename It>
234-
inline auto erase(C& container, const It& it) -> It {
235-
if constexpr (reverse) {
236-
return std::reverse_iterator(container.erase(std::next(it).base()));
237-
} else {
238-
return container.erase(it);
239-
}
240-
}
241-
242-
/// Advance an iterator on a set of candidates to at least `min_next_candidate`
243-
/// @tparam reverse is the iterator reversed?
244-
/// @tparam Candidates container type
245-
/// @param candidates set of candidates
246-
/// @param it current iterator position
247-
/// @param min_next_candidate minimum candidate value to advance to
248-
template<bool reverse, typename Iterator, typename Candidates>
249-
inline auto advance_to_at_least(
250-
const Candidates& candidates, const Iterator it, const double min_next_candidate
251-
) {
252-
if constexpr (reverse) {
253-
auto next_it = std::reverse_iterator(upper_bound(candidates, min_next_candidate));
254-
return std::max(it, next_it);
255-
} else {
256-
auto next_it = lower_bound(candidates, min_next_candidate);
257-
return std::max(it, next_it);
258-
}
259-
}
260-
261252
/// Attempt to place dots in a specific row in the grid_swarm algorithm
262253
/// @tparam reverse are we placing dots in reverse order?
263254
/// @tparam Row container type for rows of already-placed dots
@@ -296,14 +287,19 @@ inline auto place_row(
296287
for (auto it = cbegin<reverse>(candidates); it != cend<reverse>(candidates); ) {
297288
auto candidate = *it;
298289

299-
if (place_candidate<reverse>(candidate, xsize, ygrid, rows, row_i, min_next_candidate_top)) {
300-
it = erase<reverse>(candidates, it);
301-
} else if (both && place_candidate<reverse>(candidate, xsize, ygrid, rows_bottom, row_i, min_next_candidate_bottom)) {
290+
// attempt to place candidate, updating min_next_candidate_{top,bottom} so we can
291+
// skip candidates that are definitely not placeable (this is very important for performance,
292+
// especially when binwidth is large and many candidates are rejected)
293+
if (
294+
place_candidate<reverse>(candidate, xsize, ygrid, rows, row_i, min_next_candidate_top) ||
295+
(both && place_candidate<reverse>(candidate, xsize, ygrid, rows_bottom, row_i, min_next_candidate_bottom))
296+
) {
302297
it = erase<reverse>(candidates, it);
303298
} else {
304299
++it;
305300
}
306301

302+
// skip candidates that are definitely not placeable
307303
if (both) {
308304
min_next_candidate = min_candidate<reverse>(min_next_candidate_top, min_next_candidate_bottom);
309305
} else {
@@ -410,6 +406,8 @@ SEXP grid_swarm_(
410406
);
411407
}
412408

409+
// swarm cluster recentering ------------------------------------------------------------
410+
413411
//' Re-center contiguous clusters around their mean y position so that
414412
//' small clusters are visually centered (rather than e.g. a cluster of
415413
//' two points having one point on the origin line and one above it)

0 commit comments

Comments
 (0)