1 #ifndef SIMPLE_CPLUSPLUS_ALGORITHM
2 #define SIMPLE_CPLUSPLUS_ALGORITHM
62 using is_lvalue_ref_t =
typename std::is_lvalue_reference<C>::type;
69 using to_vector_t = std::vector<typename std::decay_t<C>::value_type>;
76 using container_reference_value_t =
typename std::decay_t<C>::value_type&;
82 #if __cplusplus >= 201703L
83 template <
typename F,
typename... Ts>
84 using callable_return_t =
typename std::invoke_result<std::decay_t<F>,Ts...>::type;
86 template <
typename F,
typename... Ts>
87 using callable_return_t =
typename std::result_of<std::decay_t<F>(Ts...)>::type;
95 typedef typename std::decay_t<T> BT;
96 template<
typename U,
typename U::
size_type (U::*)() const>
struct SFINAE {};
98 template<
typename U>
static int test(...);
99 static const bool has =
sizeof(test<BT>(0)) ==
sizeof(
char);
102 template <
typename T>
103 using has_size = std::integral_constant<bool, detail::has_size_struct<T>::has>;
106 template <
typename C>
107 size_t size(C& c, std::true_type) {
112 template <
typename C>
113 size_t size(C& c, std::false_type) {
114 return std::distance(c.begin(), c.end());
121 template <
typename DEST,
typename SRC>
122 void transfer(std::true_type, DEST& dst, SRC& src) {
126 template <
typename DEST,
typename SRC>
127 void transfer(std::false_type, DEST& dst, SRC& src) {
128 dst = std::move(src);
136 template <
typename DIT,
typename IT>
137 void range_transfer(std::true_type, DIT&& dst_cur, IT&& src_cur, IT&& src_end) {
138 for(; src_cur != src_end; ++src_cur, ++dst_cur) {
143 template <
typename DIT,
typename IT>
144 void range_transfer(std::false_type, DIT&& dst_cur, IT&& src_cur, IT&& src_end) {
145 for(; src_cur != src_end; ++src_cur, ++dst_cur) {
146 *dst_cur = std::move(*src_cur);
154 template <
typename OUT_IT,
typename INP_IT>
156 values(std::true_type, OUT_IT&& out_it, INP_IT&& cur_it, INP_IT&& end_it) {
157 while(cur_it != end_it) {
165 template <
typename OUT_IT,
typename INP_IT>
167 values(std::false_type, OUT_IT&& out_it, INP_IT&& cur_it, INP_IT&& end_it) {
168 while(cur_it != end_it) {
178 template <
typename V>
179 size_t sum(V cur_sum, V v) {
183 template <
typename V,
typename... Values>
184 size_t sum(V cur_sum, V v, V v2, Values... vs) {
185 return sum(cur_sum + v, v2, vs...);
191 template <
typename IT>
192 void group(IT&& cur) {
195 template <
typename IT,
typename C,
typename... Cs>
196 void group(IT&& cur, C&& c, Cs&&... cs) {
197 detail::range_transfer(detail::is_lvalue_ref_t<C>(), cur, c.begin(), c.end());
198 group(cur, std::forward<Cs>(cs)...);
207 template <
typename IT>
208 void advance_group(IT& it) {
212 template <
typename IT,
typename IT2,
typename... ITs>
213 void advance_group(IT& it, IT2& it2, ITs&... its) {
215 advance_group(it2, its...);
220 template <
typename F,
typename RIT,
typename IT,
typename... ITs>
221 void map(F&& f, RIT&& rit, IT&& it, IT&& it_end, ITs&&... its) {
222 while(it != it_end) {
223 *rit = f(*it, *its...);
224 advance_group(rit, it, its...);
230 template <
typename F,
235 fold(F& f, R&& init, IT&& it, IT&& it_end, ITs&&... its) {
236 std::decay_t<R> mutable_state(std::forward<R>(init));
238 while(it != it_end) {
239 mutable_state = f(std::move(mutable_state), *it, *its...);
240 advance_group(it, its...);
243 return mutable_state;
248 template <
typename F,
typename IT,
typename... ITs>
249 void each(F&& f, IT&& it, IT&& it_end, ITs&&... its) {
250 while(it != it_end) {
252 advance_group(it, its...);
258 template <
typename F,
typename IT,
typename... ITs>
260 all(F&& f, IT&& it, IT&& it_end, ITs&&... its) {
263 while(it != it_end) {
264 if(!f(*it, *its...)) {
269 advance_group(it, its...);
277 template <
typename F,
typename IT,
typename... ITs>
279 some(F&& f, IT&& it, IT&& it_end, ITs&&... its) {
282 while(it != it_end) {
283 if(f(*it, *its...)) {
288 advance_group(it, its...);
304 template <
typename C>
307 return detail::size(c, detail::has_size<C>());
332 template <
typename C>
335 typedef typename std::decay_t<C>::value_type CV;
337 std::transform(c.begin(), c.end(), ret.begin(), [](CV& e){ return &e; });
341 template <
typename C>
344 typedef typename std::decay_t<C>::value_type CV;
345 std::vector<const CV*> ret(
sca::size(c));
346 std::transform(c.begin(), c.end(), ret.begin(), [](
const CV& e){ return &e; });
366 template <
typename C>
369 typedef typename std::decay_t<C>::value_type CV;
370 typedef typename std::decay_t<std::remove_pointer_t<CV>> BCV;
372 detail::values(
typename std::is_pointer<CV>::type(), ret.begin(), c.begin(), c.end());
382 typedef std::decay_t<C> DC;
385 typedef typename DC::iterator iterator;
386 typedef typename DC::value_type value_type;
387 typedef typename DC::size_type size_type;
390 slice_of(
const C& c,
size_t idx,
size_t len) =
delete;
393 slice_of(C& c,
size_t idx,
size_t len) :
395 m_begin(std::next(c.begin(), idx)),
396 m_end(std::next(m_begin, len))
400 slice_of(C&& c,
size_t idx,
size_t len) :
401 m_mem(std::make_shared<DC>(std::move(c))),
403 m_begin(std::next(m_mem->begin(), idx)),
404 m_end(std::next(m_begin, len))
408 template <
typename IT>
411 m_begin(std::move(
begin)),
412 m_end(std::move(
end))
431 std::shared_ptr<DC> m_mem;
438 template <
typename C>
440 typedef std::decay_t<C> DC;
443 typedef typename DC::const_iterator const_iterator;
444 typedef typename DC::value_type value_type;
445 typedef typename DC::size_type size_type;
452 m_cbegin(std::next(c.cbegin(), idx)),
453 m_cend(std::next(m_cbegin, len))
457 template <
typename IT>
460 m_cbegin(std::move(
begin)),
461 m_cend(std::move(
end))
481 const_iterator m_cbegin;
482 const_iterator m_cend;
508 template <
typename C>
510 slice(C&& c,
size_t idx,
size_t len) {
519 template <
typename C>
521 slice(
const C& c,
size_t idx,
size_t len) {
533 template <
typename C>
535 slice(C& c,
size_t idx,
size_t len) {
556 template <
typename C>
563 template <
typename C>
565 mslice(C& c,
size_t idx,
size_t len) {
566 return slice_of<C>(c, idx, len);
580 template <
typename C,
typename C2,
typename... Cs>
584 detail::group(ret.begin(), std::forward<C>(c), std::forward<C2>(c2), std::forward<Cs>(cs)...);
596 template <
typename C>
599 detail::to_vector_t<C> ret(
sca::size(c));
600 detail::range_transfer(detail::is_lvalue_ref_t<C>(), ret.begin(), c.begin(), c.end());
601 std::reverse(ret.begin(), ret.end());
614 template <
typename C,
typename F>
617 detail::to_vector_t<C> ret(
sca::size(c));
618 detail::range_transfer(detail::is_lvalue_ref_t<C>(), ret.begin(), c.begin(), c.end());
619 std::sort(ret.begin(), ret.end(), cmp);
632 template <
typename F,
typename C>
635 detail::to_vector_t<C> ret(
sca::size(c));
640 detail::transfer(detail::is_lvalue_ref_t<C>(), ret[cur], e);
668 template <
typename F,
typename C,
typename... Cs>
670 map(F&& f, C&& c, Cs&&... cs) {
671 typedef detail::callable_return_t<
673 detail::container_reference_value_t<C>,
674 detail::container_reference_value_t<Cs>...
678 detail::map(std::forward<F>(f), ret.begin(), c.begin(), c.end(), cs.begin()...);
707 template <
typename F,
typename Result,
typename C,
typename... Cs>
709 fold(F&& f, Result&& init, C&& c, Cs&&... cs) {
710 return detail::fold(f, std::forward<Result>(init), c.begin(), c.end(), cs.begin()...);
731 template <
typename F,
typename C,
typename... Cs>
733 each(F&& f, C&& c, Cs&&... cs) {
734 detail::each(f, c.begin(), c.end(), cs.begin()...);
753 template <
typename F,
typename C,
typename... Cs>
755 all(F&& f, C&& c, Cs&&... cs) {
756 return detail::all(f, c.begin(), c.end(), cs.begin()...);
775 template <
typename F,
typename C,
typename... Cs>
777 some(F&& f, C&& c, Cs&&... cs) {
778 return detail::some(f, c.begin(), c.end(), cs.begin()...);
const variation of slice_of
Definition: scalgorithm.hpp:439
auto end() const
return a const_iterator to the end of the container subset
Definition: scalgorithm.hpp:475
size_t size() const
return the iterable length of the slice
Definition: scalgorithm.hpp:465
auto begin() const
return a const_iterator to the beginning of the container subset
Definition: scalgorithm.hpp:470
the underlying type returned by slice() representing a subset of a container
Definition: scalgorithm.hpp:381
size_t size() const
return the iterable length of the slice
Definition: scalgorithm.hpp:416
auto end()
return an iterator to the end of the container subset
Definition: scalgorithm.hpp:426
auto begin()
return an iterator to the beginning of the container subset
Definition: scalgorithm.hpp:421
Definition: scalgorithm.hpp:55
auto filter(F &&f, C &&c)
return a filtered container of elements
Definition: scalgorithm.hpp:634
auto slice(C &&c, size_t idx, size_t len)
create a slice_of object from a container which allows iteration over a subset of another container
Definition: scalgorithm.hpp:510
size_t size(C &&c)
return an iterable container's size, regardless if it implements a size() method
Definition: scalgorithm.hpp:306
auto reverse(C &&c)
return a container where the order of elements is the reverse of the input container
Definition: scalgorithm.hpp:598
auto fold(F &&f, Result &&init, C &&c, Cs &&... cs)
perform a calculation on the elements of containers grouped by index
Definition: scalgorithm.hpp:709
auto map(F &&f, C &&c, Cs &&... cs)
evaluate function with the elements of containers grouped by index and return a container filled with...
Definition: scalgorithm.hpp:670
void each(F &&f, C &&c, Cs &&... cs)
evaluate function with the elements of containers grouped by index
Definition: scalgorithm.hpp:733
auto values(C &&c)
return a container of deep value copies (never pointers) from a container of values or pointers
Definition: scalgorithm.hpp:368
auto mslice(C &&c, size_t idx, size_t len)
create a mutable slice_of object which allows iteration of a subset of another container
Definition: scalgorithm.hpp:558
bool all(F &&f, C &&c, Cs &&... cs)
evaluate if a function returns true with all the elements of containers grouped by index
Definition: scalgorithm.hpp:755
auto group(C &&c, C2 &&c2, Cs &&... cs)
assemble a container containing all elements of two or more containers
Definition: scalgorithm.hpp:582
auto sort(C &&c, F &&cmp)
return a container whose elements are sorted based on a comparison Callable
Definition: scalgorithm.hpp:616
auto pointers(C &c)
copy the addresses of elements in a container to a new container
Definition: scalgorithm.hpp:334
bool some(F &&f, C &&c, Cs &&... cs)
evaluate if a function returns true with at least one of the elements of containers grouped by index
Definition: scalgorithm.hpp:777
Definition: scalgorithm.hpp:96
Definition: scalgorithm.hpp:94