[libcamera-devel] [PATCH 15/23] libcamera: controls: Support compound controls in ControlValue

Jacopo Mondi jacopo at jmondi.org
Mon Jan 13 17:42:37 CET 2020


Add compound controls support to the ControlValue class. The polymorphic class
can now store more than a single element and supports access and
creation through the use of Span<>.

Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
---
 include/libcamera/controls.h |  37 +++-
 src/libcamera/controls.cpp   | 329 ++++++++++++++++++++++++++++++++---
 2 files changed, 333 insertions(+), 33 deletions(-)

diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h
index 8fa33d93b088..bdbdb213528d 100644
--- a/include/libcamera/controls.h
+++ b/include/libcamera/controls.h
@@ -11,6 +11,8 @@
 #include <string>
 #include <unordered_map>
 
+#include <libcamera/span.h>
+
 namespace libcamera {
 
 class ControlValidator;
@@ -21,6 +23,10 @@ enum ControlType {
 	ControlTypeInteger32,
 	ControlTypeInteger64,
 	ControlTypeFloat,
+	ControlTypeCompoundBool,
+	ControlTypeCompoundInt32,
+	ControlTypeCompoundInt64,
+	ControlTypeCompoundFloat,
 };
 
 class ControlValue
@@ -31,12 +37,18 @@ public:
 	ControlValue(int32_t value);
 	ControlValue(int64_t value);
 	ControlValue(float value);
+	ControlValue(Span<bool> &values);
+	ControlValue(Span<int32_t> &values);
+	ControlValue(Span<int64_t> &values);
+	ControlValue(Span<float> &values);
+	~ControlValue();
 
 	ControlType type() const { return type_; }
 	bool isNone() const { return type_ == ControlTypeNone; }
+	std::size_t numElements() const { return numElements_; }
 
 	template<typename T>
-	const T &get() const;
+	T get() const;
 	template<typename T>
 	void set(const T &value);
 
@@ -57,6 +69,21 @@ private:
 		int64_t integer64_;
 		float float_;
 	};
+
+	union {
+		void *pvoid_;
+		bool *pbool_;
+		int32_t *p32_;
+		int64_t *p64_;
+		float *pfloat_;
+	};
+
+	std::size_t numElements_;
+
+	void release();
+	bool compareElement(const ControlValue &other) const;
+	bool compareElement(const ControlValue &other, unsigned int i) const;
+	std::string elemToString(unsigned int i) const;
 };
 
 class ControlId
@@ -215,13 +242,11 @@ public:
 	bool contains(unsigned int id) const;
 
 	template<typename T>
-	const T &get(const Control<T> &ctrl) const
+	const T get(const Control<T> &ctrl) const
 	{
 		const ControlValue *val = find(ctrl.id());
-		if (!val) {
-			static T t(0);
-			return t;
-		}
+		if (!val)
+			return T{};
 
 		return val->get<T>();
 	}
diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp
index 74ce5d0ba4f1..7718a53911e6 100644
--- a/src/libcamera/controls.cpp
+++ b/src/libcamera/controls.cpp
@@ -9,7 +9,9 @@
 
 #include <iomanip>
 #include <sstream>
-#include <string>
+#include <string.h>
+
+#include <libcamera/span.h>
 
 #include "control_validator.h"
 #include "log.h"
@@ -60,6 +62,14 @@ LOG_DEFINE_CATEGORY(Controls)
  * The control stores a 64-bit integer value
  * \var ControlTypeFloat
  * The control stores a 32-bit floating point value
+ * \var ControlTypeCompoundBool
+ * The control stores an array of boolean values
+ * \var ControlTypeCompoundInt32
+ * The control stores an array of 32-bit integer values
+ * \var ControlTypeCompoundInt64
+ * The control stores an array of 64-bit integer values
+ * \var ControlTypeCompoundFloat
+ * The control stores an array of 32-bit floating values
  */
 
 /**
@@ -71,7 +81,7 @@ LOG_DEFINE_CATEGORY(Controls)
  * \brief Construct an empty ControlValue.
  */
 ControlValue::ControlValue()
-	: type_(ControlTypeNone)
+	: type_(ControlTypeNone), pvoid_(nullptr), numElements_(0)
 {
 }
 
@@ -80,7 +90,8 @@ ControlValue::ControlValue()
  * \param[in] value Boolean value to store
  */
 ControlValue::ControlValue(bool value)
-	: type_(ControlTypeBool), bool_(value)
+	: type_(ControlTypeBool), bool_(value), pvoid_(nullptr),
+	  numElements_(1)
 {
 }
 
