Skip to content

Commit 1a79364

Browse files
committed
xvector_like_variant iterator
1 parent d9d34e4 commit 1a79364

2 files changed

Lines changed: 283 additions & 3 deletions

File tree

include/xframe/xvector_like_variant.hpp

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,21 @@ namespace xf
102102
using const_pointer = typename value_traits::const_pointer;
103103
using size_type = typename size_traits::size_type;
104104
using difference_type = typename size_traits::difference_type;
105+
106+
using const_iterator = xtl::variant<typename V::const_iterator...>;
107+
using iterator = std::conditional_t<is_const,
108+
const_iterator,
109+
xtl::variant<typename V::iterator...>>;
110+
};
111+
112+
template <bool is_const, class traits>
113+
struct xvlv_iterator_traits
114+
{
115+
using value_type = typename traits::value_type;
116+
using reference = std::conditional_t<is_const, typename traits::const_reference, typename traits::reference>;
117+
using pointer = std::conditional_t<is_const, typename traits::const_pointer, typename traits::pointer>;
118+
using difference_type = typename traits::difference_type;
119+
using iterator = std::conditional_t<is_const, typename traits::const_iterator, typename traits::iterator>;
105120
};
106121

107122
template <class T1, class T2>
@@ -112,6 +127,9 @@ namespace xf
112127
* xvector_like_variant_base *
113128
*****************************/
114129

130+
template <class traits>
131+
class xvector_like_variant_iterator;
132+
115133
template <class traits>
116134
class xvector_like_variant_base
117135
{
@@ -127,6 +145,11 @@ namespace xf
127145
using difference_type = typename traits::difference_type;
128146
using storage_type = typename traits::storage_type;
129147

148+
using iterator_traits = detail::xvlv_iterator_traits<false, traits>;
149+
using const_iterator_traits = detail::xvlv_iterator_traits<true, traits>;
150+
151+
using iterator = xvector_like_variant_iterator<iterator_traits>;
152+
using const_iterator = xvector_like_variant_iterator<const_iterator_traits>;
130153
// Size and capacity
131154

132155
bool empty() const;
@@ -160,6 +183,16 @@ namespace xf
160183
storage_type& storage();
161184
const storage_type& storage() const;
162185

186+
// Iterators
187+
188+
iterator begin();
189+
iterator end();
190+
191+
const_iterator begin() const;
192+
const_iterator end() const;
193+
194+
const_iterator cbegin() const;
195+
const_iterator cend() const;
163196
// Comparison
164197

165198
bool equal(const self_type& rhs) const;
@@ -206,6 +239,55 @@ namespace xf
206239
template <class T>
207240
bool operator>=(const xvector_like_variant_base<T>& lhs, const xvector_like_variant_base<T>& rhs);
208241

242+
/*********************************
243+
* xvector_like_variant_iterator *
244+
*********************************/
245+
246+
template <class traits>
247+
class xvector_like_variant_iterator : public xtl::xrandom_access_iterator_base<xvector_like_variant_iterator<traits>,
248+
typename traits::value_type,
249+
typename traits::difference_type,
250+
typename traits::pointer,
251+
typename traits::reference>
252+
{
253+
public:
254+
255+
using self_type = xvector_like_variant_iterator<traits>;
256+
using value_type = typename traits::value_type;
257+
using reference = typename traits::reference;
258+
using pointer = typename traits::pointer;
259+
using difference_type = typename traits::difference_type;
260+
using iterator_category = std::random_access_iterator_tag;
261+
using subiterator = typename traits::iterator;
262+
263+
xvector_like_variant_iterator() = default;
264+
xvector_like_variant_iterator(subiterator it);
265+
266+
self_type& operator++();
267+
self_type& operator--();
268+
269+
self_type& operator+=(difference_type n);
270+
self_type& operator-=(difference_type n);
271+
272+
difference_type operator-(const self_type& rhs) const;
273+
274+
reference operator*() const;
275+
//pointer operator->() const;
276+
277+
bool equal(const self_type& rhs) const;
278+
bool less_than(const self_type& rhs) const;
279+
280+
private:
281+
282+
subiterator m_it;
283+
};
284+
285+
template <class T>
286+
bool operator==(const xvector_like_variant_iterator<T>& lhs, const xvector_like_variant_iterator<T>& rhs);
287+
288+
template <class T>
289+
bool operator<(const xvector_like_variant_iterator<T>& lhs, const xvector_like_variant_iterator<T>& rhs);
290+
209291
/************************
210292
* xvector_like_variant *
211293
************************/
@@ -477,6 +559,42 @@ namespace xf
477559
return m_storage;
478560
}
479561

