CETL's cetl::any - #113
CETL's cetl::any#113
cetl::any#113Conversation
…TTI yet. (#102) - Implemented most of constructors (close to `std::any`). - Added implementation of 3 `operator=`-s. - Added first 2 overloads of `any_cast`. - Added `make_any` overloads. - Implemented `has_value`, `emplace`, `swap` & `reset`. - `cetl::bad_any_cast` now alias to `cetl::pf17::bad_any_cast `. Also: - Appended `is_in_place_type_v` and `is_in_place_index_v` constexpr-s. - Applied clang format to `utility.hpp` header file. Related to #83 --------- Co-authored-by: Sergei Shirokov <sergei@Sergeis-Mac-mini.local>
…tures. (#104) - Added "value return" overloads of any_cast (#1️⃣, 2️⃣ & 3️⃣). - Added std::initializer_list overloads for - ctor (#6️⃣) - `emplace` (#2️⃣) - `make_any` (#2️⃣) - Added corresponding unit tests, plus more cases to increase coverage. Notes for to be continued... - `Align` param fixes will be in the next pr. - Copyable/Movable (as well as elimination of various `const_cast`) will be in the after next pr. --------- Co-authored-by: Sergei Shirokov <sergei@Sergeis-Mac-mini.local>
Also: - Fixed `sizeof` → `alignof`. - Added `TestMovableOnly` helper, and assign operators. - Reduced code duplication in tests (`TestCopyable` & `TestCopyableAndMovable`). --------- Co-authored-by: Sergei Shirokov <sergei@Sergeis-Mac-mini.local>
- Now `Copyable` and `Movable` constraints are respected. - Now instead of single handler we have 3 (destroyer, copier, mover) - allows to eliminate AUTOSAR `const_cast` violations. - In unit tests: - more tests to cover combinations of `any` template params - switch from pointer based `any_cast` to value or reference based. --------- Co-authored-by: Sergei Shirokov <sergei@Sergeis-Mac-mini.local> Co-authored-by: Pavel Kirienko <pavel.kirienko@gmail.com>
- Now CETL's polymorphic RTTI casting is in use at `cetl::detail::base_storage`. - Extended unit tests `TestXxx` helper types with virtual `what()` method - to test polymorphic RTTI casting. - Added compile tests to verify several `static_assert`-s at `cetl::any` (related to `Footprint` fitting). Also: - Reduced code duplication at unit tests `TestXxx` helper types. - Fixed incorrect applying of `-fno-exceptions` to C flags - should be C++ flags. - Addressed several unit tests todo-s. No todo-s anymore at production `cetl::any` code. - Added verification that there will be no value moved out of source `any` in case of bad cast attempt. This change was also made, but decided to revert (for now) and save it as patch (for future reference): - Added new `CETLVAST_DISABLE_CPP_RTTI` configuration parameter. `OFF` by default. [CETLVAST_DISABLE_CPP_RTTI.patch](https://github.com/OpenCyphal/CETL/files/14792699/CETLVAST_DISABLE_CPP_RTTI.patch) --------- Co-authored-by: Sergei Shirokov <sergei@Sergeis-Mac-mini.local> Co-authored-by: Sergei Shirokov <sshirokov@malwarebytes.com>
- Extended corresponding unit test to cover this case. - Renamed `uut` → `any` in all `test_any` unit tests. --------- Co-authored-by: Sergei Shirokov <sergei@Sergeis-Mac-mini.local>
Co-authored-by: Pavel Kirienko <pavel.kirienko@gmail.com>
|
@thirtytwobits this is waiting for review. The Sonar failure is due to the coverage check which we discussed at the call. |
|
|
||
| #include "rtti.hpp" | ||
| #include "pf17/cetlpf.hpp" | ||
| #include "pf17/utility.hpp" |
There was a problem hiding this comment.
move utility.hpp include inside of the #ifndef CETL_H_ERASE section below
There was a problem hiding this comment.
@thirtytwobits With my recent renaming (any → unbounded_variant) AND removing all related PF-any-stuff, is this comment (and 2 below) are still applicable? I'm asking b/c I'm not sure what needs to be done...
| #define CETL_ANY_HPP_INCLUDED | ||
|
|
||
| #include "rtti.hpp" | ||
| #include "pf17/cetlpf.hpp" |
There was a problem hiding this comment.
illegal dependency: CETL pf can use CETL first-class but not the other way around.
| #ifndef CETL_ANY_HPP_INCLUDED | ||
| #define CETL_ANY_HPP_INCLUDED | ||
|
|
||
| #include "rtti.hpp" |
| /// Copyright Amazon.com Inc. or its affiliates. | ||
| /// SPDX-License-Identifier: MIT | ||
|
|
||
| #ifndef CETL_PF17_ANY_HPP_INCLUDED |
There was a problem hiding this comment.
just omit this header for now. It's completely off the mark. What we actually want is to have something like this in the cetlpf.hpp
using bad_any_cast = std::bad_any_cast;
template <typename T> constexpr bool is_rtti_convertible = std::false_type::value;
using type_id = std::type_info;
// Forward declarations
template <std::size_t Footprint, bool Copyable, bool Movable, std::size_t Alignment> class any;
template <typename T> inline constexpr const type_id &type_id_value()
{
return typeid(T);
}
template <typename T> using in_place_type_t = std::in_place_type_t<T>;
template <typename T> inline constexpr std::in_place_type_t<T> in_place_type;
template <std::size_t I> using in_place_index_t = std::in_place_index_t<I>;
template <std::size_t I> inline constexpr std::in_place_index_t<I> in_place_index;
// Forward declarations
template <std::size_t Footprint, bool Copyable, bool Movable, std::size_t Alignment> class any;
There was a problem hiding this comment.
This is easy to change but I want to confirm a few things.
-
I think we originally discussed that the reliance on the native RTTI is not permitted, but now we're making it optional, configurable at build time, such that it conditionally replaces our
cetl_rtti. -
Our
anyis not a drop-in replacement forstd::any(unlike, say,variantorspan), so introducing it into the polyfill header as-is seems questionable. The original intention was to introduce a particular instantiation of ouranyinto the polyfill namespace, that instantiation being a better approximation ofstd::any. Alternatively, we can avoid polyfillingstd::anycompletely considering the differences. Substituting our any template forstd::anyis unlikely to be what we want.
There was a problem hiding this comment.
With a few tweaks we leave open the possibility that our implementation can be redefined to use RTTI. This seems worth the minor effort to maintain. As for inclusion in the polyfill, let's just leave that for a later time.
There was a problem hiding this comment.
No more such header.
| /// where let `U` be `std::remove_cv_t<std::remove_reference_t<ValueType>>`. | ||
| /// | ||
| template <typename ValueType, typename Any> | ||
| CETL_NODISCARD ValueType any_cast(const Any& operand) |
There was a problem hiding this comment.
We should refuse to generate any_cast for non-pointer types when exceptions are disabled. This is the approach we took with variable_length_array.hpp
There was a problem hiding this comment.
I'm expecting that in user code it will result in this:
T& val = any_cast<T>(my_any);Being replaced with this:
T* const val = any_cast<T*>(&my_any);
assert(val != nullptr);Where there is a robust assumption that the any contains T. One example would be the DynamicBuffer in LibCyphal.
Is it done to uphold compliance with a coding standard or there is other rationale?
There was a problem hiding this comment.
Of my two rules for API design:
- Make the API easy to use correctly
- Make the API hard to use incorrectly
rule 2 applies here.
There was a problem hiding this comment.
Okay. But for the record we have throwing overloads in cetl::variant, like cetl::get.
There was a problem hiding this comment.
I renamed any_cast to two functions:
- →
getfor value-returning; throwscetl::bad_unbounding_variant_accessin case of failure - →
get_iffor pointer-returning; returnsnullptrin case of failure
So now, this api is close to usual (type-bound)cetl::variant.
| void make_converters() noexcept | ||
| { | ||
| value_const_converter_ = [](const void* const storage, const type_id& id) { | ||
| return (id == type_id_value<Tp>) ? storage : nullptr; |
There was a problem hiding this comment.
We need to change type_id_value to be functional to allow for typeid's required runtime. That is, the token must be replaceable with typeid when CETL RTTI is erased. Here's an example polyfill:
template <typename T> inline constexpr const type_id &type_id_value()
{
return typeid(T);
}
This would require the token to look like type_id_value<Tp>() so we can invoke typeid.
There was a problem hiding this comment.
@thirtytwobits Scott, is it possible that we handle this request as a separate issue? I'm asking b/c I currently don't understand requirements, as well as the exact way to reproduce it.
There was a problem hiding this comment.
@serges147 this is simply about replacing this:
template <typename TypeIDType>
constexpr type_id type_id_type_value = detail::type_id_type_value_impl(TypeIDType{});with this:
template <typename TypeIDType>
constexpr type_id type_id_type_value() noexcept
{
return detail::type_id_type_value_impl(TypeIDType{});
}We must return by value because constexpr functions do not allow static storage duration locals. Alternatively, we keep the original type_id_type_value under a different name (perhaps move it into detail) and return a reference to it:
template <typename TypeIDType>
constexpr const type_id& type_id_type_value() noexcept
{
return detail::type_id_type_value<TypeIDType>;
}There was a problem hiding this comment.
ok, I did the replacement. unfortunately, I still don't understand what exactly was the problem (and how to reproduce it, f.e. in unit tests), but I did as you proposed
|
|
||
| // Forward declarations | ||
| template <std::size_t Footprint, bool Copyable, bool Movable, std::size_t Alignment> | ||
| class any; |
There was a problem hiding this comment.
This is misleading. Let's rename the header and type to static_any to avoid any confusion that this is a different implementation then the standard requires.
There was a problem hiding this comment.
static may not be a good choice if we extend this any with PMR support which we discussed in the past. Perhaps the following are better options:
any2configurable_anyheapless_any(works for PMR as well because we don't use the global heap directly)
There was a problem hiding this comment.
super_mega_anythis_any_sponsored_by_progressive__progressive_will_save_you_hundreds_on_car_insuranceless_evil_any
serious ones
many - sorta cheeky
any_of - what if we changed the template to take a variadic list of types and it does the max(sizeof(...)) so the usage would look like any_of<int, float, double> a{1};?
There was a problem hiding this comment.
ok here's another inspired by your comment:
unbounded_variant
what if we changed the template to take a variadic list of types and it does the max(sizeof(...)) so the usage would look like any_of<int, float, double> a{1};?
If you need variant, you know where to find it. Perhaps you want an overload for make_any; we could add that later.
There was a problem hiding this comment.
unbounded_variant. love it
There was a problem hiding this comment.
cetl::unbounded_variant it is; no PF stuff anymore.
also: `example_10_any` & `test_any` → `xxx_unbounded_variant`
|


Fix for issue #83