1 /***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
3 * Copyright (c) QuantStack                                                 *
4 *                                                                          *
5 * Distributed under the terms of the BSD 3-Clause License.                 *
6 *                                                                          *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9 
10 #ifndef XOPTIONAL_ASSEMBLY_STORAGE_HPP
11 #define XOPTIONAL_ASSEMBLY_STORAGE_HPP
12 
13 #include "xtl/xiterator_base.hpp"
14 
15 #include "xoptional.hpp"
16 #include "xsemantic.hpp"
17 
18 namespace xt
19 {
20     template <class VE, class FE, bool is_const>
21     class xoptional_assembly_storage_iterator;
22 
23     /******************************
24      * xoptional_assembly_storage *
25      ******************************/
26 
27     template <class VE, class FE>
28     class xoptional_assembly_storage
29     {
30     public:
31 
32         using self_type = xoptional_assembly_storage<VE, FE>;
33 
34         using value_storage = std::remove_reference_t<VE>;
35         using flag_storage = std::remove_reference_t<FE>;
36 
37         using value_type = xtl::xoptional<typename value_storage::value_type, typename flag_storage::value_type>;
38 
39         static constexpr bool is_val_const = std::is_const<value_storage>::value;
40         static constexpr bool is_flag_const = std::is_const<flag_storage>::value;
41         using val_reference = std::conditional_t<is_val_const,
42                                                  typename value_storage::const_reference,
43                                                  typename value_storage::reference>;
44         using flag_reference = std::conditional_t<is_flag_const,
45                                                   typename flag_storage::const_reference,
46                                                   typename flag_storage::reference>;
47         using reference = xtl::xoptional<val_reference, flag_reference>;
48         using const_reference = xtl::xoptional<typename value_storage::const_reference, typename flag_storage::const_reference>;
49 
50         using pointer = xtl::xclosure_pointer<reference>;
51         using const_pointer = xtl::xclosure_pointer<const_reference>;
52 
53         using size_type = typename value_storage::size_type;
54         using difference_type = typename value_storage::difference_type;
55 
56         using iterator = xoptional_assembly_storage_iterator<VE, FE, false>;
57         using const_iterator = xoptional_assembly_storage_iterator<VE, FE, true>;
58         using reverse_iterator = std::reverse_iterator<iterator>;
59         using const_reverse_iterator = std::reverse_iterator<const_iterator>;
60 
61         template <class VE1, class FE1>
62         xoptional_assembly_storage(const VE1& value_stor, const FE1& flag_stor);
63 
64         template <class VE1, class FE1>
65         xoptional_assembly_storage(VE1& value_stor, FE1& flag_stor);
66 
67         xoptional_assembly_storage(const xoptional_assembly_storage&);
68         xoptional_assembly_storage& operator=(const xoptional_assembly_storage&);
69         xoptional_assembly_storage(xoptional_assembly_storage&&);
70         xoptional_assembly_storage& operator=(xoptional_assembly_storage&&);
71 
72         bool empty() const noexcept;
73         size_type size() const noexcept;
74         void resize(size_type size);
75 
76         reference operator[](size_type i);
77         const_reference operator[](size_type i) const;
78 
79         reference front();
80         const_reference front() const;
81 
82         reference back();
83         const_reference back() const;
84 
85         pointer data() noexcept;
86         const_pointer data() const noexcept;
87 
88         iterator begin() noexcept;
89         iterator end() noexcept;
90 
91         const_iterator begin() const noexcept;
92         const_iterator end() const noexcept;
93 
94         const_iterator cbegin() const noexcept;
95         const_iterator cend() const noexcept;
96 
97         reverse_iterator rbegin() noexcept;
98         reverse_iterator rend() noexcept;
99 
100         const_reverse_iterator rbegin() const noexcept;
101         const_reverse_iterator rend() const noexcept;
102 
103         const_reverse_iterator crbegin() const noexcept;
104         const_reverse_iterator crend() const noexcept;
105 
106         void swap(self_type& rhs) noexcept;
107 
108         value_storage& value() noexcept;
109         const value_storage& value() const noexcept;
110 
111         flag_storage& has_value() noexcept;
112         const flag_storage& has_value() const noexcept;
113 
114     private:
115 
116         VE m_value;
117         FE m_has_value;
118     };
119 
120     template <class VE, class FE>
121     bool operator==(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs);
122 
123     template <class VE, class FE>
124     bool operator!=(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs);
125 
126     template <class VE, class FE>
127     bool operator<(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs);
128 
129     template <class VE, class FE>
130     bool operator<=(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs);
131 
132     template <class VE, class FE>
133     bool operator>(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs);
134 
135     template <class VE, class FE>
136     bool operator>=(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs);
137 
138     template <class VE, class FE>
139     void swap(xoptional_assembly_storage<VE, FE>& lhs, xoptional_assembly_storage<VE, FE>& rhs) noexcept;
140 
141     /***************************************
142      * xoptional_assembly_storage_iterator *
143      ***************************************/
144 
145     template <class VE, class FE, bool is_const>
146     class xoptional_assembly_storage_iterator;
147 
148     template <class VE, class FE, bool is_const>
149     struct xoptional_assembly_storage_iterator_traits
150     {
151         using iterator_type = xoptional_assembly_storage_iterator<VE, FE, is_const>;
152         using xoptional_assembly_storage_type = xoptional_assembly_storage<VE, FE>;
153         using value_type = typename xoptional_assembly_storage_type::value_type;
154         using reference = std::conditional_t<is_const,
155                                              typename xoptional_assembly_storage_type::const_reference,
156                                              typename xoptional_assembly_storage_type::reference>;
157         using difference_type = typename xoptional_assembly_storage_type::difference_type;
158         using pointer = std::conditional_t<is_const,
159                                            typename xoptional_assembly_storage_type::const_pointer,
160                                            typename xoptional_assembly_storage_type::pointer>;
161     };
162 
163     template <class VE, class FE, bool is_const>
164     class xoptional_assembly_storage_iterator
165         : public xtl::xrandom_access_iterator_base2<xoptional_assembly_storage_iterator_traits<VE, FE, is_const>>
166     {
167     public:
168 
169         using self_type = xoptional_assembly_storage_iterator<VE, FE, is_const>;
170         using base_type = xtl::xrandom_access_iterator_base2<xoptional_assembly_storage_iterator_traits<VE, FE, is_const>>;
171 
172         using xoptional_assembly_storage_type = xoptional_assembly_storage<VE, FE>;
173         using value_iterator = std::conditional_t<is_const,
174                                                   typename xoptional_assembly_storage_type::value_storage::const_iterator,
175                                                   typename xoptional_assembly_storage_type::value_storage::iterator>;
176         using flag_iterator = std::conditional_t<is_const,
177                                                  typename xoptional_assembly_storage_type::flag_storage::const_iterator,
178                                                  typename xoptional_assembly_storage_type::flag_storage::iterator>;
179 
180         using value_type = typename base_type::value_type;
181         using reference = typename base_type::reference;
182         using pointer = typename base_type::pointer;
183         using difference_type = typename base_type::difference_type;
184 
185         xoptional_assembly_storage_iterator(value_iterator value_it, flag_iterator flag_it);
186 
187         self_type& operator++();
188         self_type& operator--();
189 
190         self_type& operator+=(difference_type n);
191         self_type& operator-=(difference_type n);
192 
193         difference_type operator-(const self_type& rhs) const;
194 
195         reference operator*() const;
196         pointer operator->() const;
197 
198         bool operator==(const self_type& rhs) const;
199         bool operator<(const self_type& rhs) const;
200 
201     private:
202 
203         value_iterator m_value_it;
204         flag_iterator m_flag_it;
205     };
206 
207     /*********************************************
208      * xoptional_assembly_storage implementation *
209      *********************************************/
210 
211     template <class VE, class FE>
212     template <class VE1, class FE1>
xoptional_assembly_storage(const VE1 & value_stor,const FE1 & flag_stor)213     inline xoptional_assembly_storage<VE, FE>::xoptional_assembly_storage(const VE1& value_stor, const FE1& flag_stor)
214         : m_value(value_stor), m_has_value(flag_stor)
215     {
216     }
217 
218     template <class VE, class FE>
219     template <class VE1, class FE1>
xoptional_assembly_storage(VE1 & value_stor,FE1 & flag_stor)220     inline xoptional_assembly_storage<VE, FE>::xoptional_assembly_storage(VE1& value_stor, FE1& flag_stor)
221         : m_value(value_stor), m_has_value(flag_stor)
222     {
223     }
224 
225     template <class VE, class FE>
xoptional_assembly_storage(const self_type & rhs)226     inline xoptional_assembly_storage<VE, FE>::xoptional_assembly_storage(const self_type& rhs)
227         : m_value(rhs.m_value), m_has_value(rhs.m_has_value)
228     {
229     }
230 
231     template <class VE, class FE>
operator =(const self_type & rhs)232     inline auto xoptional_assembly_storage<VE, FE>::operator=(const self_type& rhs) -> self_type&
233     {
234         m_value = rhs.m_value;
235         m_has_value = rhs.m_has_value;
236         return *this;
237     }
238 
239     template <class VE, class FE>
xoptional_assembly_storage(self_type && rhs)240     inline xoptional_assembly_storage<VE, FE>::xoptional_assembly_storage(self_type&& rhs)
241         : m_value(std::forward<VE>(rhs.m_value)), m_has_value(std::forward<FE>(rhs.m_has_value))
242     {
243     }
244 
245     template <class VE, class FE>
operator =(self_type && rhs)246     inline auto xoptional_assembly_storage<VE, FE>::operator=(self_type&& rhs) -> self_type&
247     {
248         m_value = std::forward<VE>(rhs.m_value);
249         m_has_value = std::forward<FE>(rhs.m_has_value);
250         return *this;
251     }
252 
253     template <class VE, class FE>
empty() const254     inline bool xoptional_assembly_storage<VE, FE>::empty() const noexcept
255     {
256         return value().empty();
257     }
258 
259     template <class VE, class FE>
size() const260     inline auto xoptional_assembly_storage<VE, FE>::size() const noexcept -> size_type
261     {
262         return value().size();
263     }
264 
265     template <class VE, class FE>
resize(size_type size)266     inline void xoptional_assembly_storage<VE, FE>::resize(size_type size)
267     {
268         value().resize(size);
269         has_value().resize(size);
270     }
271 
272     template <class VE, class FE>
operator [](size_type i)273     inline auto xoptional_assembly_storage<VE, FE>::operator[](size_type i) -> reference
274     {
275         return reference(value()[i], has_value()[i]);
276     }
277 
278     template <class VE, class FE>
operator [](size_type i) const279     inline auto xoptional_assembly_storage<VE, FE>::operator[](size_type i) const -> const_reference
280     {
281         return const_reference(value()[i], has_value()[i]);
282     }
283 
284     template <class VE, class FE>
front()285     inline auto xoptional_assembly_storage<VE, FE>::front() -> reference
286     {
287         return reference(value()[0], has_value()[0]);
288     }
289 
290     template <class VE, class FE>
front() const291     inline auto xoptional_assembly_storage<VE, FE>::front() const -> const_reference
292     {
293         return const_reference(value()[0], has_value()[0]);
294     }
295 
296     template <class VE, class FE>
back()297     inline auto xoptional_assembly_storage<VE, FE>::back() -> reference
298     {
299         return reference(value()[size() - 1], has_value()[size() - 1]);
300     }
301 
302     template <class VE, class FE>
back() const303     inline auto xoptional_assembly_storage<VE, FE>::back() const -> const_reference
304     {
305         return const_reference(value()[size() - 1], has_value()[size() - 1]);
306     }
307 
308     template <class VE, class FE>
data()309     inline auto xoptional_assembly_storage<VE, FE>::data() noexcept -> pointer
310     {
311         pointer(front());
312     }
313 
314     template <class VE, class FE>
data() const315     inline auto xoptional_assembly_storage<VE, FE>::data() const noexcept -> const_pointer
316     {
317         const_pointer(front());
318     }
319 
320     template <class VE, class FE>
begin()321     inline auto xoptional_assembly_storage<VE, FE>::begin() noexcept -> iterator
322     {
323         return iterator(value().begin(), has_value().begin());
324     }
325 
326     template <class VE, class FE>
end()327     inline auto xoptional_assembly_storage<VE, FE>::end() noexcept -> iterator
328     {
329         return iterator(value().end(), has_value().end());
330     }
331 
332     template <class VE, class FE>
begin() const333     inline auto xoptional_assembly_storage<VE, FE>::begin() const noexcept -> const_iterator
334     {
335         return cbegin();
336     }
337 
338     template <class VE, class FE>
end() const339     inline auto xoptional_assembly_storage<VE, FE>::end() const noexcept -> const_iterator
340     {
341         return cend();
342     }
343 
344     template <class VE, class FE>
cbegin() const345     inline auto xoptional_assembly_storage<VE, FE>::cbegin() const noexcept -> const_iterator
346     {
347         return const_iterator(value().begin(), has_value().begin());
348     }
349 
350     template <class VE, class FE>
cend() const351     inline auto xoptional_assembly_storage<VE, FE>::cend() const noexcept -> const_iterator
352     {
353         return const_iterator(value().end(), has_value().end());
354     }
355 
356     template <class VE, class FE>
rbegin()357     inline auto xoptional_assembly_storage<VE, FE>::rbegin() noexcept -> reverse_iterator
358     {
359         return reverse_iterator(end());
360     }
361 
362     template <class VE, class FE>
rend()363     inline auto xoptional_assembly_storage<VE, FE>::rend() noexcept -> reverse_iterator
364     {
365         return reverse_iterator(begin());
366     }
367 
368     template <class VE, class FE>
rbegin() const369     inline auto xoptional_assembly_storage<VE, FE>::rbegin() const noexcept -> const_reverse_iterator
370     {
371         return crbegin();
372     }
373 
374     template <class VE, class FE>
rend() const375     inline auto xoptional_assembly_storage<VE, FE>::rend() const noexcept -> const_reverse_iterator
376     {
377         return crend();
378     }
379 
380     template <class VE, class FE>
crbegin() const381     inline auto xoptional_assembly_storage<VE, FE>::crbegin() const noexcept -> const_reverse_iterator
382     {
383         return const_reverse_iterator(cend());
384     }
385 
386     template <class VE, class FE>
crend() const387     inline auto xoptional_assembly_storage<VE, FE>::crend() const noexcept -> const_reverse_iterator
388     {
389         return const_reverse_iterator(cbegin());
390     }
391 
392     template <class VE, class FE>
swap(self_type & rhs)393     inline void xoptional_assembly_storage<VE, FE>::swap(self_type& rhs) noexcept
394     {
395         m_value.swap(rhs.m_value);
396         m_has_value.swap(rhs.m_has_value);
397     }
398 
399     template <class VE, class FE>
value()400     inline auto xoptional_assembly_storage<VE, FE>::value() noexcept -> value_storage&
401     {
402         return m_value;
403     }
404 
405     template <class VE, class FE>
value() const406     inline auto xoptional_assembly_storage<VE, FE>::value() const noexcept -> const value_storage&
407     {
408         return m_value;
409     }
410 
411     template <class VE, class FE>
has_value()412     inline auto xoptional_assembly_storage<VE, FE>::has_value() noexcept -> flag_storage&
413     {
414         return m_has_value;
415     }
416 
417     template <class VE, class FE>
has_value() const418     inline auto xoptional_assembly_storage<VE, FE>::has_value() const noexcept -> const flag_storage&
419     {
420         return m_has_value;
421     }
422 
423     template <class VE, class FE>
operator ==(const xoptional_assembly_storage<VE,FE> & lhs,const xoptional_assembly_storage<VE,FE> & rhs)424     bool operator==(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs)
425     {
426         return lhs.value() == rhs.value() && lhs.has_value() == rhs.has_value();
427     }
428 
429     template <class VE, class FE>
operator !=(const xoptional_assembly_storage<VE,FE> & lhs,const xoptional_assembly_storage<VE,FE> & rhs)430     bool operator!=(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs)
431     {
432         return !(lhs == rhs);
433     }
434 
435     template <class VE, class FE>
operator <(const xoptional_assembly_storage<VE,FE> & lhs,const xoptional_assembly_storage<VE,FE> & rhs)436     bool operator<(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs)
437     {
438         return lhs.value() < rhs.value() && lhs.has_value() == rhs.has_value();
439     }
440 
441     template <class VE, class FE>
operator <=(const xoptional_assembly_storage<VE,FE> & lhs,const xoptional_assembly_storage<VE,FE> & rhs)442     bool operator<=(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs)
443     {
444         return lhs.value() <= rhs.value() && lhs.has_value() == rhs.has_value();
445     }
446 
447     template <class VE, class FE>
operator >(const xoptional_assembly_storage<VE,FE> & lhs,const xoptional_assembly_storage<VE,FE> & rhs)448     bool operator>(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs)
449     {
450         return lhs.value() > rhs.value() && lhs.has_value() == rhs.has_value();
451     }
452 
453     template <class VE, class FE>
operator >=(const xoptional_assembly_storage<VE,FE> & lhs,const xoptional_assembly_storage<VE,FE> & rhs)454     bool operator>=(const xoptional_assembly_storage<VE, FE>& lhs, const xoptional_assembly_storage<VE, FE>& rhs)
455     {
456         return lhs.value() >= rhs.value() && lhs.has_value() == rhs.has_value();
457     }
458 
459     template <class VE, class FE>
swap(xoptional_assembly_storage<VE,FE> & lhs,xoptional_assembly_storage<VE,FE> & rhs)460     void swap(xoptional_assembly_storage<VE, FE>& lhs, xoptional_assembly_storage<VE, FE>& rhs) noexcept
461     {
462         lhs.swap(rhs);
463     }
464 
465     /******************************************************
466      * xoptional_assembly_storage_iterator implementation *
467      ******************************************************/
468 
469     template <class VE, class FE, bool C>
xoptional_assembly_storage_iterator(value_iterator value_it,flag_iterator flag_it)470     inline xoptional_assembly_storage_iterator<VE, FE, C>::xoptional_assembly_storage_iterator(value_iterator value_it, flag_iterator flag_it)
471         : m_value_it(value_it), m_flag_it(flag_it)
472     {
473     }
474 
475     template <class VE, class FE, bool C>
operator ++()476     inline auto xoptional_assembly_storage_iterator<VE, FE, C>::operator++() -> self_type&
477     {
478         ++m_value_it;
479         ++m_flag_it;
480         return *this;
481     }
482 
483     template <class VE, class FE, bool C>
operator --()484     inline auto xoptional_assembly_storage_iterator<VE, FE, C>::operator--() -> self_type&
485     {
486         --m_value_it;
487         --m_flag_it;
488         return *this;
489     }
490 
491     template <class VE, class FE, bool C>
operator +=(difference_type n)492     inline auto xoptional_assembly_storage_iterator<VE, FE, C>::operator+=(difference_type n) -> self_type&
493     {
494         m_value_it += n;
495         m_flag_it += n;
496         return *this;
497     }
498 
499     template <class VE, class FE, bool C>
operator -=(difference_type n)500     inline auto xoptional_assembly_storage_iterator<VE, FE, C>::operator-=(difference_type n) -> self_type&
501     {
502         m_value_it -= n;
503         m_flag_it -= n;
504         return *this;
505     }
506 
507     template <class VE, class FE, bool C>
operator -(const self_type & rhs) const508     inline auto xoptional_assembly_storage_iterator<VE, FE, C>::operator-(const self_type& rhs) const -> difference_type
509     {
510         return m_value_it - rhs.m_value_it;
511     }
512 
513     template <class VE, class FE, bool C>
operator *() const514     inline auto xoptional_assembly_storage_iterator<VE, FE, C>::operator*() const -> reference
515     {
516         return reference(*m_value_it, *m_flag_it);
517     }
518 
519     template <class VE, class FE, bool C>
operator ->() const520     inline auto xoptional_assembly_storage_iterator<VE, FE, C>::operator->() const -> pointer
521     {
522         return &(this->operator*());
523     }
524 
525     template <class VE, class FE, bool C>
operator ==(const self_type & rhs) const526     inline bool xoptional_assembly_storage_iterator<VE, FE, C>::operator==(const self_type& rhs) const
527     {
528         return m_value_it == rhs.m_value_it;
529     }
530 
531     template <class VE, class FE, bool C>
operator <(const self_type & rhs) const532     inline bool xoptional_assembly_storage_iterator<VE, FE, C>::operator<(const self_type& rhs) const
533     {
534         return m_value_it < rhs.m_value_it;
535     }
536 
537     template <class VE, class FE>
optional_assembly_storage(const VE & value,const FE & flag)538     inline xoptional_assembly_storage<VE, FE> optional_assembly_storage(const VE& value, const FE& flag)
539     {
540         return xoptional_assembly_storage<VE, FE>(value, flag);
541     }
542 
543     template <class VE, class FE>
optional_assembly_storage(VE & value,FE & flag)544     inline xoptional_assembly_storage<VE, FE> optional_assembly_storage(VE& value, FE& flag)
545     {
546         return xoptional_assembly_storage<VE, FE>(value, flag);
547     }
548 }
549 
550 #endif
551