kblib  0.2.3
General utilities library for modern C++
simple.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 
32 #ifndef KBLIB_SIMPLE_H
33 #define KBLIB_SIMPLE_H
34 
35 #include "iterators.h"
36 
37 #include <bitset>
38 #include <climits>
39 #include <cstdint>
40 #include <initializer_list>
41 #include <limits>
42 #include <numeric>
43 #include <utility>
44 
45 #define KBLIB_DEBUG_LOG_RANGES 0
46 #if KBLIB_DEBUG_LOG_RANGES
47 # include <iostream>
48 #endif
49 
50 namespace kblib {
51 
52 namespace detail_simple {
53  template <typename T>
54  struct simple_range {
55  const T& low;
56  const T& high;
57  };
58 } // namespace detail_simple
59 
60 template <typename T>
61 constexpr auto in_range(const T& v, detail_simple::simple_range<T> r) {
62  return (r.low <= v) and (v < r.high);
63 }
64 template <typename T>
65 constexpr auto in_range_i(const T& v, detail_simple::simple_range<T> r) {
66  return (r.low <= v) and (v <= r.high);
67 }
68 
69 #if KBLIB_USE_CXX17
70 
71 template <typename... Ts>
72 constexpr bool any_void = (std::is_void_v<Ts> or ...);
73 
74 template <typename F, typename... T>
75 KBLIB_NODISCARD auto map(F f, T&&... t) noexcept(noexcept(std::tuple{
76  kblib::apply(f, std::forward<T>(t))...}))
77  -> enable_if_t<
78  not any_void<decltype(kblib::apply(f, std::forward<T>(t)))...>,
79  decltype(std::tuple{kblib::apply(f, std::forward<T>(t))...})> {
80  return std::tuple{kblib::apply(f, std::forward<T>(t))...};
81 }
82 
83 template <typename F, typename... T>
84 auto map(F f, T&&... t) noexcept(
85  noexcept((static_cast<void>(kblib::apply(f, std::forward<T>(t))), ...)))
86  -> enable_if_t<any_void<decltype(kblib::apply(f, std::forward<T>(t)))...>,
87  void> {
88  (static_cast<void>(kblib::apply(f, std::forward<T>(t))), ...);
89 }
90 #endif
91 
92 template <typename T>
94  T t;
95  ~RAII_wrapper() noexcept(noexcept(t())) { t(); }
96 
97  RAII_wrapper(T&& t_)
98  : t(std::move(t_)) {}
99  RAII_wrapper(const T& t_)
100  : t(t_) {}
101  RAII_wrapper(const RAII_wrapper&) = delete;
105 };
106 
107 template <typename F>
108 auto defer(F f) {
109  return RAII_wrapper<F>{std::move(f)};
110 }
111 
121 template <typename BinaryOperation>
122 KBLIB_NODISCARD constexpr auto flip() -> auto {
123  return [](auto&& a, auto&& b) {
124  return BinaryOperation{}(static_cast<decltype(b)>(b),
125  static_cast<decltype(a)>(a));
126  };
127 }
128 
137 template <typename BinaryOperation>
138 KBLIB_NODISCARD constexpr auto flip(BinaryOperation op) -> auto {
139  return [op = std::move(op)](auto&& a, auto&& b) {
140  return op(static_cast<decltype(b)>(b), static_cast<decltype(a)>(a));
141  };
142 }
143 
144 template <typename T, std::size_t N>
145 KBLIB_NODISCARD constexpr auto is_consecutive(const T (&array)[N])
147  if (N <= 1) {
148  return true;
149  } else if (N == 2) {
150  return (array[1] - array[0]) == 1;
151  } else {
152  for (std::size_t i = 1; i < N; ++i) {
153  if ((array[i] - array[i - 1]) != 1) {
154  return false;
155  }
156  }
157  return true;
158  }
159 }
160 
166 KBLIB_NODISCARD constexpr auto filg2(
167  const std::bitset<std::numeric_limits<std::uintmax_t>::digits> val) noexcept
168  -> int {
169  for (auto i : range<int>(to_signed(val.size()) - 1, 0, -1)) {
170  if (val[to_unsigned(i)])
171  return i;
172  }
173  return 0;
174 }
175 
176 template <std::size_t size, typename T, typename... Ts>
178  : std::conditional<sizeof(T) >= size, detail::tag<T>,
179  typename first_bigger_than<size, Ts...>::type> {};
180 
181 template <std::size_t size, typename T>
183  : std::conditional_t<sizeof(T) >= size, detail::tag<T>, void> {};
184 
185 template <std::uintmax_t I>
187  typename first_bigger_than<1 + filg2(I) / CHAR_BIT, unsigned char,
188  unsigned short, unsigned int, unsigned long,
189  unsigned long long, std::uintmax_t>::type;
190 
191 template <std::uintmax_t I>
193  typename first_bigger_than<1 + (filg2(I) + 1) / CHAR_BIT, signed char,
194  signed short, signed int, signed long,
195  signed long long, std::uintmax_t>::type;
196 
197 template <std::uintmax_t I>
199 
200 template <std::uintmax_t I>
202 
206 struct identity {
207  template <typename T>
208  KBLIB_NODISCARD auto operator()(T&& in) -> T&& {
209  return static_cast<T&&>(in);
210  }
211 };
212 
216 template <typename T>
217 auto safe_auto(T&& in) -> T {
218  return std::forward<T>(in);
219 }
220 
224 template <typename T>
225 auto safe_auto(T& in) -> T& {
226  return in;
227 }
228 
236 template <typename LeftContainer, typename RightContainer>
237 auto arraycat(LeftContainer A, RightContainer&& B) noexcept(
238  noexcept(A.insert(A.end(), B.begin(), B.end()))
239  and std::is_nothrow_move_constructible<LeftContainer>::value)
240  -> LeftContainer {
241  A.insert(A.end(), B.begin(), B.end());
242  return std::move(A);
243 }
244 
254 template <typename T>
255 KBLIB_NODISCARD constexpr auto a(const std::initializer_list<T>& a) -> auto {
256  return a.begin();
257 }
258 // use like:
259 // auto v = a({2, 3, 5, 7, 9, 11})[2];
260 
261 #if KBLIB_USE_CXX20
262 
263 template <typename T>
264 concept zero_constructible = requires(T t) {
265  {t = 0};
266 };
267 
268 struct zero_t {
269  consteval zero_t(int i) { i == 0 ? void() : throw 0; }
270  template <zero_constructible T>
271  constexpr operator T() const noexcept {
272  return 0;
273  }
274  explicit constexpr operator std::nullptr_t() const noexcept {
275  return nullptr;
276  }
277 };
278 
279 #endif
280 
281 } // namespace kblib
282 
283 #undef KBLIB_DEBUG_LOG_RANGES
284 
285 #endif // KBLIB_SIMPLE_H
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
typename first_bigger_than< 1+(filg2(I)+1)/CHAR_BIT, signed char, signed short, signed int, signed long, signed long long, std::uintmax_t >::type int_smallest
Definition: simple.h:195
constexpr auto in_range(const T &v, detail_simple::simple_range< T > r)
Definition: simple.h:61
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:1069
constexpr auto is_consecutive(const T(&array)[N]) -> enable_if_t< std::is_integral< T >::value, bool >
Definition: simple.h:145
auto map(F f, T &&... t) noexcept(noexcept(std::tuple{ kblib::apply(f, std::forward< T >(t))...})) -> enable_if_t< not any_void< decltype(kblib::apply(f, std::forward< T >(t)))... >, decltype(std::tuple{kblib::apply(f, std::forward< T >(t))...})>
Definition: simple.h:75
constexpr auto to_signed(I x) -> std::make_signed_t< I >
Cast integral argument to corresponding signed type.
Definition: fakestd.h:592
constexpr auto a(const std::initializer_list< T > &a) -> auto
Index an array literal without naming its type.
Definition: simple.h:255
typename std::enable_if< B, T >::type enable_if_t
Definition: fakestd.h:54
constexpr auto apply(F &&f, Arg &&arg) noexcept(noexcept(detail::apply_impl< F, Arg >::do_apply(std::forward< F >(f), std::forward< Arg >(arg), std::index_sequence< std::tuple_size< Arg >::value >{}))) -> decltype(auto)
Definition: fakestd.h:561
auto arraycat(LeftContainer A, RightContainer &&B) noexcept(noexcept(A.insert(A.end(), B.begin(), B.end())) and std::is_nothrow_move_constructible< LeftContainer >::value) -> LeftContainer
Concatenate two dynamic containers together.
Definition: simple.h:237
auto safe_auto(T &&in) -> T
Safely propagate an xvalue or lvalue without dangling references.
Definition: simple.h:217
typename int_smallest< I >::type int_smallest_t
Definition: simple.h:201
constexpr auto filg2(const std::bitset< std::numeric_limits< std::uintmax_t >::digits > val) noexcept -> int
Floored integer binary logarithm. Returns floor(lb(val)).
Definition: simple.h:166
auto defer(F f)
Definition: simple.h:108
constexpr bool any_void
Definition: simple.h:72
constexpr auto flip() -> auto
Transforms a stateless binary operation into one which takes reversed arguments.
Definition: simple.h:122
typename first_bigger_than< 1+filg2(I)/CHAR_BIT, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long, std::uintmax_t >::type uint_smallest
Definition: simple.h:189
typename uint_smallest< I >::type uint_smallest_t
Definition: simple.h:198
constexpr auto to_unsigned(I x) -> std::make_unsigned_t< I >
Cast integral argument to corresponding unsigned type.
Definition: fakestd.h:585
constexpr auto in_range_i(const T &v, detail_simple::simple_range< T > r)
Definition: simple.h:65
Definition: bits.h:714
RAII_wrapper(T &&t_)
Definition: simple.h:97
RAII_wrapper(const RAII_wrapper &)=delete
RAII_wrapper(const T &t_)
Definition: simple.h:99
RAII_wrapper(RAII_wrapper &&)=delete
RAII_wrapper & operator=(RAII_wrapper &&)=delete
~RAII_wrapper() noexcept(noexcept(t()))
Definition: simple.h:95
RAII_wrapper & operator=(const RAII_wrapper &)=delete
The identity function, as a function object.
Definition: simple.h:206
auto operator()(T &&in) -> T &&
Definition: simple.h:208
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:81