ritsuko
Helper utilities for ArtifactDB C++ code
Loading...
Searching...
No Matches
choose_missing_placeholder.hpp
Go to the documentation of this file.
1#ifndef RITSUKO_CHOOSE_MISSING_PLACEHOLDER_HPP
2#define RITSUKO_CHOOSE_MISSING_PLACEHOLDER_HPP
3
4#include <limits>
5#include <set>
6#include <type_traits>
7#include <cmath>
8#include <algorithm>
9
15namespace ritsuko {
16
20template<class Iterator, class Mask, class Type>
21bool found(Iterator start, Iterator end, Mask mask, Type candidate) {
22 if constexpr(std::is_same<Mask, bool>::value) {
23 return (std::find(start, end, candidate) != end);
24 } else {
25 for (; start != end; ++start, ++mask) {
26 if (!*mask && candidate == *start) {
27 return true;
28 }
29 }
30 return false;
31 }
32}
33
34template<class Iterator, class Mask, class Type = typename std::remove_cv<typename std::remove_reference<decltype(*(std::declval<Iterator>()))>::type>::type>
35std::set<Type> create_unique_set(Iterator start, Iterator end, Mask mask) {
36 if constexpr(std::is_same<Mask, bool>::value) {
37 return std::set<Type>(start, end);
38 } else {
39 std::set<Type> output;
40 for (; start != end; ++start, ++mask) {
41 if (!*mask) {
42 output.insert(*start);
43 }
44 }
45 return output;
46 }
47}
48
49template<class Iterator, class Mask, class Type = typename std::remove_cv<typename std::remove_reference<decltype(*(std::declval<Iterator>()))>::type>::type>
50bool check_for_nan(Iterator start, Iterator end, Mask mask) {
51 if constexpr(std::is_same<Mask, bool>::value) {
52 for (auto x = start; x != end; ++x) {
53 if (std::isnan(*x)) {
54 return true;
55 }
56 }
57 } else {
58 auto sIt = mask;
59 for (auto x = start; x != end; ++x, ++sIt) {
60 if (!*sIt && std::isnan(*x)) {
61 return true;
62 }
63 }
64 }
65
66 return false;
67}
88template<class Iterator, class Mask, class Type_ = typename std::remove_cv<typename std::remove_reference<decltype(*(std::declval<Iterator>()))>::type>::type>
89std::pair<bool, Type_> choose_missing_integer_placeholder(Iterator start, Iterator end, Mask mask) {
90 static_assert(std::numeric_limits<Type_>::is_integer);
91
92 // Trying important points first; minima and maxima, and 0.
93 if constexpr(std::numeric_limits<Type_>::is_signed) {
94 auto candidate = std::numeric_limits<Type_>::min();
95 if (!found(start, end, mask, candidate)) {
96 return std::make_pair(true, candidate);
97 }
98 }
99
100 {
101 auto candidate = std::numeric_limits<Type_>::max();
102 if (!found(start, end, mask, candidate)) {
103 return std::make_pair(true, candidate);
104 }
105 }
106
107 if (!found(start, end, mask, 0)) {
108 return std::make_pair(true, 0);
109 }
110
111 // Well... going through it in order.
112 auto uniq_sort = create_unique_set(start, end, mask);
113 Type_ last = std::numeric_limits<Type_>::min();
114 for (auto x : uniq_sort) {
115 if (last + 1 < x) {
116 return std::make_pair(true, last + 1);
117 }
118 last = x;
119 }
120
121 return std::make_pair(false, 0);
122}
123
135template<class Iterator, class Type_ = typename std::remove_cv<typename std::remove_reference<decltype(*(std::declval<Iterator>()))>::type>::type>
136std::pair<bool, Type_> choose_missing_integer_placeholder(Iterator start, Iterator end) {
137 return choose_missing_integer_placeholder(start, end, false);
138}
139
156template<class Iterator, class Mask, class Type_ = typename std::remove_cv<typename std::remove_reference<decltype(*(std::declval<Iterator>()))>::type>::type>
157std::pair<bool, Type_> choose_missing_float_placeholder(Iterator start, Iterator end, Mask mask, bool skip_nan) {
158 if constexpr(std::numeric_limits<Type_>::is_iec559) {
159 if (!skip_nan) {
160 if (!check_for_nan(start, end, mask)) {
161 return std::make_pair(true, std::numeric_limits<Type_>::quiet_NaN());
162 }
163 }
164
165 // Trying positive and negative Infs.
166 auto inf = std::numeric_limits<Type_>::infinity();
167 if (!found(start, end, mask, inf)) {
168 return std::make_pair(true, inf);
169 }
170
171 auto ninf = -inf;
172 if (!found(start, end, mask, ninf)) {
173 return std::make_pair(true, ninf);
174 }
175 }
176
177 // Trying important points first; minima and maxima, and 0.
178 {
179 auto candidate = std::numeric_limits<Type_>::lowest();
180 if (!found(start, end, mask, candidate)) {
181 return std::make_pair(true, candidate);
182 }
183 }
184
185 {
186 auto candidate = std::numeric_limits<Type_>::max();
187 if (!found(start, end, mask, candidate)) {
188 return std::make_pair(true, candidate);
189 }
190 }
191
192 if (!found(start, end, mask, 0)) {
193 return std::make_pair(true, 0);
194 }
195
196 // Well... going through it in order.
197 auto uniq_sort = create_unique_set(start, end, mask);
198 Type_ last = std::numeric_limits<Type_>::lowest();
199 for (auto x : uniq_sort) {
200 if (std::isfinite(x)) {
201 Type_ candidate = last + (x - last) / 2;
202 if (candidate != last && candidate != x) {
203 return std::make_pair(true, candidate);
204 }
205 last = x;
206 }
207 }
208
209 return std::make_pair(false, 0);
210}
211
224template<class Iterator, class Type_ = typename std::remove_cv<typename std::remove_reference<decltype(*(std::declval<Iterator>()))>::type>::type>
225std::pair<bool, Type_> choose_missing_float_placeholder(Iterator start, Iterator end, bool skip_nan = false) {
226 return choose_missing_float_placeholder(start, end, false, skip_nan);
227}
228
229}
230
231#endif
Assorted helper functions for parsing and validation.
Definition choose_missing_placeholder.hpp:15
std::pair< bool, Type_ > choose_missing_integer_placeholder(Iterator start, Iterator end, Mask mask)
Definition choose_missing_placeholder.hpp:89
std::pair< bool, Type_ > choose_missing_float_placeholder(Iterator start, Iterator end, Mask mask, bool skip_nan)
Definition choose_missing_placeholder.hpp:157