[{"id":2677,"web_url":"https://patchwork.libcamera.org/comment/2677/","msgid":"<dbe98177-d70d-5cb8-8a48-458d3549df94@ideasonboard.com>","date":"2019-09-20T10:03:55","subject":"Re: [libcamera-devel] [PATCH 1/5] libcamera: Create DataValue and\n\tDataInfo","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn 18/09/2019 11:34, Jacopo Mondi wrote:\n> Add the data_value.[h|c] files that provide an abstracted polymorphic\n> data value type and a generic data info type that represent static\n> information associated with a data value.\n> \n> DataValue is a slightly re-worked copy of the ControlValue type defined\n> in controls.h, provided in a generic header to be used a foundation for\n> both Controls and V4L2Controls classes that will be re-worked in the\n> next patches in the series.\n\nSo my\n\"[RFC PATCH v2 1/9] libcamera: Value: Provide abstract value class\"\n\nconcept comes back to life at last :-D\n\n> Add a test for data value which is an adapted copy of the control value\n> test, that will be removed in the next patch.\n> \n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> ---\n>  include/libcamera/data_value.h |  84 +++++++++\n>  include/libcamera/meson.build  |   1 +\n>  src/libcamera/data_value.cpp   | 317 +++++++++++++++++++++++++++++++++\n>  src/libcamera/meson.build      |   1 +\n>  test/data_value/data_value.cpp |  59 ++++++\n>  test/data_value/meson.build    |  12 ++\n>  test/meson.build               |   1 +\n>  7 files changed, 475 insertions(+)\n>  create mode 100644 include/libcamera/data_value.h\n>  create mode 100644 src/libcamera/data_value.cpp\n>  create mode 100644 test/data_value/data_value.cpp\n>  create mode 100644 test/data_value/meson.build\n> \n> diff --git a/include/libcamera/data_value.h b/include/libcamera/data_value.h\n> new file mode 100644\n> index 000000000000..0fcd9bd04a65\n> --- /dev/null\n> +++ b/include/libcamera/data_value.h\n> @@ -0,0 +1,84 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * data_value.h - Polymorphic data value type\n> + */\n> +#ifndef __LIBCAMERA_DATA_VALUE_H__\n> +#define __LIBCAMERA_DATA_VALUE_H__\n> +\n> +#include <cstdint>\n> +#include <string>\n> +\n> +namespace libcamera {\n> +\n> +enum DataType {\n> +\tDataTypeNone,\n> +\tDataTypeBool,\n> +\tDataTypeInteger,\n> +\tDataTypeInteger64,\n> +\tDataTypeNumber,\n> +};\n> +\n> +static constexpr size_t DataSize[DataTypeNumber] = {\n> +\t[DataTypeNone]\t\t= 1,\n\nShouldn't this be 0?\n\n> +\t[DataTypeBool]\t\t= 4,\n\nsizeof(bool) == 1 ...\n\n\n\n> +\t[DataTypeInteger]\t= 4,\n> +\t[DataTypeInteger64]\t= 8,\n\nYou could instead do:\n\nstatic constexpr size_t DataSize[DataTypeNumber] = {\n\t[DataTypeNone]\t\t= 0,\n\t[DataTypeBool]\t\t= sizeof(bool),\n\t[DataTypeInteger]\t= sizeof(int32_t),\n\t[DataTypeInteger64]\t= sizeof(int64_t),\n};\n\n> +};\n> +\n> +class DataValue\n> +{\n> +public:\n> +\tDataValue();\n> +\tDataValue(const DataValue &other);\n> +\tDataValue(bool value);\n> +\tDataValue(int value);\n> +\tDataValue(int64_t value);\n> +\n> +\tDataValue &operator=(const DataValue &other);\n> +\n> +\tenum DataType type() const { return type_; }\n> +\tsize_t size() const { return size_; }\n> +\n> +\tvoid set(bool value);\n> +\tvoid set(int value);\n> +\tvoid set(int64_t value);\n> +\n> +\tbool getBool() const;\n> +\tint getInt() const;\n> +\tint64_t getInt64() const;\n> +\n> +\tstd::string toString() const;\n> +\n> +private:\n> +\tDataType type_;\n> +\tsize_t size_;\n> +\n> +\tunion {\n> +\t\tbool bool_;\n> +\t\tint integer_;\n> +\t\tint64_t integer64_;\n> +\t};\n> +};\n> +\n> +class DataInfo\n> +{\n> +public:\n> +\tDataInfo(const DataValue &min, const DataValue &max)\n> +\t{\n> +\t\tmin_ = min;\n> +\t\tmax_ = max;\n> +\t}\n> +\n> +\tconst DataValue &min() const { return min_; }\n> +\tconst DataValue &max() const { return max_; }\n> +\n> +private:\n> +\tDataValue max_;\n> +\tDataValue min_;\n> +};\n> +\n> +} /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_DATA_VALUE_H__ */\n> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build\n> index 868f1a6bf1ab..e3f3ad504446 100644\n> --- a/include/libcamera/meson.build\n> +++ b/include/libcamera/meson.build\n> @@ -5,6 +5,7 @@ libcamera_api = files([\n>      'camera_manager.h',\n>      'control_ids.h',\n>      'controls.h',\n> +    'data_value.h',\n>      'event_dispatcher.h',\n>      'event_notifier.h',\n>      'geometry.h',\n> diff --git a/src/libcamera/data_value.cpp b/src/libcamera/data_value.cpp\n> new file mode 100644\n> index 000000000000..f07b5fb75a8a\n> --- /dev/null\n> +++ b/src/libcamera/data_value.cpp\n> @@ -0,0 +1,317 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * data_value.cpp - Polymorphic data value type\n> + */\n> +\n> +#include <libcamera/data_value.h>\n> +\n> +#include <cstdint>\n> +#include <sstream>\n> +#include <string>\n> +\n> +#include \"utils.h\"\n> +#include \"log.h\"\n> +\n> +/**\n> + * \\file data_value.h\n> + * \\brief Polymorphic data type\n> + */\n> +\n> +namespace libcamera {\n> +\n> +/**\n> + * \\enum DataType\n> + * \\brief Define the supported data types\n> + * \\var DataTypeNone\n> + * Identifies an unset value\n> + * \\var DataTypeBool\n> + * Identifies DataType storing a boolean value\n> + * \\var DataTypeInteger\n> + * Identifies DataType storing an integer value\n> + * \\var DataTypeInteger64\n> + * Identifies DataType storing a 64-bit integer value\n> + */\n> +\n> +/**\n> + * \\var DataSize\n> + * \\brief Associate to each data type the memory size in bytes\n> + */\n> +\n\n\nYou have a rogue if 0 below\n\n> +#if 0\n> +/**\n> + * \\class Data\n> + * \\brief Base class for data value and data info instances\n> + *\n> + * DataValue and DataInfo share basic information like size and type.\n> + * This class provides common fields and operations for them.\n> + */\n> +\n> +/**\n> + * \\brief Construct a Data of \\a type\n> + * \\param[in] type The Data type defined by DataType\n> + */\n> +Data::Data(DataType type)\n> +\t: type_(type)\n> +{\n> +\t/*\n> +\t * \\todo The size of compound data types depend on the number of\n> +\t * elements too.\n> +\t */\n> +\tsize_ = DataSize[type_];\n> +}\n> +\n> +/**\n> + * \\var Data::type_\n> + * \\brief The data type\n> + */\n> +\n> +/**\n> + * \\var Data::size_\n> + * \\brief The data size\n> + */\n> +\n> +#endif\n\n\nTo here ...\n\n\n> +\n> +/**\n> + * \\class DataValue\n> + * \\brief Polymorphic data value\n> + *\n> + * DataValue holds values of different types, defined by DataType providing\n> + * a unified interface to access and modify the data content.\n> + *\n> + * DataValue instances are used by classes that need to represent and store\n> + * numerical values of different types.\n> + *\n> + * \\todo Add support for compound data types, such as arrays.\n> + */\n> +\n> +/**\n> + * \\brief Construct an empty DataValue\n> + */\n> +DataValue::DataValue()\n> +\t: type_(DataTypeNone), size_(DataSize[type_])\n> +{\n> +}\n> +\n> +/**\n> + * \\brief Construct a DataValue copying data from \\a other\n> + * \\param[in] other The DataValue to copy data from\n> + *\n> + * DataValue copy constructor.\n> + */\n> +DataValue::DataValue(const DataValue &other)\n> +\t: type_(other.type()), size_(DataSize[type_])\n\nDoes this type need a copy constructor currently?\nWon't C++ just copy the whole object, which would be equivalent?\n\nThat said, if/when this class becomes more complex then it would likely\nneed some sort of specialisation - so it doesn't hurt to have it already.\n\n> +{\n> +\tswitch (type_) {\n> +\tcase DataTypeBool:\n> +\t\tbool_ = other.getBool();\n> +\t\tbreak;\n> +\tcase DataTypeInteger:\n> +\t\tinteger_ = other.getInt();\n> +\t\tbreak;\n> +\tcase DataTypeInteger64:\n> +\t\tinteger64_ = other.getInt64();\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tbool_ = integer_ = integer64_ = 0;\n> +\t\tbreak;\n> +\t}\n> +}\n> +\n> +/**\n> + * \\brief Construct a boolean DataValue\n> + * \\param[in] value Boolean value to store\n> + */\n> +DataValue::DataValue(bool value)\n> +\t: type_(DataTypeBool), size_(DataSize[type_]), bool_(value)\n> +{\n> +}\n> +\n> +/**\n> + * \\brief Construct an integer DataValue\n> + * \\param[in] value Integer value to store\n> + */\n> +DataValue::DataValue(int value)\n> +\t: type_(DataTypeInteger), size_(DataSize[type_]), integer_(value)\n> +{\n> +}\n> +\n> +/**\n> + * \\brief Construct a 64 bit integer DataValue\n> + * \\param[in] value 64-bits integer value to store\n> + */\n> +DataValue::DataValue(int64_t value)\n> +\t: type_(DataTypeInteger64), size_(DataSize[type_]), integer64_(value)\n> +{\n> +}\n> +\n> +/**\n> + * \\brief Assign the DataValue type and value using the ones from \\a other\n> + * \\param[in] other The DataValue to copy type and value from\n> + *\n> + * DataValue assignement operator.\n\ns/assignement/assignment/\n\n> + *\n> + * \\return The DataValue with fields updated using the ones from \\a other\n> + */\n> +DataValue &DataValue::operator=(const DataValue &other)\n> +{\n> +\tDataType newType = other.type();\n> +\ttype_ = newType;\n> +\tsize_ = DataSize[type_];\n> +\n> +\tswitch (newType) {\n> +\tcase DataTypeBool:\n> +\t\tbool_ = other.getBool();\n> +\t\tbreak;\n> +\tcase DataTypeInteger:\n> +\t\tinteger_ = other.getInt();\n> +\t\tbreak;\n> +\tcase DataTypeInteger64:\n> +\t\tinteger64_ = other.getInt64();\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tbool_ = integer_ = integer64_ = 0;\n> +\t\tbreak;\n> +\t}\n> +\n> +\treturn *this;\n> +}\n> +\n> +/**\n> + * \\fn DataValue::type()\n> + * \\brief Retrieve the data type of the data\n> + * \\return The type of the data\n> + */\n> +\n> +/**\n> + * \\fn DataValue::size()\n> + * \\brief Retrieve the size in bytes of the data\n> + * \\return The size in bytes of the data\n> + */\n> +\n> +/**\n> + * \\brief Set the value with a boolean\n> + * \\param[in] value Boolean value to store\n> + */\n> +void DataValue::set(bool value)\n> +{\n> +\ttype_ = DataTypeBool;\n> +\tsize_ = DataSize[type_];\n> +\tbool_ = value;\n> +}\n> +\n> +/**\n> + * \\brief Set the value with an integer\n> + * \\param[in] value Integer value to store\n> + */\n> +void DataValue::set(int value)\n> +{\n> +\ttype_ = DataTypeInteger;\n> +\tsize_ = DataSize[type_];\n> +\tinteger_ = value;\n> +}\n> +\n> +/**\n> + * \\brief Set the value with a 64 bit integer\n> + * \\param[in] value 64 bit integer value to store\n> + */\n> +void DataValue::set(int64_t value)\n> +{\n> +\ttype_ = DataTypeInteger64;\n> +\tsize_ = DataSize[type_];\n> +\tinteger64_ = value;\n> +}\n> +\n> +/**\n> + * \\brief Get the boolean value\n> + *\n> + * The value type must be Boolean.\n> + *\n> + * \\return The boolean value\n> + */\n> +bool DataValue::getBool() const\n> +{\n> +\tASSERT(type_ == DataTypeBool);\n> +\n> +\treturn bool_;\n> +}\n> +\n> +/**\n> + * \\brief Get the integer value\n> + *\n> + * The value type must be Integer or Integer64.\n> + *\n> + * \\return The integer value\n> + */\n> +int DataValue::getInt() const\n> +{\n> +\tASSERT(type_ == DataTypeInteger || type_ == DataTypeInteger64);\n> +\n> +\treturn integer_;\n> +}\n> +\n> +/**\n> + * \\brief Get the 64-bit integer value\n> + *\n> + * The value type must be Integer or Integer64.\n> + *\n> + * \\return The 64-bit integer value\n> + */\n> +int64_t DataValue::getInt64() const\n> +{\n> +\tASSERT(type_ == DataTypeInteger || type_ == DataTypeInteger64);\n> +\n> +\treturn integer64_;\n> +}\n> +\n> +/**\n> + * \\brief Assemble and return a string describing the value\n> + * \\return A string describing the DataValue\n> + */\n> +std::string DataValue::toString() const\n> +{\n> +\tswitch (type_) {\n> +\tcase DataTypeBool:\n> +\t\treturn bool_ ? \"True\" : \"False\";\n> +\tcase DataTypeInteger:\n> +\t\treturn std::to_string(integer_);\n> +\tcase DataTypeInteger64:\n> +\t\treturn std::to_string(integer64_);\n> +\tdefault:\n> +\t\treturn \"<None>\";\n\n\nI haven't tried to compile this yet, but doesn't this generate a\ncompiler warning?\n\nI thought C++ was very picky about switch statements not explicitly\nstating all enum types... Perhaps not when a default statement is provided.\n\nchanging this to:\n\n\t...\n\n\tcase DataTypeNone:\n\t\treturn \"<None>\";\n\t}\n\n\treturn \"<INVALID TYPE>\";\n}\n\nwould in that case ensure that this function is always updated (forced\nby the compiler) whenever a new type is added?\n\n> +\t}\n> +}\n> +\n> +/**\n> + * \\class DataInfo\n> + * \\brief Validation informations associated with a data value\n> + *\n> + * The DataInfo class represents static information associated with data\n> + * types that represent plymorhpic values abstracted by the DataValue class.\n\ns/plymorhpic/polymorphic/\n\n\n> + *\n> + * DataInfo stores static informations such as the value minimum and maximum\n> + * values and for compound values the maximum and minimum number of elements.\n> + */\n> +\n> +/**\n> + * \\fn DataInfo::DataInfo\n> + * \\brief Construct a data info with \\a min and \\a max values\n> + * \\param[in] min The minimum allowed value\n> + * \\param[in] max The maximum allowed value\n> + */\n> +\n> +/**\n> + * \\fn DataInfo::min()\n> + * \\brief Retrieve the DataInfo minimum allowed value\n> + * \\return A DataValue representing the minimum allowed value\n> + */\n> +\n> +/**\n> + * \\fn DataInfo::max()\n> + * \\brief Retrieve the DataInfo maximum allowed value\n> + * \\return A DataValue representing the maximum allowed value\n> + */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index 755149c55c7b..c3100a1709e0 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -5,6 +5,7 @@ libcamera_sources = files([\n>      'camera_manager.cpp',\n>      'camera_sensor.cpp',\n>      'controls.cpp',\n> +    'data_value.cpp',\n>      'device_enumerator.cpp',\n>      'device_enumerator_sysfs.cpp',\n>      'event_dispatcher.cpp',\n> diff --git a/test/data_value/data_value.cpp b/test/data_value/data_value.cpp\n> new file mode 100644\n> index 000000000000..64061000c1e4\n> --- /dev/null\n> +++ b/test/data_value/data_value.cpp\n> @@ -0,0 +1,59 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * data_value.cpp - DataValue tests\n> + */\n> +\n> +#include <iostream>\n> +\n> +#include <libcamera/data_value.h>\n> +\n> +#include \"test.h\"\n> +\n> +using namespace std;\n> +using namespace libcamera;\n> +\n> +class DataValueTest : public Test\n> +{\n> +protected:\n> +\tint run()\n> +\t{\n> +\t\tDataValue integer(1234);\n> +\t\tDataValue boolean(true);\n> +\n> +\t\t/* Just a string conversion output test... no validation */\n> +\t\tcout << \"Int: \" << integer.toString()\n> +\t\t     << \" Bool: \" << boolean.toString()\n> +\t\t     << endl;\n> +\n> +\t\tif (integer.getInt() != 1234) {\n> +\t\t\tcerr << \"Failed to get Integer\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (boolean.getBool() != true) {\n> +\t\t\tcerr << \"Failed to get Boolean\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Test an uninitialised value, and updating it. */\n> +\n> +\t\tDataValue value;\n> +\t\tvalue.set(true);\n> +\t\tif (value.getBool() != true) {\n> +\t\t\tcerr << \"Failed to get Booleans\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tvalue.set(10);\n> +\t\tif (value.getInt() != 10) {\n> +\t\t\tcerr << \"Failed to get Integer\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +};\n> +\n> +TEST_REGISTER(DataValueTest)\n> diff --git a/test/data_value/meson.build b/test/data_value/meson.build\n> new file mode 100644\n> index 000000000000..3858e6085a1f\n> --- /dev/null\n> +++ b/test/data_value/meson.build\n> @@ -0,0 +1,12 @@\n> +data_value_tests = [\n> +    [ 'data_value',   'data_value.cpp' ],\n> +]\n> +\n> +foreach t : data_value_tests\n> +    exe = executable(t[0], t[1],\n> +                     dependencies : libcamera_dep,\n> +                     link_with : test_libraries,\n> +                     include_directories : test_includes_internal)\n> +    test(t[0], exe, suite : 'data_value', is_parallel : false)\n> +endforeach\n\n\nDoes data_value need a whole subdirectory for a single test? Will it\nhave multiple tests in the (near) future?\n\nI really dislike adding a subdirectory/test suite just for a single test\nunless we really know it's going to be extended.\n\n> +\n> diff --git a/test/meson.build b/test/meson.build\n> index 84722cceb35d..5d414b22dc0c 100644\n> --- a/test/meson.build\n> +++ b/test/meson.build\n> @@ -2,6 +2,7 @@ subdir('libtest')\n> \n>  subdir('camera')\n>  subdir('controls')\n> +subdir('data_value')\n>  subdir('ipa')\n>  subdir('ipc')\n>  subdir('log')\n> --\n> 2.23.0\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel\n>","headers":{"Return-Path":"<kieran.bingham@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3C7F660BED\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 20 Sep 2019 12:03:59 +0200 (CEST)","from [192.168.0.20]\n\t(cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 99EE12F9;\n\tFri, 20 Sep 2019 12:03:58 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1568973838;\n\tbh=xKTsqYkXeaDgb3pA4g/OQsqJ9F0/6u9ihmpI2tVOWLA=;\n\th=Reply-To:Subject:To:References:From:Date:In-Reply-To:From;\n\tb=u0Va17J0lTZOWQp6VsKwINqOPQA97ap76OWkfE/gYwZNlbYp09elJDq2GAAl2y4tj\n\tSrmSBH4Dtr4pTe1Kd2Xgbr6vehy5iIAWpJm8bRbZOg1YUgKgYsK6FWwWuIJn1L0GNV\n\tsaLI73QUB9lAstVOXKg2Hfk4AcpVTwza8VkjNZYU=","Reply-To":"kieran.bingham@ideasonboard.com","To":"Jacopo Mondi <jacopo@jmondi.org>, libcamera-devel@lists.libcamera.org","References":"<20190918103424.14536-1-jacopo@jmondi.org>\n\t<20190918103424.14536-2-jacopo@jmondi.org>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Openpgp":"preference=signencrypt","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\t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","Organization":"Ideas on Board","Message-ID":"<dbe98177-d70d-5cb8-8a48-458d3549df94@ideasonboard.com>","Date":"Fri, 20 Sep 2019 11:03:55 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.8.0","MIME-Version":"1.0","In-Reply-To":"<20190918103424.14536-2-jacopo@jmondi.org>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH 1/5] libcamera: Create DataValue and\n\tDataInfo","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Fri, 20 Sep 2019 10:03:59 -0000"}},{"id":2682,"web_url":"https://patchwork.libcamera.org/comment/2682/","msgid":"<20190923110257.itgysbf5hc6etk5m@uno.localdomain>","date":"2019-09-23T11:02:57","subject":"Re: [libcamera-devel] [PATCH 1/5] libcamera: Create DataValue and\n\tDataInfo","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Kieran,\n\nOn Fri, Sep 20, 2019 at 11:03:55AM +0100, Kieran Bingham wrote:\n> Hi Jacopo,\n>\n> On 18/09/2019 11:34, Jacopo Mondi wrote:\n> > Add the data_value.[h|c] files that provide an abstracted polymorphic\n> > data value type and a generic data info type that represent static\n> > information associated with a data value.\n> >\n> > DataValue is a slightly re-worked copy of the ControlValue type defined\n> > in controls.h, provided in a generic header to be used a foundation for\n> > both Controls and V4L2Controls classes that will be re-worked in the\n> > next patches in the series.\n>\n> So my\n> \"[RFC PATCH v2 1/9] libcamera: Value: Provide abstract value class\"\n>\n> concept comes back to life at last :-D\n>\n\nPossibly, sorry for having ignored the patch at the time\n\n> > Add a test for data value which is an adapted copy of the control value\n> > test, that will be removed in the next patch.\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> > ---\n> >  include/libcamera/data_value.h |  84 +++++++++\n> >  include/libcamera/meson.build  |   1 +\n> >  src/libcamera/data_value.cpp   | 317 +++++++++++++++++++++++++++++++++\n> >  src/libcamera/meson.build      |   1 +\n> >  test/data_value/data_value.cpp |  59 ++++++\n> >  test/data_value/meson.build    |  12 ++\n> >  test/meson.build               |   1 +\n> >  7 files changed, 475 insertions(+)\n> >  create mode 100644 include/libcamera/data_value.h\n> >  create mode 100644 src/libcamera/data_value.cpp\n> >  create mode 100644 test/data_value/data_value.cpp\n> >  create mode 100644 test/data_value/meson.build\n> >\n> > diff --git a/include/libcamera/data_value.h b/include/libcamera/data_value.h\n> > new file mode 100644\n> > index 000000000000..0fcd9bd04a65\n> > --- /dev/null\n> > +++ b/include/libcamera/data_value.h\n> > @@ -0,0 +1,84 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * data_value.h - Polymorphic data value type\n> > + */\n> > +#ifndef __LIBCAMERA_DATA_VALUE_H__\n> > +#define __LIBCAMERA_DATA_VALUE_H__\n> > +\n> > +#include <cstdint>\n> > +#include <string>\n> > +\n> > +namespace libcamera {\n> > +\n> > +enum DataType {\n> > +\tDataTypeNone,\n> > +\tDataTypeBool,\n> > +\tDataTypeInteger,\n> > +\tDataTypeInteger64,\n> > +\tDataTypeNumber,\n> > +};\n> > +\n> > +static constexpr size_t DataSize[DataTypeNumber] = {\n> > +\t[DataTypeNone]\t\t= 1,\n>\n> Shouldn't this be 0?\n>\n\nI would prefer 1, to avoid division by 0\n\n> > +\t[DataTypeBool]\t\t= 4,\n>\n> sizeof(bool) == 1 ...\n>\n\nTIL\n>\n>\n> > +\t[DataTypeInteger]\t= 4,\n> > +\t[DataTypeInteger64]\t= 8,\n>\n> You could instead do:\n>\n> static constexpr size_t DataSize[DataTypeNumber] = {\n> \t[DataTypeNone]\t\t= 0,\n> \t[DataTypeBool]\t\t= sizeof(bool),\n> \t[DataTypeInteger]\t= sizeof(int32_t),\n> \t[DataTypeInteger64]\t= sizeof(int64_t),\n\nbetter, I'll take this is with TypeNone = 1\n\n> };\n>\n> > +};\n> > +\n> > +class DataValue\n> > +{\n> > +public:\n> > +\tDataValue();\n> > +\tDataValue(const DataValue &other);\n> > +\tDataValue(bool value);\n> > +\tDataValue(int value);\n> > +\tDataValue(int64_t value);\n> > +\n> > +\tDataValue &operator=(const DataValue &other);\n> > +\n> > +\tenum DataType type() const { return type_; }\n> > +\tsize_t size() const { return size_; }\n> > +\n> > +\tvoid set(bool value);\n> > +\tvoid set(int value);\n> > +\tvoid set(int64_t value);\n> > +\n> > +\tbool getBool() const;\n> > +\tint getInt() const;\n> > +\tint64_t getInt64() const;\n> > +\n> > +\tstd::string toString() const;\n> > +\n> > +private:\n> > +\tDataType type_;\n> > +\tsize_t size_;\n> > +\n> > +\tunion {\n> > +\t\tbool bool_;\n> > +\t\tint integer_;\n> > +\t\tint64_t integer64_;\n> > +\t};\n> > +};\n> > +\n> > +class DataInfo\n> > +{\n> > +public:\n> > +\tDataInfo(const DataValue &min, const DataValue &max)\n> > +\t{\n> > +\t\tmin_ = min;\n> > +\t\tmax_ = max;\n> > +\t}\n> > +\n> > +\tconst DataValue &min() const { return min_; }\n> > +\tconst DataValue &max() const { return max_; }\n> > +\n> > +private:\n> > +\tDataValue max_;\n> > +\tDataValue min_;\n> > +};\n> > +\n> > +} /* namespace libcamera */\n> > +\n> > +#endif /* __LIBCAMERA_DATA_VALUE_H__ */\n> > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build\n> > index 868f1a6bf1ab..e3f3ad504446 100644\n> > --- a/include/libcamera/meson.build\n> > +++ b/include/libcamera/meson.build\n> > @@ -5,6 +5,7 @@ libcamera_api = files([\n> >      'camera_manager.h',\n> >      'control_ids.h',\n> >      'controls.h',\n> > +    'data_value.h',\n> >      'event_dispatcher.h',\n> >      'event_notifier.h',\n> >      'geometry.h',\n> > diff --git a/src/libcamera/data_value.cpp b/src/libcamera/data_value.cpp\n> > new file mode 100644\n> > index 000000000000..f07b5fb75a8a\n> > --- /dev/null\n> > +++ b/src/libcamera/data_value.cpp\n> > @@ -0,0 +1,317 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * data_value.cpp - Polymorphic data value type\n> > + */\n> > +\n> > +#include <libcamera/data_value.h>\n> > +\n> > +#include <cstdint>\n> > +#include <sstream>\n> > +#include <string>\n> > +\n> > +#include \"utils.h\"\n> > +#include \"log.h\"\n> > +\n> > +/**\n> > + * \\file data_value.h\n> > + * \\brief Polymorphic data type\n> > + */\n> > +\n> > +namespace libcamera {\n> > +\n> > +/**\n> > + * \\enum DataType\n> > + * \\brief Define the supported data types\n> > + * \\var DataTypeNone\n> > + * Identifies an unset value\n> > + * \\var DataTypeBool\n> > + * Identifies DataType storing a boolean value\n> > + * \\var DataTypeInteger\n> > + * Identifies DataType storing an integer value\n> > + * \\var DataTypeInteger64\n> > + * Identifies DataType storing a 64-bit integer value\n> > + */\n> > +\n> > +/**\n> > + * \\var DataSize\n> > + * \\brief Associate to each data type the memory size in bytes\n> > + */\n> > +\n>\n>\n> You have a rogue if 0 below\n>\n\nUps! thanks!\n\n> > +#if 0\n> > +/**\n> > + * \\class Data\n> > + * \\brief Base class for data value and data info instances\n> > + *\n> > + * DataValue and DataInfo share basic information like size and type.\n> > + * This class provides common fields and operations for them.\n> > + */\n> > +\n> > +/**\n> > + * \\brief Construct a Data of \\a type\n> > + * \\param[in] type The Data type defined by DataType\n> > + */\n> > +Data::Data(DataType type)\n> > +\t: type_(type)\n> > +{\n> > +\t/*\n> > +\t * \\todo The size of compound data types depend on the number of\n> > +\t * elements too.\n> > +\t */\n> > +\tsize_ = DataSize[type_];\n> > +}\n> > +\n> > +/**\n> > + * \\var Data::type_\n> > + * \\brief The data type\n> > + */\n> > +\n> > +/**\n> > + * \\var Data::size_\n> > + * \\brief The data size\n> > + */\n> > +\n> > +#endif\n>\n>\n> To here ...\n>\n>\n> > +\n> > +/**\n> > + * \\class DataValue\n> > + * \\brief Polymorphic data value\n> > + *\n> > + * DataValue holds values of different types, defined by DataType providing\n> > + * a unified interface to access and modify the data content.\n> > + *\n> > + * DataValue instances are used by classes that need to represent and store\n> > + * numerical values of different types.\n> > + *\n> > + * \\todo Add support for compound data types, such as arrays.\n> > + */\n> > +\n> > +/**\n> > + * \\brief Construct an empty DataValue\n> > + */\n> > +DataValue::DataValue()\n> > +\t: type_(DataTypeNone), size_(DataSize[type_])\n> > +{\n> > +}\n> > +\n> > +/**\n> > + * \\brief Construct a DataValue copying data from \\a other\n> > + * \\param[in] other The DataValue to copy data from\n> > + *\n> > + * DataValue copy constructor.\n> > + */\n> > +DataValue::DataValue(const DataValue &other)\n> > +\t: type_(other.type()), size_(DataSize[type_])\n>\n> Does this type need a copy constructor currently?\n\nI think it will be used during serialization implementation\n\n> Won't C++ just copy the whole object, which would be equivalent?\n>\n\nPossibly, I wanted this explicit because of the above assignements to\nthe correct field. I'll check if I need this.\n\n> That said, if/when this class becomes more complex then it would likely\n> need some sort of specialisation - so it doesn't hurt to have it already.\n>\n> > +{\n> > +\tswitch (type_) {\n> > +\tcase DataTypeBool:\n> > +\t\tbool_ = other.getBool();\n> > +\t\tbreak;\n> > +\tcase DataTypeInteger:\n> > +\t\tinteger_ = other.getInt();\n> > +\t\tbreak;\n> > +\tcase DataTypeInteger64:\n> > +\t\tinteger64_ = other.getInt64();\n> > +\t\tbreak;\n> > +\tdefault:\n> > +\t\tbool_ = integer_ = integer64_ = 0;\n> > +\t\tbreak;\n> > +\t}\n> > +}\n> > +\n> > +/**\n> > + * \\brief Construct a boolean DataValue\n> > + * \\param[in] value Boolean value to store\n> > + */\n> > +DataValue::DataValue(bool value)\n> > +\t: type_(DataTypeBool), size_(DataSize[type_]), bool_(value)\n> > +{\n> > +}\n> > +\n> > +/**\n> > + * \\brief Construct an integer DataValue\n> > + * \\param[in] value Integer value to store\n> > + */\n> > +DataValue::DataValue(int value)\n> > +\t: type_(DataTypeInteger), size_(DataSize[type_]), integer_(value)\n> > +{\n> > +}\n> > +\n> > +/**\n> > + * \\brief Construct a 64 bit integer DataValue\n> > + * \\param[in] value 64-bits integer value to store\n> > + */\n> > +DataValue::DataValue(int64_t value)\n> > +\t: type_(DataTypeInteger64), size_(DataSize[type_]), integer64_(value)\n> > +{\n> > +}\n> > +\n> > +/**\n> > + * \\brief Assign the DataValue type and value using the ones from \\a other\n> > + * \\param[in] other The DataValue to copy type and value from\n> > + *\n> > + * DataValue assignement operator.\n>\n> s/assignement/assignment/\n>\n> > + *\n> > + * \\return The DataValue with fields updated using the ones from \\a other\n> > + */\n> > +DataValue &DataValue::operator=(const DataValue &other)\n> > +{\n> > +\tDataType newType = other.type();\n> > +\ttype_ = newType;\n> > +\tsize_ = DataSize[type_];\n> > +\n> > +\tswitch (newType) {\n> > +\tcase DataTypeBool:\n> > +\t\tbool_ = other.getBool();\n> > +\t\tbreak;\n> > +\tcase DataTypeInteger:\n> > +\t\tinteger_ = other.getInt();\n> > +\t\tbreak;\n> > +\tcase DataTypeInteger64:\n> > +\t\tinteger64_ = other.getInt64();\n> > +\t\tbreak;\n> > +\tdefault:\n> > +\t\tbool_ = integer_ = integer64_ = 0;\n> > +\t\tbreak;\n> > +\t}\n> > +\n> > +\treturn *this;\n> > +}\n> > +\n> > +/**\n> > + * \\fn DataValue::type()\n> > + * \\brief Retrieve the data type of the data\n> > + * \\return The type of the data\n> > + */\n> > +\n> > +/**\n> > + * \\fn DataValue::size()\n> > + * \\brief Retrieve the size in bytes of the data\n> > + * \\return The size in bytes of the data\n> > + */\n> > +\n> > +/**\n> > + * \\brief Set the value with a boolean\n> > + * \\param[in] value Boolean value to store\n> > + */\n> > +void DataValue::set(bool value)\n> > +{\n> > +\ttype_ = DataTypeBool;\n> > +\tsize_ = DataSize[type_];\n> > +\tbool_ = value;\n> > +}\n> > +\n> > +/**\n> > + * \\brief Set the value with an integer\n> > + * \\param[in] value Integer value to store\n> > + */\n> > +void DataValue::set(int value)\n> > +{\n> > +\ttype_ = DataTypeInteger;\n> > +\tsize_ = DataSize[type_];\n> > +\tinteger_ = value;\n> > +}\n> > +\n> > +/**\n> > + * \\brief Set the value with a 64 bit integer\n> > + * \\param[in] value 64 bit integer value to store\n> > + */\n> > +void DataValue::set(int64_t value)\n> > +{\n> > +\ttype_ = DataTypeInteger64;\n> > +\tsize_ = DataSize[type_];\n> > +\tinteger64_ = value;\n> > +}\n> > +\n> > +/**\n> > + * \\brief Get the boolean value\n> > + *\n> > + * The value type must be Boolean.\n> > + *\n> > + * \\return The boolean value\n> > + */\n> > +bool DataValue::getBool() const\n> > +{\n> > +\tASSERT(type_ == DataTypeBool);\n> > +\n> > +\treturn bool_;\n> > +}\n> > +\n> > +/**\n> > + * \\brief Get the integer value\n> > + *\n> > + * The value type must be Integer or Integer64.\n> > + *\n> > + * \\return The integer value\n> > + */\n> > +int DataValue::getInt() const\n> > +{\n> > +\tASSERT(type_ == DataTypeInteger || type_ == DataTypeInteger64);\n> > +\n> > +\treturn integer_;\n> > +}\n> > +\n> > +/**\n> > + * \\brief Get the 64-bit integer value\n> > + *\n> > + * The value type must be Integer or Integer64.\n> > + *\n> > + * \\return The 64-bit integer value\n> > + */\n> > +int64_t DataValue::getInt64() const\n> > +{\n> > +\tASSERT(type_ == DataTypeInteger || type_ == DataTypeInteger64);\n> > +\n> > +\treturn integer64_;\n> > +}\n> > +\n> > +/**\n> > + * \\brief Assemble and return a string describing the value\n> > + * \\return A string describing the DataValue\n> > + */\n> > +std::string DataValue::toString() const\n> > +{\n> > +\tswitch (type_) {\n> > +\tcase DataTypeBool:\n> > +\t\treturn bool_ ? \"True\" : \"False\";\n> > +\tcase DataTypeInteger:\n> > +\t\treturn std::to_string(integer_);\n> > +\tcase DataTypeInteger64:\n> > +\t\treturn std::to_string(integer64_);\n> > +\tdefault:\n> > +\t\treturn \"<None>\";\n>\n>\n> I haven't tried to compile this yet, but doesn't this generate a\n> compiler warning?\n>\n> I thought C++ was very picky about switch statements not explicitly\n> stating all enum types... Perhaps not when a default statement is provided.\n>\n> changing this to:\n>\n> \t...\n>\n> \tcase DataTypeNone:\n> \t\treturn \"<None>\";\n> \t}\n>\n> \treturn \"<INVALID TYPE>\";\n> }\n>\n> would in that case ensure that this function is always updated (forced\n> by the compiler) whenever a new type is added?\n\nYeah, default catches all the remaning cases but hides issues when we\nmiss adding a value. I'll change.\n\n>\n> > +\t}\n> > +}\n> > +\n> > +/**\n> > + * \\class DataInfo\n> > + * \\brief Validation informations associated with a data value\n> > + *\n> > + * The DataInfo class represents static information associated with data\n> > + * types that represent plymorhpic values abstracted by the DataValue class.\n>\n> s/plymorhpic/polymorphic/\n>\n>\n> > + *\n> > + * DataInfo stores static informations such as the value minimum and maximum\n> > + * values and for compound values the maximum and minimum number of elements.\n> > + */\n> > +\n> > +/**\n> > + * \\fn DataInfo::DataInfo\n> > + * \\brief Construct a data info with \\a min and \\a max values\n> > + * \\param[in] min The minimum allowed value\n> > + * \\param[in] max The maximum allowed value\n> > + */\n> > +\n> > +/**\n> > + * \\fn DataInfo::min()\n> > + * \\brief Retrieve the DataInfo minimum allowed value\n> > + * \\return A DataValue representing the minimum allowed value\n> > + */\n> > +\n> > +/**\n> > + * \\fn DataInfo::max()\n> > + * \\brief Retrieve the DataInfo maximum allowed value\n> > + * \\return A DataValue representing the maximum allowed value\n> > + */\n> > +\n> > +} /* namespace libcamera */\n> > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> > index 755149c55c7b..c3100a1709e0 100644\n> > --- a/src/libcamera/meson.build\n> > +++ b/src/libcamera/meson.build\n> > @@ -5,6 +5,7 @@ libcamera_sources = files([\n> >      'camera_manager.cpp',\n> >      'camera_sensor.cpp',\n> >      'controls.cpp',\n> > +    'data_value.cpp',\n> >      'device_enumerator.cpp',\n> >      'device_enumerator_sysfs.cpp',\n> >      'event_dispatcher.cpp',\n> > diff --git a/test/data_value/data_value.cpp b/test/data_value/data_value.cpp\n> > new file mode 100644\n> > index 000000000000..64061000c1e4\n> > --- /dev/null\n> > +++ b/test/data_value/data_value.cpp\n> > @@ -0,0 +1,59 @@\n> > +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * data_value.cpp - DataValue tests\n> > + */\n> > +\n> > +#include <iostream>\n> > +\n> > +#include <libcamera/data_value.h>\n> > +\n> > +#include \"test.h\"\n> > +\n> > +using namespace std;\n> > +using namespace libcamera;\n> > +\n> > +class DataValueTest : public Test\n> > +{\n> > +protected:\n> > +\tint run()\n> > +\t{\n> > +\t\tDataValue integer(1234);\n> > +\t\tDataValue boolean(true);\n> > +\n> > +\t\t/* Just a string conversion output test... no validation */\n> > +\t\tcout << \"Int: \" << integer.toString()\n> > +\t\t     << \" Bool: \" << boolean.toString()\n> > +\t\t     << endl;\n> > +\n> > +\t\tif (integer.getInt() != 1234) {\n> > +\t\t\tcerr << \"Failed to get Integer\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\tif (boolean.getBool() != true) {\n> > +\t\t\tcerr << \"Failed to get Boolean\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/* Test an uninitialised value, and updating it. */\n> > +\n> > +\t\tDataValue value;\n> > +\t\tvalue.set(true);\n> > +\t\tif (value.getBool() != true) {\n> > +\t\t\tcerr << \"Failed to get Booleans\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\tvalue.set(10);\n> > +\t\tif (value.getInt() != 10) {\n> > +\t\t\tcerr << \"Failed to get Integer\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\treturn TestPass;\n> > +\t}\n> > +};\n> > +\n> > +TEST_REGISTER(DataValueTest)\n> > diff --git a/test/data_value/meson.build b/test/data_value/meson.build\n> > new file mode 100644\n> > index 000000000000..3858e6085a1f\n> > --- /dev/null\n> > +++ b/test/data_value/meson.build\n> > @@ -0,0 +1,12 @@\n> > +data_value_tests = [\n> > +    [ 'data_value',   'data_value.cpp' ],\n> > +]\n> > +\n> > +foreach t : data_value_tests\n> > +    exe = executable(t[0], t[1],\n> > +                     dependencies : libcamera_dep,\n> > +                     link_with : test_libraries,\n> > +                     include_directories : test_includes_internal)\n> > +    test(t[0], exe, suite : 'data_value', is_parallel : false)\n> > +endforeach\n>\n>\n> Does data_value need a whole subdirectory for a single test? Will it\n> have multiple tests in the (near) future?\n\nI thought so, but in the end I only added one\n\n>\n> I really dislike adding a subdirectory/test suite just for a single test\n> unless we really know it's going to be extended.\n>\n\nWhere would you put this?\n\n> > +\n> > diff --git a/test/meson.build b/test/meson.build\n> > index 84722cceb35d..5d414b22dc0c 100644\n> > --- a/test/meson.build\n> > +++ b/test/meson.build\n> > @@ -2,6 +2,7 @@ subdir('libtest')\n> >\n> >  subdir('camera')\n> >  subdir('controls')\n> > +subdir('data_value')\n> >  subdir('ipa')\n> >  subdir('ipc')\n> >  subdir('log')\n> > --\n> > 2.23.0\n> >\n> > _______________________________________________\n> > libcamera-devel mailing list\n> > libcamera-devel@lists.libcamera.org\n> > https://lists.libcamera.org/listinfo/libcamera-devel\n> >\n>\n> --\n> Regards\n> --\n> Kieran","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net\n\t[217.70.183.199])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7B12860BCE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 23 Sep 2019 13:01:22 +0200 (CEST)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay9-d.mail.gandi.net (Postfix) with ESMTPSA id C6DABFF80F;\n\tMon, 23 Sep 2019 11:01:21 +0000 (UTC)"],"X-Originating-IP":"2.224.242.101","Date":"Mon, 23 Sep 2019 13:02:57 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190923110257.itgysbf5hc6etk5m@uno.localdomain>","References":"<20190918103424.14536-1-jacopo@jmondi.org>\n\t<20190918103424.14536-2-jacopo@jmondi.org>\n\t<dbe98177-d70d-5cb8-8a48-458d3549df94@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"m6y6qo4rwi67yhbd\"","Content-Disposition":"inline","In-Reply-To":"<dbe98177-d70d-5cb8-8a48-458d3549df94@ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH 1/5] libcamera: Create DataValue and\n\tDataInfo","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Mon, 23 Sep 2019 11:01:22 -0000"}},{"id":2687,"web_url":"https://patchwork.libcamera.org/comment/2687/","msgid":"<a52facd9-32aa-5a42-bf0d-2f1905b02011@ideasonboard.com>","date":"2019-09-23T11:53:29","subject":"Re: [libcamera-devel] [PATCH 1/5] libcamera: Create DataValue and\n\tDataInfo","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn 23/09/2019 12:02, Jacopo Mondi wrote:\n> Hi Kieran,\n> \n> On Fri, Sep 20, 2019 at 11:03:55AM +0100, Kieran Bingham wrote:\n>> Hi Jacopo,\n>>\n\n<snip>\n\n>>> +TEST_REGISTER(DataValueTest)\n>>> diff --git a/test/data_value/meson.build b/test/data_value/meson.build\n>>> new file mode 100644\n>>> index 000000000000..3858e6085a1f\n>>> --- /dev/null\n>>> +++ b/test/data_value/meson.build\n>>> @@ -0,0 +1,12 @@\n>>> +data_value_tests = [\n>>> +    [ 'data_value',   'data_value.cpp' ],\n>>> +]\n>>> +\n>>> +foreach t : data_value_tests\n>>> +    exe = executable(t[0], t[1],\n>>> +                     dependencies : libcamera_dep,\n>>> +                     link_with : test_libraries,\n>>> +                     include_directories : test_includes_internal)\n>>> +    test(t[0], exe, suite : 'data_value', is_parallel : false)\n>>> +endforeach\n>>\n>>\n>> Does data_value need a whole subdirectory for a single test? Will it\n>> have multiple tests in the (near) future?\n> \n> I thought so, but in the end I only added one\n> \n>>\n>> I really dislike adding a subdirectory/test suite just for a single test\n>> unless we really know it's going to be extended.\n>>\n> \n> Where would you put this?\n\njust test/data_value.cpp for the moment!\n\n>> Regards\n>> --\n>> Kieran","headers":{"Return-Path":"<kieran.bingham@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 16FAA60BB0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 23 Sep 2019 13:53:33 +0200 (CEST)","from [192.168.0.20]\n\t(cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 374FB53B;\n\tMon, 23 Sep 2019 13:53:32 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1569239612;\n\tbh=+IfOG8nKqRTDXQGTRDqZIxq/Xl4dPVgkT+BffkTKxQc=;\n\th=Reply-To:Subject:To:Cc:References:From:Date:In-Reply-To:From;\n\tb=BP31Y3BfDtN31ua9/cqb1puRjZnIUwAqqoyaKnY16007al0ijWjpRdQ+r88j7L+5J\n\tG+YbM5bE8YcIZ9O22YPNJ5IXR8gG8mXiZ3ZSGWxTPzftzL+zxJ/HDKJg3siboWXRYt\n\tbphc0o36RZP2tIk9ss4d9LwRJMhaA/htam7m/kKM=","Reply-To":"kieran.bingham@ideasonboard.com","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20190918103424.14536-1-jacopo@jmondi.org>\n\t<20190918103424.14536-2-jacopo@jmondi.org>\n\t<dbe98177-d70d-5cb8-8a48-458d3549df94@ideasonboard.com>\n\t<20190923110257.itgysbf5hc6etk5m@uno.localdomain>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Openpgp":"preference=signencrypt","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\t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","Organization":"Ideas on Board","Message-ID":"<a52facd9-32aa-5a42-bf0d-2f1905b02011@ideasonboard.com>","Date":"Mon, 23 Sep 2019 12:53:29 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.8.0","MIME-Version":"1.0","In-Reply-To":"<20190923110257.itgysbf5hc6etk5m@uno.localdomain>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"7bit","Subject":"Re: [libcamera-devel] [PATCH 1/5] libcamera: Create DataValue and\n\tDataInfo","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Mon, 23 Sep 2019 11:53:34 -0000"}},{"id":2704,"web_url":"https://patchwork.libcamera.org/comment/2704/","msgid":"<20190926221240.GC4864@pendragon.ideasonboard.com>","date":"2019-09-26T22:12:40","subject":"Re: [libcamera-devel] [PATCH 1/5] libcamera: Create DataValue and\n\tDataInfo","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hello,\n\nOn Mon, Sep 23, 2019 at 01:02:57PM +0200, Jacopo Mondi wrote:\n> On Fri, Sep 20, 2019 at 11:03:55AM +0100, Kieran Bingham wrote:\n> > On 18/09/2019 11:34, Jacopo Mondi wrote:\n> > > Add the data_value.[h|c] files that provide an abstracted polymorphic\n> > > data value type and a generic data info type that represent static\n> > > information associated with a data value.\n> > >\n> > > DataValue is a slightly re-worked copy of the ControlValue type defined\n> > > in controls.h, provided in a generic header to be used a foundation for\n> > > both Controls and V4L2Controls classes that will be re-worked in the\n> > > next patches in the series.\n> >\n> > So my\n> > \"[RFC PATCH v2 1/9] libcamera: Value: Provide abstract value class\"\n> >\n> > concept comes back to life at last :-D\n> \n> Possibly, sorry for having ignored the patch at the time\n> \n> > > Add a test for data value which is an adapted copy of the control value\n> > > test, that will be removed in the next patch.\n> > >\n> > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> > > ---\n> > >  include/libcamera/data_value.h |  84 +++++++++\n> > >  include/libcamera/meson.build  |   1 +\n> > >  src/libcamera/data_value.cpp   | 317 +++++++++++++++++++++++++++++++++\n> > >  src/libcamera/meson.build      |   1 +\n> > >  test/data_value/data_value.cpp |  59 ++++++\n> > >  test/data_value/meson.build    |  12 ++\n> > >  test/meson.build               |   1 +\n> > >  7 files changed, 475 insertions(+)\n> > >  create mode 100644 include/libcamera/data_value.h\n> > >  create mode 100644 src/libcamera/data_value.cpp\n> > >  create mode 100644 test/data_value/data_value.cpp\n> > >  create mode 100644 test/data_value/meson.build\n> > >\n> > > diff --git a/include/libcamera/data_value.h b/include/libcamera/data_value.h\n> > > new file mode 100644\n> > > index 000000000000..0fcd9bd04a65\n> > > --- /dev/null\n> > > +++ b/include/libcamera/data_value.h\n> > > @@ -0,0 +1,84 @@\n> > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > > +/*\n> > > + * Copyright (C) 2019, Google Inc.\n> > > + *\n> > > + * data_value.h - Polymorphic data value type\n> > > + */\n> > > +#ifndef __LIBCAMERA_DATA_VALUE_H__\n> > > +#define __LIBCAMERA_DATA_VALUE_H__\n> > > +\n> > > +#include <cstdint>\n> > > +#include <string>\n> > > +\n> > > +namespace libcamera {\n> > > +\n> > > +enum DataType {\n> > > +\tDataTypeNone,\n> > > +\tDataTypeBool,\n> > > +\tDataTypeInteger,\n> > > +\tDataTypeInteger64,\n> > > +\tDataTypeNumber,\n> > > +};\n> > > +\n> > > +static constexpr size_t DataSize[DataTypeNumber] = {\n> > > +\t[DataTypeNone]\t\t= 1,\n> >\n> > Shouldn't this be 0?\n> \n> I would prefer 1, to avoid division by 0\n> \n> > > +\t[DataTypeBool]\t\t= 4,\n> >\n> > sizeof(bool) == 1 ...\n> \n> TIL\n\nhttps://en.cppreference.com/w/cpp/language/types\n\nBoolean type\n\n    bool - type, capable of holding one of the two values: true or\n    false. The value of sizeof(bool) is implementation defined and might\n    differ from 1.\n\nIf you need to ensure inter-operability between compilers (for instance\nif the sizes are used to serialise/deserialise data) then you probably\nwant to specify the size of a bool explicitly. I think I would do the\nsame for the other types then.\n\n> > > +\t[DataTypeInteger]\t= 4,\n> > > +\t[DataTypeInteger64]\t= 8,\n> >\n> > You could instead do:\n> >\n> > static constexpr size_t DataSize[DataTypeNumber] = {\n> > \t[DataTypeNone]\t\t= 0,\n> > \t[DataTypeBool]\t\t= sizeof(bool),\n> > \t[DataTypeInteger]\t= sizeof(int32_t),\n> > \t[DataTypeInteger64]\t= sizeof(int64_t),\n> \n> better, I'll take this is with TypeNone = 1\n> \n> > };\n> >\n> > > +};\n> > > +\n> > > +class DataValue\n> > > +{\n> > > +public:\n> > > +\tDataValue();\n> > > +\tDataValue(const DataValue &other);\n> > > +\tDataValue(bool value);\n> > > +\tDataValue(int value);\n> > > +\tDataValue(int64_t value);\n> > > +\n> > > +\tDataValue &operator=(const DataValue &other);\n> > > +\n> > > +\tenum DataType type() const { return type_; }\n> > > +\tsize_t size() const { return size_; }\n> > > +\n> > > +\tvoid set(bool value);\n> > > +\tvoid set(int value);\n> > > +\tvoid set(int64_t value);\n> > > +\n> > > +\tbool getBool() const;\n> > > +\tint getInt() const;\n> > > +\tint64_t getInt64() const;\n> > > +\n> > > +\tstd::string toString() const;\n> > > +\n> > > +private:\n> > > +\tDataType type_;\n> > > +\tsize_t size_;\n> > > +\n> > > +\tunion {\n> > > +\t\tbool bool_;\n> > > +\t\tint integer_;\n> > > +\t\tint64_t integer64_;\n> > > +\t};\n> > > +};\n> > > +\n> > > +class DataInfo\n> > > +{\n> > > +public:\n> > > +\tDataInfo(const DataValue &min, const DataValue &max)\n> > > +\t{\n> > > +\t\tmin_ = min;\n> > > +\t\tmax_ = max;\n> > > +\t}\n> > > +\n> > > +\tconst DataValue &min() const { return min_; }\n> > > +\tconst DataValue &max() const { return max_; }\n> > > +\n> > > +private:\n> > > +\tDataValue max_;\n> > > +\tDataValue min_;\n> > > +};\n> > > +\n> > > +} /* namespace libcamera */\n> > > +\n> > > +#endif /* __LIBCAMERA_DATA_VALUE_H__ */\n> > > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build\n> > > index 868f1a6bf1ab..e3f3ad504446 100644\n> > > --- a/include/libcamera/meson.build\n> > > +++ b/include/libcamera/meson.build\n> > > @@ -5,6 +5,7 @@ libcamera_api = files([\n> > >      'camera_manager.h',\n> > >      'control_ids.h',\n> > >      'controls.h',\n> > > +    'data_value.h',\n> > >      'event_dispatcher.h',\n> > >      'event_notifier.h',\n> > >      'geometry.h',\n> > > diff --git a/src/libcamera/data_value.cpp b/src/libcamera/data_value.cpp\n> > > new file mode 100644\n> > > index 000000000000..f07b5fb75a8a\n> > > --- /dev/null\n> > > +++ b/src/libcamera/data_value.cpp\n> > > @@ -0,0 +1,317 @@\n> > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > > +/*\n> > > + * Copyright (C) 2019, Google Inc.\n> > > + *\n> > > + * data_value.cpp - Polymorphic data value type\n> > > + */\n> > > +\n> > > +#include <libcamera/data_value.h>\n> > > +\n> > > +#include <cstdint>\n> > > +#include <sstream>\n> > > +#include <string>\n> > > +\n> > > +#include \"utils.h\"\n> > > +#include \"log.h\"\n> > > +\n> > > +/**\n> > > + * \\file data_value.h\n> > > + * \\brief Polymorphic data type\n> > > + */\n> > > +\n> > > +namespace libcamera {\n> > > +\n> > > +/**\n> > > + * \\enum DataType\n> > > + * \\brief Define the supported data types\n> > > + * \\var DataTypeNone\n> > > + * Identifies an unset value\n> > > + * \\var DataTypeBool\n> > > + * Identifies DataType storing a boolean value\n> > > + * \\var DataTypeInteger\n> > > + * Identifies DataType storing an integer value\n> > > + * \\var DataTypeInteger64\n> > > + * Identifies DataType storing a 64-bit integer value\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\var DataSize\n> > > + * \\brief Associate to each data type the memory size in bytes\n> > > + */\n> > > +\n> >\n> > You have a rogue if 0 below\n> \n> Ups! thanks!\n> \n> > > +#if 0\n> > > +/**\n> > > + * \\class Data\n> > > + * \\brief Base class for data value and data info instances\n> > > + *\n> > > + * DataValue and DataInfo share basic information like size and type.\n> > > + * This class provides common fields and operations for them.\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\brief Construct a Data of \\a type\n> > > + * \\param[in] type The Data type defined by DataType\n> > > + */\n> > > +Data::Data(DataType type)\n> > > +\t: type_(type)\n> > > +{\n> > > +\t/*\n> > > +\t * \\todo The size of compound data types depend on the number of\n> > > +\t * elements too.\n> > > +\t */\n> > > +\tsize_ = DataSize[type_];\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\var Data::type_\n> > > + * \\brief The data type\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\var Data::size_\n> > > + * \\brief The data size\n> > > + */\n> > > +\n> > > +#endif\n> >\n> > To here ...\n> >\n> > > +\n> > > +/**\n> > > + * \\class DataValue\n> > > + * \\brief Polymorphic data value\n> > > + *\n> > > + * DataValue holds values of different types, defined by DataType providing\n> > > + * a unified interface to access and modify the data content.\n> > > + *\n> > > + * DataValue instances are used by classes that need to represent and store\n> > > + * numerical values of different types.\n> > > + *\n> > > + * \\todo Add support for compound data types, such as arrays.\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\brief Construct an empty DataValue\n> > > + */\n> > > +DataValue::DataValue()\n> > > +\t: type_(DataTypeNone), size_(DataSize[type_])\n> > > +{\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Construct a DataValue copying data from \\a other\n> > > + * \\param[in] other The DataValue to copy data from\n> > > + *\n> > > + * DataValue copy constructor.\n> > > + */\n> > > +DataValue::DataValue(const DataValue &other)\n> > > +\t: type_(other.type()), size_(DataSize[type_])\n> >\n> > Does this type need a copy constructor currently?\n> \n> I think it will be used during serialization implementation\n> \n> > Won't C++ just copy the whole object, which would be equivalent?\n> \n> Possibly, I wanted this explicit because of the above assignements to\n> the correct field. I'll check if I need this.\n> \n> > That said, if/when this class becomes more complex then it would likely\n> > need some sort of specialisation - so it doesn't hurt to have it already.\n> >\n> > > +{\n> > > +\tswitch (type_) {\n> > > +\tcase DataTypeBool:\n> > > +\t\tbool_ = other.getBool();\n> > > +\t\tbreak;\n> > > +\tcase DataTypeInteger:\n> > > +\t\tinteger_ = other.getInt();\n> > > +\t\tbreak;\n> > > +\tcase DataTypeInteger64:\n> > > +\t\tinteger64_ = other.getInt64();\n> > > +\t\tbreak;\n> > > +\tdefault:\n> > > +\t\tbool_ = integer_ = integer64_ = 0;\n> > > +\t\tbreak;\n> > > +\t}\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Construct a boolean DataValue\n> > > + * \\param[in] value Boolean value to store\n> > > + */\n> > > +DataValue::DataValue(bool value)\n> > > +\t: type_(DataTypeBool), size_(DataSize[type_]), bool_(value)\n> > > +{\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Construct an integer DataValue\n> > > + * \\param[in] value Integer value to store\n> > > + */\n> > > +DataValue::DataValue(int value)\n> > > +\t: type_(DataTypeInteger), size_(DataSize[type_]), integer_(value)\n> > > +{\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Construct a 64 bit integer DataValue\n> > > + * \\param[in] value 64-bits integer value to store\n> > > + */\n> > > +DataValue::DataValue(int64_t value)\n> > > +\t: type_(DataTypeInteger64), size_(DataSize[type_]), integer64_(value)\n> > > +{\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Assign the DataValue type and value using the ones from \\a other\n> > > + * \\param[in] other The DataValue to copy type and value from\n> > > + *\n> > > + * DataValue assignement operator.\n> >\n> > s/assignement/assignment/\n> >\n> > > + *\n> > > + * \\return The DataValue with fields updated using the ones from \\a other\n> > > + */\n> > > +DataValue &DataValue::operator=(const DataValue &other)\n> > > +{\n> > > +\tDataType newType = other.type();\n> > > +\ttype_ = newType;\n> > > +\tsize_ = DataSize[type_];\n> > > +\n> > > +\tswitch (newType) {\n> > > +\tcase DataTypeBool:\n> > > +\t\tbool_ = other.getBool();\n> > > +\t\tbreak;\n> > > +\tcase DataTypeInteger:\n> > > +\t\tinteger_ = other.getInt();\n> > > +\t\tbreak;\n> > > +\tcase DataTypeInteger64:\n> > > +\t\tinteger64_ = other.getInt64();\n> > > +\t\tbreak;\n> > > +\tdefault:\n> > > +\t\tbool_ = integer_ = integer64_ = 0;\n> > > +\t\tbreak;\n> > > +\t}\n> > > +\n> > > +\treturn *this;\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\fn DataValue::type()\n> > > + * \\brief Retrieve the data type of the data\n> > > + * \\return The type of the data\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\fn DataValue::size()\n> > > + * \\brief Retrieve the size in bytes of the data\n> > > + * \\return The size in bytes of the data\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\brief Set the value with a boolean\n> > > + * \\param[in] value Boolean value to store\n> > > + */\n> > > +void DataValue::set(bool value)\n> > > +{\n> > > +\ttype_ = DataTypeBool;\n> > > +\tsize_ = DataSize[type_];\n> > > +\tbool_ = value;\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Set the value with an integer\n> > > + * \\param[in] value Integer value to store\n> > > + */\n> > > +void DataValue::set(int value)\n> > > +{\n> > > +\ttype_ = DataTypeInteger;\n> > > +\tsize_ = DataSize[type_];\n> > > +\tinteger_ = value;\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Set the value with a 64 bit integer\n> > > + * \\param[in] value 64 bit integer value to store\n> > > + */\n> > > +void DataValue::set(int64_t value)\n> > > +{\n> > > +\ttype_ = DataTypeInteger64;\n> > > +\tsize_ = DataSize[type_];\n> > > +\tinteger64_ = value;\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Get the boolean value\n> > > + *\n> > > + * The value type must be Boolean.\n> > > + *\n> > > + * \\return The boolean value\n> > > + */\n> > > +bool DataValue::getBool() const\n> > > +{\n> > > +\tASSERT(type_ == DataTypeBool);\n> > > +\n> > > +\treturn bool_;\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Get the integer value\n> > > + *\n> > > + * The value type must be Integer or Integer64.\n> > > + *\n> > > + * \\return The integer value\n> > > + */\n> > > +int DataValue::getInt() const\n> > > +{\n> > > +\tASSERT(type_ == DataTypeInteger || type_ == DataTypeInteger64);\n> > > +\n> > > +\treturn integer_;\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Get the 64-bit integer value\n> > > + *\n> > > + * The value type must be Integer or Integer64.\n> > > + *\n> > > + * \\return The 64-bit integer value\n> > > + */\n> > > +int64_t DataValue::getInt64() const\n> > > +{\n> > > +\tASSERT(type_ == DataTypeInteger || type_ == DataTypeInteger64);\n> > > +\n> > > +\treturn integer64_;\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\brief Assemble and return a string describing the value\n> > > + * \\return A string describing the DataValue\n> > > + */\n> > > +std::string DataValue::toString() const\n> > > +{\n> > > +\tswitch (type_) {\n> > > +\tcase DataTypeBool:\n> > > +\t\treturn bool_ ? \"True\" : \"False\";\n> > > +\tcase DataTypeInteger:\n> > > +\t\treturn std::to_string(integer_);\n> > > +\tcase DataTypeInteger64:\n> > > +\t\treturn std::to_string(integer64_);\n> > > +\tdefault:\n> > > +\t\treturn \"<None>\";\n> >\n> > I haven't tried to compile this yet, but doesn't this generate a\n> > compiler warning?\n> >\n> > I thought C++ was very picky about switch statements not explicitly\n> > stating all enum types... Perhaps not when a default statement is provided.\n> >\n> > changing this to:\n> >\n> > \t...\n> >\n> > \tcase DataTypeNone:\n> > \t\treturn \"<None>\";\n> > \t}\n> >\n> > \treturn \"<INVALID TYPE>\";\n> > }\n> >\n> > would in that case ensure that this function is always updated (forced\n> > by the compiler) whenever a new type is added?\n> \n> Yeah, default catches all the remaning cases but hides issues when we\n> miss adding a value. I'll change.\n> \n> > > +\t}\n> > > +}\n> > > +\n> > > +/**\n> > > + * \\class DataInfo\n> > > + * \\brief Validation informations associated with a data value\n> > > + *\n> > > + * The DataInfo class represents static information associated with data\n> > > + * types that represent plymorhpic values abstracted by the DataValue class.\n> >\n> > s/plymorhpic/polymorphic/\n> >\n> > > + *\n> > > + * DataInfo stores static informations such as the value minimum and maximum\n> > > + * values and for compound values the maximum and minimum number of elements.\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\fn DataInfo::DataInfo\n> > > + * \\brief Construct a data info with \\a min and \\a max values\n> > > + * \\param[in] min The minimum allowed value\n> > > + * \\param[in] max The maximum allowed value\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\fn DataInfo::min()\n> > > + * \\brief Retrieve the DataInfo minimum allowed value\n> > > + * \\return A DataValue representing the minimum allowed value\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\fn DataInfo::max()\n> > > + * \\brief Retrieve the DataInfo maximum allowed value\n> > > + * \\return A DataValue representing the maximum allowed value\n> > > + */\n> > > +\n> > > +} /* namespace libcamera */\n> > > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> > > index 755149c55c7b..c3100a1709e0 100644\n> > > --- a/src/libcamera/meson.build\n> > > +++ b/src/libcamera/meson.build\n> > > @@ -5,6 +5,7 @@ libcamera_sources = files([\n> > >      'camera_manager.cpp',\n> > >      'camera_sensor.cpp',\n> > >      'controls.cpp',\n> > > +    'data_value.cpp',\n> > >      'device_enumerator.cpp',\n> > >      'device_enumerator_sysfs.cpp',\n> > >      'event_dispatcher.cpp',\n> > > diff --git a/test/data_value/data_value.cpp b/test/data_value/data_value.cpp\n> > > new file mode 100644\n> > > index 000000000000..64061000c1e4\n> > > --- /dev/null\n> > > +++ b/test/data_value/data_value.cpp\n> > > @@ -0,0 +1,59 @@\n> > > +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> > > +/*\n> > > + * Copyright (C) 2019, Google Inc.\n> > > + *\n> > > + * data_value.cpp - DataValue tests\n> > > + */\n> > > +\n> > > +#include <iostream>\n> > > +\n> > > +#include <libcamera/data_value.h>\n> > > +\n> > > +#include \"test.h\"\n> > > +\n> > > +using namespace std;\n> > > +using namespace libcamera;\n> > > +\n> > > +class DataValueTest : public Test\n> > > +{\n> > > +protected:\n> > > +\tint run()\n> > > +\t{\n> > > +\t\tDataValue integer(1234);\n> > > +\t\tDataValue boolean(true);\n> > > +\n> > > +\t\t/* Just a string conversion output test... no validation */\n> > > +\t\tcout << \"Int: \" << integer.toString()\n> > > +\t\t     << \" Bool: \" << boolean.toString()\n> > > +\t\t     << endl;\n> > > +\n> > > +\t\tif (integer.getInt() != 1234) {\n> > > +\t\t\tcerr << \"Failed to get Integer\" << endl;\n> > > +\t\t\treturn TestFail;\n> > > +\t\t}\n> > > +\n> > > +\t\tif (boolean.getBool() != true) {\n> > > +\t\t\tcerr << \"Failed to get Boolean\" << endl;\n> > > +\t\t\treturn TestFail;\n> > > +\t\t}\n> > > +\n> > > +\t\t/* Test an uninitialised value, and updating it. */\n> > > +\n> > > +\t\tDataValue value;\n> > > +\t\tvalue.set(true);\n> > > +\t\tif (value.getBool() != true) {\n> > > +\t\t\tcerr << \"Failed to get Booleans\" << endl;\n> > > +\t\t\treturn TestFail;\n> > > +\t\t}\n> > > +\n> > > +\t\tvalue.set(10);\n> > > +\t\tif (value.getInt() != 10) {\n> > > +\t\t\tcerr << \"Failed to get Integer\" << endl;\n> > > +\t\t\treturn TestFail;\n> > > +\t\t}\n> > > +\n> > > +\t\treturn TestPass;\n> > > +\t}\n> > > +};\n> > > +\n> > > +TEST_REGISTER(DataValueTest)\n> > > diff --git a/test/data_value/meson.build b/test/data_value/meson.build\n> > > new file mode 100644\n> > > index 000000000000..3858e6085a1f\n> > > --- /dev/null\n> > > +++ b/test/data_value/meson.build\n> > > @@ -0,0 +1,12 @@\n> > > +data_value_tests = [\n> > > +    [ 'data_value',   'data_value.cpp' ],\n> > > +]\n> > > +\n> > > +foreach t : data_value_tests\n> > > +    exe = executable(t[0], t[1],\n> > > +                     dependencies : libcamera_dep,\n> > > +                     link_with : test_libraries,\n> > > +                     include_directories : test_includes_internal)\n> > > +    test(t[0], exe, suite : 'data_value', is_parallel : false)\n> > > +endforeach\n> >\n> >\n> > Does data_value need a whole subdirectory for a single test? Will it\n> > have multiple tests in the (near) future?\n> \n> I thought so, but in the end I only added one\n> \n> > I really dislike adding a subdirectory/test suite just for a single test\n> > unless we really know it's going to be extended.\n> \n> Where would you put this?\n> \n> > > +\n> > > diff --git a/test/meson.build b/test/meson.build\n> > > index 84722cceb35d..5d414b22dc0c 100644\n> > > --- a/test/meson.build\n> > > +++ b/test/meson.build\n> > > @@ -2,6 +2,7 @@ subdir('libtest')\n> > >\n> > >  subdir('camera')\n> > >  subdir('controls')\n> > > +subdir('data_value')\n> > >  subdir('ipa')\n> > >  subdir('ipc')\n> > >  subdir('log')","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A768160BCF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 27 Sep 2019 00:12:50 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id D99709BF;\n\tFri, 27 Sep 2019 00:12:49 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1569535970;\n\tbh=xwPg9j4rgvcfZ233CNn9NSaUEi+0OmUoKgDB8o1zXRo=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=S7epj+wALK7xJweestJsy6VnTDfhcw1IkEx95N3r560qn/K0jXd6yW1YDqDWQmIog\n\tpO7iESuComoNwPnVnC+2gyGuXUgvMILnmXrJW3Dl+L4aCEzUllMehMCbq/RUjcxzyO\n\tC852AcqD+Cj5QKmmEMQovtzPpA+xQ2ZG+pj44WB4=","Date":"Fri, 27 Sep 2019 01:12:40 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Message-ID":"<20190926221240.GC4864@pendragon.ideasonboard.com>","References":"<20190918103424.14536-1-jacopo@jmondi.org>\n\t<20190918103424.14536-2-jacopo@jmondi.org>\n\t<dbe98177-d70d-5cb8-8a48-458d3549df94@ideasonboard.com>\n\t<20190923110257.itgysbf5hc6etk5m@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190923110257.itgysbf5hc6etk5m@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH 1/5] libcamera: Create DataValue and\n\tDataInfo","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Thu, 26 Sep 2019 22:12:50 -0000"}}]