[libcamera-devel] [PATCH 3/5] provide a default fixed-sized Span constructor
Jacopo Mondi
jacopo at jmondi.org
Fri Apr 1 16:28:26 CEST 2022
Hi Christian
On Fri, Apr 01, 2022 at 01:06:14AM +0100, Christian Rauch via libcamera-devel wrote:
> The new default constructor allows to construct a fixed-sized Span via the
> default constructor of its stored data type.
> This prevents the construction of empty fixed-sized Spans that cannot hold
> any data.
>
> Signed-off-by: Christian Rauch <Rauch.Christian at gmx.de>
> ---
> include/libcamera/base/span.h | 5 +++++
> include/libcamera/controls.h | 2 +-
> test/span.cpp | 2 +-
> 3 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/include/libcamera/base/span.h b/include/libcamera/base/span.h
> index 88d2e3de..7a4806dc 100644
> --- a/include/libcamera/base/span.h
> +++ b/include/libcamera/base/span.h
> @@ -112,6 +112,11 @@ public:
> {
> }
>
> + Span()
> + {
> + Span(std::array<value_type, extent>{});
> + }
> +
This constructor creates a span of 'extent' elements all of them
initialized to 0 then ?
If I remove it I get
../include/libcamera/controls.h:380:34: error: no matching function for call to ‘libcamera::Span<const float, 2>::Span(<brace-enclosed initializer list>)’
380 | return T{};
Caused by
template<typename T>
T get(const Control<T> &ctrl) const
{
const ControlValue *val = find(ctrl.id());
if (!val)
return T{}; <------
return val->get<T>();
}
as now that extent is != 0 the expression doesn't bind anymore to the
existing constructor:
template<bool Dependent = false,
typename = std::enable_if_t<Dependent || Extent == 0>>
constexpr Span() noexcept
: data_(nullptr)
{
}
(I don't fully get what is the use of Dependent in the above definition :)
However I feel like creating a Span of Extent elements all zeroed is a
bit hill-defined, considering it is only used to return an error
condition. In example, if I'm not mistaken a Span constructed with
your proposed constructor will
constexpr size_type size() const noexcept { return Extent; }
constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
constexpr bool empty() const noexcept { return size() == 0; }
be !empty and of size == 2, which is misleading considering we really
want to return an empty Span in case of error and the caller should
not be mis-leaded thinking it is valid.
I don't have any super smart proposal to offer, if not recording the
'valid' or 'empty' state in a class member and use it in size() and
empty() instead of relying on Extent which is defined at overload
resolution time and cannot be assigned at run time.
> explicit constexpr Span(pointer ptr, [[maybe_unused]] size_type count)
> : data_(ptr)
> {
> diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h
> index 665bcac1..de8a7770 100644
> --- a/include/libcamera/controls.h
> +++ b/include/libcamera/controls.h
> @@ -167,7 +167,7 @@ public:
>
> using V = typename T::value_type;
> const V *value = reinterpret_cast<const V *>(data().data());
> - return { value, numElements_ };
> + return T{ value, numElements_ };
this applies to overload
template<typename T, typename std::enable_if_t<details::is_span<T>::value ||
std::is_same<std::string, std::remove_cv_t<T>>::value,
T get() const
{
assert(type_ == details::control_type<std::remove_cv_t<T>>::value);
assert(isArray_);
using V = typename T::value_type;
const V *value = reinterpret_cast<const V *>(data().data());
return { value, numElements_ };
}
Isn't the returned { value, numElements_ } already used to construct an
instance of T if assigned to an lvalue expression ?
IOW why do you need to contruct an instance of T and return it
explicitely ? Thanks to return value optimization this shouldn't have
any performance impact but I have missed why it is needed.
<2 minutes later>
And now that I wrote this, if I remove it I get
include/libcamera/controls.h:170:46: error: converting to
‘libcamera::Span<const float, 2>’ from initializer list would use
explicit constructor ‘constexpr libcamera::Span<T,
Extent>::Span(libcamera::Span<T, Extent>::pointer, libcamera::Span<T,
Extent>::size_type) [with T = const float; long unsigned int Extent =
2; libcamera::Span<T, Extent>::pointer = const float*;
libcamera::Span<T, Extent>::size_type = long unsigned int]’
Because indeed
explicit constexpr Span(pointer ptr, [[maybe_unused]] size_type count)
is, well, explicit (which I think it's ok and should not be removed)
I'll leave here the above text anyway for others that might have the
same question :)
> }
>
> #ifndef __DOXYGEN__
> diff --git a/test/span.cpp b/test/span.cpp
> index abf3a5d6..c37e2a66 100644
> --- a/test/span.cpp
> +++ b/test/span.cpp
> @@ -37,7 +37,7 @@ protected:
> * to generate undefined behaviour.
> */
>
> - Span<int, 0>{};
> + /* Span<int, 0>{}; */
You should remove it, or if the above issue with constructing an
'empty' Span of size > 0 is resolved, prove that it works as intended.
Span<int, 4> s{}
if (!s.empty())
error!
Thanks
j
> /* Span<int, 4>{}; */
>
> Span<int, 4>{ &i[0], 4 };
> --
> 2.25.1
>
More information about the libcamera-devel
mailing list