@@ -89,7 +100,8 @@ ControlValue::ControlValue(bool value)
  * \param[in] value Integer value to store
  */
 ControlValue::ControlValue(int32_t value)
-	: type_(ControlTypeInteger32), integer32_(value)
+	: type_(ControlTypeInteger32), integer32_(value), pvoid_(nullptr),
+	  numElements_(1)
 {
 }
 
@@ -98,7 +110,8 @@ ControlValue::ControlValue(int32_t value)
  * \param[in] value Integer value to store
  */
 ControlValue::ControlValue(int64_t value)
-	: type_(ControlTypeInteger64), integer64_(value)
+	: type_(ControlTypeInteger64), integer64_(value), pvoid_(nullptr),
+	  numElements_(1)
 {
 }
 
@@ -107,8 +120,73 @@ ControlValue::ControlValue(int64_t value)
  * \param[in] value Float value to store
  */
 ControlValue::ControlValue(float value)
-	: type_(ControlTypeFloat), float_(value)
+	: type_(ControlTypeFloat), float_(value), pvoid_(nullptr),
+	  numElements_(1)
+{
+}
+
+/**
+ * \brief Construct a ControlValue with a Span of boolean elements
+ * \param[in] values Span of boolean values to store
+ */
+ControlValue::ControlValue(Span<bool> &values)
+	: type_(ControlTypeCompoundBool), numElements_(values.size())
 {
+	pbool_ = new bool[numElements_];
+	memcpy(pbool_, values.data(), sizeof(bool) * numElements_);
+}
+
+/**
+ * \brief Construct a ControlValue with a Span of 32 bit integers elements
+ * \param[in] values Span of 32 bit integer values to store
+ */
+ControlValue::ControlValue(Span<int32_t> &values)
+	: type_(ControlTypeCompoundInt32), numElements_(values.size())
+{
+	p32_ = new int32_t[numElements_];
+	memcpy(p32_, values.data(), sizeof(int32_t) * numElements_);
+}
+
+/**
+ * \brief Construct a ControlValue with a Span of 64 bit integers elements
+ * \param[in] values Span of 64 bit integer values to store
+ */
+ControlValue::ControlValue(Span<int64_t> &values)
+	: type_(ControlTypeCompoundInt64), numElements_(values.size())
+{
+	p64_ = new int64_t[numElements_];
+	memcpy(p64_, values.data(), sizeof(int64_t) * numElements_);
+}
+
+/**
+ * \brief Construct a ControlValue with a Span of float elements
+ * \param[in] values Span of float values to store
+ */
+ControlValue::ControlValue(Span<float> &values)
+	: type_(ControlTypeCompoundFloat), numElements_(values.size())
+{
+	pfloat_ = new float[numElements_];
+	memcpy(pfloat_, values.data(), sizeof(float) * numElements_);
+}
+
+void ControlValue::release()
+{
+	switch (type_) {
+	case ControlTypeCompoundBool:
+	case ControlTypeCompoundInt32:
+	case ControlTypeCompoundInt64:
+	case ControlTypeCompoundFloat:
+		delete[] pbool_;
+		pbool_ = nullptr;
+		/* fall-through. */
+	default:
+		return;
+	}
+}
+
+ControlValue::~ControlValue()
+{
+	release();
 }
 
 /**
@@ -124,24 +202,38 @@ ControlValue::ControlValue(float value)
  */
 
 /**
- * \fn template<typename T> const T &ControlValue::get() const
- * \brief Get the control value
+ * \fn ControlValue::numElements()
+ * \brief Retrieve the number of elements stored in the ControlValue
+ * \return The number of elements stored in the ControlValue
+ */
+
+/**
+ * \fn template<typename T> const T ControlValue::get() const
+ * \brief Get the control values
  *
  * The control value type shall match the type T, otherwise the behaviour is
  * undefined.
  *
- * \return The control value
+ * This function applies to ControlValue instances which store a single or
+ * multiple values. The ControlValue's elements are returned in a Span in the
+ * former case.
+ *
+ * \return The control value or a Span of values
  */
 
 /**
- * \fn template<typename T> void ControlValue::set(const T &value)
- * \brief Set the control value to \a value
- * \param[in] value The control value
+ * \fn template<typename T> void ControlValue::set(const T &values)
+ * \brief Set the control values to \a values
+ * \param[in] values The control values
+ *
+ * This function can be used to set the ControlValue to a single value, or
+ * to store multiple values by providing a Span<> of elements to the
+ * function.
  */
 
 #ifndef __DOXYGEN__
 template<>
