Skip to content

Commit

Permalink
Add utility::metrics and simple tests (#214)
Browse files Browse the repository at this point in the history
  • Loading branch information
Morwenn committed May 19, 2023
1 parent 3a5a691 commit ae34841
Show file tree
Hide file tree
Showing 4 changed files with 266 additions and 19 deletions.
31 changes: 30 additions & 1 deletion include/cpp-sort/detail/type_traits.h
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2022 Morwenn
* Copyright (c) 2015-2023 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_DETAIL_TYPE_TRAITS_H_
Expand Down Expand Up @@ -357,6 +357,35 @@ namespace detail

template<std::size_t Value>
constexpr bool is_in_pack<Value> = false;

////////////////////////////////////////////////////////////
// index_of: return the index of the first occurence of a
// type in a list of type, or -1 if the type is not in the
// list

template<typename Needle, typename... Haystack>
struct index_of_impl;

template<typename Needle>
struct index_of_impl<Needle>
{
static constexpr int value = -1;
};

template<typename Needle, typename... Tail>
struct index_of_impl<Needle, Needle, Tail...>
{
static constexpr int value = 0;
};

template<typename Needle, typename Head, typename... Tail>
struct index_of_impl<Needle, Head, Tail...>
{
static constexpr int value = index_of_impl<Needle, Tail...>::value + 1;
};

template<typename Needle, typename... Haystack>
constexpr int index_of = index_of_impl<Needle, Haystack...>::value;
}}

#endif // CPPSORT_DETAIL_TYPE_TRAITS_H_
141 changes: 123 additions & 18 deletions include/cpp-sort/utility/metrics_tools.h
Expand Up @@ -86,14 +86,23 @@ namespace utility
return *this;
}

template<typename U>
constexpr auto operator=(const metric<U, Tag>& other)
noexcept(std::is_nothrow_copy_assignable<U>::value)
-> metric&
{
_value = other.value();
return *this;
}

////////////////////////////////////////////////////////////
// Comparison operators

template<typename T1, typename T2>
friend constexpr auto operator==(const metric<T1, Tag>& lhs, const metric<T2, Tag>& rhs)
template<typename U>
friend constexpr auto operator==(const metric& lhs, const metric<U, Tag>& rhs)
-> bool
{
return lhs._value == rhs._value;
return lhs._value == rhs.value();
}

friend constexpr auto operator==(const metric& lhs, const T& rhs)
Expand All @@ -108,11 +117,11 @@ namespace utility
return lhs == rhs._value;
}

template<typename T1, typename T2>
friend constexpr auto operator!=(const metric<T1, Tag>& lhs, const metric<T2, Tag>& rhs)
template<typename U>
friend constexpr auto operator!=(const metric& lhs, const metric<U, Tag>& rhs)
-> bool
{
return lhs._value != rhs._value;
return lhs._value != rhs.value();
}

friend constexpr auto operator!=(const metric& lhs, const T& rhs)
Expand All @@ -130,11 +139,11 @@ namespace utility
////////////////////////////////////////////////////////////
// Relational operators

template<typename T1, typename T2>
friend constexpr auto operator<(const metric<T1, Tag>& lhs, const metric<T2, Tag>& rhs)
template<typename U>
friend constexpr auto operator<(const metric& lhs, const metric<U, Tag>& rhs)
-> bool
{
return lhs._value < rhs._value;
return lhs._value < rhs.value();
}

friend constexpr auto operator<(const metric& lhs, const T& rhs)
Expand All @@ -149,11 +158,11 @@ namespace utility
return lhs < rhs._value;
}

template<typename T1, typename T2>
friend constexpr auto operator<=(const metric<T1, Tag>& lhs, const metric<T2, Tag>& rhs)
template<typename U>
friend constexpr auto operator<=(const metric& lhs, const metric<U, Tag>& rhs)
-> bool
{
return lhs._value <= rhs._value;
return lhs._value <= rhs.value();
}