562+
template <class T>
563+
inline auto xvector_like_variant_base<T>::begin() -> iterator
564+
{
565+
return xtl::visit([](auto& arg) { return iterator(detail::unwrap(arg).begin()); }, m_storage);
566+
}
567+
568+
template <class T>
569+
inline auto xvector_like_variant_base<T>::end() -> iterator
570+
{
571+
return xtl::visit([](auto& arg) { return iterator(detail::unwrap(arg).end()); }, m_storage);
572+
}
573+
574+
template <class T>
575+
inline auto xvector_like_variant_base<T>::begin() const -> const_iterator
576+
{
577+
return cbegin();
578+
}
579+
580+
template <class T>
581+
inline auto xvector_like_variant_base<T>::end() const -> const_iterator
582+
{
583+
return cend();
584+
}
585+
586+
template <class T>
587+
inline auto xvector_like_variant_base<T>::cbegin() const -> const_iterator
588+
{
589+
return xtl::visit([](const auto& arg) { return const_iterator(detail::unwrap(arg).cbegin()); }, m_storage);
590+
}
591+
592+
template <class T>
593+
inline auto xvector_like_variant_base<T>::cend() const -> const_iterator
594+
{
595+
return xtl::visit([](const auto& arg) { return const_iterator(detail::unwrap(arg).cend()); }, m_storage);
596+
}
597+
480598
template <class T>
481599
inline bool xvector_like_variant_base<T>::equal(const self_type& rhs) const
482600
{
@@ -525,6 +643,80 @@ namespace xf
525643
return !(lhs < rhs);
526644
}
527645

646+
/*********************************
647+
* xvector_like_variant_iterator *
648+
*********************************/
649+
650+
template <class T>
651+
inline xvector_like_variant_iterator<T>::xvector_like_variant_iterator(subiterator it)
652+
: m_it(it)
653+
{
654+
}
655+
656+
template <class T>
657+
inline auto xvector_like_variant_iterator<T>::operator++() -> self_type&
658+
{
659+
xtl::visit([](auto& arg) { ++arg; }, m_it);
660+
return *this;
661+
}
662+
663+
template <class T>
664+
inline auto xvector_like_variant_iterator<T>::operator--() -> self_type&
665+
{
666+
xtl::visit([](auto& arg) { --arg; }, m_it);
667+
return *this;
668+
}
669+
670+
template <class T>
671+
inline auto xvector_like_variant_iterator<T>::operator+=(difference_type n) -> self_type&
672+
{
673+
xtl::visit([n](auto& arg) { arg += n; }, m_it);
674+
return *this;
675+
}
676+
677+
template <class T>
678+
inline auto xvector_like_variant_iterator<T>::operator-=(difference_type n) -> self_type&
679+
{
680+
xtl::visit([n](auto& arg) { arg -= n; }, m_it);
681+
return *this;
682+
}
683+
684+
template <class T>
685+
inline auto xvector_like_variant_iterator<T>::operator-(const self_type& rhs) const -> difference_type
686+
{
687+
return xtl::visit([&rhs](auto& arg) { return arg - xtl::xget<std::decay_t<decltype(arg)>>(rhs.m_it); }, m_it);
688+
}
689+
690+
template <class T>
691+
inline auto xvector_like_variant_iterator<T>::operator*() const -> reference
692+
{
693+
return xtl::visit([](auto& arg) { return reference(xtl::closure(*arg)); }, m_it);
694+
}
695+
696+
template <class T>
697+
inline bool xvector_like_variant_iterator<T>::equal(const self_type& rhs) const
698+
{
699+
return m_it == rhs.m_it;
700+
}
701+
702+
template <class T>
703+
inline bool xvector_like_variant_iterator<T>::less_than(const self_type& rhs) const
704+
{
705+
return m_it < rhs.m_it;
706+
}
707+
708+
template <class T>
709+
inline bool operator==(const xvector_like_variant_iterator<T>& lhs, const xvector_like_variant_iterator<T>& rhs)
710+
{
711+
return lhs.equal(rhs);
712+
}
713+
714+
template <class T>
715+
inline bool operator<(const xvector_like_variant_iterator<T>& lhs, const xvector_like_variant_iterator<T>& rhs)
716+
{
717+
return lhs.less_than(rhs);
718+
}
719+
528720
/***************************************
529721
* xvector_like_variant implementation *
530722
***************************************/

