Skip to content

Commit

Permalink
Refactor the test suite: extract SMF policies into a separate header …
Browse files Browse the repository at this point in the history
…because I am going to need that for the variant #verification #docs #sonar
  • Loading branch information
pavel-kirienko committed Feb 23, 2024
1 parent 533f132 commit de91978
Show file tree
Hide file tree
Showing 4 changed files with 341 additions and 287 deletions.
312 changes: 312 additions & 0 deletions cetlvast/include/cetlvast/smf_policies.hpp
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
13 changes: 13 additions & 0 deletions cetlvast/include/cetlvast/typelist.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,19 @@ class into
using from = typename impl<Ts...>::type;
};

// ------------------------------------------------------------------------------------------------

/// Takes two arguments: a single-argument template F and a typelist Q.
/// Creates a new typelist of the same container type as Q by applying F to each type in Q.
/// E.g., map<std::add_pointer_t, std::tuple<int, char>> results in std::tuple<int*, char*>.
template <template <typename> class, typename>
struct map;
template <template <typename> class F, template <typename...> class Q, typename... Ts>
struct map<F, Q<Ts...>>
{
using type = Q<F<Ts>...>;
};

} // namespace typelist
} // namespace cetlvast

Expand Down
Loading

0 comments on commit de91978

Please sign in to comment.