aboutsummaryrefslogblamecommitdiffstats
path: root/util/generic/adaptor.h
blob: b88a65fc81e3b17fa1b04e9844261c04eea63cb8 (plain) (tree)
1
2
3
4
5
6
7
8
9
            
                         

                       
                          
                                


                                               
 

























                                                                                                  
                          
                           
                            
                                   
         
                          
                                 

                      
                                   

                    
                                 

         

                                                                               
 
           
                          

                            
                           
                                                           
         
                          
                             
                                                             
         
                      
                           
                                                           
         
                    
                             
                                                             
         
 
                          
                                                          
                                               
 
           
                          
                           
 
                                                      

                             
                                 


                           
                               


                             
                                 


                           
                               
         
 














                                                                                            
 
#pragma once

#include "store_policy.h"
#include "typetraits.h"

namespace NPrivate {
    template <class Range>
    class TReverseRangeStorage {
    public:
        TReverseRangeStorage(Range&& range)
            : Base_(std::forward<Range>(range))
        {
        }

        decltype(auto) Base() const {
            return *Base_.Ptr();
        }

        decltype(auto) Base() {
            return *Base_.Ptr();
        }

    private:
        TAutoEmbedOrPtrPolicy<Range> Base_;
    };

    template <class Range>
    constexpr bool HasReverseIterators(i32, decltype(std::declval<Range>().rbegin())*) {
        return true;
    }

    template <class Range>
    constexpr bool HasReverseIterators(char, std::nullptr_t*) {
        return false;
    }

    template <class Range, bool hasReverseIterators = HasReverseIterators<Range>((i32)0, nullptr)>
    class TReverseRangeBase: public TReverseRangeStorage<Range> {
        using TBase = TReverseRangeStorage<Range>;

    public:
        using TBase::Base;
        using TBase::TBase;

        auto begin() const {
            return Base().rbegin();
        }

        auto end() const {
            return Base().rend();
        }

        auto begin() {
            return Base().rbegin();
        }

        auto end() {
            return Base().rend();
        }
    };

    template <class Range>
    class TReverseRangeBase<Range, false>: public TReverseRangeStorage<Range> {
        using TBase = TReverseRangeStorage<Range>;

    public:
        using TBase::Base;
        using TBase::TBase;

        auto begin() const {
            using std::end;
            return std::make_reverse_iterator(end(Base()));
        }

        auto end() const {
            using std::begin;
            return std::make_reverse_iterator(begin(Base()));
        }

        auto begin() {
            using std::end;
            return std::make_reverse_iterator(end(Base()));
        }

        auto end() {
            using std::begin;
            return std::make_reverse_iterator(begin(Base()));
        }
    };

    template <class Range>
    class TReverseRange: public TReverseRangeBase<Range> {
        using TBase = TReverseRangeBase<Range>;

    public:
        using TBase::Base;
        using TBase::TBase;

        TReverseRange(TReverseRange&&) = default;
        TReverseRange(const TReverseRange&) = default;

        auto rbegin() const {
            using std::begin;
            return begin(Base());
        }

        auto rend() const {
            using std::end;
            return end(Base());
        }

        auto rbegin() {
            using std::begin;
            return begin(Base());
        }

        auto rend() {
            using std::end;
            return end(Base());
        }
    };
}

/**
 * Provides a reverse view into the provided container.
 *
 * Example usage:
 * @code
 * for(auto&& value: Reversed(container)) {
 *     // use value here.
 * }
 * @endcode
 *
 * @param cont                          Container to provide a view into. Must be an lvalue.
 * @returns                             A reverse view into the provided container.
 */
template <class Range>
constexpr ::NPrivate::TReverseRange<Range> Reversed(Range&& range) {
    return ::NPrivate::TReverseRange<Range>(std::forward<Range>(range));
}