#ifndef COMPACT_SET_INL_H_ #error "Direct inclusion of this file is not allowed, include compact_set.h" // For the sake of sane code completion. #include "compact_set.h" #endif #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// template class TCompactSet::const_iterator { private: friend class TCompactSet; union { TVectorConstIterator VIter; TSetConstIterator SIter; }; bool Small; const_iterator(TVectorConstIterator it) : VIter(it) , Small(true) { } const_iterator(TSetConstIterator it) : SIter(it) , Small(false) { } template void ConstructFrom(TOther&& rhs) { YT_ASSERT(Small == rhs.Small); if (Small) { new (&VIter)TVectorConstIterator(std::forward(rhs).VIter); } else { new (&SIter)TSetConstIterator(std::forward(rhs).SIter); } } template const_iterator& AssignFrom(TOther&& rhs) { if (this == &rhs) { return *this; } if (Small && rhs.Small) { VIter = std::forward(rhs).VIter; } else if (!Small && !rhs.Small) { SIter = std::forward(rhs).SIter; } else { if (Small) { VIter.~TVectorConstIterator(); } else { SIter.~TSetConstIterator(); } if (rhs.Small) { new (&VIter)TVectorConstIterator(std::forward(rhs).VIter); } else { new (&SIter)TSetConstIterator(std::forward(rhs).SIter); } } Small = rhs.Small; return *this; } public: static_assert(std::is_same_v< typename std::iterator_traits::difference_type, typename std::iterator_traits::difference_type>); static_assert(std::is_same_v< typename std::iterator_traits::value_type, typename std::iterator_traits::value_type>); static_assert(std::is_same_v< typename std::iterator_traits::pointer, typename std::iterator_traits::pointer>); static_assert(std::is_same_v< typename std::iterator_traits::reference, typename std::iterator_traits::reference>); using difference_type = typename std::iterator_traits::difference_type; using value_type = typename std::iterator_traits::value_type; using pointer = typename std::iterator_traits::pointer; using reference = typename std::iterator_traits::reference; using iterator_category = std::bidirectional_iterator_tag; const_iterator(const const_iterator& rhs) : Small(rhs.Small) { ConstructFrom(rhs); } const_iterator(const_iterator&& rhs) : Small(rhs.Small) { ConstructFrom(std::move(rhs)); } ~const_iterator() { if (Small) { VIter.~TVectorConstIterator(); } else { SIter.~TSetConstIterator(); } } const_iterator& operator=(const const_iterator& rhs) { return AssignFrom(rhs); } const_iterator& operator=(const_iterator&& rhs) { return AssignFrom(std::move(rhs)); } const_iterator& operator++() { if (Small) { ++VIter; } else { ++SIter; } return *this; } const_iterator operator++(int) { auto result = *this; if (Small) { ++VIter; } else { ++SIter; } return result; } const_iterator& operator--() { if (Small) { --VIter; } else { --SIter; } return *this; } const_iterator operator--(int) { auto result = *this; if (Small) { --VIter; } else { --SIter; } return result; } bool operator==(const const_iterator& rhs) const { if (Small != rhs.Small) { return false; } return Small ? (VIter == rhs.VIter) : (SIter == rhs.SIter); } bool operator!=(const const_iterator& rhs) const { return !(*this == rhs); } const T& operator*() const { return Small ? *VIter : *SIter; } const T* operator->() const { return &operator*(); } }; //////////////////////////////////////////////////////////////////////////////// template TCompactSet::TCompactSet(const A& allocator) : Set_(allocator) { } template bool TCompactSet::empty() const { return Vector_.empty() && Set_.empty(); } template typename TCompactSet::size_type TCompactSet::size() const { return is_small() ? Vector_.size() : Set_.size(); } template const T& TCompactSet::front() const { return is_small() ? Vector_.front() : *Set_.begin(); } template typename TCompactSet::size_type TCompactSet::count(const T& v) const { if (is_small()) { return std::binary_search(Vector_.begin(), Vector_.end(), v, C()) ? 1 : 0; } else { return Set_.count(v); } } template bool TCompactSet::contains(const T& v) const { return count(v) == 1; } template std::pair::const_iterator, bool> TCompactSet::insert(const T& v) { if (!is_small()) { auto [it, inserted] = Set_.insert(v); return {const_iterator(std::move(it)), inserted}; } auto it = std::lower_bound(Vector_.begin(), Vector_.end(), v, C()); if (it != Vector_.end() && !C()(v, *it)) { return {const_iterator(std::move(it)), false}; // Don't reinsert if it already exists. } if (Vector_.size() < N) { auto newIt = Vector_.insert(it, v); return {const_iterator(std::move(newIt)), true}; } Set_.insert(Vector_.begin(), Vector_.end()); Vector_.clear(); auto [newIt, inserted] = Set_.insert(v); YT_ASSERT(inserted); return {const_iterator(std::move(newIt)), true}; } template template void TCompactSet::insert(TIter i, TIter e) { for (; i != e; ++i) { insert(*i); } } template bool TCompactSet::erase(const T& v) { if (!is_small()) { return Set_.erase(v); } auto [rangeBegin, rangeEnd] = std::equal_range(Vector_.begin(), Vector_.end(), v, C()); if (rangeBegin != rangeEnd) { Vector_.erase(rangeBegin, rangeEnd); return true; } else { return false; } } template void TCompactSet::clear() { Vector_.clear(); Set_.clear(); } template typename TCompactSet::const_iterator TCompactSet::begin() const { return is_small() ? const_iterator(Vector_.begin()) : const_iterator(Set_.begin()); } template typename TCompactSet::const_iterator TCompactSet::cbegin() const { return begin(); } template typename TCompactSet::const_iterator TCompactSet::end() const { return is_small() ? const_iterator(Vector_.end()) : const_iterator(Set_.end()); } template typename TCompactSet::const_iterator TCompactSet::cend() const { return end(); } template bool TCompactSet::is_small() const { return Set_.empty(); } //////////////////////////////////////////////////////////////////////////////// } // namespace NYT