-const bool &ControlValue::get<bool>() const
+bool ControlValue::get<bool>() const
 {
 	ASSERT(type_ == ControlTypeBool);
 
@@ -149,7 +241,19 @@ const bool &ControlValue::get<bool>() const
 }
 
 template<>
-const int32_t &ControlValue::get<int32_t>() const
+Span<bool> ControlValue::get<Span<bool>>() const
+{
+	ASSERT(type_ == ControlTypeCompoundBool);
+
+	/*
+	 * Explicitly create a Span<bool> instance, otherwise the compiler
+	 * tries to match with the Span class initializer_list constructor.
+	 */
+	return Span<bool>(pbool_, static_cast<std::size_t>(numElements_));
+}
+
+template<>
+int32_t ControlValue::get<int32_t>() const
 {
 	ASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);
 
@@ -157,7 +261,16 @@ const int32_t &ControlValue::get<int32_t>() const
 }
 
 template<>
-const int64_t &ControlValue::get<int64_t>() const
+Span<int32_t> ControlValue::get<Span<int32_t>>() const
+{
+	ASSERT(type_ == ControlTypeCompoundInt32 ||
+	       type_ == ControlTypeCompoundInt64);
+
+	return { p32_, numElements_ };
+}
+
+template<>
+int64_t ControlValue::get<int64_t>() const
 {
 	ASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);
 
@@ -165,62 +278,190 @@ const int64_t &ControlValue::get<int64_t>() const
 }
 
 template<>
-const float &ControlValue::get<float>() const
+Span<int64_t> ControlValue::get<Span<int64_t>>() const
+{
+	ASSERT(type_ == ControlTypeCompoundInt32 ||
+	       type_ == ControlTypeCompoundInt64);
+
+	return { p64_, numElements_ };
+}
+
+template<>
+float ControlValue::get<float>() const
 {
 	ASSERT(type_ == ControlTypeFloat);
 
 	return float_;
 }
 
+template<>
+Span<float> ControlValue::get<Span<float>>() const
+{
+	ASSERT(type_ == ControlTypeCompoundFloat);
+
+	return { pfloat_, numElements_ };
+}
+
 template<>
 void ControlValue::set<bool>(const bool &value)
 {
+	release();
+
 	type_ = ControlTypeBool;
 	bool_ = value;
+	numElements_ = 1;
+}
+
+template<>
+void ControlValue::set<Span<bool>>(const Span<bool> &values)
+{
+	release();
+
+	type_ = ControlTypeCompoundBool;
+	numElements_ = values.size();
+
+	pbool_ = new bool[numElements_];
+	memcpy(pbool_, values.data(), sizeof(bool) * numElements_);
 }
 
 template<>
 void ControlValue::set<int32_t>(const int32_t &value)
 {
+	release();
+
 	type_ = ControlTypeInteger32;
 	integer32_ = value;
+	numElements_ = 1;
+}
+
+template<>
+void ControlValue::set<Span<int32_t>>(const Span<int32_t> &values)
+{
+	release();
+
+	type_ = ControlTypeCompoundInt32;
+	numElements_ = values.size();
+
+	p32_ = new int32_t[numElements_];
+	memcpy(p32_, values.data(), sizeof(int32_t) * numElements_);
 }
 
 template<>
 void ControlValue::set<int64_t>(const int64_t &value)
 {
+	release();
+
 	type_ = ControlTypeInteger64;
 	integer64_ = value;
+	numElements_ = 1;
+}
+
+template<>
+void ControlValue::set<Span<int64_t>>(const Span<int64_t> &values)
+{
+	release();
+
+	type_ = ControlTypeCompoundInt64;
+	numElements_ = values.size();
+
+	p64_ = new int64_t[numElements_];
+	memcpy(p64_, values.data(), sizeof(int64_t) * numElements_);
 }
 
 template<>
 void ControlValue::set<float>(const float &value)
 {
+	release();
+
 	type_ = ControlTypeFloat;
 	float_ = value;
+	numElements_ = 1;
 }
+
+template<>
+void ControlValue::set<Span<float>>(const Span<float> &values)
+{
+	release();
+
+	type_ = ControlTypeCompoundFloat;
+	numElements_ = values.size();
+
+	pfloat_ = new float[numElements_];
+	memcpy(pfloat_, values.data(), sizeof(float) * numElements_);
+}
+
 #endif /* __DOXYGEN__ */
 