test/test_xvector_like_variant.cpp

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,17 @@ namespace xf
6767

6868
std::vector<double> build_vector()
6969
{
70-
return {1., 3., 4.};
70+
return {1., 3., 4., 6., 7.};
7171
}
7272

7373
xt::svector<int> build_svector()
7474
{
75-
return {1, 3, 4};
75+
return {1, 3, 4, 6, 7};
7676
}
7777

7878
xt::uvector<double> build_uvector()
7979
{
80-
return {1., 3., 4.};
80+
return {1., 3., 4., 6., 7.};
8181
}
8282

8383
/*****************************
@@ -609,5 +609,93 @@ namespace xf
609609
int d = xtl::xget<const xt::svector<int>&>(vt.storage())[0];
610610
EXPECT_EQ(v[0], d);
611611
}
612+
613+
/************
614+
* Iterator *
615+
************/
616+
617+
TEST(xvector_like_variant_ref, iterator)
618+
{
619+
// 1, 3, 4, 6, 7
620+
auto v = build_svector();
621+
variant_ref_type vt(v);
622+
623+
auto iter = vt.begin();
624+
xtl::xget<int&>(*iter) = 2;
625+
EXPECT_EQ(v[0], 2);
626+
++iter;
627+
xtl::xget<int&>(*iter) = 4;
628+
EXPECT_EQ(v[1], 4);
629+
iter += 2;
630+
xtl::xget<int&>(*iter) = 21;
631+
EXPECT_EQ(v[3], 21);
632+
iter++;
633+
iter -= 2;
634+
xtl::xget<int&>(*iter) = 35;
635+
EXPECT_EQ(v[2], 35);
636+
--iter;
637+
iter--;
638+
iter += 5;
639+
EXPECT_EQ(iter, vt.end());
640+
641+
EXPECT_EQ(vt.end() - vt.begin(), 5);
642+
EXPECT_TRUE(vt.begin() < vt.end());
643+
}
644+
645+
TEST(xvector_like_variant_ref, const_iterator)
646+
{
647+
// 1, 3, 4, 6, 7
648+
auto v = build_svector();
649+
variant_ref_type vt(v);
650+
651+
auto iter = vt.cbegin();
652+
auto d0 = xtl::xget<const int&>(*iter);
653+
EXPECT_EQ(d0, 1);
654+
++iter;
655+
auto d1 = xtl::xget<const int&>(*iter);
656+
EXPECT_EQ(d1, 3);
657+
iter += 2;
658+
auto d2 = xtl::xget<const int&>(*iter);
659+
EXPECT_EQ(d2, 6);
660+
iter++;
661+
iter -= 2;
662+
auto d3 = xtl::xget<const int&>(*iter);
663+
EXPECT_EQ(d3, 4);
664+
--iter;
665+
iter--;
666+
iter += 5;
667+
EXPECT_EQ(iter, vt.cend());
668+
669+
EXPECT_EQ(vt.cend() - vt.cbegin(), 5);
670+
EXPECT_TRUE(vt.cbegin() < vt.cend());
671+
}
672+
673+
TEST(xvector_like_variant_cref, const_iterator)
674+
{
675+
// 1, 3, 4, 6, 7
676+
auto v = build_svector();
677+
variant_cref_type vt(v);
678+
679+
auto iter = vt.cbegin();
680+
auto d0 = xtl::xget<const int&>(*iter);
681+
EXPECT_EQ(d0, 1);
682+
++iter;
683+
auto d1 = xtl::xget<const int&>(*iter);
684+
EXPECT_EQ(d1, 3);
685+
iter += 2;
686+
auto d2 = xtl::xget<const int&>(*iter);
687+
EXPECT_EQ(d2, 6);
688+
iter++;
689+
iter -= 2;
690+
auto d3 = xtl::xget<const int&>(*iter);
691+
EXPECT_EQ(d3, 4);
692+
--iter;
693+
iter--;
694+
iter += 5;
695+
EXPECT_EQ(iter, vt.cend());
696+
697+
EXPECT_EQ(vt.cend() - vt.cbegin(), 5);
698+
EXPECT_TRUE(vt.cbegin() < vt.cend());
699+
}
612700
}
613701

0 commit comments

Comments
 (0)