kfr

Fast, modern C++ DSP framework, FFT, Sample Rate Conversion, FIR/IIR/Biquad Filters (SSE, AVX, AVX-512, ARM NEON)
Log | Files | Refs | README

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:
Mexamples/dft.cpp | 2+-
Minclude/kfr/base.hpp | 2+-
Minclude/kfr/base/expression.hpp | 2++
Minclude/kfr/base/types.hpp | 9+++------
Minclude/kfr/base/univector.hpp | 2++
Minclude/kfr/cometa.hpp | 615++-----------------------------------------------------------------------------
Ainclude/kfr/cometa/array.hpp | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/kfr/cometa/cstring.hpp | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/kfr/cometa/ctti.hpp | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/kfr/cometa/function.hpp | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/kfr/cometa/named_arg.hpp | 30++++++++++++++++++++++++++++++
Ainclude/kfr/cometa/range.hpp | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/kfr/cometa/result.hpp | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/kfr/cometa/string.hpp | 3+++
Ainclude/kfr/cometa/tuple.hpp | 40++++++++++++++++++++++++++++++++++++++++
Msources.cmake | 8++++++++
Mtests/dft_test.cpp | 2+-
Mtests/testo/testo.hpp | 3+++
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>