1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
     100
     101
     102
     103
     104
     105
     106
     107
     108
     109
     110
     111
     112
     113
     114
     115
     116
     117
     118
     119
     120
     121
     122
     123
     124
     125
     126
     127
     128
     129
     130
     131
     132
     133
     134
     135
     136
     137
     138
     139
     140
     141
     142
     143
     144
     145
     146
     147
     148
     149
     150
     151
     152
     153
     154
     155
     156
     157
     158
     159
     160
     161
     162
     163
     164
     165
     166
     167
     168
     169
#ifndef CONCATENATE_HPP
#define CONCATENATE_HPP 1

#include <cassert>
#include <utility>
#include <type_traits>

template <typename C1, typename C2>
class ConcatenatedContainerView
{
    public:
        template <typename IT1, typename IT2>
        class iterator;

        using const_iterator = iterator<typename C1::const_iterator,
                                        typename C2::const_iterator>;
        using value_type = typename C1::value_type;

        ConcatenatedContainerView(const C1& c1, const C2& c2)
            : it(c1.begin(), c1.end(), c2.begin(), c2.end())
        {
        }

        const_iterator
        begin() const
        {
            return it;
        }

        const_iterator
        end() const
        {
            return const_iterator();
        }

        template <typename IT1, typename IT2>
        class iterator
        {
            public:
                using value_type = typename IT1::value_type;
                using reference  = typename IT1::reference;

                iterator()
                    : end(true)
                {
                }

                iterator(IT1 it1_begin, IT1 it1_end,
                         IT2 it2_begin, IT2 it2_end)
                    : it1_begin(it1_begin), it1_end(it1_end),
                      it2_begin(it2_begin), it2_end(it2_end),
                      end(false)
                {
                }

                friend void
                swap(iterator &a, iterator &b)
                {
                    std::swap(a.end, b.end);
                    std::swap(a.it1_begin, b.it1_begin);
                    std::swap(a.it1_end,   b.it1_end);
                    std::swap(a.it2_begin, b.it2_begin);
                    std::swap(a.it2_end,   b.it2_end);
                }

                iterator(const iterator &rhs)
                    : it1_begin(rhs.it1_begin), it1_end(rhs.it1_end),
                      it2_begin(rhs.it2_begin), it2_end(rhs.it2_end),
                      end(rhs.end)
                {
                }

                iterator(iterator &&rhs) : iterator()
                {
                    swap(*this, rhs);
                }

                iterator &
                operator=(iterator &&rhs)
                {
                    swap(*this, rhs);
                    return *this;
                }

                reference
                operator*() const
                {
                    assert(!end);
                    if (it1_begin!=it1_end) {
                        return *it1_begin;
                    }
                    return *it2_begin;
                }

                iterator &
                operator++()
                {
                    assert(!end);
                    if (it1_begin!=it1_end) {
                        ++it1_begin;
                    } else {
                        ++it2_begin;
                    }
                    if (it1_begin==it1_end && it2_begin==it2_end) {
                        endtrue;
                    }
                    return *this;
                }

                bool
                operator==(const iterator &rhs) const
                {
                    if (end && rhs.end) {
                        return true;
                    }
                    if (end != rhs.end) {
                        return false;
                    }
                    if (it1_begin!=it1_end && rhs.it1_end!=rhs.it1_begin) {
                        return it1_begin == rhs.it1_begin;
                    }
                    if (it1_begin==it1_end && rhs.it1_end==rhs.it1_begin) {
                        if (it2_begin!=it2_end && rhs.it2_end!=rhs.it2_begin) {
                            return it2_begin == rhs.it2_begin;
                        }
                    }
                    return false;
                }

                bool
                operator!=(const iterator &rhs) const
                {
                    return !(*this==rhs);
                }

            private:
                IT1     it1_begin, it1_end;
                IT2     it2_begin, it2_end;
                bool    end;
        };


    private:
        const const_iterator it;
};

template <typename C1, typename C2>
ConcatenatedContainerView<C1,C2>
concatenate(const C1 &c1, const C2 &c2)
{
    return ConcatenatedContainerView<C1,C2>(c1, c2);
}

template <typename C1, typename C2>
typename std::enable_if<
   std::is_same<
         decltype(*std::declval<const C1&>().begin()),
         decltype(*std::declval<const C2&>().begin())
        >::value,
   typename std::remove_reference<
          decltype(concatenate(std::declval<C1&>(), std::declval<C2&>()))
       >::type
   >::type
   operator&(const C1& c1, const C2& c2) {
       return concatenate(c1, c2);
   }


#endif // CONCATENATE_HPP