////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2025-2026. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/container for documentation. // ////////////////////////////////////////////////////////////////////////////// #ifndef BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_ITERATOR_TRAITS_HPP #define BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_ITERATOR_TRAITS_HPP #ifndef BOOST_CONFIG_HPP # include #endif #if defined(BOOST_HAS_PRAGMA_ONCE) # pragma once #endif #include #include #include #include namespace boost { namespace container { //! Tag type indicating a segmented iterator. struct segmented_iterator_tag { static const bool value = true; }; //! Tag type indicating a non-segmented (flat) iterator. struct non_segmented_iterator_tag { static const bool value = false; }; //! Sentinel whose comparison with any iterator always yields false (not equal). //! Passes through segmented_remove_if_result_bounded to express an unbounded //! destination, letting the compiler eliminate the dead destination-full branch. template struct segduo { T1 first; T2 second; BOOST_CONTAINER_FORCEINLINE segduo() {} template BOOST_CONTAINER_FORCEINLINE segduo(const U1 &f, const U2 &s) : first(f), second(s) {} template BOOST_CONTAINER_FORCEINLINE segduo(const segduo &sd) : first(sd.first), second(sd.second) {} }; template struct segtrio { T1 first; T2 second; T3 third; BOOST_CONTAINER_FORCEINLINE segtrio() {} template BOOST_CONTAINER_FORCEINLINE segtrio(const U1 &f, const U2 &s, const U3 &t) : first(f), second(s), third(t) {} template BOOST_CONTAINER_FORCEINLINE segtrio(const segtrio &sd) : first(sd.first), second(sd.second), third(sd.third) {} }; struct unreachable_sentinel_t { template BOOST_CONTAINER_FORCEINLINE friend bool operator==(const It&, unreachable_sentinel_t) { return false; } template BOOST_CONTAINER_FORCEINLINE friend bool operator==(unreachable_sentinel_t, const It&) { return false; } template BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const It&, unreachable_sentinel_t) { return true; } template BOOST_CONTAINER_FORCEINLINE friend bool operator!=(unreachable_sentinel_t, const It&) { return true; } }; //! Disambiguator tag passed by the dual-RA fast-path overload of certain //! bounded helpers (e.g. segmented_copy_if_dst_bounded, //! segmented_remove_copy_if_dst_bounded) when it has decided that the //! remaining source does not fit the destination capacity and a real //! bounded scan is required. The tag's only role is to perturb the //! signature of the recursive call so that the dual-RA overload itself //! cannot re-match: only the unrolled / generic terminal overloads remain //! viable, leaving the random-access category of both iterators intact. struct dual_ra_skip_t {}; namespace detail_algo { //! Default less-than function object used by segmented algorithms when the //! user does not provide an explicit comparator. Centralised here to avoid //! duplicating the same struct across every algorithm header. struct segmented_default_less { template BOOST_CONTAINER_FORCEINLINE bool operator()(const T& a, const T& b) const { return a < b; } }; //! Proxy-safe "equal to *it" predicate. Holds the iterator by value and //! re-dereferences on every invocation, so a prvalue proxy returned by //! operator*() only lives for the full expression of the comparison and //! never outlives it. This avoids the lifetime hazard of caching *it in //! a const-reference member (as equal_to_value would). template struct equal_to_deref { Iter it_; BOOST_CONTAINER_FORCEINLINE explicit equal_to_deref(Iter it) : it_(it) {} template BOOST_CONTAINER_FORCEINLINE bool operator()(const U &u) const { return u == *it_; } }; template struct void_if_true; template <> struct void_if_true { typedef void type; }; template struct make_void { typedef void type; }; template struct algo_enable_if_c {}; template struct algo_enable_if_c { typedef T type; }; template struct has_iterator_category { static const bool value = false; }; template struct has_iterator_category::type> { static const bool value = true; }; template struct constref_generator { const T& value; BOOST_CONTAINER_FORCEINLINE explicit constref_generator(const T& v) : value(v) {} BOOST_CONTAINER_FORCEINLINE const T& operator()() const { return value; } }; ////////////////////////////////////////////////////////////////////////////// // Transfer helper: copy (Move=false) or move (Move=true) a single element. ////////////////////////////////////////////////////////////////////////////// template struct transfer_op; template <> struct transfer_op { template BOOST_CONTAINER_FORCEINLINE static void apply(D& d, S& s) { d = s; } }; template <> struct transfer_op { template BOOST_CONTAINER_FORCEINLINE static void apply(D& d, S& s) { d = boost::move(s); } }; } // namespace detail_algo //! Traits class to detect and decompose segmented iterators. //! //! The default definition marks all iterators as non-segmented. //! Specializations for segmented iterator types must provide: //! //! typedef segmented_iterator_tag is_segmented_iterator; //! typedef segment_iterator; //! typedef local_iterator; //! //! static segment_iterator segment(Iterator it); //! static local_iterator local(Iterator it); //! static Iterator compose(segment_iterator s, local_iterator l); //! static local_iterator begin(segment_iterator s); //! static local_iterator end(segment_iterator s); //! //! An explicit specialization is not required when the iterator type //! provides the intrusive interface: //! //! typedef segmented_iterator_tag is_segmented_iterator; //! typedef segment_iterator; //! typedef local_iterator; //! segment_iterator segment() const; //! local_iterator local() const; //! Iterator(segment_iterator s, local_iterator l); // composing constructor //! //! and segment_iterator provides begin()/end() returning local_iterator. //! //! Based on: M. Austern, "Segmented Iterators and Hierarchical Algorithms" template struct segmented_iterator_traits { typedef non_segmented_iterator_tag is_segmented_iterator; }; //! Detects whether \c Sent is a true sentinel for \c Iter. //! A sentinel is a type that is not the same as the iterator and //! does not model an iterator (lacks \c iterator_category). //! When \c is_sentinel is false, algorithms use the \c (Iter, Iter) //! overload, avoiding extra template instantiations from mixed //! iterator types such as \c iterator / \c const_iterator. template struct is_sentinel { static const bool value = !detail_algo::has_iterator_category::value; }; template struct is_sentinel { static const bool value = false; }; namespace detail_algo { ////////////////////////////////////////////////////////////////////////////// // sent_filter: when [first, last) is closed by a true sentinel // (Sent != Iter), segment walkers cannot decompose Sent and bidirectional // algorithms cannot step backwards from it; in that case both the iterator // category and the segmentation tag are downgraded to // (std::forward_iterator_tag, non_segmented_iterator_tag) so that algorithms // route through the flat, forward-only path. When Sent == Iter, the // iterator's natural category and segmentation are preserved. // // Used by bidirectional/segmented algorithms (e.g. segmented_partition, // segmented_find_last_if) that need a single dispatch point covering both // the (Iter, Iter) and (Iter, Sentinel) call signatures. ////////////////////////////////////////////////////////////////////////////// template ::value> struct sent_filter { typedef std::forward_iterator_tag cat_t; typedef non_segmented_iterator_tag seg_t; }; template struct sent_filter { typedef typename boost::container::iterator_traits ::iterator_category cat_t; typedef typename segmented_iterator_traits ::is_segmented_iterator seg_t; }; template struct sent_filter : public sent_filter {}; // Compile-time metafunction that unwraps a (possibly recursively) segmented // iterator to its deepest non-segmented `local_iterator` type. // // deepest_local_iterator::type == It (non-segmented) // deepest_local_iterator::type == // deepest_local_iterator::local_iterator>::type // (segmented) // // Used by segmented algorithms that need to hold cross-segment state of // iterator type rather than element type (e.g. a "previous element" pointer // that survives the boundary between sub-ranges), by reducing that state to a // single unified type across all levels of recursion. template struct deepest_local_iterator_impl; template struct deepest_local_iterator_impl { typedef It type; BOOST_CONTAINER_FORCEINLINE static type get(It it) { return it; } }; template struct deepest_local_iterator_impl { private: typedef typename segmented_iterator_traits::local_iterator local_t; typedef deepest_local_iterator_impl < segmented_iterator_traits::is_segmented_iterator::value , local_t> next_layer_t; public: typedef typename next_layer_t::type type; BOOST_CONTAINER_FORCEINLINE static typename next_layer_t::type get(It it) { return next_layer_t::get(segmented_iterator_traits::local(it)); } }; template struct deepest_local_iterator { typedef deepest_local_iterator_impl < segmented_iterator_traits::is_segmented_iterator::value , It> next_layer_t; public: typedef typename next_layer_t::type type; BOOST_CONTAINER_FORCEINLINE static typename next_layer_t::type get(It it) { return next_layer_t::get(it); } }; } // namespace detail_algo } // namespace container } // namespace boost #include ////////////////////////////////////////////////////////////////////////////// // BOOST_CONTAINER_DISABLE_MULTI_SEGMENTED_ALGO // // When defined, segmented algorithms that write to an output iterator will // NOT exploit segmentation on the output side. Only input (source) iterator // segmentation is used. This is useful for benchmarking the advantage of // the segmented output optimisation in isolation. // // Define BOOST_CONTAINER_DISABLE_MULTI_SEGMENTED_ALGO before including any // segmented algorithm header to disable the optimisation. ////////////////////////////////////////////////////////////////////////////// //#define BOOST_CONTAINER_DISABLE_MULTI_SEGMENTED_ALGO // When defined, segmented algorithms that count elements (e.g. segmented_count, // segmented_count_if) will use a branchless counting strategy in their // innermost loops, incrementing the count by the boolean result of the // predicate rather than testing the predicate result in a branch and conditionally // incrementing. This can improve performance on some platforms by avoiding branch mispredictions, // at the cost of potentially increased instruction count and/or reduced vectorization opportunities. // // However, the optimal strategy is highly platform- and algorithm-specific, so this is disabled by default. // There are regressions on some algorithms and platforms when this is enabled, and the performance impact // varies widely across different scenarios. // //#define BOOST_CONTAINER_SEGMENTED_COUNT_BRANCHLESS //#define BOOST_CONTAINER_SEGMENTED_DISABLE_PRAGMA_UNROLL //#define BOOST_CONTAINER_SEGMENTED_ENABLE_PRAGMA_UNROLL #if defined(BOOST_CONTAINER_SEGMENTED_DISABLE_PRAGMA_UNROLL) && defined (BOOST_CONTAINER_SEGMENTED_ENABLE_PRAGMA_UNROLL) #error "Cannot define both BOOST_CONTAINER_SEGMENTED_DISABLE_PRAGMA_UNROLL and BOOST_CONTAINER_SEGMENTED_ENABLE_PRAGMA_UNROLL" #endif #if !defined(BOOST_CONTAINER_SEGMENTED_DISABLE_PRAGMA_UNROLL) && !defined (BOOST_CONTAINER_SEGMENTED_ENABLE_PRAGMA_UNROLL) #if defined(BOOST_CLANG) //Let clang decide when to unroll loops, as it can auto-vectorize more aggressively when unrolling is disabled. #define BOOST_CONTAINER_SEGMENTED_DISABLE_PRAGMA_UNROLL #else #define BOOST_CONTAINER_SEGMENTED_ENABLE_PRAGMA_UNROLL #endif #endif #if defined(BOOST_CONTAINER_SEGMENTED_ENABLE_PRAGMA_UNROLL) #define BOOST_CONTAINER_SEGMENTED_UNROLL(N) BOOST_CONTAINER_UNROLL(N) #define BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL BOOST_CONTAINER_AUTO_UNROLL #elif defined(BOOST_CONTAINER_SEGMENTED_DISABLE_PRAGMA_UNROLL) #define BOOST_CONTAINER_SEGMENTED_UNROLL(N) #define BOOST_CONTAINER_SEGMENTED_AUTO_UNROLL #else #error "Must define either BOOST_CONTAINER_SEGMENTED_ENABLE_PRAGMA_UNROLL or BOOST_CONTAINER_SEGMENTED_DISABLE_PRAGMA_UNROLL" #endif #endif // BOOST_CONTAINER_EXPERIMENTAL_SEGMENTED_ITERATOR_TRAITS_HPP