friend constexpr auto operator<=(const metric& lhs, const T& rhs)
Expand All @@ -168,11 +177,11 @@ namespace utility
return lhs <= rhs._value;
}

template<typename T1, typename T2>
friend constexpr auto operator>(const metric<T1, Tag>& lhs, const metric<T2, Tag>& rhs)
template<typename U>
friend constexpr auto operator>(const metric& lhs, const metric<U, Tag>& rhs)
-> bool
{
return lhs._value > rhs._value;
return lhs._value > rhs.value();
}

friend constexpr auto operator>(const metric& lhs, const T& rhs)
Expand All @@ -187,11 +196,11 @@ namespace utility
return lhs > rhs._value;
}

template<typename T1, typename T2>
friend constexpr auto operator>=(const metric<T1, Tag>& lhs, const metric<T2, Tag>& rhs)
template<typename U>
friend constexpr auto operator>=(const metric& lhs, const metric<U, Tag>& rhs)
-> bool
{
return lhs._value >= rhs._value;
return lhs._value >= rhs.value();
}

friend constexpr auto operator>=(const metric& lhs, const T& rhs)
Expand All @@ -216,6 +225,102 @@ namespace utility
return stream;
}
};

////////////////////////////////////////////////////////////
// metrics<metric<T1, Tag1>, metric<T2, Tag2>...>

template<typename... Args>
class metrics;

template<typename... TT, typename... Tags>
class metrics<metric<TT, Tags>...>
{
private:

std::tuple<metric<TT, Tags>...> metrics_;

public:

////////////////////////////////////////////////////////////
// Construction

metrics() = default;
metrics(const metrics&) = default;
metrics(metrics&&) = default;

template<typename... Args>
constexpr explicit metrics(Args&&... args):
metrics_(std::forward<Args>(args)...)
{}

////////////////////////////////////////////////////////////
// operator=

metrics& operator=(const metrics&) = default;
metrics& operator=(metrics&&) = default;

////////////////////////////////////////////////////////////
// Index-based get()

template<std::size_t Idx>
friend constexpr auto get(metrics& mm)
-> std::tuple_element_t<Idx, std::tuple<metric<TT, Tags>...>>&
{
return std::get<Idx>(mm.metrics_);
}

template<std::size_t Idx>
friend constexpr auto get(const metrics& mm)
-> const std::tuple_element_t<Idx, std::tuple<metric<TT, Tags>...>>&
{
return std::get<Idx>(mm.metrics_);
}

template<std::size_t Idx>
friend constexpr auto get(metrics&& mm)
-> std::tuple_element_t<Idx, std::tuple<metric<TT, Tags>...>>&&
{
return std::get<Idx>(std::move(mm).metrics_);
}

template<std::size_t Idx>
friend constexpr auto get(const metrics&& mm)
-> const std::tuple_element_t<Idx, std::tuple<metric<TT, Tags>...>>&&
{
return std::get<Idx>(std::move(mm).metrics_);
}

////////////////////////////////////////////////////////////
// Tag-based get()

template<typename Tag, std::size_t Idx=cppsort::detail::index_of<Tag, Tags...>>
friend constexpr auto get(metrics& mm)
-> std::tuple_element_t<Idx, std::tuple<metric<TT, Tags>...>>&
{
return std::get<Idx>(mm.metrics_);
}

template<typename Tag, std::size_t Idx=cppsort::detail::index_of<Tag, Tags...>>
friend constexpr auto get(const metrics& mm)
-> const std::tuple_element_t<Idx, std::tuple<metric<TT, Tags>...>>&
{
return std::get<Idx>(mm.metrics_);
}

template<typename Tag, std::size_t Idx=cppsort::detail::index_of<Tag, Tags...>>
friend constexpr auto get(metrics&& mm)
-> std::tuple_element_t<Idx, std::tuple<metric<TT, Tags>...>>&&
{
return std::get<Idx>(std::move(mm).metrics_);
}

template<typename Tag, std::size_t Idx=cppsort::detail::index_of<Tag, Tags...>>
friend constexpr auto get(const metrics&& mm)
-> const std::tuple_element_t<Idx, std::tuple<metric<TT, Tags>...>>&&
{
return std::get<Idx>(std::move(mm).metrics_);
}
};
}}