+std::string ControlValue::elemToString(unsigned int i) const
+{
+	switch (type_) {
+	case ControlTypeBool:
+		return bool_ ? "True " : "False ";
+	case ControlTypeInteger32:
+		return std::to_string(integer32_);
+	case ControlTypeInteger64:
+		return std::to_string(integer64_);
+	case ControlTypeFloat:
+		return std::to_string(float_);
+	case ControlTypeCompoundBool:
+		return pbool_[i] ? "True " : "False ";
+	case ControlTypeCompoundInt32:
+		return std::to_string(p32_[i]) + " ";
+	case ControlTypeCompoundInt64:
+		return std::to_string(p64_[i]) + " ";
+	case ControlTypeCompoundFloat:
+		return std::to_string(pfloat_[i]) + " ";
+	default:
+		return "<None>";
+	}
+}
+
 /**
  * \brief Assemble and return a string describing the value
  * \return A string describing the ControlValue
  */
 std::string ControlValue::toString() const
+{
+	if (ControlTypeNone)
+		return "<ValueType Error>";
+
+	std::string str;
+	for (unsigned int i = 0; i < numElements_; ++i)
+		str += elemToString(i);
+
+	return str;
+}
+
+bool ControlValue::compareElement(const ControlValue &other) const
 {
 	switch (type_) {
-	case ControlTypeNone:
-		return "<None>";
 	case ControlTypeBool:
-		return bool_ ? "True" : "False";
+		return bool_ == other.bool_;
 	case ControlTypeInteger32:
-		return std::to_string(integer32_);
+		return integer32_ == other.integer32_;
 	case ControlTypeInteger64:
-		return std::to_string(integer64_);
+		return integer64_ == other.integer64_;
 	case ControlTypeFloat:
-		return std::to_string(float_);
+		return float_ == other.float_;
+	default:
+		return false;
 	}
+}
 
-	return "<ValueType Error>";
+bool ControlValue::compareElement(const ControlValue &other, unsigned int i) const
+{
+	switch (type_) {
+	case ControlTypeCompoundBool:
+		return pbool_[i] == other.pbool_[i];
+	case ControlTypeCompoundInt32:
+		return p32_[i] == other.p32_[i];
+	case ControlTypeCompoundInt64:
+		return p64_[i] == other.p64_[i];
+	case ControlTypeCompoundFloat:
+		return pfloat_[i] == other.pfloat_[i];
+	default:
+		return false;
+	}
 }
 
 /**
@@ -232,15 +473,25 @@ bool ControlValue::operator==(const ControlValue &other) const
 	if (type_ != other.type_)
 		return false;
 
+	if (numElements_ != other.numElements())
+		return false;
+
 	switch (type_) {
 	case ControlTypeBool:
-		return bool_ == other.bool_;
 	case ControlTypeInteger32:
-		return integer32_ == other.integer32_;
 	case ControlTypeInteger64:
-		return integer64_ == other.integer64_;
 	case ControlTypeFloat:
-		return float_ == other.float_;
+		return compareElement(other);
+	case ControlTypeCompoundBool:
+	case ControlTypeCompoundInt32:
+	case ControlTypeCompoundInt64:
+	case ControlTypeCompoundFloat:
+		for (unsigned int i = 0; i < numElements_; ++i) {
+			if (!compareElement(other, i))
+				return false;
+		}
+
+		return true;
 	default:
 		return false;
 	}
@@ -360,23 +611,47 @@ Control<bool>::Control(unsigned int id, const char *name)
 {
 }
 
+template<>
+Control<Span<bool>>::Control(unsigned int id, const char *name)
+	: ControlId(id, name, ControlTypeCompoundBool)
+{
+}
+
 template<>
 Control<int32_t>::Control(unsigned int id, const char *name)
 	: ControlId(id, name, ControlTypeInteger32)
 {
 }
 
+template<>
+Control<Span<int32_t>>::Control(unsigned int id, const char *name)
+	: ControlId(id, name, ControlTypeCompoundInt32)
+{
+}
+
 template<>
 Control<int64_t>::Control(unsigned int id, const char *name)
 	: ControlId(id, name, ControlTypeInteger64)
 {
 }
 
+template<>
+Control<Span<int64_t>>::Control(unsigned int id, const char *name)
+	: ControlId(id, name, ControlTypeCompoundInt64)
+{
+}
+
 template<>
 Control<float>::Control(unsigned int id, const char *name)
 	: ControlId(id, name, ControlTypeFloat)
 {
 }
+
+template<>
+Control<Span<float>>::Control(unsigned int id, const char *name)
+	: ControlId(id, name, ControlTypeCompoundFloat)
+{
+}
 #endif /* __DOXYGEN__ */
 
 /**
-- 
2.24.0



More information about the libcamera-devel mailing list