[RFC PATCH v1 02/23] libcamera: controls: Add `ControlValueView`

Barnabás Pőcze barnabas.pocze at ideasonboard.com
Fri Jun 6 18:41:35 CEST 2025


Add `ControlValueView`, which is a non-owning read-only handle to a control
value with a very similar interface.

Signed-off-by: Barnabás Pőcze <barnabas.pocze at ideasonboard.com>
---
 include/libcamera/controls.h |  69 +++++++++++++
 src/libcamera/controls.cpp   | 194 +++++++++++++++++++++++++++++++++++
 2 files changed, 263 insertions(+)

diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h
index b170e30cb..8734479cf 100644
--- a/include/libcamera/controls.h
+++ b/include/libcamera/controls.h
@@ -8,6 +8,7 @@
 #pragma once
 
 #include <assert.h>
+#include <cstddef>
 #include <map>
 #include <optional>
 #include <set>
@@ -25,6 +26,7 @@
 namespace libcamera {
 
 class ControlValidator;
+class ControlValueView;
 
 enum ControlType {
 	ControlTypeNone,
@@ -160,6 +162,8 @@ public:
 		    value.data(), value.size(), sizeof(typename T::value_type));
 	}
 
+	explicit ControlValue(const ControlValueView &cvv);
+
 	~ControlValue();
 
 	ControlValue(const ControlValue &other);
@@ -247,6 +251,71 @@ private:
 		 std::size_t numElements, std::size_t elementSize);
 };
 