#endif // CPPSORT_UTILITY_METRICS_TOOLS_H_
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Expand Up @@ -234,6 +234,7 @@ add_executable(main-tests
utility/buffer.cpp
utility/chainable_projections.cpp
utility/iter_swap.cpp
utility/metric_tools.cpp
utility/sorted_indices.cpp
utility/sorted_iterators.cpp
utility/sorting_networks.cpp
Expand Down
112 changes: 112 additions & 0 deletions tests/utility/metric_tools.cpp
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2023 Morwenn
* SPDX-License-Identifier: MIT
*/
#include <chrono>
#include <utility>
#include <catch2/catch_test_macros.hpp>
#include <cpp-sort/sorter_facade.h>
#include <cpp-sort/utility/adapter_storage.h>
#include <cpp-sort/utility/metrics_tools.h>

namespace
{
struct foo_tag {};

template<typename Sorter>
struct foo_metric_impl
{
using tag_t = foo_tag;
using metric_t = cppsort::utility::metric<int, tag_t>;

foo_metric_impl() = default;

constexpr explicit foo_metric_impl(Sorter&& sorter):
cppsort::utility::adapter_storage<Sorter>(std::move(sorter))
{}

template<typename ForwardIterator>
auto operator()(ForwardIterator first, ForwardIterator last) const
-> metric_t
{
return metric_t(42);
}
};

template<typename Sorter>
struct foo_metric:
cppsort::sorter_facade<foo_metric_impl<Sorter>>
{
foo_metric() = default;

constexpr explicit foo_metric(Sorter sorter):
cppsort::sorter_facade<foo_metric_impl<Sorter>>(std::move(sorter))
{}
};

struct bar_tag {};

template<typename Sorter>
struct bar_metric_impl
{
using tag_t = foo_tag;
using metric_t = cppsort::utility::metric<double, tag_t>;

bar_metric_impl() = default;

constexpr explicit bar_metric_impl(Sorter&& sorter):
cppsort::utility::adapter_storage<Sorter>(std::move(sorter))
{}

template<typename ForwardIterator>
auto operator()(ForwardIterator first, ForwardIterator last) const
-> metric_t
{
return metric_t(145.0);
}
};

template<typename Sorter>
struct bar_metric:
cppsort::sorter_facade<bar_metric_impl<Sorter>>
{
bar_metric() = default;

constexpr explicit bar_metric(Sorter sorter):
cppsort::sorter_facade<bar_metric_impl<Sorter>>(std::move(sorter))
{}
};
}

TEST_CASE("simple utility::metric tests", "[utility][metrics]")
{
using namespace cppsort::utility;
using namespace std::chrono_literals;

struct time_tag {};

constexpr metric<std::chrono::seconds, time_tag> m1(5s);
constexpr metric<std::chrono::milliseconds, time_tag> m2(5000ms);
constexpr metric<std::chrono::milliseconds, time_tag> m3(4000ms);
STATIC_CHECK( m1 == m2 );
STATIC_CHECK( m3 != m2 );
STATIC_CHECK( m3 < m1 );
}

TEST_CASE("simple utility::metrics tests", "[utility][metrics]")
{
using std::get;
using namespace cppsort::utility;

using metric1 = metric<int, foo_tag>;
using metric2 = metric<float, bar_tag>;

metrics<metric1, metric2> mm(metric1(42), metric2(140.0));
auto& m1 = get<foo_tag>(mm);
CHECK( m1 == 42 );
auto m2 = get<bar_tag>(mm);
CHECK( m2 == 140.0 );

get<foo_tag>(mm) = 35;
CHECK( m1 == 35 );
}

0 comments on commit ae34841

Please sign in to comment.