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
50namespace KBLIB_NS {
51
65template <typename Container, typename InputIt, typename UnaryFunction>
66KBLIB_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}
90template <typename Container, typename InputIt, typename InputIt2,
91 typename BinaryFunction>
92KBLIB_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
119template <typename Array, typename InputIt, typename UnaryFunction,
120 enable_if_t<not is_resizable_v<Array>, int> = 0>
121KBLIB_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}
145template <typename Array, typename InputIt, typename InputIt2,
146 typename BinaryFunction,
147 enable_if_t<not is_resizable_v<Array>, int> = 0>
148KBLIB_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
167template <typename Container, typename Functor>
168KBLIB_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
193template <typename Array, typename Functor,
194 enable_if_t<not is_resizable_v<Array>, int> = 0>
195KBLIB_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
217template <typename Container, typename InputIt, typename UnaryFunction>
218KBLIB_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}
240template <typename Container, typename InputIt, typename InputIt2,
241 typename BinaryFunction>
242KBLIB_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
259template <typename Container, typename Functor>
260KBLIB_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
274template <typename Container, typename Range, typename UnaryFunction,
275 enable_if_t<is_resizable_v<Container>, int> = 0>
276KBLIB_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.
288template <typename Container, typename ExecutionPolicy, typename InputIt,
289 typename UnaryFunction>
291build(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}
299template <typename Container, typename ExecutionPolicy, typename InputIt,
300 typename InputIt2, typename BinaryFunction>
302build(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}
311template <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>
317KBLIB_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}
323template <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>
329KBLIB_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}
336template <typename Container, typename ExecutionPolicy, typename Functor>
338build(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}
346template <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>
351KBLIB_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
360namespace 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
424template <typename Container, typename... Args>
425KBLIB_NODISCARD constexpr auto buildiota(Args&&... args) -> auto {
427 std::forward<Args>(args)...);
428}
429
438template <typename Container, typename InputIt>
439KBLIB_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
455template <typename Container, typename Range,
456 enable_if_t<is_resizable_v<Container>, int> = 0>
457KBLIB_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
472template <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
489template <typename Container, typename InputIt,
490 enable_if_t<not is_resizable_v<Container>, int> = 0>
491KBLIB_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
508template <typename Container, typename Range,
509 enable_if_t<not is_resizable_v<Container>, int> = 0>
510KBLIB_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
530template <typename Container, typename InputIt,
531 enable_if_t<not is_resizable_v<Container>, int> = 0>
532KBLIB_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
551template <typename Container, typename Range,
552 enable_if_t<not is_resizable_v<Container>, int> = 0>
553KBLIB_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
575template <typename Container, typename InputIt, typename Predicate>
576KBLIB_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
593template <typename Container, typename InputIt, typename Size>
594KBLIB_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
612template <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_NS
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...
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:366
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:1070
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_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:1565
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_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(Range &&r, std::size_t size) -> Container
Definition: build.h:553
auto build_dy(Range &&r, UnaryFunction f) -> Container
Definition: build.h:276
auto build(Functor f, size_t size=std::tuple_size< Array >::value) -> Array
Constructs an array-like container with elements initialized by repeatedly calling a generating funct...
Definition: build.h:195
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:1632
static constexpr auto impl(T value, I incr) -> Array
Definition: build.h:399
static constexpr auto impl(T value) -> Array
Definition: build.h:390
static constexpr auto impl(std::size_t count, T value) -> Container
Definition: build.h:365
static constexpr auto impl(std::size_t count, T value, I incr) -> Container
Definition: build.h:375
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_NS
Definition: tdecl.h:113
#define KBLIB_UNUSED
This internal macro is used to provide a fallback for [[maybe_unused]] in C++14.
Definition: tdecl.h:130
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:129
Contains some type traits not in the standard library that are useful in the implementation of kblib.