+class ControlValueView
+{
+public:
+	constexpr ControlValueView() noexcept
+		: type_(ControlTypeNone)
+	{
+	}
+
+	ControlValueView(const ControlValue &cv) noexcept
+		: ControlValueView(cv.type(), cv.isArray(), cv.numElements(),
+				   reinterpret_cast<const std::byte *>(cv.data().data()))
+	{
+	}
+
+#ifndef __DOXYGEN__
+	// TODO: should have restricted access?
+	ControlValueView(ControlType type, bool isArray, std::size_t numElements, const std::byte *data) noexcept
+		: type_(type),
+		  isArray_(isArray),
+		  numElements_(numElements),
+		  data_(data)
+	{
+		assert(isArray || numElements == 1);
+	}
+#endif
+
+	[[nodiscard]] explicit operator bool() const { return type_ != ControlTypeNone; }
+	[[nodiscard]] ControlType type() const { return type_; }
+	[[nodiscard]] bool isNone() const { return type_ == ControlTypeNone; }
+	[[nodiscard]] bool isArray() const { return isArray_; }
+	[[nodiscard]] std::size_t numElements() const { return numElements_; }
+	[[nodiscard]] Span<const std::byte> data() const;
+
+	[[nodiscard]] bool operator==(const ControlValueView &other) const;
+
+	[[nodiscard]] bool operator!=(const ControlValueView &other) const
+	{
+		return !(*this == other);
+	}
+
+	template<typename T>
+	[[nodiscard]] auto get() const
+	{
+		using TypeInfo = details::control_type<std::remove_cv_t<T>>;
+
+		assert(type_ == TypeInfo::value);
+		assert(isArray_ == (TypeInfo::size > 0));
+
+		if constexpr (TypeInfo::size > 0) {
+			return T(reinterpret_cast<const typename T::value_type *>(data().data()), numElements_);
+		} else {
+			assert(numElements_ == 1);
+			return *reinterpret_cast<const T *>(data().data());
+		}
+	}
+
+private:
+	ControlType type_ : 8;
+	bool isArray_ = false;
+	uint32_t numElements_ = 0;
+	const std::byte *data_ = nullptr;
+};
+
+std::ostream &operator<<(std::ostream &s, const ControlValueView &v);
+
 class ControlId
 {
 public:
diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp
index 98fa7583d..e7e2781e8 100644
--- a/src/libcamera/controls.cpp
+++ b/src/libcamera/controls.cpp
@@ -106,6 +106,16 @@ ControlValue::ControlValue()
 {
 }
 
+/**
+ * \brief Construct a ControlValue from a ControlValueView
+ */
+ControlValue::ControlValue(const ControlValueView &cvv)
+	: ControlValue()
+{
+	set(cvv.type(), cvv.isArray(), cvv.data().data(),
+	    cvv.numElements(), ControlValueSize[cvv.type()]);
+}
+
 /**
  * \fn template<typename T> T ControlValue::ControlValue(const T &value)
  * \brief Construct a ControlValue of type T
@@ -395,6 +405,190 @@ void ControlValue::reserve(ControlType type, bool isArray, std::size_t numElemen
 		storage_ = reinterpret_cast<void *>(new uint8_t[newSize]);
 }
 
+/**
+ * \class ControlValueView
+ * \brief A non-owning view-like type to the value of a control
+ */
+
+/**
+ * \fn ControlValueView::ControlValueView()
+ * \brief Construct an empty view
+ * \sa ControlValue::ControlValue()
+ */
+
+/**
+ * \fn ControlValueView::ControlValueView(const ControlValue &v)
+ * \brief Construct a view referring to \a v
+ *
+ * The constructed view will refer to the value stored by \a v, and
+ * thus \a v must not be modified or destroyed before the view.
+ *
+ * \sa ControlValue::ControlValue()
+ */
+
+/**
+ * \fn ControlValueView::operator bool() const
+ * \brief Determine if the referred value is valid
+ * \sa ControlValueView::isNone()
+ */
+
+/**
+ * \fn ControlType ControlValueView::type() const
+ * \copydoc ControlValue::type()
+ * \sa ControlValue::type()
+ */
+
+/**
+ * \fn ControlValueView::isNone() const
+ * \copydoc ControlValue::isNone()
+ * \sa ControlValue::isNone()
+ */
+
+/**
+ * \fn ControlValueView::isArray() const
+ * \copydoc ControlValue::isArray()
+ * \sa ControlValue::isArray()
+ */
+
+/**
+ * \fn ControlValueView::numElements() const
+ * \copydoc ControlValue::numElements()
+ * \sa ControlValue::numElements()
+ */
+
+/**
+ * \copydoc ControlValue::data()
+ * \sa ControlValue::data()
+ */
+Span<const std::byte> ControlValueView::data() const
+{
+	return { data_, numElements_ * ControlValueSize[type_] };
+}
+
+/**
+ * \copydoc ControlValue::operator==()
+ * \sa ControlValue::operator==()
+ * \sa ControlValueView::operator!=()
+ */
+bool ControlValueView::operator==(const ControlValueView &other) const
+{
+	if (type_ != other.type_)
+		return false;
+
+	if (numElements_ != other.numElements_)
+		return false;
+
+	if (isArray_ != other.isArray_)
+		return false;
+
+	const auto d = data();
+
+	return memcmp(d.data(), other.data_, d.size_bytes()) == 0;
+}
+
+/**
+ * \fn ControlValueView::operator!=() const
+ * \copydoc ControlValue::operator!=()
+ * \sa ControlValue::operator!=()
+ * \sa ControlValueView::operator==()
+ */
+
+/**
+ * \fn template<typename T> T ControlValueView::get() const
+ * \copydoc ControlValue::get()
+ * \sa ControlValue::get()
+ */
+
+/**
+ * \brief Insert a text representation of a value into an output stream
+ * \sa ControlValue::toString()
+ */
+std::ostream &operator<<(std::ostream &s, const ControlValueView &v)
+{
+	const auto type = v.type();
+	if (type == ControlTypeNone)
+		return s << "None";
+
+	const auto *data = v.data().data();
+	const auto numElements = v.numElements();
+
+	if (type == ControlTypeString)
+		return s << std::string_view(reinterpret_cast<const char *>(data),
+					     numElements);
+
+	const bool isArray = v.isArray();
+	if (isArray)
+		s << "[ ";
+
+	for (std::size_t i = 0; i < numElements; ++i) {
+		if (i > 0)
+			s << ", ";
+
+		switch (type) {
+		case ControlTypeBool: {
+			const bool *value = reinterpret_cast<const bool *>(data);
+			s << (*value ? "true" : "false");
+			break;
+		}
+		case ControlTypeByte: {
+			const auto *value = reinterpret_cast<const uint8_t *>(data);
+			s << static_cast<unsigned int>(*value);
+			break;
+		}
+		case ControlTypeUnsigned16: {
+			const auto *value = reinterpret_cast<const uint16_t *>(data);
+			s << *value;
+			break;
+		}
+		case ControlTypeUnsigned32: {
+			const auto *value = reinterpret_cast<const uint32_t *>(data);
+			s << *value;
+			break;
+		}
+		case ControlTypeInteger32: {
+			const auto *value = reinterpret_cast<const int32_t *>(data);
+			s << *value;
+			break;
+		}
+		case ControlTypeInteger64: {
+			const auto *value = reinterpret_cast<const int64_t *>(data);
+			s << *value;
+			break;
+		}
+		case ControlTypeFloat: {
+			const auto *value = reinterpret_cast<const float *>(data);
+			s << std::fixed << *value;
+			break;
+		}
+		case ControlTypeRectangle: {
+			const auto *value = reinterpret_cast<const Rectangle *>(data);
+			s << *value;
+			break;
+		}
+		case ControlTypeSize: {
+			const auto *value = reinterpret_cast<const Size *>(data);
+			s << *value;
+			break;
+		}
+		case ControlTypePoint: {
+			const auto *value = reinterpret_cast<const Point *>(data);
+			s << *value;
+			break;
+		}
+		case ControlTypeNone:
+		case ControlTypeString:
+			break;
+		}
+
+		data += ControlValueSize[type];
+	}
+
+	if (isArray)
+		s << " ]";
+
+	return s;
+}
+
 /**
  * \class ControlId
  * \brief Control static metadata
-- 
2.49.0



More information about the libcamera-devel mailing list