/* *****************************************************************************
* kblib is a general utility library for C++14 and C++17, intended to provide
* performant high-level abstractions and more expressive ways to do simple
* things.
*
* Copyright (c) 2021 killerbee
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
* ****************************************************************************/
/**
* @file
* @brief Provides general utilities which do not fit in any more specific
* header.
*
* @author killerbee
* @date 2019-2021
* @copyright GNU General Public Licence v3.0
*/
#ifndef KBLIB_SIMPLE_H
#define KBLIB_SIMPLE_H
#include "iterators.h"
#include
#include
#include
#include
#include
#include
#include
#define KBLIB_DEBUG_LOG_RANGES 0
#if KBLIB_DEBUG_LOG_RANGES
# include
#endif
namespace KBLIB_NS {
namespace detail_simple {
template
struct simple_range {
const T& low;
const T& high;
};
} // namespace detail_simple
template
constexpr auto in_range(const T& v, detail_simple::simple_range r) {
return (r.low <= v) and (v < r.high);
}
template
constexpr auto in_range_i(const T& v, detail_simple::simple_range r) {
return (r.low <= v) and (v <= r.high);
}
#if KBLIB_USE_CXX17
template
constexpr bool any_void = (std::is_void_v or ...);
template
KBLIB_NODISCARD auto map(F f, T&&... t) noexcept(noexcept(std::tuple{
kblib::apply(f, std::forward(t))...}))
-> enable_if_t<
not any_void(t)))...>,
decltype(std::tuple{kblib::apply(f, std::forward(t))...})> {
return std::tuple{kblib::apply(f, std::forward(t))...};
}
template
auto map(F f, T&&... t) noexcept(
noexcept((static_cast(kblib::apply(f, std::forward(t))), ...)))
-> enable_if_t(t)))...>,
void> {
(static_cast(kblib::apply(f, std::forward(t))), ...);
}
#endif
template
struct KBLIB_NODISCARD RAII_wrapper {
T t;
~RAII_wrapper() noexcept(noexcept(t())) { t(); }
RAII_wrapper(T&& t_)
: t(std::move(t_)) {}
RAII_wrapper(const T& t_)
: t(t_) {}
RAII_wrapper(const RAII_wrapper&) = delete;
RAII_wrapper(RAII_wrapper&&) = delete;
RAII_wrapper& operator=(const RAII_wrapper&) = delete;
RAII_wrapper& operator=(RAII_wrapper&&) = delete;
};
template
auto defer(F f) {
return RAII_wrapper{std::move(f)};
}
/**
* @brief Transforms a stateless binary operation into one which takes reversed
* arguments.
*
* For example, kblib::flip>() returns a function object which
* subtracts its first argument from its second.
*
* @tparam BinaryOperation The operation to reverse.
*/
template
KBLIB_NODISCARD constexpr auto flip() -> auto {
return [](auto&& a, auto&& b) {
return BinaryOperation{}(static_cast(b),
static_cast(a));
};
}
/**
* @brief Transforms a binary operation into one which takes reversed arguments.
*
* For example, kblib::flip(std::minus<>{}) returns a function object which
* subtracts its first argument from its second.
*
* @param op The operation to reverse.
*/
template
KBLIB_NODISCARD constexpr auto flip(BinaryOperation op) -> auto {
return [op = std::move(op)](auto&& a, auto&& b) {
return op(static_cast(b), static_cast(a));
};
}
template
KBLIB_NODISCARD constexpr auto is_consecutive(const T (&array)[N])
-> enable_if_t::value, bool> {
if (N <= 1) {
return true;
} else if (N == 2) {
return (array[1] - array[0]) == 1;
} else {
for (std::size_t i = 1; i < N; ++i) {
if ((array[i] - array[i - 1]) != 1) {
return false;
}
}
return true;
}
}
/**
* @brief Floored integer binary logarithm. Returns floor(lb(val)).
*
* Returns the number of significant bits in the given integer.
*/
KBLIB_NODISCARD constexpr auto filg2(
const std::bitset::digits> val) noexcept
-> int {
for (auto i : range(to_signed(val.size()) - 1, 0, -1)) {
if (val[to_unsigned(i)])
return i;
}
return 0;
}
template
struct first_bigger_than
: std::conditional= size, detail::tag,
typename first_bigger_than::type> {};
template
struct first_bigger_than
: std::conditional_t= size, detail::tag, void> {};
template
using uint_smallest =
typename first_bigger_than<1 + filg2(I) / CHAR_BIT, unsigned char,
unsigned short, unsigned int, unsigned long,
unsigned long long, std::uintmax_t>::type;
template
using int_smallest =
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;
template
using uint_smallest_t = typename uint_smallest::type;
template
using int_smallest_t = typename int_smallest::type;
/**
* @brief The identity function, as a function object.
*/
struct identity {
template
KBLIB_NODISCARD auto operator()(T&& in) -> T&& {
return static_cast(in);
}
};
/**
* @brief Safely propagate an xvalue or lvalue without dangling references
*/
template
auto safe_auto(T&& in) -> T {
return std::forward(in);
}
/**
* @brief Safely propagate an xvalue or lvalue without dangling references
*/
template
auto safe_auto(T& in) -> T& {
return in;
}
/**
* @brief Concatenate two dynamic containers together.
*
* @param A,B The containers to concatenate together.
* @return Container A container consisting of the elements of A and B in that
* order.
*/
template
auto arraycat(LeftContainer A, RightContainer&& B) noexcept(
noexcept(A.insert(A.end(), B.begin(), B.end()))
and std::is_nothrow_move_constructible::value)
-> LeftContainer {
A.insert(A.end(), B.begin(), B.end());
return std::move(A);
}
/**
* @brief Index an array literal without naming its type
*
* @attention The return value must not be stored unless the argument is also
* stored. This is indexable because temporaries live until the end of their
* full-expression, rather than sub-expression
*
* @param a The array literal to index into.
*/
template
KBLIB_NODISCARD constexpr auto a(const std::initializer_list& a) -> auto {
return a.begin();
}
// use like:
// auto v = a({2, 3, 5, 7, 9, 11})[2];
#if KBLIB_USE_CXX20
template
concept zero_constructible = requires(T t) {
{t = 0};
};
struct zero_t {
consteval zero_t(int i) { i == 0 ? void() : throw 0; }
template
constexpr operator T() const noexcept {
return 0;
}
explicit constexpr operator std::nullptr_t() const noexcept {
return nullptr;
}
};
#endif
} // namespace KBLIB_NS
#undef KBLIB_DEBUG_LOG_RANGES
#endif // KBLIB_SIMPLE_H