// Copyright (c) 2026 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #ifndef NCollection_ForwardRange_HeaderFile #define NCollection_ForwardRange_HeaderFile #include #include #include //! @file NCollection_ForwardRange.hxx //! @brief STL range-for adapter for OCCT iterators following the More()/Next() pattern. //! //! Provides reusable iterator/sentinel types that enable range-based for loops //! on any OCCT iterator or explorer class with More(), Next(), and a value accessor. //! //! The value accessor is detected automatically via SFINAE with priority: //! Value() > Current() > CurrentId(). //! //! Two usage modes: //! 1. In-class integration: add begin()/end() methods using the provided types. //! @code //! NCollection_ForwardRangeIterator begin() //! { //! return NCollection_ForwardRangeIterator(this); //! } //! NCollection_ForwardRangeSentinel end() const { return {}; } //! @endcode //! 2. Standalone wrapper for unmodified classes: //! @code //! for (const TopoDS_Shape& aFace : //! NCollection_ForwardRange(TopExp_Explorer(aShape, TopAbs_FACE))) //! { //! // ... //! } //! @endcode namespace NCollection_ForwardRangeDetail { //! SFINAE: detect .Value() const template struct HasValue : std::false_type { }; template struct HasValue().Value())>> : std::true_type { }; //! SFINAE: detect .Current() const template struct HasCurrent : std::false_type { }; template struct HasCurrent().Current())>> : std::true_type { }; //! SFINAE: detect .CurrentId() const template struct HasCurrentId : std::false_type { }; template struct HasCurrentId().CurrentId())>> : std::true_type { }; //! Accessor dispatch trait: resolves to the correct value accessor and its return type. //! Uses std::enable_if_t for mutually-exclusive priority selection. template struct AccessorTraits; //! Priority 1: has Value() template struct AccessorTraits::value>> { using ReturnType = decltype(std::declval().Value()); static ReturnType Get(const T& theIter) { return theIter.Value(); } }; //! Priority 2: has Current() but not Value() template struct AccessorTraits::value && HasCurrent::value>> { using ReturnType = decltype(std::declval().Current()); static ReturnType Get(const T& theIter) { return theIter.Current(); } }; //! Priority 3: has CurrentId() but not Value() or Current() template struct AccessorTraits< T, std::enable_if_t::value && !HasCurrent::value && HasCurrentId::value>> { using ReturnType = decltype(std::declval().CurrentId()); static ReturnType Get(const T& theIter) { return theIter.CurrentId(); } }; //! Proxy for operator-> when the accessor returns a value (not a reference). template struct ArrowProxy { ValueT myValue; const ValueT* operator->() const { return &myValue; } }; } // namespace NCollection_ForwardRangeDetail //! Empty sentinel type used as the end marker for range-for loops. struct NCollection_ForwardRangeSentinel { }; //! @brief STL input iterator that wraps an OCCT More()/Next() iterator. //! //! Holds a non-owning pointer to the host iterator/explorer. //! The host must outlive this iterator (guaranteed by range-for semantics). //! //! @tparam HostType OCCT iterator/explorer with More(), Next(), and a value accessor. template class NCollection_ForwardRangeIterator { using Accessor = NCollection_ForwardRangeDetail::AccessorTraits; using RawReturn = typename Accessor::ReturnType; public: using value_type = std::remove_cv_t>; using difference_type = std::ptrdiff_t; using iterator_category = std::input_iterator_tag; using reference = RawReturn; using pointer = std::conditional_t, std::add_pointer_t>, NCollection_ForwardRangeDetail::ArrowProxy>; //! Construct from a pointer to the host iterator. explicit NCollection_ForwardRangeIterator(HostType* theHost) : myHost(theHost) { } //! Dereference: returns the current value from the host. RawReturn operator*() const { return Accessor::Get(*myHost); } //! Arrow operator: returns a pointer or proxy to the current value. pointer operator->() const { if constexpr (std::is_reference_v) { return &Accessor::Get(*myHost); } else { return NCollection_ForwardRangeDetail::ArrowProxy{Accessor::Get(*myHost)}; } } //! Prefix increment: advances the host iterator. NCollection_ForwardRangeIterator& operator++() { myHost->Next(); return *this; } //! Postfix increment: captures the current value, then advances. //! Returns a proxy holding the old value (safe for non-copyable hosts). struct PostfixProxy { value_type myValue; const value_type& operator*() const { return myValue; } }; PostfixProxy operator++(int) { PostfixProxy aProxy{Accessor::Get(*myHost)}; myHost->Next(); return aProxy; } //! Equality with sentinel: true when the host is exhausted. friend bool operator==(const NCollection_ForwardRangeIterator& theLhs, NCollection_ForwardRangeSentinel) { return !theLhs.myHost->More(); } friend bool operator!=(const NCollection_ForwardRangeIterator& theLhs, NCollection_ForwardRangeSentinel) { return theLhs.myHost->More(); } friend bool operator==(NCollection_ForwardRangeSentinel, const NCollection_ForwardRangeIterator& theRhs) { return !theRhs.myHost->More(); } friend bool operator!=(NCollection_ForwardRangeSentinel, const NCollection_ForwardRangeIterator& theRhs) { return theRhs.myHost->More(); } private: HostType* myHost; //!< Non-owning pointer to the host iterator. }; //! @brief Standalone range wrapper for OCCT iterators. //! //! Owns a copy/move of the host iterator and provides begin()/end() //! for range-based for loops. Use this when the host class does not //! have its own begin()/end() methods. //! //! @code //! for (const TopoDS_Shape& aFace : //! NCollection_ForwardRange(TopExp_Explorer(aShape, TopAbs_FACE))) //! { //! // process aFace //! } //! @endcode //! //! @tparam HostType OCCT iterator/explorer with More(), Next(), and a value accessor. template class NCollection_ForwardRange { public: using iterator = NCollection_ForwardRangeIterator; using const_iterator = iterator; using sentinel = NCollection_ForwardRangeSentinel; //! Construct from a copyable host (lvalue). template >> explicit NCollection_ForwardRange(const HostType& theHost) : myHost(theHost) { } //! Construct from an rvalue (moves the host). explicit NCollection_ForwardRange(HostType&& theHost) : myHost(std::move(theHost)) { } NCollection_ForwardRange(const NCollection_ForwardRange&) = delete; NCollection_ForwardRange& operator=(const NCollection_ForwardRange&) = delete; NCollection_ForwardRange(NCollection_ForwardRange&&) = default; NCollection_ForwardRange& operator=(NCollection_ForwardRange&&) = default; //! Returns iterator to the current position of the host. //! Const-qualified: iteration advances the internal cursor (mutable), //! not the logical state of the range. [[nodiscard]] iterator begin() const { return iterator(&myHost); } //! Returns sentinel marking the end. [[nodiscard]] sentinel end() const { return sentinel{}; } //! Returns const-access iterator (same as begin). [[nodiscard]] const_iterator cbegin() const { return const_iterator(&myHost); } //! Returns sentinel marking the end. [[nodiscard]] sentinel cend() const { return sentinel{}; } private: mutable HostType myHost; //!< Owned host iterator (mutable: iteration is cursor movement). }; //! CTAD deduction guide: deduces HostType from the constructor argument. template NCollection_ForwardRange(T&&) -> NCollection_ForwardRange>; #endif // NCollection_ForwardRange_HeaderFile