#pragma once #include #include namespace DB { template struct Interval { using IntervalStorageType = TIntervalStorageType; IntervalStorageType left; IntervalStorageType right; Interval(IntervalStorageType left_, IntervalStorageType right_) : left(left_) , right(right_) {} inline bool contains(IntervalStorageType point) const { return left <= point && point <= right; } }; template bool operator<(const Interval & lhs, const Interval & rhs) { return std::tie(lhs.left, lhs.right) < std::tie(rhs.left, rhs.right); } template bool operator==(const Interval & lhs, const Interval & rhs) { return std::tie(lhs.left, lhs.right) == std::tie(lhs.left, rhs.right); } template bool operator>(const Interval & lhs, const Interval & rhs) { return std::tie(lhs.left, lhs.right) > std::tie(rhs.left, rhs.right); } struct IntervalTreeVoidValue {}; template class IntervalTree { public: using IntervalStorageType = typename Interval::IntervalStorageType; static constexpr bool is_empty_value = std::is_same_v; static constexpr bool is_nonempty_value = !std::is_same_v; template , bool> = true> void emplace(Interval interval) { ++intervals_size; sorted_intervals.emplace_back(interval); } template , bool> = true, typename ...Args> void emplace(Interval interval, Args && ... args) { ++intervals_size; sorted_intervals.emplace_back(interval, Value(std::forward(args)...)); } template , bool> = true> void insert(Interval interval) { ++intervals_size; sorted_intervals.emplace_back(interval); } template , bool> = true> void insert(Interval interval, const Value & value) { ++intervals_size; sorted_intervals.emplace_back(interval, value); } template , bool> = true> void insert(Interval interval, Value && value) { ++intervals_size; sorted_intervals.emplace_back(interval, std::move(value)); } void construct() { nodes.resize(sorted_intervals.size()); buildTree(); } template void find(IntervalStorageType point, IntervalCallback && callback) const { findIntervalsImpl(point, callback); } bool has(IntervalStorageType point) const { bool has_intervals = false; if constexpr (is_empty_value) { find(point, [&](auto &) { has_intervals = true; return false; }); } else { find(point, [&](auto &, auto &) { has_intervals = true; return false; }); } return has_intervals; } struct Node { size_t sorted_intervals_range_start_index; size_t sorted_intervals_range_size; IntervalStorageType middle_element; inline bool hasValue() const { return sorted_intervals_range_size != 0; } }; using IntervalWithEmptyValue = Interval; using IntervalWithNonEmptyValue = std::pair; using IntervalWithValue = std::conditional_t; class Iterator { public: bool operator==(const Iterator & rhs) const { return node_index == rhs.node_index & tree == rhs.tree && current_interval_index == rhs.current_interval_index; } bool operator!=(const Iterator & rhs) const { return !(*this == rhs); } const IntervalWithValue & operator*() { return getCurrentValue(); } const IntervalWithValue & operator*() const { return getCurrentValue(); } const IntervalWithValue *operator->() { return &getCurrentValue(); } const IntervalWithValue *operator->() const { return &getCurrentValue(); } Iterator &operator++() { iterateToNext(); return *this; } // Iterator operator++(int) { // Iterator copy(*this); // iterateToNext(); // return copy; // } // Iterator &operator--() { // iterateToPrevious(); // return *this; // } // Iterator operator--(int) { // Iterator copy(*this); // iterateToNext(); // return copy; // } private: friend class IntervalTree; Iterator(size_t node_index_, size_t current_interval_index_, const IntervalTree * tree_) : node_index(node_index_) , current_interval_index(current_interval_index_) , tree(tree_) {} size_t node_index; size_t current_interval_index; const IntervalTree * tree; void iterateToNext() { size_t nodes_size = tree->nodes.size(); auto & current_node = tree->nodes[node_index]; ++current_interval_index; if (current_interval_index < current_node.sorted_intervals_range_size) return; size_t node_index_copy = node_index + 1; for (; node_index_copy < nodes_size; ++node_index_copy) { auto & node = tree->nodes[node_index_copy]; if (node.hasValue()) { node_index = node_index_copy; current_interval_index = 0; break; } } } void iterateToPrevious() { if (current_interval_index > 0) { --current_interval_index; return; } while (node_index > 0) { auto & node = tree->nodes[node_index - 1]; if (node.hasValue()) { current_interval_index = node.sorted_intervals_range_size - 1; break; } --node_index; } } const IntervalWithValue & getCurrentValue() { auto & current_node = tree->nodes[node_index]; size_t interval_index = current_node.sorted_intervals_range_start_index + current_interval_index; return tree->sorted_intervals[interval_index]; } }; using iterator = Iterator; using const_iterator = Iterator; iterator begin() { size_t start_index = findFirstIteratorNodeIndex(); return Iterator(start_index, 0, this); } iterator end() { size_t end_index = findLastIteratorNodeIndex(); size_t last_interval_index = nodes[end_index].sorted_intervals_range_size; return Iterator(end_index, last_interval_index, this); } const_iterator begin() const { size_t start_index = findFirstIteratorNodeIndex(); return Iterator(start_index, 0, this); } const_iterator end() const { size_t end_index = findLastIteratorNodeIndex(); size_t last_interval_index = nodes[end_index].sorted_intervals_range_size; return Iterator(end_index, last_interval_index, this); } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } size_t getIntervalsSize() const { return intervals_size; } private: void buildTree() { std::vector temporary_points_storage; temporary_points_storage.reserve(sorted_intervals.size() * 2); std::vector left_intervals; std::vector right_intervals; std::vector intervals_sorted_by_left_asc; std::vector intervals_sorted_by_right_desc; struct StackFrame { size_t index; std::vector intervals; }; std::vector stack; stack.emplace_back(StackFrame{0, std::move(sorted_intervals)}); sorted_intervals.clear(); while (!stack.empty()) { auto frame = std::move(stack.back()); stack.pop_back(); size_t current_index = frame.index; auto & current_intervals = frame.intervals; if (current_intervals.empty()) continue; if (current_index >= nodes.size()) nodes.resize(current_index + 1); temporary_points_storage.clear(); intervalsToPoints(current_intervals, temporary_points_storage); auto median = pointsMedian(temporary_points_storage); left_intervals.clear(); right_intervals.clear(); intervals_sorted_by_left_asc.clear(); intervals_sorted_by_right_desc.clear(); for (const auto & interval_with_value : current_intervals) { auto & interval = getInterval(interval_with_value); if (interval.right < median) { left_intervals.emplace_back(interval_with_value); } else if (interval.left > median) { right_intervals.emplace_back(interval_with_value); } else { intervals_sorted_by_left_asc.emplace_back(interval_with_value); intervals_sorted_by_right_desc.emplace_back(interval_with_value); } } std::sort(intervals_sorted_by_left_asc.begin(), intervals_sorted_by_left_asc.end(), [](auto & lhs, auto & rhs) { auto & lhs_interval = getInterval(lhs); auto & rhs_interval = getInterval(rhs); return lhs_interval < rhs_interval; }); std::sort(intervals_sorted_by_right_desc.begin(), intervals_sorted_by_right_desc.end(), [](auto & lhs, auto & rhs) { auto & lhs_interval = getInterval(lhs); auto & rhs_interval = getInterval(rhs); return lhs_interval > rhs_interval; }); size_t sorted_intervals_range_start_index = sorted_intervals.size(); sorted_intervals.insert(sorted_intervals.end(), intervals_sorted_by_left_asc.begin(), intervals_sorted_by_left_asc.end()); sorted_intervals.insert(sorted_intervals.end(), intervals_sorted_by_right_desc.begin(), intervals_sorted_by_right_desc.end()); auto & node = nodes[current_index]; node.middle_element = median; node.sorted_intervals_range_start_index = sorted_intervals_range_start_index; node.sorted_intervals_range_size = intervals_sorted_by_left_asc.size(); size_t left_child_index = current_index * 2 + 1; stack.emplace_back(StackFrame{left_child_index, std::move(left_intervals)}); size_t right_child_index = current_index * 2 + 2; stack.emplace_back(StackFrame{right_child_index, std::move(right_intervals)}); } } template void findIntervalsImpl(IntervalStorageType point, IntervalCallback && callback) const { size_t current_index = 0; while (true) { if (current_index >= nodes.size()) break; auto & node = nodes[current_index]; if (!node.hasValue()) break; auto middle_element = node.middle_element; if (point < middle_element) { size_t start = node.sorted_intervals_range_start_index; size_t end = start + node.sorted_intervals_range_size; for (; start != end; ++start) { auto & interval_with_value_left_sorted_asc = sorted_intervals[start]; auto & interval_left_sorted_asc = getInterval(interval_with_value_left_sorted_asc); if (interval_left_sorted_asc.left > point) break; bool should_continue = callCallback(interval_with_value_left_sorted_asc, callback); if (unlikely(!should_continue)) return; } size_t left_child_index = current_index * 2 + 1; current_index = left_child_index; } else { size_t start = node.sorted_intervals_range_start_index + node.sorted_intervals_range_size; size_t end = start + node.sorted_intervals_range_size; for (; start != end; ++start) { auto & interval_with_value_right_sorted_desc = sorted_intervals[start]; auto & interval_right_sorted_desc = getInterval(interval_with_value_right_sorted_desc); if (interval_right_sorted_desc.right < point) break; bool should_continue = callCallback(interval_with_value_right_sorted_desc, callback); if (unlikely(!should_continue)) return; } if (likely(point > middle_element)) { size_t right_child_index = current_index * 2 + 2; current_index = right_child_index; } else { break; } } } } size_t findFirstIteratorNodeIndex() const { if (nodes.empty()) return 0; size_t nodes_size = nodes.size(); size_t result_index = 0; for (; result_index < nodes_size; ++result_index) { if (nodes[result_index].hasValue()) break; } return result_index; } size_t findLastIteratorNodeIndex() const { if (nodes.empty()) return 0; size_t nodes_size = nodes.size(); int64_t result_index = static_cast(nodes_size - 1); for (; result_index >= 0; --result_index) { if (nodes[result_index].hasValue()) break; } size_t result = static_cast(result_index); return result; } std::vector nodes; std::vector sorted_intervals; size_t intervals_size = 0; static const Interval & getInterval(const IntervalWithValue & interval_with_value) { if constexpr (is_empty_value) return interval_with_value; else return interval_with_value.first; } template static bool callCallback(const IntervalWithValue & interval, IntervalCallback && callback) { if constexpr (is_empty_value) return callback(interval); else return callback(interval.first, interval.second); } static void intervalsToPoints(const std::vector & intervals, std::vector & temporary_points_storage) { for (const auto & interval_with_value : intervals) { auto & interval = getInterval(interval_with_value); temporary_points_storage.emplace_back(interval.left); temporary_points_storage.emplace_back(interval.right); } } static IntervalStorageType pointsMedian(std::vector & points) { size_t size = points.size(); size_t middle_element_index = size / 2; std::nth_element(points.begin(), points.begin() + middle_element_index, points.end()); if (size % 2 == 0) { return (points[middle_element_index] + points[middle_element_index - 1]) / 2; } else { return points[middle_element_index]; } } }; template using IntervalSet = IntervalTree; template using IntervalMap = IntervalTree; }