kblib  0.2.3
General utilities library for modern C++
build.h
Go to the documentation of this file.
1 /* *****************************************************************************
2  * kblib is a general utility library for C++14 and C++17, intended to provide
3  * performant high-level abstractions and more expressive ways to do simple
4  * things.
5  *
6  * Copyright (c) 2021 killerbee
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  * ****************************************************************************/
21 
31 #ifndef KBLIB_BUILD_H
32 #define KBLIB_BUILD_H
33 
34 #include "tdecl.h"
35 
36 #include "algorithm.h"
37 #include "fakestd.h"
38 #include "iterators.h"
39 #include "traits.h"
40 
41 #include <algorithm>
42 #include <iterator>
43 #include <numeric>
44 #include <tuple>
45 
46 #if __cplusplus >= 201703L
47 # include <optional>
48 #endif
49 
50 namespace kblib {
51 
65 template <typename Container, typename InputIt, typename UnaryFunction>
66 KBLIB_NODISCARD auto build(InputIt first, InputIt last, UnaryFunction f,
67  typename Container::allocator_type allocator
68  = typename Container::allocator_type{})
69  -> Container {
70  Container out(allocator);
71  std::transform(first, last, std::back_inserter(out), f);
72  return static_cast<void>(out.resize(out.size())), out;
73 }
90 template <typename Container, typename InputIt, typename InputIt2,
91  typename BinaryFunction>
92 KBLIB_NODISCARD auto build(InputIt first, InputIt last, InputIt2 first2,
93  BinaryFunction f,
94  typename Container::allocator_type allocator
95  = typename Container::allocator_type{})
96  -> Container {
97  Container out(allocator);
98  std::transform(first, last, first2, std::back_inserter(out), f);
99  return out;
100 }
101 
119 template <typename Array, typename InputIt, typename UnaryFunction,
120  enable_if_t<not is_resizable_v<Array>, int> = 0>
121 KBLIB_NODISCARD auto build(InputIt first, InputIt last, UnaryFunction f)
122  -> Array {
123  Array out;
124  std::transform(first, last, out.begin(), f);
125  return out;
126 }
145 template <typename Array, typename InputIt, typename InputIt2,
146  typename BinaryFunction,
147  enable_if_t<not is_resizable_v<Array>, int> = 0>
148 KBLIB_NODISCARD auto build(InputIt first, InputIt last, InputIt2 first2,
149  BinaryFunction f) -> Array {
150  Array out;
151  std::transform(first, last, first2, out.begin(), f);
152  return out;
153 }
154 
167 template <typename Container, typename Functor>
168 KBLIB_NODISCARD auto build(Functor f, size_t size,
169  typename Container::allocator_type allocator
170  = typename Container::allocator_type{})
171  -> Container {
172  Container out(allocator);
173  try_reserve(out, size);
174  std::generate_n(std::back_inserter(out), size, f);
175  return out;
176 }
177 
193 template <typename Array, typename Functor,
194  enable_if_t<not is_resizable_v<Array>, int> = 0>
195 KBLIB_NODISCARD auto build(Functor f,
196  size_t size = std::tuple_size<Array>::value)
197  -> Array {
198  Array out;
199  std::generate_n(out.begin(), size, f);
200  return out;
201 }
202 
203 // build_dy: workaround for non-allocator-aware dynamic containers
217 template <typename Container, typename InputIt, typename UnaryFunction>
218 KBLIB_NODISCARD auto build_dy(InputIt first, InputIt last, UnaryFunction f)
219  -> Container {
220  Container out;
221  std::transform(first, last, std::back_inserter(out), f);
222  return out;
223 }
240 template <typename Container, typename InputIt, typename InputIt2,
241  typename BinaryFunction>
242 KBLIB_NODISCARD auto build_dy(InputIt first, InputIt last, InputIt2 first2,
243  BinaryFunction f) -> Container {
244  Container out;
245  std::transform(first, last, first2, std::back_inserter(out), f);
246  return out;
247 }
248 
259 template <typename Container, typename Functor>
260 KBLIB_NODISCARD auto build_dy(Functor f, size_t size) -> Container {
261  Container out;
262  try_reserve(out, size);
263  std::generate_n(std::back_inserter(out), size, f);
264  return out;
265 }
266 
274 template <typename Container, typename Range, typename UnaryFunction,
275  enable_if_t<is_resizable_v<Container>, int> = 0>
276 KBLIB_NODISCARD auto build_dy(Range&& r, UnaryFunction f) -> Container {
277  using std::begin;
278  using std::end;
279  Container out(kblib::size(r));
280  std::transform(begin(r), end(r), begin(out), std::ref(f));
281  return out;
282 }
283 
284 #if 0
285 // I can't overload on both array vs. dynamic container and execution policy
286 // in any sane way without concepts, so this whole set of functions is cut
287 // because they're less useful than the array overloads.
288 template <typename Container, typename ExecutionPolicy, typename InputIt,
289  typename UnaryFunction>
290 KBLIB_NODISCARD auto
291 build(ExecutionPolicy&& policy, InputIt first, InputIt last, UnaryFunction f,
293  typename Container::allocator_type = typename Container::allocator_type{})
294  -> Container {
295  Container out;
296  std::transform(policy, first, last, std::back_inserter(out), f);
297  return static_cast<void>(out.resize(out.size())), out;
298 }
299 template <typename Container, typename ExecutionPolicy, typename InputIt,
300  typename InputIt2, typename BinaryFunction>
301 KBLIB_NODISCARD auto
302 build(ExecutionPolicy&& policy, InputIt first, InputIt last, InputIt2 first2,
303  BinaryFunction f,
305  typename Container::allocator_type = typename Container::allocator_type{})
306  -> Container {
307  Container out;
308  std::transform(policy, first, last, first2, std::back_inserter(out), f);
309  return out;
310 }
311 template <typename Array, typename ExecutionPolicy, typename InputIt,
312  typename UnaryFunction,
313  typename std::enable_if<
314  std::is_convertible<typename std::tuple_size<Array>::value_type,
315  size_t>::value,
316  int>::type = 0>
317 KBLIB_NODISCARD auto build(ExecutionPolicy&& policy, InputIt first,
318  InputIt last, UnaryFunction f) -> Array {
319  Array out;
320  std::transform(policy, first, last, out.begin(), f);
321  return out;
322 }
323 template <typename Array, typename ExecutionPolicy, typename InputIt,
324  typename InputIt2, typename BinaryFunction,
325  typename std::enable_if<
326  std::is_convertible<typename std::tuple_size<Array>::value_type,
327  size_t>::value,
328  int>::type = 0>
329 KBLIB_NODISCARD auto build(ExecutionPolicy&& policy, InputIt first,
330  InputIt last, InputIt2 first2, BinaryFunction f)
331  -> Array {
332  Array out;
333  std::transform(policy, first, last, first2, out.begin(), f);
334  return out;
335 }
336 template <typename Container, typename ExecutionPolicy, typename Functor>
337 KBLIB_NODISCARD auto
338 build(ExecutionPolicy&& policy, Functor f, size_t size,
339  [[gnu::unused]]
340  typename Container::allocator_type = typename Container::allocator_type{})
341  -> Container {
342  Container out(size);
343  std::generate_n(policy, out.begin(), size, f);
344  return out;
345 }
346 template <typename Array, typename ExecutionPolicy, typename Functor,
347  typename std::enable_if<
348  std::is_convertible<typename std::tuple_size<Array>::value_type,
349  size_t>::value,
350  int>::type = 0>
351 KBLIB_NODISCARD auto build(ExecutionPolicy&& policy, Functor f,
352  size_t size = std::tuple_size<Array>::value)
353  -> Array {
354  Array out;
355  std::generate_n(policy, out.begin(), size, f);
356  return out;
357 }
358 #endif
359 
360 namespace detail {
361 
362  template <typename Container>
363  struct buildiota_impl<Container, true> {
364  template <typename T>
365  constexpr static auto impl(std::size_t count, T value) -> Container {
366  Container out;
367  try_reserve(out, count);
368  while (count-- > 0) {
369  out.push_back(value);
370  ++value;
371  }
372  return out;
373  }
374  template <typename T, typename I>
375  constexpr static auto impl(std::size_t count, T value, I incr)
376  -> Container {
377  Container out;
378  try_reserve(out, count);
379  while (count-- > 0) {
380  out.push_back(value);
381  value += incr;
382  }
383  return out;
384  }
385  };
386 
387  template <typename Array>
388  struct buildiota_impl<Array, false> {
389  template <typename T>
390  constexpr static auto impl(T value) -> Array {
391  Array out{};
392  for (auto& v : out) {
393  v = value;
394  ++value;
395  }
396  return out;
397  }
398  template <typename T, typename I>
399  constexpr static auto impl(T value, I incr) -> Array {
400  Array out{};
401  for (auto& v : out) {
402  v = value;
403  value += incr;
404  }
405  return out;
406  }
407  };
408 
409 } // namespace detail
410 
424 template <typename Container, typename... Args>
425 KBLIB_NODISCARD constexpr auto buildiota(Args&&... args) -> auto {
427  std::forward<Args>(args)...);
428 }
429 
438 template <typename Container, typename InputIt>
439 KBLIB_NODISCARD auto build_copy(InputIt first, InputIt last,
440  typename Container::allocator_type allocator
441  = typename Container::allocator_type{})
442  -> Container {
443  Container out(allocator);
444  std::copy(first, last, std::back_inserter(out));
445  return out;
446 }
447 
455 template <typename Container, typename Range,
456  enable_if_t<is_resizable_v<Container>, int> = 0>
457 KBLIB_NODISCARD auto build_copy(Range&& r) -> Container {
458  using std::begin;
459  using std::end;
460  Container out(kblib::size(r));
461  std::copy(begin(r), end(r), begin(out));
462  return out;
463 }
464 
472 template <typename Container, typename Range>
474  typename Container::allocator_type allocator
475  = typename Container::allocator_type{})
476  -> Container {
477  Container out(allocator);
478  std::copy(std::begin(r), std::end(r), std::back_inserter(out));
479  return out;
480 }
481 
489 template <typename Container, typename InputIt,
490  enable_if_t<not is_resizable_v<Container>, int> = 0>
491 KBLIB_NODISCARD constexpr auto build_copy(InputIt first, InputIt last)
492  -> Container {
493  Container out{};
494  auto pos = std::begin(out);
495  auto end = std::end(out);
496  for (; first != last and pos != end; ++first, ++pos) {
497  *pos = *first;
498  }
499  return out;
500 }
501 
508 template <typename Container, typename Range,
509  enable_if_t<not is_resizable_v<Container>, int> = 0>
510 KBLIB_NODISCARD constexpr auto build_copy(Range&& r) -> Container {
511  Container out{};
512  auto first = std::begin(r);
513  auto last = std::end(r);
514  auto pos = std::begin(out);
515  auto end = std::end(out);
516  for (; first != last and pos != end; ++first, ++pos) {
517  *pos = *first;
518  }
519  return out;
520 }
521 
530 template <typename Container, typename InputIt,
531  enable_if_t<not is_resizable_v<Container>, int> = 0>
532 KBLIB_NODISCARD auto build_copy(InputIt first, InputIt last, std::size_t size)
533  -> Container {
534  Container out;
535  auto pos = std::begin(out);
536  auto end = std::end(out);
537  for (std::size_t count = 0; count != size and first != last and pos != end;
538  ++first, ++pos, ++count) {
539  *pos = *first;
540  }
541  return out;
542 }
543 
551 template <typename Container, typename Range,
552  enable_if_t<not is_resizable_v<Container>, int> = 0>
553 KBLIB_NODISCARD auto build_copy(Range&& r, std::size_t size) -> Container {
554  Container out;
555  auto first = std::begin(r);
556  auto last = std::end(r);
557  auto pos = std::begin(out);
558  auto end = std::end(out);
559  for (std::size_t count = 0; count != size and first != last and pos != end;
560  ++first, ++pos, ++count) {
561  *pos = *first;
562  }
563  return out;
564 }
565 
575 template <typename Container, typename InputIt, typename Predicate>
576 KBLIB_NODISCARD auto build_copy_if(InputIt first, InputIt last, Predicate f,
577  typename Container::allocator_type allocator
578  = typename Container::allocator_type{})
579  -> Container {
580  Container out(allocator);
581  kblib::copy_if(first, last, std::back_inserter(out), f);
582  return out;
583 }
584 
593 template <typename Container, typename InputIt, typename Size>
594 KBLIB_NODISCARD auto build_copy_n(InputIt first, Size count,
595  typename Container::allocator_type allocator
596  = typename Container::allocator_type{})
597  -> Container {
598  Container out(allocator);
599  std::copy_n(first, count, std::back_inserter(out));
600  return out;
601 }
602 
612 template <typename Container, typename InputIt, typename Size,
613  typename Predicate>
615  InputIt first, Size count, Predicate f,
616  typename Container::allocator_type allocator
617  = typename Container::allocator_type{}) -> Container {
618  Container out(allocator);
619  kblib::copy_n_if(first, count, std::back_inserter(out), f);
620  return out;
621 }
622 
623 // transform_accumulate
624 // transform_partial_sum
625 
626 } // namespace kblib
627 
628 #endif // KBLIB_BUILD_H
Provides general-purpose algorithms, similar to the <algorithms> header.
This header provides some features of C++17 <type_traits> and other headers for C++14,...
This file provides some iterators, ranges, iterator/range adapters, and operations that can be perfor...
The main namespace in which all entities from kblib are defined.
Definition: algorithm.h:44
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:1069
auto build_copy_n(InputIt first, Size count, typename Container::allocator_type allocator=typename Container::allocator_type{}) -> Container
Definition: build.h:594
constexpr auto buildiota(Args &&... args) -> auto
Builds a container of increasing values.
Definition: build.h:425
auto build(InputIt first, InputIt last, UnaryFunction f, typename Container::allocator_type allocator=typename Container::allocator_type{}) -> Container
Constructs a container by applying a UnaryFunction to every element of an input range.
Definition: build.h:66
auto build_copy_n_if(InputIt first, Size count, Predicate f, typename Container::allocator_type allocator=typename Container::allocator_type{}) -> Container
Definition: build.h:614
constexpr auto copy_n(InputIt first, Size count, OutputIt out) -> OutputIt
Copies all elements of [first, std::advance(first, n)) to out.
Definition: algorithm.h:1365
constexpr auto generate_n(OutputIt first, Size count, Generator g) noexcept(noexcept(*first++=g())) -> OutputIt
Like std::generate_n except that it is constexpr.
Definition: algorithm.h:1564
constexpr auto copy_if(InputIt first, EndIt last, OutputIt out, UnaryPredicate pred) -> OutputIt
Copies those elements of [first, last) which satisfy pred to out. It also allows for a sentinel end i...
Definition: algorithm.h:1343
auto try_reserve(C &c, std::size_t s) noexcept(noexcept(c.reserve(s))) -> void
Attempt to reserve capacity in a container. No-op if unsupported.
Definition: traits.h:239
auto build_dy(InputIt first, InputIt last, UnaryFunction f) -> Container
Constructs a container by applying a UnaryFunction to every element of an input range....
Definition: build.h:218
auto build_copy_if(InputIt first, InputIt last, Predicate f, typename Container::allocator_type allocator=typename Container::allocator_type{}) -> Container
Definition: build.h:576
constexpr auto copy_n_if(InputIt first, Size count, OutputIt out, UnaryPredicate pred) -> OutputIt
Copies those elements of [first, std::advance(first, n)) which satisfy pred to out.
Definition: algorithm.h:1386
constexpr auto copy(InputIt first, EndIt last, OutputIt out) -> OutputIt
Copies all elements of [first, last) to out. It also allows for a sentinel end iterator.
Definition: algorithm.h:1322
auto build_copy(InputIt first, InputIt last, typename Container::allocator_type allocator=typename Container::allocator_type{}) -> Container
Definition: build.h:439
constexpr auto transform(InputIt first, EndIt last, OutputIt d_first, UnaryOperation unary_op) -> OutputIt
transform applies the given function to a range and stores the result in another range,...
Definition: algorithm.h:1631
constexpr static auto impl(T value) -> Array
Definition: build.h:390
constexpr static auto impl(T value, I incr) -> Array
Definition: build.h:399
constexpr static auto impl(std::size_t count, T value, I incr) -> Container
Definition: build.h:375
constexpr static auto impl(std::size_t count, T value) -> Container
Definition: build.h:365
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_UNUSED
This internal macro is used to provide a fallback for [[maybe_unused]] in C++14.
Definition: tdecl.h:92
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:81
Contains some type traits not in the standard library that are useful in the implementation of kblib.