commit f0357d565c6efae154c2a08585ba276d802719fc
parent 4481d473057d49e4c643f81384f254039d6ee9fe
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date: Mon, 5 Sep 2016 11:37:21 +0300
Split and refactor CoMeta, remove unused includes
Diffstat:
18 files changed, 735 insertions(+), 613 deletions(-)
diff --git a/examples/dft.cpp b/examples/dft.cpp
@@ -7,8 +7,8 @@
#include <kfr/io/tostring.hpp>
#include <kfr/base.hpp>
-#include <kfr/dsp.hpp>
#include <kfr/dft.hpp>
+#include <kfr/dsp.hpp>
// plot_save()
#include <kfr/io/python_plot.hpp>
diff --git a/include/kfr/base.hpp b/include/kfr/base.hpp
@@ -22,7 +22,6 @@
*/
#pragma once
-#include "version.hpp"
#include "base/abs.hpp"
#include "base/asin_acos.hpp"
#include "base/atan.hpp"
@@ -62,3 +61,4 @@
#include "base/types.hpp"
#include "base/univector.hpp"
#include "base/vec.hpp"
+#include "version.hpp"
diff --git a/include/kfr/base/expression.hpp b/include/kfr/base/expression.hpp
@@ -28,6 +28,8 @@
#include "types.hpp"
#include "vec.hpp"
+#include <tuple>
+
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
diff --git a/include/kfr/base/types.hpp b/include/kfr/base/types.hpp
@@ -28,13 +28,10 @@
#include "intrinsics.h"
-#include <algorithm>
#include <cmath>
-#include <tuple>
-#include <type_traits>
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
#include "../cometa.hpp"
@@ -813,4 +810,4 @@ struct compound_type_traits<kfr::vec_t<T, N>>
};
}
-#pragma clang diagnostic pop
+#pragma GCC diagnostic pop
diff --git a/include/kfr/base/univector.hpp b/include/kfr/base/univector.hpp
@@ -25,6 +25,8 @@
*/
#pragma once
+#include "../cometa/array.hpp"
+
#include "function.hpp"
#include "memory.hpp"
#include "read_write.hpp"
diff --git a/include/kfr/cometa.hpp b/include/kfr/cometa.hpp
@@ -5,11 +5,10 @@
#include "cident.h"
-#include <algorithm>
-#include <array>
-#include <tuple>
+#include <cstdint>
+#include <limits>
#include <type_traits>
-#include <vector>
+#include <utility>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
@@ -1236,11 +1235,6 @@ CMT_INTRIN void cforeach(const T (&array)[N], Fn&& fn)
namespace details
{
-template <typename... Ts, typename Fn, size_t... indices>
-CMT_INTRIN void cforeach_tuple_impl(const std::tuple<Ts...>& tuple, Fn&& fn, csizes_t<indices...>)
-{
- swallow{ (fn(std::get<indices>(tuple)), void(), 0)... };
-}
template <size_t index, typename... types>
CMT_INTRIN auto get_type_arg(ctypes_t<types...> type_list)
@@ -1261,12 +1255,6 @@ CMT_INTRIN void cforeach(ctypes_t<Ts...> types, Fn&& fn)
details::cforeach_types_impl(types, std::forward<Fn>(fn), csizeseq<sizeof...(Ts)>);
}
-template <typename... Ts, typename Fn>
-CMT_INTRIN void cforeach(const std::tuple<Ts...>& tuple, Fn&& fn)
-{
- details::cforeach_tuple_impl(tuple, std::forward<Fn>(fn), csizeseq<sizeof...(Ts)>);
-}
-
template <typename A0, typename A1, typename Fn>
CMT_INTRIN void cforeach(A0&& a0, A1&& a1, Fn&& fn)
{
@@ -1373,156 +1361,17 @@ inline decltype(auto) cmatch(T&& value, Fn&& fn, Args... args)
return details::cmatch_impl(std::forward<T>(value), std::forward<Fn>(fn), std::forward<Args>(args)...);
}
-namespace details
-{
-
-template <typename Result, typename... Args>
-struct virtual_function
-{
- virtual Result operator()(Args... args) = 0;
- virtual virtual_function* make_copy() const = 0;
- CMT_INTRIN virtual ~virtual_function() = default;
-};
-
-template <typename Fn, typename Result, typename... Args>
-struct virtual_function_impl : virtual_function<Result, Args...>
-{
-public:
- CMT_INTRIN virtual_function_impl(const Fn& fn) : fn(fn) {}
- CMT_INTRIN Result operator()(Args... args) override final { return fn(args...); }
- CMT_INTRIN virtual_function<Result, Args...>* make_copy() const override final
- {
- return new virtual_function_impl{ fn };
- }
- CMT_INTRIN ~virtual_function_impl() {}
-
-private:
- Fn fn;
-};
-
-template <typename Fn>
-struct func_filter
-{
- typedef Fn type;
-};
-template <typename Result, typename... Args>
-struct func_filter<Result(Args...)>
-{
- typedef Result (*type)(Args...);
-};
-
-template <typename T>
-constexpr CMT_INTRIN T return_val() noexcept
-{
- return {};
-}
-
-template <>
-constexpr CMT_INTRIN void return_val<void>() noexcept
-{
-}
-}
-
-template <typename>
-struct function;
-
-/**
- * @brief std::function-like lightweight function wrapper
- * @code
- * function<int( float )> f = []( float x ){ return static_cast<int>( x ); };
- * CHECK( f( 3.4f ) == 3 )
- * @encode
- */
-template <typename Result, typename... Args>
-struct function<Result(Args...)>
-{
- using this_t = function<Result(Args...)>;
-
- function(function&& other) : fn(other.fn) { other.fn = nullptr; }
- function& operator=(function&& other)
- {
- fn = other.fn;
- other.fn = nullptr;
- return *this;
- }
-
- CMT_INTRIN function() : fn(nullptr) {}
- CMT_INTRIN function(std::nullptr_t) : fn(nullptr) {}
- template <typename Func>
- CMT_INTRIN function(const Func& x)
- : fn(new details::virtual_function_impl<typename details::func_filter<Func>::type, Result, Args...>(
- x))
- {
- }
- function(const this_t& other) : fn(other.fn ? other.fn->make_copy() : nullptr) {}
- CMT_INTRIN function& operator=(const this_t& other)
- {
- if ((&other != this) && (other.fn))
- {
- auto* temp = other.fn->make_copy();
- delete fn;
- fn = temp;
- }
- return *this;
- }
- CMT_INTRIN function& operator=(std::nullptr_t)
- {
- delete fn;
- fn = nullptr;
- return *this;
- }
- template <typename Fn>
- CMT_INTRIN function& operator=(const Fn& x)
- {
- using FnImpl =
- details::virtual_function_impl<typename details::func_filter<Fn>::type, Result, Args...>;
- FnImpl* temp = new FnImpl(x);
- delete fn;
- fn = temp;
- return *this;
- }
- CMT_INTRIN Result operator()(Args... args) const { return (*fn)(std::forward<Args>(args)...); }
- template <typename TResult>
- CMT_INTRIN Result call(TResult&& default_result, Args... args) const
- {
- return fn ? (*fn)(std::forward<Args>(args)...) : std::forward<TResult>(default_result);
- }
- CMT_INTRIN explicit operator bool() const noexcept { return !!fn; }
-
- CMT_INTRIN ~function() { delete fn; }
-private:
- details::virtual_function<Result, Args...>* fn;
-};
-
-template <typename Ret, typename... Args, typename T, typename Fn, typename DefFn = fn_noop>
-CMT_INLINE function<Ret(Args...)> cdispatch(cvals_t<T>, identity<T>, Fn&&, DefFn&& deffn = DefFn())
-{
- return [=](Args... args) CMT_INLINE_MEMBER -> Ret { return deffn(std::forward<Args>(args)...); };
-}
-
-template <typename Ret, typename... Args, typename T, T v0, T... values, typename Fn,
- typename DefFn = fn_noop>
-inline function<Ret(Args...)> cdispatch(cvals_t<T, v0, values...>, identity<T> value, Fn&& fn,
- DefFn&& deffn = DefFn())
-{
- if (value == v0)
- {
- return [=](Args... args)
- CMT_INLINE_MEMBER -> Ret { return fn(cval<T, v0>, std::forward<Args>(args)...); };
- }
- else
- {
- return cdispatch<Ret, Args...>(cvals_t<T, values...>(), value, std::forward<Fn>(fn),
- std::forward<DefFn>(deffn));
- }
-}
-
template <typename T, T... values>
inline size_t cfind(cvals_t<T, values...>, identity<T> value)
{
- static const T temp[] = { values... };
- return static_cast<size_t>(
- std::distance(std::begin(temp), std::find(std::begin(temp), std::end(temp), value)));
+ static constexpr T temp[] = { values... };
+ static constexpr size_t size = sizeof...(values);
+ for (size_t i = 0; i < size; i++)
+ {
+ if (temp[i] == value)
+ return i;
+ }
+ return size_t(-1);
}
template <typename Fn, typename... Args>
@@ -1549,76 +1398,6 @@ CMT_INTRIN NonMemFn make_nonmember(const Fn&)
}
template <typename T>
-struct array_ref
-{
-public:
- using value_type = T;
- using pointer = value_type*;
- using const_pointer = const value_type*;
- using reference = value_type&;
- using const_reference = const value_type&;
- using iterator = pointer;
- using const_iterator = const_pointer;
- using reverse_iterator = std::reverse_iterator<pointer>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
-
- constexpr array_ref() noexcept : m_data(nullptr), m_size(0) {}
- constexpr array_ref(const array_ref&) noexcept = default;
- constexpr array_ref(array_ref&&) noexcept = default;
- constexpr array_ref& operator=(const array_ref&) noexcept = default;
- constexpr array_ref& operator=(array_ref&&) noexcept = default;
-
- template <size_t N>
- constexpr array_ref(value_type (&arr)[N]) noexcept : m_data(arr), m_size(N)
- {
- }
- template <size_t N>
- constexpr array_ref(const std::array<T, N>& arr) noexcept : m_data(arr.data()), m_size(N)
- {
- }
- template <size_t N>
- constexpr array_ref(std::array<T, N>& arr) noexcept : m_data(arr.data()), m_size(N)
- {
- }
- template <typename... Ts>
- constexpr array_ref(const std::vector<T, Ts...>& vec) noexcept : m_data(vec.data()), m_size(vec.size())
- {
- }
- template <typename... Ts, CMT_ENABLE_IF(sizeof...(Ts), is_const<T>::value)>
- constexpr array_ref(const std::vector<remove_const<T>, Ts...>& vec) noexcept : m_data(vec.data()),
- m_size(vec.size())
- {
- }
- template <typename... Ts>
- constexpr array_ref(std::vector<T, Ts...>& vec) noexcept : m_data(vec.data()), m_size(vec.size())
- {
- }
- template <typename InputIter>
- constexpr array_ref(InputIter first, InputIter last) noexcept : m_data(std::addressof(*first)),
- m_size(std::distance(first, last))
- {
- }
- constexpr array_ref(T* data, size_type size) noexcept : m_data(data), m_size(size) {}
-
- constexpr reference front() const noexcept { return m_data[0]; }
- constexpr reference back() const noexcept { return m_data[m_size - 1]; }
- constexpr iterator begin() const noexcept { return m_data; }
- constexpr iterator end() const noexcept { return m_data + m_size; }
- constexpr const_iterator cbegin() const noexcept { return m_data; }
- constexpr const_iterator cend() const noexcept { return m_data + m_size; }
- constexpr pointer data() const noexcept { return m_data; }
- constexpr std::size_t size() const noexcept { return m_size; }
- constexpr bool empty() const noexcept { return !m_size; }
- constexpr reference operator[](std::size_t index) const { return m_data[index]; }
-
-private:
- pointer m_data;
- size_type m_size;
-};
-
-template <typename T>
constexpr inline T choose_const()
{
static_assert(sizeof(T) != 0, "T not found in the list of template arguments");
@@ -1638,84 +1417,6 @@ constexpr inline T choose_const(C1 c1, Cs... constants)
return std::is_same<T, C1>::value ? static_cast<T>(c1) : choose_const<T>(constants...);
}
-template <typename T, std::size_t size>
-inline array_ref<T> make_array_ref(T (&data)[size])
-{
- return array_ref<T>(data);
-}
-
-template <typename T>
-inline array_ref<T> make_array_ref(T* data, std::size_t size)
-{
- return array_ref<T>(data, data + size);
-}
-
-template <typename Container, CMT_ENABLE_IF(has_data_size<Container>::value),
- typename T = remove_pointer<decltype(std::declval<Container>().data())>>
-inline array_ref<T> make_array_ref(Container& cont)
-{
- return array_ref<T>(cont.data(), cont.size());
-}
-
-template <typename Container, CMT_ENABLE_IF(has_data_size<Container>::value),
- typename T = remove_pointer<decltype(std::declval<Container>().data())>>
-inline array_ref<const T> make_array_ref(const Container& cont)
-{
- return array_ref<const T>(cont.data(), cont.size());
-}
-
-template <typename T>
-inline array_ref<T> make_array_ref(std::vector<T>& cont)
-{
- return array_ref<T>(cont.data(), cont.size());
-}
-template <typename T>
-inline array_ref<const T> make_array_ref(const std::vector<T>& cont)
-{
- return array_ref<const T>(cont.data(), cont.size());
-}
-
-template <typename Type, typename ErrEnum, ErrEnum OkValue = static_cast<ErrEnum>(0)>
-struct result
-{
- using value_type = Type;
- using reference = value_type&;
- using const_reference = const value_type&;
- using pointer = value_type*;
- using const_pointer = const value_type*;
-
- using error_type = ErrEnum;
-
- constexpr static error_type ok_value = OkValue;
-
- constexpr result(const result&) = default;
- constexpr result(result&&) noexcept = default;
-
- constexpr result(ErrEnum error) noexcept : m_error(error) {}
-
- template <typename ValueInit, CMT_ENABLE_IF(std::is_constructible<value_type, ValueInit>::value)>
- constexpr result(ValueInit&& value) noexcept : m_value(std::forward<ValueInit>(value)), m_error(OkValue)
- {
- }
-
- constexpr result(const Type& value) noexcept : m_value(value), m_error(OkValue) {}
- constexpr result(Type&& value) noexcept : m_value(std::move(value)), m_error(OkValue) {}
-
- constexpr explicit operator bool() const { return m_error == OkValue; }
- constexpr const_reference operator*() const { return m_value; }
- constexpr reference operator*() { return m_value; }
- constexpr const_pointer operator->() const { return &m_value; }
- constexpr pointer operator->() { return &m_value; }
-
- constexpr const_reference value() const { return m_value; }
- constexpr reference value() { return m_value; }
- constexpr ErrEnum error() const { return m_error; }
- constexpr bool ok() const { return m_error == OkValue; }
-private:
- Type m_value;
- ErrEnum m_error;
-};
-
template <typename Tfrom>
struct autocast_impl
{
@@ -1751,300 +1452,6 @@ struct signed_type_impl<T, void_t<enable_if<std::is_unsigned<T>::value>>>
template <typename T>
using signed_type = typename details::signed_type_impl<T>::type;
-
-template <typename T>
-struct range
-{
- using value_type = T;
- using reference = T&;
- using const_reference = const T&;
- using pointer = T*;
- using const_pointer = const T*;
- using diff_type = decltype(std::declval<T>() - std::declval<T>());
-
- constexpr range(value_type begin, value_type end, diff_type step) noexcept : value_begin(begin),
- value_end(end),
- step(step)
- {
- }
-
- struct iterator
- {
- value_type value;
- diff_type step;
- const_reference operator*() const { return value; }
- const_pointer operator->() const { return &value; }
- iterator& operator++()
- {
- value += step;
- return *this;
- }
- iterator operator++(int)
- {
- iterator copy = *this;
- ++(*this);
- return copy;
- }
- bool operator!=(const iterator& other) const
- {
- return step > 0 ? value < other.value : value > other.value;
- }
- };
- value_type value_begin;
- value_type value_end;
- diff_type step;
- iterator begin() const { return iterator{ value_begin, step }; }
- iterator end() const { return iterator{ value_end, step }; }
-};
-
-template <typename T>
-range<T> make_range(T begin, T end)
-{
- return range<T>(begin, end, end > begin ? 1 : -1);
-}
-
-template <typename T, typename diff_type = decltype(std::declval<T>() - std::declval<T>())>
-range<T> make_range(T begin, T end, diff_type step)
-{
- return range<T>(begin, end, step);
-}
-
-template <typename T>
-struct named_arg
-{
- T value;
- const char* name;
-};
-
-struct named
-{
- constexpr named(const char* name) noexcept : name(name) {}
-
- template <typename T>
- CMT_INTRIN constexpr named_arg<T> operator=(T&& value)
- {
- return named_arg<T>{ std::forward<T>(value), name };
- }
- const char* name;
-};
-
-inline named operator""_arg(const char* name, size_t) { return name; }
-
-template <size_t N>
-struct cstring
-{
- using value_type = char;
- using size_type = size_t;
-
- constexpr const value_type* c_str() const noexcept { return value; }
- constexpr const value_type* data() const noexcept { return value; }
-
- const value_type value[N];
- constexpr size_type length() const noexcept { return N - 1; }
- constexpr size_type size() const noexcept { return N; }
-
- constexpr friend bool operator==(const cstring& left, const cstring& right) noexcept
- {
- for (size_t i = 0; i < 1; i++)
- if (left.value[i] != right.value[i])
- return false;
- return true;
- }
- constexpr friend bool operator!=(const cstring& left, const cstring& right) noexcept
- {
- return !(left == right);
- }
-
- template <size_t NN>
- constexpr bool operator==(const cstring<NN>& other) const noexcept
- {
- return false;
- }
- template <size_t NN>
- constexpr bool operator!=(const cstring<NN>& other) const noexcept
- {
- return true;
- }
- constexpr char operator[](size_t index) const noexcept { return value[index]; }
-};
-
-namespace details
-{
-
-template <size_t N, size_t... indices>
-CMT_INLINE constexpr cstring<N> make_cstring_impl(const char (&str)[N], csizes_t<indices...>)
-{
- return { { str[indices]..., 0 } };
-}
-
-template <size_t N1, size_t N2, size_t... indices>
-CMT_INLINE constexpr cstring<N1 - 1 + N2 - 1 + 1> concat_str_impl(const cstring<N1>& str1,
- const cstring<N2>& str2,
- csizes_t<indices...>)
-{
- constexpr size_t L1 = N1 - 1;
- return { { (indices < L1 ? str1[indices] : str2[indices - L1])..., 0 } };
-}
-template <size_t N1, size_t N2, typename... Args>
-CMT_INLINE constexpr cstring<N1 - 1 + N2 - 1 + 1> concat_str_impl(const cstring<N1>& str1,
- const cstring<N2>& str2)
-{
- return concat_str_impl(str1, str2, csizeseq<N1 - 1 + N2 - 1>);
-}
-template <size_t N1, size_t Nfrom, size_t Nto, size_t... indices>
-CMT_INTRIN cstring<N1 - Nfrom + Nto> str_replace_impl(size_t pos, const cstring<N1>& str,
- const cstring<Nfrom>&, const cstring<Nto>& to,
- csizes_t<indices...>)
-{
- if (pos == size_t(-1))
- stop_constexpr();
- return { { (indices < pos ? str[indices] : (indices < pos + Nto - 1) ? to[indices - pos]
- : str[indices - Nto + Nfrom])...,
- 0 } };
-}
-}
-
-CMT_INTRIN constexpr cstring<1> concat_cstring() { return { { 0 } }; }
-
-template <size_t N1>
-CMT_INTRIN constexpr cstring<N1> concat_cstring(const cstring<N1>& str1)
-{
- return str1;
-}
-
-template <size_t N1, size_t N2, typename... Args>
-CMT_INTRIN constexpr auto concat_cstring(const cstring<N1>& str1, const cstring<N2>& str2,
- const Args&... args)
-{
- return details::concat_str_impl(str1, concat_cstring(str2, args...));
-}
-
-template <size_t N>
-CMT_INTRIN constexpr cstring<N> make_cstring(const char (&str)[N])
-{
- return details::make_cstring_impl(str, csizeseq<N - 1>);
-}
-
-template <char... chars>
-CMT_INTRIN constexpr cstring<sizeof...(chars) + 1> make_cstring(cchars_t<chars...>)
-{
- return { { chars..., 0 } };
-}
-
-template <size_t N1, size_t Nneedle>
-CMT_INTRIN size_t str_find(const cstring<N1>& str, const cstring<Nneedle>& needle)
-{
- size_t count = 0;
- for (size_t i = 0; i < N1; i++)
- {
- if (str[i] == needle[count])
- count++;
- else
- count = 0;
- if (count == Nneedle - 1)
- return i + 1 - (Nneedle - 1);
- }
- return size_t(-1);
-}
-
-template <size_t N1, size_t Nfrom, size_t Nto>
-CMT_INTRIN cstring<N1 - Nfrom + Nto> str_replace(const cstring<N1>& str, const cstring<Nfrom>& from,
- const cstring<Nto>& to)
-{
- return details::str_replace_impl(str_find(str, from), str, from, to, csizeseq<N1 - Nfrom + Nto - 1>);
-}
-
-using pconstvoid = const void*;
-
-struct type_id_t
-{
- constexpr type_id_t(const void* id) noexcept : id(id) {}
- constexpr bool operator==(type_id_t other) const { return id == other.id; }
- constexpr bool operator!=(type_id_t other) const { return !(id == other.id); }
- const void* const id;
-};
-
-namespace details
-{
-
-constexpr inline size_t strlen(const char* str) { return *str ? 1 + cometa::details::strlen(str + 1) : 0; }
-
-template <typename T>
-constexpr inline type_id_t typeident_impl() noexcept
-{
- return type_id_t(pconstvoid(&typeident_impl<T>));
-}
-
-#ifdef CMT_COMPILER_CLANG
-constexpr size_t typename_prefix = sizeof("auto cometa::ctype_name() [T = ") - 1;
-constexpr size_t typename_postfix = sizeof("]") - 1;
-#else
-constexpr size_t typename_prefix = sizeof("constexpr auto cometa::ctype_name() [with T = ") - 1;
-constexpr size_t typename_postfix = sizeof("]") - 1;
-#endif
-
-template <size_t... indices, size_t Nout = 1 + sizeof...(indices)>
-constexpr cstring<Nout> gettypename_impl(const char* str, csizes_t<indices...>) noexcept
-{
- return cstring<Nout>{ { (str[indices])..., 0 } };
-}
-}
-
-template <typename T>
-constexpr auto ctype_name() noexcept
-{
- constexpr size_t length =
- sizeof(CMT_FUNC_SIGNATURE) - 1 - details::typename_prefix - details::typename_postfix;
- return details::gettypename_impl(CMT_FUNC_SIGNATURE + details::typename_prefix, csizeseq<length>);
-}
-
-/**
- * @brief Gets the fully qualified name of the type, including namespace and
- * template parameters (if any)
- * @tparam T type
- * @return name of the type
- */
-template <typename T>
-inline const char* type_name() noexcept
-{
- static const auto name = ctype_name<T>();
- return name.c_str();
-}
-
-/**
- * @brief Gets the fully qualified name of the type, including namespace and
- * template parameters (if any)
- * @param x value of specific type
- * @return name of the type
- */
-template <typename T>
-inline const char* type_name(T x) noexcept
-{
- (void)x;
- return type_name<T>();
-}
-
-/**
- * @brief Gets unique value associated with the type
- * @tparam T type
- * @return value of type that supports operator== and operator!=
- */
-template <typename T>
-constexpr inline type_id_t ctypeid()
-{
- return details::typeident_impl<T>();
-}
-/**
- * @brief Gets unique value associated with the type
- * @param x value of specific type
- * @return value of type that supports operator== and operator!=
- */
-template <typename T>
-constexpr inline type_id_t ctypeid(T x)
-{
- (void)x;
- return details::typeident_impl<T>();
-}
}
#pragma GCC diagnostic pop
diff --git a/include/kfr/cometa/array.hpp b/include/kfr/cometa/array.hpp
@@ -0,0 +1,119 @@
+/** @addtogroup cometa
+ * @{
+ */
+#pragma once
+
+#include "../cometa.hpp"
+#include <array>
+#include <iterator>
+
+namespace cometa
+{
+
+template <typename T>
+struct array_ref
+{
+public:
+ using value_type = T;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<pointer>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+
+ constexpr array_ref() noexcept : m_data(nullptr), m_size(0) {}
+ constexpr array_ref(const array_ref&) noexcept = default;
+ constexpr array_ref(array_ref&&) noexcept = default;
+ constexpr array_ref& operator=(const array_ref&) noexcept = default;
+ constexpr array_ref& operator=(array_ref&&) noexcept = default;
+
+ template <size_t N>
+ constexpr array_ref(value_type (&arr)[N]) noexcept : m_data(arr), m_size(N)
+ {
+ }
+ template <size_t N>
+ constexpr array_ref(const std::array<T, N>& arr) noexcept : m_data(arr.data()), m_size(N)
+ {
+ }
+ template <size_t N>
+ constexpr array_ref(std::array<T, N>& arr) noexcept : m_data(arr.data()), m_size(N)
+ {
+ }
+ template <typename... Ts>
+ constexpr array_ref(const std::vector<T, Ts...>& vec) noexcept : m_data(vec.data()), m_size(vec.size())
+ {
+ }
+ template <typename... Ts, CMT_ENABLE_IF(sizeof...(Ts), is_const<T>::value)>
+ constexpr array_ref(const std::vector<remove_const<T>, Ts...>& vec) noexcept : m_data(vec.data()),
+ m_size(vec.size())
+ {
+ }
+ template <typename... Ts>
+ constexpr array_ref(std::vector<T, Ts...>& vec) noexcept : m_data(vec.data()), m_size(vec.size())
+ {
+ }
+ template <typename InputIter>
+ constexpr array_ref(InputIter first, InputIter last) noexcept : m_data(std::addressof(*first)),
+ m_size(std::distance(first, last))
+ {
+ }
+ constexpr array_ref(T* data, size_type size) noexcept : m_data(data), m_size(size) {}
+
+ constexpr reference front() const noexcept { return m_data[0]; }
+ constexpr reference back() const noexcept { return m_data[m_size - 1]; }
+ constexpr iterator begin() const noexcept { return m_data; }
+ constexpr iterator end() const noexcept { return m_data + m_size; }
+ constexpr const_iterator cbegin() const noexcept { return m_data; }
+ constexpr const_iterator cend() const noexcept { return m_data + m_size; }
+ constexpr pointer data() const noexcept { return m_data; }
+ constexpr std::size_t size() const noexcept { return m_size; }
+ constexpr bool empty() const noexcept { return !m_size; }
+ constexpr reference operator[](std::size_t index) const { return m_data[index]; }
+
+private:
+ pointer m_data;
+ size_type m_size;
+};
+
+template <typename T, std::size_t size>
+inline array_ref<T> make_array_ref(T (&data)[size])
+{
+ return array_ref<T>(data);
+}
+
+template <typename T>
+inline array_ref<T> make_array_ref(T* data, std::size_t size)
+{
+ return array_ref<T>(data, data + size);
+}
+
+template <typename Container, CMT_ENABLE_IF(has_data_size<Container>::value),
+ typename T = remove_pointer<decltype(std::declval<Container>().data())>>
+inline array_ref<T> make_array_ref(Container& cont)
+{
+ return array_ref<T>(cont.data(), cont.size());
+}
+
+template <typename Container, CMT_ENABLE_IF(has_data_size<Container>::value),
+ typename T = remove_pointer<decltype(std::declval<Container>().data())>>
+inline array_ref<const T> make_array_ref(const Container& cont)
+{
+ return array_ref<const T>(cont.data(), cont.size());
+}
+
+template <typename T>
+inline array_ref<T> make_array_ref(std::vector<T>& cont)
+{
+ return array_ref<T>(cont.data(), cont.size());
+}
+template <typename T>
+inline array_ref<const T> make_array_ref(const std::vector<T>& cont)
+{
+ return array_ref<const T>(cont.data(), cont.size());
+}
+}
diff --git a/include/kfr/cometa/cstring.hpp b/include/kfr/cometa/cstring.hpp
@@ -0,0 +1,141 @@
+/** @addtogroup cometa
+ * @{
+ */
+#pragma once
+
+#include "../cometa.hpp"
+#include <string>
+#include <utility>
+
+namespace cometa
+{
+
+namespace details
+{
+constexpr inline size_t strlen(const char* str) { return *str ? 1 + cometa::details::strlen(str + 1) : 0; }
+}
+
+template <size_t N>
+struct cstring
+{
+ using value_type = char;
+ using size_type = size_t;
+
+ constexpr const value_type* c_str() const noexcept { return value; }
+ constexpr const value_type* data() const noexcept { return value; }
+
+ const value_type value[N];
+ constexpr size_type length() const noexcept { return N - 1; }
+ constexpr size_type size() const noexcept { return N; }
+
+ constexpr friend bool operator==(const cstring& left, const cstring& right) noexcept
+ {
+ for (size_t i = 0; i < 1; i++)
+ if (left.value[i] != right.value[i])
+ return false;
+ return true;
+ }
+ constexpr friend bool operator!=(const cstring& left, const cstring& right) noexcept
+ {
+ return !(left == right);
+ }
+
+ template <size_t NN>
+ constexpr bool operator==(const cstring<NN>& other) const noexcept
+ {
+ return false;
+ }
+ template <size_t NN>
+ constexpr bool operator!=(const cstring<NN>& other) const noexcept
+ {
+ return true;
+ }
+ constexpr char operator[](size_t index) const noexcept { return value[index]; }
+};
+
+namespace details
+{
+
+template <size_t N, size_t... indices>
+CMT_INLINE constexpr cstring<N> make_cstring_impl(const char (&str)[N], csizes_t<indices...>)
+{
+ return { { str[indices]..., 0 } };
+}
+
+template <size_t N1, size_t N2, size_t... indices>
+CMT_INLINE constexpr cstring<N1 - 1 + N2 - 1 + 1> concat_str_impl(const cstring<N1>& str1,
+ const cstring<N2>& str2,
+ csizes_t<indices...>)
+{
+ constexpr size_t L1 = N1 - 1;
+ return { { (indices < L1 ? str1[indices] : str2[indices - L1])..., 0 } };
+}
+template <size_t N1, size_t N2, typename... Args>
+CMT_INLINE constexpr cstring<N1 - 1 + N2 - 1 + 1> concat_str_impl(const cstring<N1>& str1,
+ const cstring<N2>& str2)
+{
+ return concat_str_impl(str1, str2, csizeseq<N1 - 1 + N2 - 1>);
+}
+template <size_t N1, size_t Nfrom, size_t Nto, size_t... indices>
+CMT_INTRIN cstring<N1 - Nfrom + Nto> str_replace_impl(size_t pos, const cstring<N1>& str,
+ const cstring<Nfrom>&, const cstring<Nto>& to,
+ csizes_t<indices...>)
+{
+ if (pos == size_t(-1))
+ stop_constexpr();
+ return { { (indices < pos ? str[indices] : (indices < pos + Nto - 1) ? to[indices - pos]
+ : str[indices - Nto + Nfrom])...,
+ 0 } };
+}
+}
+
+CMT_INTRIN constexpr cstring<1> concat_cstring() { return { { 0 } }; }
+
+template <size_t N1>
+CMT_INTRIN constexpr cstring<N1> concat_cstring(const cstring<N1>& str1)
+{
+ return str1;
+}
+
+template <size_t N1, size_t N2, typename... Args>
+CMT_INTRIN constexpr auto concat_cstring(const cstring<N1>& str1, const cstring<N2>& str2,
+ const Args&... args)
+{
+ return details::concat_str_impl(str1, concat_cstring(str2, args...));
+}
+
+template <size_t N>
+CMT_INTRIN constexpr cstring<N> make_cstring(const char (&str)[N])
+{
+ return details::make_cstring_impl(str, csizeseq<N - 1>);
+}
+
+template <char... chars>
+CMT_INTRIN constexpr cstring<sizeof...(chars) + 1> make_cstring(cchars_t<chars...>)
+{
+ return { { chars..., 0 } };
+}
+
+template <size_t N1, size_t Nneedle>
+CMT_INTRIN size_t str_find(const cstring<N1>& str, const cstring<Nneedle>& needle)
+{
+ size_t count = 0;
+ for (size_t i = 0; i < N1; i++)
+ {
+ if (str[i] == needle[count])
+ count++;
+ else
+ count = 0;
+ if (count == Nneedle - 1)
+ return i + 1 - (Nneedle - 1);
+ }
+ return size_t(-1);
+}
+
+template <size_t N1, size_t Nfrom, size_t Nto>
+CMT_INTRIN cstring<N1 - Nfrom + Nto> str_replace(const cstring<N1>& str, const cstring<Nfrom>& from,
+ const cstring<Nto>& to)
+{
+ return details::str_replace_impl(str_find(str, from), str, from, to, csizeseq<N1 - Nfrom + Nto - 1>);
+}
+}
diff --git a/include/kfr/cometa/ctti.hpp b/include/kfr/cometa/ctti.hpp
@@ -0,0 +1,100 @@
+/** @addtogroup cometa
+ * @{
+ */
+#pragma once
+
+#include "../cometa.hpp"
+#include "cstring.hpp"
+
+namespace cometa
+{
+using pconstvoid = const void*;
+
+struct type_id_t
+{
+ constexpr type_id_t(const void* id) noexcept : id(id) {}
+ constexpr bool operator==(type_id_t other) const { return id == other.id; }
+ constexpr bool operator!=(type_id_t other) const { return !(id == other.id); }
+ const void* const id;
+};
+
+namespace details
+{
+
+template <typename T>
+constexpr inline type_id_t typeident_impl() noexcept
+{
+ return type_id_t(pconstvoid(&typeident_impl<T>));
+}
+
+#ifdef CMT_COMPILER_CLANG
+constexpr size_t typename_prefix = sizeof("auto cometa::ctype_name() [T = ") - 1;
+constexpr size_t typename_postfix = sizeof("]") - 1;
+#else
+constexpr size_t typename_prefix = sizeof("constexpr auto cometa::ctype_name() [with T = ") - 1;
+constexpr size_t typename_postfix = sizeof("]") - 1;
+#endif
+
+template <size_t... indices, size_t Nout = 1 + sizeof...(indices)>
+constexpr cstring<Nout> gettypename_impl(const char* str, csizes_t<indices...>) noexcept
+{
+ return cstring<Nout>{ { (str[indices])..., 0 } };
+}
+}
+
+template <typename T>
+constexpr auto ctype_name() noexcept
+{
+ constexpr size_t length =
+ sizeof(CMT_FUNC_SIGNATURE) - 1 - details::typename_prefix - details::typename_postfix;
+ return details::gettypename_impl(CMT_FUNC_SIGNATURE + details::typename_prefix, csizeseq<length>);
+}
+
+/**
+ * @brief Gets the fully qualified name of the type, including namespace and
+ * template parameters (if any)
+ * @tparam T type
+ * @return name of the type
+ */
+template <typename T>
+inline const char* type_name() noexcept
+{
+ static const auto name = ctype_name<T>();
+ return name.c_str();
+}
+
+/**
+ * @brief Gets the fully qualified name of the type, including namespace and
+ * template parameters (if any)
+ * @param x value of specific type
+ * @return name of the type
+ */
+template <typename T>
+inline const char* type_name(T x) noexcept
+{
+ (void)x;
+ return type_name<T>();
+}
+
+/**
+ * @brief Gets unique value associated with the type
+ * @tparam T type
+ * @return value of type that supports operator== and operator!=
+ */
+template <typename T>
+constexpr inline type_id_t ctypeid()
+{
+ return details::typeident_impl<T>();
+}
+/**
+ * @brief Gets unique value associated with the type
+ * @param x value of specific type
+ * @return value of type that supports operator== and operator!=
+ */
+template <typename T>
+constexpr inline type_id_t ctypeid(T x)
+{
+ (void)x;
+ return details::typeident_impl<T>();
+}
+}
diff --git a/include/kfr/cometa/function.hpp b/include/kfr/cometa/function.hpp
@@ -0,0 +1,154 @@
+/** @addtogroup cometa
+ * @{
+ */
+#pragma once
+
+#include "../cometa.hpp"
+
+namespace cometa
+{
+
+namespace details
+{
+
+template <typename Result, typename... Args>
+struct virtual_function
+{
+ virtual Result operator()(Args... args) = 0;
+ virtual virtual_function* make_copy() const = 0;
+ CMT_INTRIN virtual ~virtual_function() = default;
+};
+
+template <typename Fn, typename Result, typename... Args>
+struct virtual_function_impl : virtual_function<Result, Args...>
+{
+public:
+ CMT_INTRIN virtual_function_impl(const Fn& fn) : fn(fn) {}
+ CMT_INTRIN Result operator()(Args... args) override final { return fn(args...); }
+ CMT_INTRIN virtual_function<Result, Args...>* make_copy() const override final
+ {
+ return new virtual_function_impl{ fn };
+ }
+ CMT_INTRIN ~virtual_function_impl() {}
+
+private:
+ Fn fn;
+};
+
+template <typename Fn>
+struct func_filter
+{
+ typedef Fn type;
+};
+template <typename Result, typename... Args>
+struct func_filter<Result(Args...)>
+{
+ typedef Result (*type)(Args...);
+};
+
+template <typename T>
+constexpr CMT_INTRIN T return_val() noexcept
+{
+ return {};
+}
+
+template <>
+constexpr CMT_INTRIN void return_val<void>() noexcept
+{
+}
+}
+
+template <typename>
+struct function;
+
+/**
+ * @brief std::function-like lightweight function wrapper
+ * @code
+ * function<int( float )> f = []( float x ){ return static_cast<int>( x ); };
+ * CHECK( f( 3.4f ) == 3 )
+ * @encode
+ */
+template <typename Result, typename... Args>
+struct function<Result(Args...)>
+{
+ using this_t = function<Result(Args...)>;
+
+ function(function&& other) : fn(other.fn) { other.fn = nullptr; }
+ function& operator=(function&& other)
+ {
+ fn = other.fn;
+ other.fn = nullptr;
+ return *this;
+ }
+
+ CMT_INTRIN function() : fn(nullptr) {}
+ CMT_INTRIN function(std::nullptr_t) : fn(nullptr) {}
+ template <typename Func>
+ CMT_INTRIN function(const Func& x)
+ : fn(new details::virtual_function_impl<typename details::func_filter<Func>::type, Result, Args...>(
+ x))
+ {
+ }
+ function(const this_t& other) : fn(other.fn ? other.fn->make_copy() : nullptr) {}
+ CMT_INTRIN function& operator=(const this_t& other)
+ {
+ if ((&other != this) && (other.fn))
+ {
+ auto* temp = other.fn->make_copy();
+ delete fn;
+ fn = temp;
+ }
+ return *this;
+ }
+ CMT_INTRIN function& operator=(std::nullptr_t)
+ {
+ delete fn;
+ fn = nullptr;
+ return *this;
+ }
+ template <typename Fn>
+ CMT_INTRIN function& operator=(const Fn& x)
+ {
+ using FnImpl =
+ details::virtual_function_impl<typename details::func_filter<Fn>::type, Result, Args...>;
+ FnImpl* temp = new FnImpl(x);
+ delete fn;
+ fn = temp;
+ return *this;
+ }
+ CMT_INTRIN Result operator()(Args... args) const { return (*fn)(std::forward<Args>(args)...); }
+ template <typename TResult>
+ CMT_INTRIN Result call(TResult&& default_result, Args... args) const
+ {
+ return fn ? (*fn)(std::forward<Args>(args)...) : std::forward<TResult>(default_result);
+ }
+ CMT_INTRIN explicit operator bool() const noexcept { return !!fn; }
+
+ CMT_INTRIN ~function() { delete fn; }
+private:
+ details::virtual_function<Result, Args...>* fn;
+};
+
+template <typename Ret, typename... Args, typename T, typename Fn, typename DefFn = fn_noop>
+CMT_INLINE function<Ret(Args...)> cdispatch(cvals_t<T>, identity<T>, Fn&&, DefFn&& deffn = DefFn())
+{
+ return [=](Args... args) CMT_INLINE_MEMBER -> Ret { return deffn(std::forward<Args>(args)...); };
+}
+
+template <typename Ret, typename... Args, typename T, T v0, T... values, typename Fn,
+ typename DefFn = fn_noop>
+inline function<Ret(Args...)> cdispatch(cvals_t<T, v0, values...>, identity<T> value, Fn&& fn,
+ DefFn&& deffn = DefFn())
+{
+ if (value == v0)
+ {
+ return [=](Args... args)
+ CMT_INLINE_MEMBER -> Ret { return fn(cval<T, v0>, std::forward<Args>(args)...); };
+ }
+ else
+ {
+ return cdispatch<Ret, Args...>(cvals_t<T, values...>(), value, std::forward<Fn>(fn),
+ std::forward<DefFn>(deffn));
+ }
+}
+}
diff --git a/include/kfr/cometa/named_arg.hpp b/include/kfr/cometa/named_arg.hpp
@@ -0,0 +1,30 @@
+/** @addtogroup cometa
+ * @{
+ */
+#pragma once
+
+#include "../cometa.hpp"
+
+namespace cometa
+{
+template <typename T>
+struct named_arg
+{
+ T value;
+ const char* name;
+};
+
+struct named
+{
+ constexpr named(const char* name) noexcept : name(name) {}
+
+ template <typename T>
+ CMT_INTRIN constexpr named_arg<T> operator=(T&& value)
+ {
+ return named_arg<T>{ std::forward<T>(value), name };
+ }
+ const char* name;
+};
+
+inline named operator""_arg(const char* name, size_t) { return name; }
+}
diff --git a/include/kfr/cometa/range.hpp b/include/kfr/cometa/range.hpp
@@ -0,0 +1,66 @@
+/** @addtogroup cometa
+ * @{
+ */
+#pragma once
+
+#include "../cometa.hpp"
+
+namespace cometa
+{
+template <typename T>
+struct range
+{
+ using value_type = T;
+ using reference = T&;
+ using const_reference = const T&;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using diff_type = decltype(std::declval<T>() - std::declval<T>());
+
+ constexpr range(value_type begin, value_type end, diff_type step) noexcept : value_begin(begin),
+ value_end(end),
+ step(step)
+ {
+ }
+
+ struct iterator
+ {
+ value_type value;
+ diff_type step;
+ const_reference operator*() const { return value; }
+ const_pointer operator->() const { return &value; }
+ iterator& operator++()
+ {
+ value += step;
+ return *this;
+ }
+ iterator operator++(int)
+ {
+ iterator copy = *this;
+ ++(*this);
+ return copy;
+ }
+ bool operator!=(const iterator& other) const
+ {
+ return step > 0 ? value < other.value : value > other.value;
+ }
+ };
+ value_type value_begin;
+ value_type value_end;
+ diff_type step;
+ iterator begin() const { return iterator{ value_begin, step }; }
+ iterator end() const { return iterator{ value_end, step }; }
+};
+
+template <typename T>
+range<T> make_range(T begin, T end)
+{
+ return range<T>(begin, end, end > begin ? 1 : -1);
+}
+
+template <typename T, typename diff_type = decltype(std::declval<T>() - std::declval<T>())>
+range<T> make_range(T begin, T end, diff_type step)
+{
+ return range<T>(begin, end, step);
+}
+}
diff --git a/include/kfr/cometa/result.hpp b/include/kfr/cometa/result.hpp
@@ -0,0 +1,50 @@
+/** @addtogroup cometa
+ * @{
+ */
+#pragma once
+
+#include "../cometa.hpp"
+
+namespace cometa
+{
+template <typename Type, typename ErrEnum, ErrEnum OkValue = static_cast<ErrEnum>(0)>
+struct result
+{
+ using value_type = Type;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+
+ using error_type = ErrEnum;
+
+ constexpr static error_type ok_value = OkValue;
+
+ constexpr result(const result&) = default;
+ constexpr result(result&&) noexcept = default;
+
+ constexpr result(ErrEnum error) noexcept : m_error(error) {}
+
+ template <typename ValueInit, CMT_ENABLE_IF(std::is_constructible<value_type, ValueInit>::value)>
+ constexpr result(ValueInit&& value) noexcept : m_value(std::forward<ValueInit>(value)), m_error(OkValue)
+ {
+ }
+
+ constexpr result(const Type& value) noexcept : m_value(value), m_error(OkValue) {}
+ constexpr result(Type&& value) noexcept : m_value(std::move(value)), m_error(OkValue) {}
+
+ constexpr explicit operator bool() const { return m_error == OkValue; }
+ constexpr const_reference operator*() const { return m_value; }
+ constexpr reference operator*() { return m_value; }
+ constexpr const_pointer operator->() const { return &m_value; }
+ constexpr pointer operator->() { return &m_value; }
+
+ constexpr const_reference value() const { return m_value; }
+ constexpr reference value() { return m_value; }
+ constexpr ErrEnum error() const { return m_error; }
+ constexpr bool ok() const { return m_error == OkValue; }
+private:
+ Type m_value;
+ ErrEnum m_error;
+};
+}
diff --git a/include/kfr/cometa/string.hpp b/include/kfr/cometa/string.hpp
@@ -4,6 +4,9 @@
#pragma once
#include "../cometa.hpp"
+#include "cstring.hpp"
+#include "ctti.hpp"
+#include "named_arg.hpp"
#include <array>
#include <cstdio>
#include <string>
diff --git a/include/kfr/cometa/tuple.hpp b/include/kfr/cometa/tuple.hpp
@@ -0,0 +1,40 @@
+/** @addtogroup cometa
+ * @{
+ */
+#pragma once
+
+#include <tuple>
+
+namespace cometa
+{
+
+template <typename T, T...>
+struct cvals_t;
+
+template <size_t... values>
+using csizes_t = cvals_t<size_t, values...>;
+
+struct swallow;
+
+namespace details
+{
+
+
+template <typename T, size_t Nsize, T Nstart, ptrdiff_t Nstep>
+struct cvalseq_impl;
+
+template <typename... Ts, typename Fn, size_t... indices>
+void cforeach_tuple_impl(const std::tuple<Ts...>& tuple, Fn&& fn, csizes_t<indices...>)
+{
+ swallow{ (fn(std::get<indices>(tuple)), void(), 0)... };
+}
+}
+
+template <typename... Ts, typename Fn>
+void cforeach(const std::tuple<Ts...>& tuple, Fn&& fn)
+{
+ details::cforeach_tuple_impl(tuple, std::forward<Fn>(fn), typename details::cvalseq_impl<size_t, sizeof...(Ts), 0, 1>::type());
+}
+}
+
+#include "../cometa.hpp"
diff --git a/sources.cmake b/sources.cmake
@@ -56,7 +56,15 @@ set(
${PROJECT_SOURCE_DIR}/include/kfr/base/intrinsics.h
${PROJECT_SOURCE_DIR}/include/kfr/base/kfr.h
${PROJECT_SOURCE_DIR}/include/kfr/base/specializations.i
+ ${PROJECT_SOURCE_DIR}/include/kfr/cometa/array.hpp
+ ${PROJECT_SOURCE_DIR}/include/kfr/cometa/cstring.hpp
+ ${PROJECT_SOURCE_DIR}/include/kfr/cometa/ctti.hpp
+ ${PROJECT_SOURCE_DIR}/include/kfr/cometa/function.hpp
+ ${PROJECT_SOURCE_DIR}/include/kfr/cometa/named_arg.hpp
+ ${PROJECT_SOURCE_DIR}/include/kfr/cometa/range.hpp
+ ${PROJECT_SOURCE_DIR}/include/kfr/cometa/result.hpp
${PROJECT_SOURCE_DIR}/include/kfr/cometa/string.hpp
+ ${PROJECT_SOURCE_DIR}/include/kfr/cometa/tuple.hpp
${PROJECT_SOURCE_DIR}/include/kfr/data/bitrev.hpp
${PROJECT_SOURCE_DIR}/include/kfr/data/sincos.hpp
${PROJECT_SOURCE_DIR}/include/kfr/dft/bitrev.hpp
diff --git a/tests/dft_test.cpp b/tests/dft_test.cpp
@@ -4,9 +4,9 @@
* See LICENSE.txt for details
*/
+#include "testo/testo.hpp"
#include <kfr/io/tostring.hpp>
-#include "testo/testo.hpp"
#include <kfr/base.hpp>
#include <kfr/dft.hpp>
#include <kfr/dsp.hpp>
diff --git a/tests/testo/testo.hpp b/tests/testo/testo.hpp
@@ -1,10 +1,13 @@
#pragma once
+#include <kfr/cometa/tuple.hpp>
#include <kfr/cometa.hpp>
#include <kfr/cometa/string.hpp>
+#include <kfr/cometa/range.hpp>
#include <ctime>
#include <functional>
+#include <algorithm>
#include <sstream>
#include <utility>
#include <vector>