-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor the test suite: extract SMF policies into a separate header …
…because I am going to need that for the variant #verification #docs #sonar
- Loading branch information
1 parent
533f132
commit de91978
Showing
4 changed files
with
341 additions
and
287 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,312 @@ | ||
/// @file | ||
/// CETL VerificAtion SuiTe – Test suite helpers. | ||
/// | ||
/// @copyright | ||
/// Copyright (C) OpenCyphal Development Team <opencyphal.org> | ||
/// Copyright Amazon.com Inc. or its affiliates. | ||
/// SPDX-License-Identifier: MIT | ||
/// | ||
|
||
#ifndef CETLVAST_SMF_POLICIES_HPP_INCLUDED | ||
#define CETLVAST_SMF_POLICIES_HPP_INCLUDED | ||
|
||
#include <cetl/pf17/attribute.hpp> | ||
#include <cstdint> | ||
|
||
namespace cetlvast | ||
{ | ||
namespace smf_policies | ||
{ | ||
/// This has to be an old-style enum because C++14 requires it to be convertible to int. | ||
enum special_function_policy | ||
{ | ||
policy_deleted = 0, | ||
policy_trivial = 1, | ||
policy_nontrivial = 2, | ||
}; | ||
|
||
/// COPY CONSTRUCTION POLICY | ||
template <std::uint8_t> | ||
struct copy_ctor_policy; | ||
template <> | ||
struct copy_ctor_policy<policy_nontrivial> | ||
{ | ||
static constexpr auto copy_ctor_policy_value = policy_nontrivial; | ||
copy_ctor_policy() = default; | ||
copy_ctor_policy(const copy_ctor_policy& other) | ||
: copy_constructed{other.copy_constructed + 1U} | ||
{ | ||
} | ||
copy_ctor_policy(copy_ctor_policy&&) = default; | ||
copy_ctor_policy& operator=(const copy_ctor_policy&) = default; | ||
copy_ctor_policy& operator=(copy_ctor_policy&&) = default; | ||
~copy_ctor_policy() = default; | ||
CETL_NODISCARD auto get_copy_ctor_count() const | ||
{ | ||
return copy_constructed; | ||
} | ||
std::uint32_t copy_constructed = 0; | ||
}; | ||
template <> | ||
struct copy_ctor_policy<policy_trivial> | ||
{ | ||
static constexpr auto copy_ctor_policy_value = policy_trivial; | ||
CETL_NODISCARD auto get_copy_ctor_count() const | ||
{ | ||
(void) this; | ||
return 0U; | ||
} | ||
}; | ||
template <> | ||
struct copy_ctor_policy<policy_deleted> | ||
{ | ||
static constexpr auto copy_ctor_policy_value = policy_deleted; | ||
copy_ctor_policy() = default; | ||
copy_ctor_policy(const copy_ctor_policy&) = delete; | ||
copy_ctor_policy(copy_ctor_policy&&) = default; | ||
copy_ctor_policy& operator=(const copy_ctor_policy&) = default; | ||
copy_ctor_policy& operator=(copy_ctor_policy&&) = default; | ||
~copy_ctor_policy() = default; | ||
CETL_NODISCARD auto get_copy_ctor_count() const | ||
{ | ||
(void) this; | ||
return 0U; | ||
} | ||
}; | ||
|
||
/// MOVE CONSTRUCTION POLICY | ||
template <std::uint8_t> | ||
struct move_ctor_policy; | ||
template <> | ||
struct move_ctor_policy<policy_nontrivial> | ||
{ | ||
static constexpr auto move_ctor_policy_value = policy_nontrivial; | ||
move_ctor_policy() = default; | ||
move_ctor_policy(const move_ctor_policy&) = default; | ||
move_ctor_policy(move_ctor_policy&& other) noexcept | ||
: move_constructed{other.move_constructed + 1U} | ||
{ | ||
} | ||
move_ctor_policy& operator=(const move_ctor_policy&) = default; | ||
move_ctor_policy& operator=(move_ctor_policy&&) = default; | ||
~move_ctor_policy() = default; | ||
CETL_NODISCARD auto get_move_ctor_count() const | ||
{ | ||
return move_constructed; | ||
} | ||
std::uint32_t move_constructed = 0; | ||
}; | ||
template <> | ||
struct move_ctor_policy<policy_trivial> | ||
{ | ||
static constexpr auto move_ctor_policy_value = policy_trivial; | ||
CETL_NODISCARD auto get_move_ctor_count() const | ||
{ | ||
(void) this; | ||
return 0U; | ||
} | ||
}; | ||
template <> | ||
struct move_ctor_policy<policy_deleted> | ||
{ | ||
static constexpr auto move_ctor_policy_value = policy_deleted; | ||
move_ctor_policy() = default; | ||
move_ctor_policy(const move_ctor_policy&) = default; | ||
move_ctor_policy(move_ctor_policy&&) = delete; | ||
move_ctor_policy& operator=(const move_ctor_policy&) = default; | ||
move_ctor_policy& operator=(move_ctor_policy&&) = default; | ||
~move_ctor_policy() = default; | ||
CETL_NODISCARD auto get_move_ctor_count() const | ||
{ | ||
(void) this; | ||
return 0U; | ||
} | ||
}; | ||
|
||
/// COPY ASSIGNMENT POLICY | ||
template <std::uint8_t> | ||
struct copy_assignment_policy; | ||
template <> | ||
struct copy_assignment_policy<policy_nontrivial> | ||
{ | ||
static constexpr auto copy_assignment_policy_value = policy_nontrivial; | ||
copy_assignment_policy() = default; | ||
copy_assignment_policy(const copy_assignment_policy&) = default; | ||
copy_assignment_policy(copy_assignment_policy&&) = default; | ||
copy_assignment_policy& operator=(const copy_assignment_policy& other) | ||
{ | ||
copy_assigned = other.copy_assigned + 1U; | ||
return *this; | ||
} | ||
copy_assignment_policy& operator=(copy_assignment_policy&&) = default; | ||
~copy_assignment_policy() = default; | ||
CETL_NODISCARD auto get_copy_assignment_count() const | ||
{ | ||
return copy_assigned; | ||
} | ||
std::uint32_t copy_assigned = 0; | ||
}; | ||
template <> | ||
struct copy_assignment_policy<policy_trivial> | ||
{ | ||
static constexpr auto copy_assignment_policy_value = policy_trivial; | ||
CETL_NODISCARD auto get_copy_assignment_count() const | ||
{ | ||
(void) this; | ||
return 0U; | ||
} | ||
}; | ||
template <> | ||
struct copy_assignment_policy<policy_deleted> | ||
{ | ||
static constexpr auto copy_assignment_policy_value = policy_deleted; | ||
copy_assignment_policy() = default; | ||
copy_assignment_policy(const copy_assignment_policy&) = default; | ||
copy_assignment_policy(copy_assignment_policy&&) = default; | ||
copy_assignment_policy& operator=(const copy_assignment_policy&) = delete; | ||
copy_assignment_policy& operator=(copy_assignment_policy&&) = default; | ||
~copy_assignment_policy() = default; | ||
CETL_NODISCARD auto get_copy_assignment_count() const | ||
{ | ||
(void) this; | ||
return 0U; | ||
} | ||
}; | ||
|
||
/// MOVE ASSIGNMENT POLICY | ||
template <std::uint8_t> | ||
struct move_assignment_policy; | ||
template <> | ||
struct move_assignment_policy<policy_nontrivial> | ||
{ | ||
static constexpr auto move_assignment_policy_value = policy_nontrivial; | ||
move_assignment_policy() = default; | ||
move_assignment_policy(const move_assignment_policy&) = default; | ||
move_assignment_policy(move_assignment_policy&&) = default; | ||
move_assignment_policy& operator=(const move_assignment_policy&) = default; | ||
move_assignment_policy& operator=(move_assignment_policy&& other) noexcept | ||
{ | ||
move_assigned = other.move_assigned + 1U; | ||
return *this; | ||
} | ||
~move_assignment_policy() = default; | ||
CETL_NODISCARD auto get_move_assignment_count() const | ||
{ | ||
return move_assigned; | ||
} | ||
std::uint32_t move_assigned = 0; | ||
}; | ||
template <> | ||
struct move_assignment_policy<policy_trivial> | ||
{ | ||
static constexpr auto move_assignment_policy_value = policy_trivial; | ||
CETL_NODISCARD auto get_move_assignment_count() const | ||
{ | ||
(void) this; | ||
return 0U; | ||
} | ||
}; | ||
template <> | ||
struct move_assignment_policy<policy_deleted> | ||
{ | ||
static constexpr auto move_assignment_policy_value = policy_deleted; | ||
move_assignment_policy() = default; | ||
move_assignment_policy(const move_assignment_policy&) = default; | ||
move_assignment_policy(move_assignment_policy&&) = default; | ||
move_assignment_policy& operator=(const move_assignment_policy&) = default; | ||
move_assignment_policy& operator=(move_assignment_policy&&) = delete; | ||
~move_assignment_policy() = default; | ||
CETL_NODISCARD auto get_move_assignment_count() const | ||
{ | ||
(void) this; | ||
return 0U; | ||
} | ||
}; | ||
|
||
/// DESTRUCTION POLICY | ||
/// Before the object is destroyed, the destruction counter should be configured by calling | ||
/// configure_destruction_counter. The reason we don't keep the destruction counter as a member variable is that | ||
/// we can't safely access it after the object is destroyed. | ||
/// The trivial destruction policy does not maintain the destruction counter and the method does nothing. | ||
template <std::uint8_t> | ||
struct dtor_policy; | ||
template <> | ||
struct dtor_policy<policy_nontrivial> | ||
{ | ||
static constexpr auto dtor_policy_value = policy_nontrivial; | ||
dtor_policy() = default; | ||
dtor_policy(const dtor_policy&) = default; | ||
dtor_policy(dtor_policy&&) noexcept = default; | ||
dtor_policy& operator=(const dtor_policy&) = default; | ||
dtor_policy& operator=(dtor_policy&&) noexcept = default; | ||
~dtor_policy() | ||
{ | ||
if (nullptr != destructed) | ||
{ | ||
++*destructed; | ||
} | ||
} | ||
void configure_destruction_counter(std::uint32_t* const counter) | ||
{ | ||
destructed = counter; | ||
} | ||
std::uint32_t* destructed = nullptr; | ||
}; | ||
template <> | ||
struct dtor_policy<policy_trivial> | ||
{ | ||
static constexpr auto dtor_policy_value = policy_trivial; | ||
void configure_destruction_counter(std::uint32_t* const) {} | ||
}; | ||
template <> | ||
struct dtor_policy<policy_deleted> | ||
{ | ||
static constexpr auto dtor_policy_value = policy_deleted; | ||
dtor_policy() = default; | ||
dtor_policy(const dtor_policy&) = default; | ||
dtor_policy(dtor_policy&&) = default; | ||
dtor_policy& operator=(const dtor_policy&) = default; | ||
dtor_policy& operator=(dtor_policy&&) = default; | ||
~dtor_policy() = delete; | ||
void configure_destruction_counter(std::uint32_t* const) {} | ||
}; | ||
|
||
/// Creates a new type that inherits from all the given types in the specified order. | ||
/// The list of types shall be given in a typelist container, like std::tuple. | ||
template <typename> | ||
struct combine_bases; | ||
template <template <typename...> class Q, typename... Ts> | ||
struct combine_bases<Q<Ts...>> : public Ts... | ||
{}; | ||
|
||
namespace self_check | ||
{ | ||
template <std::uint8_t P, std::uint8_t DtorPolicy = P> | ||
using same_policy = combine_bases<std::tuple<copy_ctor_policy<P>, | ||
move_ctor_policy<P>, | ||
copy_assignment_policy<P>, | ||
move_assignment_policy<P>, | ||
dtor_policy<DtorPolicy>>>; | ||
// | ||
static_assert(std::is_trivially_copy_constructible<same_policy<policy_trivial>>::value, ""); | ||
static_assert(std::is_trivially_move_constructible<same_policy<policy_trivial>>::value, ""); | ||
static_assert(std::is_trivially_copy_assignable<same_policy<policy_trivial>>::value, ""); | ||
static_assert(std::is_trivially_move_assignable<same_policy<policy_trivial>>::value, ""); | ||
static_assert(std::is_trivially_destructible<same_policy<policy_trivial>>::value, ""); | ||
// | ||
static_assert(!std::is_trivially_copy_constructible<same_policy<policy_nontrivial>>::value, ""); | ||
static_assert(!std::is_trivially_move_constructible<same_policy<policy_nontrivial>>::value, ""); | ||
static_assert(!std::is_trivially_copy_assignable<same_policy<policy_nontrivial>>::value, ""); | ||
static_assert(!std::is_trivially_move_assignable<same_policy<policy_nontrivial>>::value, ""); | ||
static_assert(!std::is_trivially_destructible<same_policy<policy_nontrivial>>::value, ""); | ||
// | ||
static_assert(!std::is_copy_constructible<same_policy<policy_deleted, policy_trivial>>::value, ""); | ||
static_assert(!std::is_move_constructible<same_policy<policy_deleted, policy_trivial>>::value, ""); | ||
static_assert(!std::is_copy_assignable<same_policy<policy_deleted, policy_trivial>>::value, ""); | ||
static_assert(!std::is_move_assignable<same_policy<policy_deleted, policy_trivial>>::value, ""); | ||
} // namespace self_check | ||
|
||
} // namespace smf_policies | ||
} // namespace cetlvast | ||
|
||
#endif // CETLVAST_SMF_POLICIES_HPP_INCLUDED |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.