1 //  Copyright (c) 2016 Agustin Berge
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef HPX_UTIL_RANGE_HPP
7 #define HPX_UTIL_RANGE_HPP
8 
9 #include <hpx/config.hpp>
10 
11 #include <cstddef>
12 #include <iterator>
13 #include <utility>
14 
15 namespace hpx { namespace util
16 {
17     namespace detail
18     {
19         ///////////////////////////////////////////////////////////////////////
20         template <typename T, std::size_t N>
21         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
begin_impl(T (& array)[N],long)22         T* begin_impl(T (&array)[N], long) noexcept
23         {
24             return &array[0];
25         }
26 
27         template <typename T, std::size_t N>
28         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
end_impl(T (& array)[N],long)29         T* end_impl(T (&array)[N], long) noexcept
30         {
31             return &array[N];
32         }
33 
34         template <typename T, std::size_t N>
35         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
size_impl(T const (& array)[N],long)36         std::size_t size_impl(T const (&array)[N], long) noexcept
37         {
38             return N;
39         }
40 
41         template <typename T, std::size_t N>
42         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
empty_impl(T const (& array)[N],long)43         bool empty_impl(T const (&array)[N], long) noexcept
44         {
45             return false;
46         }
47 
48         ///////////////////////////////////////////////////////////////////////
49         template <typename C, typename R = decltype(std::declval<C&>().begin())>
50         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
begin_impl(C & c,long)51         R begin_impl(C& c, long)
52             noexcept(noexcept(c.begin()))
53         {
54             return c.begin();
55         }
56 
57         template <typename C, typename R = decltype(std::declval<C&>().end())>
58         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
end_impl(C & c,long)59         R end_impl(C& c, long)
60             noexcept(noexcept(c.begin()))
61         {
62             return c.end();
63         }
64 
65         template <typename C, typename R = decltype(std::declval<C const&>().size())>
66         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
size_impl(C const & c,long)67         R size_impl(C const& c, long)
68             noexcept(noexcept(c.size()))
69         {
70             return c.size();
71         }
72 
73         template <typename C, typename R = decltype(std::declval<C const&>().empty())>
74         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
empty_impl(C const & c,long)75         R empty_impl(C const& c, long)
76             noexcept(noexcept(c.empty()))
77         {
78             return c.empty();
79         }
80 
81         ///////////////////////////////////////////////////////////////////////
82         namespace range_impl
83         {
84             struct fallback
85             {
86                 template <typename T>
fallbackhpx::util::detail::range_impl::fallback87                 fallback(T const&){}
88             };
89 
90             fallback begin(fallback);
91 
92             template <typename C, typename R = decltype(begin(std::declval<C&>()))>
93             HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
begin_impl(C & c,int)94             R begin_impl(C& c, int)
95                 noexcept(noexcept(begin(c)))
96             {
97                 return begin(c);
98             }
99 
100             fallback end(fallback);
101 
102             template <typename C, typename R = decltype(end(std::declval<C&>()))>
103             HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
end_impl(C & c,int)104             R end_impl(C& c, int)
105                 noexcept(noexcept(end(c)))
106             {
107                 return end(c);
108             }
109         }
110         using range_impl::begin_impl;
111         using range_impl::end_impl;
112 
113         template <typename C>
114         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
size_impl(C const & c,int)115         std::size_t size_impl(C const& c, int)
116         {
117             return std::distance(begin_impl(c, 0L), end_impl(c, 0L));
118         }
119 
120         template <typename C>
121         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
empty_impl(C const & c,int)122         bool empty_impl(C const& c, int)
123         {
124             return begin_impl(c, 0L) == end_impl(c, 0L);
125         }
126 
127         ///////////////////////////////////////////////////////////////////////
128         template <typename T>
129         struct result_of_begin
130         {
131             typedef decltype(detail::begin_impl(std::declval<T&>(), 0L)) type;
132         };
133 
134         template <typename T, typename Iter = typename result_of_begin<T>::type>
135         struct iterator
136         {
137             typedef Iter type;
138         };
139 
140         template <typename T>
141         struct iterator<T, range_impl::fallback>
142         {};
143 
144         ///////////////////////////////////////////////////////////////////////
145         template <typename T>
146         struct result_of_end
147         {
148             typedef decltype(detail::end_impl(std::declval<T&>(), 0L)) type;
149         };
150 
151         template <typename T, typename Iter = typename result_of_end<T>::type>
152         struct sentinel
153         {
154             typedef Iter type;
155         };
156 
157         template <typename T>
158         struct sentinel<T, range_impl::fallback>
159         {};
160     }
161 
162     ///////////////////////////////////////////////////////////////////////////
163     namespace range_adl
164     {
165         template <
166             typename C,
167             typename Iterator = typename detail::iterator<C>::type>
168         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
begin(C & c)169         Iterator begin(C& c)
170             noexcept(noexcept(detail::begin_impl(c, 0L)))
171         {
172             return detail::begin_impl(c, 0L);
173         }
174 
175         template <
176             typename C,
177             typename Iterator = typename detail::iterator<C const>::type>
178         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
begin(C const & c)179         Iterator begin(C const& c)
180             noexcept(noexcept(detail::begin_impl(c, 0L)))
181         {
182             return detail::begin_impl(c, 0L);
183         }
184 
185         template <
186             typename C,
187             typename Sentinel = typename detail::sentinel<C>::type>
188         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
end(C & c)189         Sentinel end(C& c)
190             noexcept(noexcept(detail::end_impl(c, 0L)))
191         {
192             return detail::end_impl(c, 0L);
193         }
194 
195         template <
196             typename C,
197             typename Sentinel = typename detail::sentinel<C const>::type>
198         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
end(C const & c)199         Sentinel end(C const& c)
200             noexcept(noexcept(detail::end_impl(c, 0L)))
201         {
202             return detail::end_impl(c, 0L);
203         }
204 
205         template <
206             typename C,
207             typename Iterator = typename detail::iterator<C const>::type,
208             typename Sentinel = typename detail::sentinel<C const>::type>
209         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
size(C const & c)210         std::size_t size(C const& c)
211             noexcept(noexcept(detail::size_impl(c, 0L)))
212         {
213             return detail::size_impl(c, 0L);
214         }
215 
216         template <
217             typename C,
218             typename Iterator = typename detail::iterator<C const>::type,
219             typename Sentinel = typename detail::sentinel<C const>::type>
220         HPX_HOST_DEVICE HPX_CONSTEXPR HPX_FORCEINLINE
empty(C const & c)221         bool empty(C const& c)
222             noexcept(noexcept(detail::empty_impl(c, 0L)))
223         {
224             return detail::empty_impl(c, 0L);
225         }
226     }
227     using namespace range_adl;
228 }}
229 
230 #endif /*HPX_UTIL_RANGE_HPP*/
231