ClickHouse
357 строк · 9.5 Кб
1#include <Core/Range.h>
2#include <Common/FieldVisitorToString.h>
3#include <IO/WriteBufferFromString.h>
4#include <IO/Operators.h>
5
6
7namespace DB
8{
9
10Range::Range(const FieldRef & point) /// NOLINT
11: left(point), right(point), left_included(true), right_included(true) {}
12
13/// A bounded two-sided range.
14Range::Range(const FieldRef & left_, bool left_included_, const FieldRef & right_, bool right_included_)
15: left(left_)
16, right(right_)
17, left_included(left_included_)
18, right_included(right_included_)
19{
20shrinkToIncludedIfPossible();
21}
22
23Range Range::createWholeUniverse()
24{
25return Range(NEGATIVE_INFINITY, true, POSITIVE_INFINITY, true);
26}
27
28Range Range::createWholeUniverseWithoutNull()
29{
30return Range(NEGATIVE_INFINITY, false, POSITIVE_INFINITY, false);
31}
32
33Range Range::createRightBounded(const FieldRef & right_point, bool right_included, bool with_null)
34{
35Range r = with_null ? createWholeUniverse() : createWholeUniverseWithoutNull();
36r.right = right_point;
37r.right_included = right_included;
38r.shrinkToIncludedIfPossible();
39// Special case for [-Inf, -Inf]
40if (r.right.isNegativeInfinity() && right_included)
41r.left_included = true;
42return r;
43}
44
45Range Range::createLeftBounded(const FieldRef & left_point, bool left_included, bool with_null)
46{
47Range r = with_null ? createWholeUniverse() : createWholeUniverseWithoutNull();
48r.left = left_point;
49r.left_included = left_included;
50r.shrinkToIncludedIfPossible();
51// Special case for [+Inf, +Inf]
52if (r.left.isPositiveInfinity() && left_included)
53r.right_included = true;
54return r;
55}
56
57/** Optimize the range. If it has an open boundary and the Field type is "loose"
58* - then convert it to closed, narrowing by one.
59* That is, for example, turn (0,2) into [1].
60*/
61void Range::shrinkToIncludedIfPossible()
62{
63if (left.isExplicit() && !left_included)
64{
65if (left.getType() == Field::Types::UInt64 && left.get<UInt64>() != std::numeric_limits<UInt64>::max())
66{
67++left.get<UInt64 &>();
68left_included = true;
69}
70if (left.getType() == Field::Types::Int64 && left.get<Int64>() != std::numeric_limits<Int64>::max())
71{
72++left.get<Int64 &>();
73left_included = true;
74}
75}
76if (right.isExplicit() && !right_included)
77{
78if (right.getType() == Field::Types::UInt64 && right.get<UInt64>() != std::numeric_limits<UInt64>::min())
79{
80--right.get<UInt64 &>();
81right_included = true;
82}
83if (right.getType() == Field::Types::Int64 && right.get<Int64>() != std::numeric_limits<Int64>::min())
84{
85--right.get<Int64 &>();
86right_included = true;
87}
88}
89}
90
91bool Range::equals(const Field & lhs, const Field & rhs)
92{
93return applyVisitor(FieldVisitorAccurateEquals(), lhs, rhs);
94}
95
96bool Range::less(const Field & lhs, const Field & rhs)
97{
98return applyVisitor(FieldVisitorAccurateLess(), lhs, rhs);
99}
100
101bool Range::empty() const
102{
103return less(right, left)
104|| ((!left_included || !right_included)
105&& !less(left, right));
106}
107
108/// x contained in the range
109bool Range::contains(const FieldRef & x) const
110{
111return !leftThan(x) && !rightThan(x);
112}
113
114/// x is to the left
115bool Range::rightThan(const FieldRef & x) const
116{
117return less(left, x) || (left_included && equals(x, left));
118}
119
120/// x is to the right
121bool Range::leftThan(const FieldRef & x) const
122{
123return less(x, right) || (right_included && equals(x, right));
124}
125
126bool Range::rightThan(const Range & x) const
127{
128return less(x.right, left) || (!(left_included && x.right_included) && equals(left, x.right));
129}
130
131bool Range::leftThan(const Range & x) const
132{
133return less(right, x.left) || (!(x.left_included && right_included) && equals(right, x.left));
134}
135
136bool Range::fullBounded() const
137{
138return left.getType() != Field::Types::Null && right.getType() != Field::Types::Null;
139}
140
141/// (-inf, +inf)
142bool Range::isInfinite() const
143{
144return left.isNegativeInfinity() && right.isPositiveInfinity();
145}
146
147bool Range::intersectsRange(const Range & r) const
148{
149/// r to the left of me.
150if (less(r.right, left) || ((!left_included || !r.right_included) && equals(r.right, left)))
151return false;
152
153/// r to the right of me.
154if (less(right, r.left) || ((!right_included || !r.left_included) && equals(r.left, right)))
155return false;
156
157return true;
158}
159
160bool Range::containsRange(const Range & r) const
161{
162/// r starts to the left of me.
163if (less(r.left, left) || (r.left_included && !left_included && equals(r.left, left)))
164return false;
165
166/// r ends right of me.
167if (less(right, r.right) || (r.right_included && !right_included && equals(r.right, right)))
168return false;
169
170return true;
171}
172
173void Range::invert()
174{
175std::swap(left, right);
176if (left.isPositiveInfinity())
177left = NEGATIVE_INFINITY;
178if (right.isNegativeInfinity())
179right = POSITIVE_INFINITY;
180std::swap(left_included, right_included);
181}
182
183Ranges Range::invertRange() const
184{
185Ranges ranges;
186/// For full bounded range will generate two ranges.
187if (fullBounded()) /// case: [1, 3] -> (-inf, 1), (3, +inf)
188{
189ranges.push_back({NEGATIVE_INFINITY, false, left, !left_included});
190ranges.push_back({right, !right_included, POSITIVE_INFINITY, false});
191}
192else if (isInfinite())
193{
194/// blank ranges
195}
196else /// case: (-inf, 1] or [1, +inf)
197{
198Range r = *this;
199std::swap(r.left, r.right);
200if (r.left.isPositiveInfinity()) /// [1, +inf)
201{
202r.left = NEGATIVE_INFINITY;
203r.right_included = !r.left_included;
204r.left_included = false;
205}
206else if (r.right.isNegativeInfinity()) /// (-inf, 1]
207{
208r.right = POSITIVE_INFINITY;
209r.left_included = !r.right_included;
210r.right_included = false;
211}
212ranges.push_back(r);
213}
214return ranges;
215}
216
217std::optional<Range> Range::intersectWith(const Range & r) const
218{
219if (!intersectsRange(r))
220return {};
221
222bool left_bound_use_mine = true;
223bool right_bound_use_mine = true;
224
225if (less(left, r.left) || ((!left_included && r.left_included) && equals(left, r.left)))
226left_bound_use_mine = false;
227
228if (less(r.right, right) || ((!r.right_included && right_included) && equals(r.right, right)))
229right_bound_use_mine = false;
230
231return Range(
232left_bound_use_mine ? left : r.left,
233left_bound_use_mine ? left_included : r.left_included,
234right_bound_use_mine ? right : r.right,
235right_bound_use_mine ? right_included : r.right_included);
236}
237
238std::optional<Range> Range::unionWith(const Range & r) const
239{
240if (!intersectsRange(r) && !nearByWith(r))
241return {};
242
243bool left_bound_use_mine = false;
244bool right_bound_use_mine = false;
245
246if (less(left, r.left) || ((!left_included && r.left_included) && equals(left, r.left)))
247left_bound_use_mine = true;
248
249if (less(r.right, right) || ((!r.right_included && right_included) && equals(r.right, right)))
250right_bound_use_mine = true;
251
252return Range(
253left_bound_use_mine ? left : r.left,
254left_bound_use_mine ? left_included : r.left_included,
255right_bound_use_mine ? right : r.right,
256right_bound_use_mine ? right_included : r.right_included);
257}
258
259bool Range::nearByWith(const Range & r) const
260{
261/// me locates at left
262if (((right_included && !r.left_included) || (!right_included && r.left_included)) && equals(right, r.left))
263return true;
264
265/// r locate left
266if (((r.right_included && !left_included) || (r.right_included && !left_included)) && equals(r.right, left))
267return true;
268
269return false;
270}
271
272Range intersect(const Range & a, const Range & b)
273{
274Range res = Range::createWholeUniverse();
275
276if (Range::less(a.left, b.left))
277{
278res.left = b.left;
279res.left_included = b.left_included;
280}
281else if (Range::equals(a.left, b.left))
282{
283res.left = a.left;
284res.left_included = a.left_included && b.left_included;
285}
286else
287{
288res.left = a.left;
289res.left_included = a.left_included;
290}
291
292if (Range::less(a.right, b.right))
293{
294res.right = a.right;
295res.right_included = a.right_included;
296}
297else if (Range::equals(a.right, b.right))
298{
299res.right = a.right;
300res.right_included = a.right_included && b.right_included;
301}
302else
303{
304res.right = b.right;
305res.right_included = b.right_included;
306}
307
308if (res.empty())
309{
310res.right = res.left;
311res.right_included = false;
312res.left_included = false;
313}
314
315return res;
316}
317
318String Range::toString() const
319{
320WriteBufferFromOwnString str;
321
322str << (left_included ? '[' : '(') << applyVisitor(FieldVisitorToString(), left) << ", ";
323str << applyVisitor(FieldVisitorToString(), right) << (right_included ? ']' : ')');
324
325return str.str();
326}
327
328Hyperrectangle intersect(const Hyperrectangle & a, const Hyperrectangle & b)
329{
330size_t result_size = std::min(a.size(), b.size());
331
332Hyperrectangle res;
333res.reserve(result_size);
334
335for (size_t i = 0; i < result_size; ++i)
336res.push_back(intersect(a[i], b[i]));
337
338return res;
339}
340
341String toString(const Hyperrectangle & x)
342{
343WriteBufferFromOwnString str;
344
345bool first = true;
346for (const auto & range : x)
347{
348if (!first)
349str << " × ";
350str << range.toString();
351first = false;
352}
353
354return str.str();
355}
356
357}
358