[{"id":18345,"web_url":"https://patchwork.libcamera.org/comment/18345/","msgid":"<20210726094223.iudsqfk4crawvvmn@uno.localdomain>","date":"2021-07-26T09:42:23","subject":"Re: [libcamera-devel] [PATCH v2 1/5] libcamera: flags: Add\n\ttype-safe enum-based flags","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent\n\nOn Sun, Jul 25, 2021 at 08:18:23PM +0300, Laurent Pinchart wrote:\n> Add a Flags template class that provide type-safe bitwise operators on\n> enum values. This allows using enum types for bit fields, without giving\n> away type-safety as usually done when storing combined flags in integer\n> variables.\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n>  include/libcamera/base/flags.h     | 195 +++++++++++++++++++++++++++++\n>  include/libcamera/base/meson.build |   1 +\n>  src/libcamera/base/flags.cpp       | 192 ++++++++++++++++++++++++++++\n>  src/libcamera/base/meson.build     |   1 +\n>  4 files changed, 389 insertions(+)\n>  create mode 100644 include/libcamera/base/flags.h\n>  create mode 100644 src/libcamera/base/flags.cpp\n>\n> diff --git a/include/libcamera/base/flags.h b/include/libcamera/base/flags.h\n> new file mode 100644\n> index 000000000000..adec549dccc9\n> --- /dev/null\n> +++ b/include/libcamera/base/flags.h\n> @@ -0,0 +1,195 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * flags.h - Type-safe enum-based bitfields\n> + */\n> +#ifndef __LIBCAMERA_BASE_FLAGS_H__\n> +#define __LIBCAMERA_BASE_FLAGS_H__\n> +\n> +#include <type_traits>\n> +\n> +namespace libcamera {\n> +\n> +template<typename E>\n> +class Flags\n> +{\n> +public:\n> +\tstatic_assert(std::is_enum<E>::value,\n> +\t\t      \"Flags<> template parameter must be an enum\");\n> +\n> +\tusing Type = std::underlying_type_t<E>;\n> +\n> +\tconstexpr Flags()\n> +\t\t: value_(0)\n> +\t{\n> +\t}\n> +\n> +\tconstexpr Flags(E flag)\n> +\t\t: value_(static_cast<Type>(flag))\n> +\t{\n> +\t}\n> +\n> +\tconstexpr Flags &operator&=(E flag)\n> +\t{\n> +\t\tvalue_ &= static_cast<Type>(flag);\n> +\t\treturn *this;\n> +\t}\n> +\n> +\tconstexpr Flags &operator&=(Flags other)\n\nShould other be const ?\n\n> +\t{\n> +\t\tvalue_ &= other.value_;\n> +\t\treturn *this;\n> +\t}\n> +\n> +\tconstexpr Flags &operator|=(E flag)\n> +\t{\n> +\t\tvalue_ |= static_cast<Type>(flag);\n> +\t\treturn *this;\n> +\t}\n> +\n> +\tconstexpr Flags &operator|=(Flags other)\n> +\t{\n> +\t\tvalue_ |= other.value_;\n> +\t\treturn *this;\n> +\t}\n> +\n> +\tconstexpr Flags &operator^=(E flag)\n> +\t{\n> +\t\tvalue_ ^= static_cast<Type>(flag);\n> +\t\treturn *this;\n> +\t}\n> +\n> +\tconstexpr Flags &operator^=(Flags other)\n> +\t{\n> +\t\tvalue_ ^= other.value_;\n> +\t\treturn *this;\n> +\t}\n> +\n> +\tconstexpr bool operator==(E flag)\n> +\t{\n> +\t\treturn value_ == static_cast<Type>(flag);\n> +\t}\n> +\n> +\tconstexpr bool operator==(Flags other)\n> +\t{\n> +\t\treturn value_ == static_cast<Type>(other);\n> +\t}\n> +\n> +\tconstexpr bool operator!=(E flag)\n> +\t{\n> +\t\treturn value_ != static_cast<Type>(flag);\n> +\t}\n> +\n> +\tconstexpr bool operator!=(Flags other)\n> +\t{\n> +\t\treturn value_ != static_cast<Type>(other);\n> +\t}\n> +\n> +\tconstexpr explicit operator Type() const\n> +\t{\n> +\t\treturn value_;\n> +\t}\n> +\n> +\tconstexpr explicit operator bool() const\n> +\t{\n> +\t\treturn !!value_;\n> +\t}\n> +\n> +\tconstexpr Flags operator&(E flag) const\n> +\t{\n> +\t\treturn Flags(static_cast<E>(value_ & static_cast<Type>(flag)));\n> +\t}\n> +\n> +\tconstexpr Flags operator&(Flags other) const\n> +\t{\n> +\t\treturn Flags(static_cast<E>(value_ & other.value_));\n> +\t}\n> +\n> +\tconstexpr Flags operator|(E flag) const\n> +\t{\n> +\t\treturn Flags(static_cast<E>(value_ | static_cast<Type>(flag)));\n> +\t}\n> +\n> +\tconstexpr Flags operator|(Flags other) const\n> +\t{\n> +\t\treturn Flags(static_cast<E>(value_ | other.value_));\n> +\t}\n> +\n> +\tconstexpr Flags operator^(E flag) const\n> +\t{\n> +\t\treturn Flags(static_cast<E>(value_ ^ static_cast<Type>(flag)));\n> +\t}\n> +\n> +\tconstexpr Flags operator^(Flags other) const\n> +\t{\n> +\t\treturn Flags(static_cast<E>(value_ ^ other.value_));\n> +\t}\n> +\n> +\tconstexpr Flags operator~() const\n> +\t{\n> +\t\treturn Flags(static_cast<E>(~value_));\n> +\t}\n> +\n> +\tconstexpr bool operator!() const\n> +\t{\n> +\t\treturn !value_;\n> +\t}\n> +\n> +private:\n> +\tType value_;\n> +};\n> +\n> +#ifndef __DOXYGEN__\n> +template<typename E>\n> +struct flags_enable_operators {\n> +\tstatic const bool enable = false;\n> +};\n> +\n> +template<typename E>\n> +typename std::enable_if_t<flags_enable_operators<E>::enable, Flags<E>>\n> +operator|(E lhs, E rhs)\n> +{\n> +\tusing type = std::underlying_type_t<E>;\n> +\treturn Flags<E>(static_cast<E>(static_cast<type>(lhs) | static_cast<type>(rhs)));\n> +}\n> +\n> +template<typename E>\n> +typename std::enable_if_t<flags_enable_operators<E>::enable, Flags<E>>\n> +operator&(E lhs, E rhs)\n> +{\n> +\tusing type = std::underlying_type_t<E>;\n> +\treturn Flags<E>(static_cast<E>(static_cast<type>(lhs) & static_cast<type>(rhs)));\n> +}\n> +\n> +template<typename E>\n> +typename std::enable_if_t<flags_enable_operators<E>::enable, Flags<E>>\n> +operator^(E lhs, E rhs)\n> +{\n> +\tusing type = std::underlying_type_t<E>;\n> +\treturn Flags<E>(static_cast<E>(static_cast<type>(lhs) ^ static_cast<type>(rhs)));\n> +}\n> +\n> +template<typename E>\n> +typename std::enable_if_t<flags_enable_operators<E>::enable, Flags<E>>\n> +operator~(E rhs)\n> +{\n> +\tusing type = std::underlying_type_t<E>;\n> +\treturn Flags<E>(static_cast<E>(~static_cast<type>(rhs)));\n> +}\n> +\n> +#define LIBCAMERA_FLAGS_ENABLE_OPERATORS(_enum)\t\t\t\t\\\n> +template<>\t\t\t\t\t\t\t\t\\\n> +struct flags_enable_operators<_enum> {\t\t\t\t\t\\\n> +\tstatic const bool enable = true;\t\t\t\t\\\n> +};\n> +\n> +#else /* __DOXYGEN__ */\n> +\n> +#define LIBCAMERA_FLAGS_ENABLE_OPERATORS(_enum)\n> +\n> +#endif /* __DOXYGEN__ */\n> +\n> +} /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_BASE_FLAGS_H__ */\n> diff --git a/include/libcamera/base/meson.build b/include/libcamera/base/meson.build\n> index 7c499b558fb0..9feb4b9346d5 100644\n> --- a/include/libcamera/base/meson.build\n> +++ b/include/libcamera/base/meson.build\n> @@ -9,6 +9,7 @@ libcamera_base_headers = files([\n>      'event_dispatcher_poll.h',\n>      'event_notifier.h',\n>      'file.h',\n> +    'flags.h',\n>      'log.h',\n>      'message.h',\n>      'object.h',\n> diff --git a/src/libcamera/base/flags.cpp b/src/libcamera/base/flags.cpp\n> new file mode 100644\n> index 000000000000..3e4320ace7c8\n> --- /dev/null\n> +++ b/src/libcamera/base/flags.cpp\n> @@ -0,0 +1,192 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * flags.cpp - Type-safe enum-based bitfields\n> + */\n> +\n> +#include <libcamera/base/flags.h>\n> +\n> +/**\n> + * \\file base/flags.h\n> + * \\brief Enum-based bit fields\n> + */\n> +\n> +namespace libcamera {\n> +\n> +/**\n> + * \\class Flags\n> + * \\brief Type-safe container for enum-based bitfields\n> + *\n> + * The Flags template class provides type-safe bitwise operators on enum values.\n> + * It allows using enum types for bitfields, while preventing unsafe casts from\n> + * integer types and mixing of flags from different enum types.\n> + *\n> + * To use the Flags class, declare an enum containing the desired bit flags, and\n> + * use the Flags<enum> class to store bitfields based on the enum. If bitwise\n> + * operators on the underlying enum are also desired, they can be enabled with\n> + * the LIBCAMERA_FLAGS_ENABLE_OPERATORS(enum) macro.\n> + */\n> +\n> +/**\n> + * \\typedef Flags::Type\n> + * \\brief The underlying data type of the enum\n> + */\n> +\n> +/**\n> + * \\fn Flags::Flags()\n> + * \\brief Construct a Flags instance with a zero value\n> + */\n> +\n> +/**\n> + * \\fn Flags::Flags(E flag)\n> + * \\brief Construct a Flags instance storing the \\a flag\n> + * \\param[in] flag The initial value\n> + */\n> +\n> +/**\n> + * \\fn Flags &Flags::operator&=(E flag)\n> + * \\brief Store the bitwise AND of this Flags and the \\a flag in this Flags\n> + * \\param[in] flag The second operand\n> + * \\return A reference to this Flags\n> + */\n> +\n> +/**\n> + * \\fn Flags &Flags::operator&=(Flags other)\n> + * \\brief Store the bitwise AND of this Flags and the \\a other Flags in this Flags\n> + * \\param[in] other The second operand\n> + * \\return A reference to this Flags\n> + */\n> +\n> +/**\n> + * \\fn Flags &Flags::operator|=(E flag)\n> + * \\brief Store the bitwise OR of this Flags and the \\a flag in this Flags\n> + * \\param[in] flag The second operand\n> + * \\return A reference to this Flags\n> + */\n> +\n> +/**\n> + * \\fn Flags &Flags::operator|=(Flags other)\n> + * \\brief Store the bitwise OR of this Flags and the \\a other Flags in this Flags\n> + * \\param[in] other The second operand\n> + * \\return A reference to this Flags\n> + */\n> +\n> +/**\n> + * \\fn Flags &Flags::operator^=(E flag)\n> + * \\brief Store the bitwise XOR of this Flags and the \\a flag in this Flags\n> + * \\param[in] flag The second operand\n> + * \\return A reference to this Flags\n> + */\n> +\n> +/**\n> + * \\fn Flags &Flags::operator^=(Flags other)\n> + * \\brief Store the bitwise XOR of this Flags and the \\a other Flags in this Flags\n> + * \\param[in] other The second operand\n> + * \\return A reference to this Flags\n> + */\n> +\n> +/**\n> + * \\fn bool Flags::operator==(E flag)\n> + * \\brief Compare flags for equality\n> + * \\param[in] flag The second operand\n> + * \\return True if the Flags and \\a flag are equal, false otherwise\n> + */\n> +\n> +/**\n> + * \\fn bool Flags::operator==(Flags other)\n> + * \\brief Compare flags for equality\n> + * \\param[in] other The second operand\n> + * \\return True if the Flags and \\a other are equal, false otherwise\n> + */\n> +\n> +/**\n> + * \\fn bool Flags::operator!=(E flag)\n> + * \\brief Compare flags for non-equality\n> + * \\param[in] flag The second operand\n> + * \\return True if the Flags and \\a flag are not equal, false otherwise\n> + */\n> +\n> +/**\n> + * \\fn bool Flags::operator!=(Flags other)\n> + * \\brief Compare flags for non-equality\n> + * \\param[in] other The second operand\n> + * \\return True if the Flags and \\a other are not equal, false otherwise\n> + */\n> +\n> +/**\n> + * \\fn Flags::operator Type() const\n> + * \\brief Convert the Flags to the underlying integer type\n> + * \\return The Flags value as an integer\n> + */\n> +\n> +/**\n> + * \\fn Flags::operator bool() const\n> + * \\brief Convert the Flags to a boolean\n> + * \\return True if at least one flag is set, false otherwise\n> + */\n> +\n> +/**\n> + * \\fn Flags Flags::operator&(E flag) const\n> + * \\brief Compute the bitwise AND of this Flags and the \\a flag\n> + * \\param[in] flag The second operand\n> + * \\return A Flags containing the result of the AND operation\n> + */\n> +\n> +/**\n> + * \\fn Flags Flags::operator&(Flags other) const\n> + * \\brief Compute the bitwise AND of this Flags and the \\a other Flags\n> + * \\param[in] other The second operand\n> + * \\return A Flags containing the result of the AND operation\n> + */\n> +\n> +/**\n> + * \\fn Flags Flags::operator|(E flag) const\n> + * \\brief Compute the bitwise OR of this Flags and the \\a flag\n> + * \\param[in] flag The second operand\n> + * \\return A Flags containing the result of the OR operation\n> + */\n> +\n> +/**\n> + * \\fn Flags Flags::operator|(Flags other) const\n> + * \\brief Compute the bitwise OR of this Flags and the \\a other Flags\n> + * \\param[in] other The second operand\n> + * \\return A Flags containing the result of the OR operation\n> + */\n> +\n> +/**\n> + * \\fn Flags Flags::operator^(E flag) const\n> + * \\brief Compute the bitwise XOR of this Flags and the \\a flag\n> + * \\param[in] flag The second operand\n> + * \\return A Flags containing the result of the XOR operation\n> + */\n> +\n> +/**\n> + * \\fn Flags Flags::operator^(Flags other) const\n> + * \\brief Compute the bitwise XOR of this Flags and the \\a other Flags\n> + * \\param[in] other The second operand\n> + * \\return A Flags containing the result of the XOR operation\n> + */\n> +\n> +/**\n> + * \\fn Flags Flags::operator~() const\n> + * \\brief Compute the bitwise NOT of this Flags\n> + * \\return A Flags containing the result of the NOT operation\n> + */\n> +\n> +/**\n> + * \\fn bool Flags::operator!() const\n> + * \\brief Check if flags are set\n> + * \\return True if no flags is set, false otherwise\n> + */\n> +\n> +/**\n> + * \\def LIBCAMERA_FLAGS_ENABLE_OPERATORS(enum)\n> + * \\brief Enable bitwise operations on the \\a enum enumeration\n> + *\n> + * This macro enables the bitwise AND, OR, XOR and NOT operators on the given\n> + * \\a enum. This allows the enum values to be safely used in bitwise operations\n> + * with the Flags<> class.\n> + */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build\n> index 871721571e98..d799c66d8b3a 100644\n> --- a/src/libcamera/base/meson.build\n> +++ b/src/libcamera/base/meson.build\n> @@ -7,6 +7,7 @@ libcamera_base_sources = files([\n>      'event_dispatcher_poll.cpp',\n>      'event_notifier.cpp',\n>      'file.cpp',\n> +    'flags.cpp',\n>      'log.cpp',\n>      'message.cpp',\n>      'object.cpp',\n\nGreat!\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\nThanks\n   j\n\n> --\n> Regards,\n>\n> Laurent Pinchart\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 8643DC322C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 26 Jul 2021 09:41:38 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E5BF9687BE;\n\tMon, 26 Jul 2021 11:41:37 +0200 (CEST)","from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net\n\t[217.70.183.196])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A065660272\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 26 Jul 2021 11:41:36 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby relay4-d.mail.gandi.net (Postfix) with ESMTPSA id 0DC19E0011;\n\tMon, 26 Jul 2021 09:41:35 +0000 (UTC)"],"Date":"Mon, 26 Jul 2021 11:42:23 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20210726094223.iudsqfk4crawvvmn@uno.localdomain>","References":"<20210725171827.23643-1-laurent.pinchart@ideasonboard.com>\n\t<20210725171827.23643-2-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20210725171827.23643-2-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v2 1/5] libcamera: flags: Add\n\ttype-safe enum-based flags","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>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":18347,"web_url":"https://patchwork.libcamera.org/comment/18347/","msgid":"<YP6FUmSl9nnG99cH@pendragon.ideasonboard.com>","date":"2021-07-26T09:50:10","subject":"Re: [libcamera-devel] [PATCH v2 1/5] libcamera: flags: Add\n\ttype-safe enum-based flags","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Mon, Jul 26, 2021 at 11:42:23AM +0200, Jacopo Mondi wrote:\n> On Sun, Jul 25, 2021 at 08:18:23PM +0300, Laurent Pinchart wrote:\n> > Add a Flags template class that provide type-safe bitwise operators on\n> > enum values. This allows using enum types for bit fields, without giving\n> > away type-safety as usually done when storing combined flags in integer\n> > variables.\n> >\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > ---\n> >  include/libcamera/base/flags.h     | 195 +++++++++++++++++++++++++++++\n> >  include/libcamera/base/meson.build |   1 +\n> >  src/libcamera/base/flags.cpp       | 192 ++++++++++++++++++++++++++++\n> >  src/libcamera/base/meson.build     |   1 +\n> >  4 files changed, 389 insertions(+)\n> >  create mode 100644 include/libcamera/base/flags.h\n> >  create mode 100644 src/libcamera/base/flags.cpp\n> >\n> > diff --git a/include/libcamera/base/flags.h b/include/libcamera/base/flags.h\n> > new file mode 100644\n> > index 000000000000..adec549dccc9\n> > --- /dev/null\n> > +++ b/include/libcamera/base/flags.h\n> > @@ -0,0 +1,195 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2020, Google Inc.\n> > + *\n> > + * flags.h - Type-safe enum-based bitfields\n> > + */\n> > +#ifndef __LIBCAMERA_BASE_FLAGS_H__\n> > +#define __LIBCAMERA_BASE_FLAGS_H__\n> > +\n> > +#include <type_traits>\n> > +\n> > +namespace libcamera {\n> > +\n> > +template<typename E>\n> > +class Flags\n> > +{\n> > +public:\n> > +\tstatic_assert(std::is_enum<E>::value,\n> > +\t\t      \"Flags<> template parameter must be an enum\");\n> > +\n> > +\tusing Type = std::underlying_type_t<E>;\n> > +\n> > +\tconstexpr Flags()\n> > +\t\t: value_(0)\n> > +\t{\n> > +\t}\n> > +\n> > +\tconstexpr Flags(E flag)\n> > +\t\t: value_(static_cast<Type>(flag))\n> > +\t{\n> > +\t}\n> > +\n> > +\tconstexpr Flags &operator&=(E flag)\n> > +\t{\n> > +\t\tvalue_ &= static_cast<Type>(flag);\n> > +\t\treturn *this;\n> > +\t}\n> > +\n> > +\tconstexpr Flags &operator&=(Flags other)\n> \n> Should other be const ?\n\nIt's a value, not a reference, so I don't see a need to make it const.\n\n> > +\t{\n> > +\t\tvalue_ &= other.value_;\n> > +\t\treturn *this;\n> > +\t}\n> > +\n> > +\tconstexpr Flags &operator|=(E flag)\n> > +\t{\n> > +\t\tvalue_ |= static_cast<Type>(flag);\n> > +\t\treturn *this;\n> > +\t}\n> > +\n> > +\tconstexpr Flags &operator|=(Flags other)\n> > +\t{\n> > +\t\tvalue_ |= other.value_;\n> > +\t\treturn *this;\n> > +\t}\n> > +\n> > +\tconstexpr Flags &operator^=(E flag)\n> > +\t{\n> > +\t\tvalue_ ^= static_cast<Type>(flag);\n> > +\t\treturn *this;\n> > +\t}\n> > +\n> > +\tconstexpr Flags &operator^=(Flags other)\n> > +\t{\n> > +\t\tvalue_ ^= other.value_;\n> > +\t\treturn *this;\n> > +\t}\n> > +\n> > +\tconstexpr bool operator==(E flag)\n> > +\t{\n> > +\t\treturn value_ == static_cast<Type>(flag);\n> > +\t}\n> > +\n> > +\tconstexpr bool operator==(Flags other)\n> > +\t{\n> > +\t\treturn value_ == static_cast<Type>(other);\n> > +\t}\n> > +\n> > +\tconstexpr bool operator!=(E flag)\n> > +\t{\n> > +\t\treturn value_ != static_cast<Type>(flag);\n> > +\t}\n> > +\n> > +\tconstexpr bool operator!=(Flags other)\n> > +\t{\n> > +\t\treturn value_ != static_cast<Type>(other);\n> > +\t}\n> > +\n> > +\tconstexpr explicit operator Type() const\n> > +\t{\n> > +\t\treturn value_;\n> > +\t}\n> > +\n> > +\tconstexpr explicit operator bool() const\n> > +\t{\n> > +\t\treturn !!value_;\n> > +\t}\n> > +\n> > +\tconstexpr Flags operator&(E flag) const\n> > +\t{\n> > +\t\treturn Flags(static_cast<E>(value_ & static_cast<Type>(flag)));\n> > +\t}\n> > +\n> > +\tconstexpr Flags operator&(Flags other) const\n> > +\t{\n> > +\t\treturn Flags(static_cast<E>(value_ & other.value_));\n> > +\t}\n> > +\n> > +\tconstexpr Flags operator|(E flag) const\n> > +\t{\n> > +\t\treturn Flags(static_cast<E>(value_ | static_cast<Type>(flag)));\n> > +\t}\n> > +\n> > +\tconstexpr Flags operator|(Flags other) const\n> > +\t{\n> > +\t\treturn Flags(static_cast<E>(value_ | other.value_));\n> > +\t}\n> > +\n> > +\tconstexpr Flags operator^(E flag) const\n> > +\t{\n> > +\t\treturn Flags(static_cast<E>(value_ ^ static_cast<Type>(flag)));\n> > +\t}\n> > +\n> > +\tconstexpr Flags operator^(Flags other) const\n> > +\t{\n> > +\t\treturn Flags(static_cast<E>(value_ ^ other.value_));\n> > +\t}\n> > +\n> > +\tconstexpr Flags operator~() const\n> > +\t{\n> > +\t\treturn Flags(static_cast<E>(~value_));\n> > +\t}\n> > +\n> > +\tconstexpr bool operator!() const\n> > +\t{\n> > +\t\treturn !value_;\n> > +\t}\n> > +\n> > +private:\n> > +\tType value_;\n> > +};\n> > +\n> > +#ifndef __DOXYGEN__\n> > +template<typename E>\n> > +struct flags_enable_operators {\n> > +\tstatic const bool enable = false;\n> > +};\n> > +\n> > +template<typename E>\n> > +typename std::enable_if_t<flags_enable_operators<E>::enable, Flags<E>>\n> > +operator|(E lhs, E rhs)\n> > +{\n> > +\tusing type = std::underlying_type_t<E>;\n> > +\treturn Flags<E>(static_cast<E>(static_cast<type>(lhs) | static_cast<type>(rhs)));\n> > +}\n> > +\n> > +template<typename E>\n> > +typename std::enable_if_t<flags_enable_operators<E>::enable, Flags<E>>\n> > +operator&(E lhs, E rhs)\n> > +{\n> > +\tusing type = std::underlying_type_t<E>;\n> > +\treturn Flags<E>(static_cast<E>(static_cast<type>(lhs) & static_cast<type>(rhs)));\n> > +}\n> > +\n> > +template<typename E>\n> > +typename std::enable_if_t<flags_enable_operators<E>::enable, Flags<E>>\n> > +operator^(E lhs, E rhs)\n> > +{\n> > +\tusing type = std::underlying_type_t<E>;\n> > +\treturn Flags<E>(static_cast<E>(static_cast<type>(lhs) ^ static_cast<type>(rhs)));\n> > +}\n> > +\n> > +template<typename E>\n> > +typename std::enable_if_t<flags_enable_operators<E>::enable, Flags<E>>\n> > +operator~(E rhs)\n> > +{\n> > +\tusing type = std::underlying_type_t<E>;\n> > +\treturn Flags<E>(static_cast<E>(~static_cast<type>(rhs)));\n> > +}\n> > +\n> > +#define LIBCAMERA_FLAGS_ENABLE_OPERATORS(_enum)\t\t\t\t\\\n> > +template<>\t\t\t\t\t\t\t\t\\\n> > +struct flags_enable_operators<_enum> {\t\t\t\t\t\\\n> > +\tstatic const bool enable = true;\t\t\t\t\\\n> > +};\n> > +\n> > +#else /* __DOXYGEN__ */\n> > +\n> > +#define LIBCAMERA_FLAGS_ENABLE_OPERATORS(_enum)\n> > +\n> > +#endif /* __DOXYGEN__ */\n> > +\n> > +} /* namespace libcamera */\n> > +\n> > +#endif /* __LIBCAMERA_BASE_FLAGS_H__ */\n> > diff --git a/include/libcamera/base/meson.build b/include/libcamera/base/meson.build\n> > index 7c499b558fb0..9feb4b9346d5 100644\n> > --- a/include/libcamera/base/meson.build\n> > +++ b/include/libcamera/base/meson.build\n> > @@ -9,6 +9,7 @@ libcamera_base_headers = files([\n> >      'event_dispatcher_poll.h',\n> >      'event_notifier.h',\n> >      'file.h',\n> > +    'flags.h',\n> >      'log.h',\n> >      'message.h',\n> >      'object.h',\n> > diff --git a/src/libcamera/base/flags.cpp b/src/libcamera/base/flags.cpp\n> > new file mode 100644\n> > index 000000000000..3e4320ace7c8\n> > --- /dev/null\n> > +++ b/src/libcamera/base/flags.cpp\n> > @@ -0,0 +1,192 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2020, Google Inc.\n> > + *\n> > + * flags.cpp - Type-safe enum-based bitfields\n> > + */\n> > +\n> > +#include <libcamera/base/flags.h>\n> > +\n> > +/**\n> > + * \\file base/flags.h\n> > + * \\brief Enum-based bit fields\n> > + */\n> > +\n> > +namespace libcamera {\n> > +\n> > +/**\n> > + * \\class Flags\n> > + * \\brief Type-safe container for enum-based bitfields\n> > + *\n> > + * The Flags template class provides type-safe bitwise operators on enum values.\n> > + * It allows using enum types for bitfields, while preventing unsafe casts from\n> > + * integer types and mixing of flags from different enum types.\n> > + *\n> > + * To use the Flags class, declare an enum containing the desired bit flags, and\n> > + * use the Flags<enum> class to store bitfields based on the enum. If bitwise\n> > + * operators on the underlying enum are also desired, they can be enabled with\n> > + * the LIBCAMERA_FLAGS_ENABLE_OPERATORS(enum) macro.\n> > + */\n> > +\n> > +/**\n> > + * \\typedef Flags::Type\n> > + * \\brief The underlying data type of the enum\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags::Flags()\n> > + * \\brief Construct a Flags instance with a zero value\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags::Flags(E flag)\n> > + * \\brief Construct a Flags instance storing the \\a flag\n> > + * \\param[in] flag The initial value\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags &Flags::operator&=(E flag)\n> > + * \\brief Store the bitwise AND of this Flags and the \\a flag in this Flags\n> > + * \\param[in] flag The second operand\n> > + * \\return A reference to this Flags\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags &Flags::operator&=(Flags other)\n> > + * \\brief Store the bitwise AND of this Flags and the \\a other Flags in this Flags\n> > + * \\param[in] other The second operand\n> > + * \\return A reference to this Flags\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags &Flags::operator|=(E flag)\n> > + * \\brief Store the bitwise OR of this Flags and the \\a flag in this Flags\n> > + * \\param[in] flag The second operand\n> > + * \\return A reference to this Flags\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags &Flags::operator|=(Flags other)\n> > + * \\brief Store the bitwise OR of this Flags and the \\a other Flags in this Flags\n> > + * \\param[in] other The second operand\n> > + * \\return A reference to this Flags\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags &Flags::operator^=(E flag)\n> > + * \\brief Store the bitwise XOR of this Flags and the \\a flag in this Flags\n> > + * \\param[in] flag The second operand\n> > + * \\return A reference to this Flags\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags &Flags::operator^=(Flags other)\n> > + * \\brief Store the bitwise XOR of this Flags and the \\a other Flags in this Flags\n> > + * \\param[in] other The second operand\n> > + * \\return A reference to this Flags\n> > + */\n> > +\n> > +/**\n> > + * \\fn bool Flags::operator==(E flag)\n> > + * \\brief Compare flags for equality\n> > + * \\param[in] flag The second operand\n> > + * \\return True if the Flags and \\a flag are equal, false otherwise\n> > + */\n> > +\n> > +/**\n> > + * \\fn bool Flags::operator==(Flags other)\n> > + * \\brief Compare flags for equality\n> > + * \\param[in] other The second operand\n> > + * \\return True if the Flags and \\a other are equal, false otherwise\n> > + */\n> > +\n> > +/**\n> > + * \\fn bool Flags::operator!=(E flag)\n> > + * \\brief Compare flags for non-equality\n> > + * \\param[in] flag The second operand\n> > + * \\return True if the Flags and \\a flag are not equal, false otherwise\n> > + */\n> > +\n> > +/**\n> > + * \\fn bool Flags::operator!=(Flags other)\n> > + * \\brief Compare flags for non-equality\n> > + * \\param[in] other The second operand\n> > + * \\return True if the Flags and \\a other are not equal, false otherwise\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags::operator Type() const\n> > + * \\brief Convert the Flags to the underlying integer type\n> > + * \\return The Flags value as an integer\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags::operator bool() const\n> > + * \\brief Convert the Flags to a boolean\n> > + * \\return True if at least one flag is set, false otherwise\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags Flags::operator&(E flag) const\n> > + * \\brief Compute the bitwise AND of this Flags and the \\a flag\n> > + * \\param[in] flag The second operand\n> > + * \\return A Flags containing the result of the AND operation\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags Flags::operator&(Flags other) const\n> > + * \\brief Compute the bitwise AND of this Flags and the \\a other Flags\n> > + * \\param[in] other The second operand\n> > + * \\return A Flags containing the result of the AND operation\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags Flags::operator|(E flag) const\n> > + * \\brief Compute the bitwise OR of this Flags and the \\a flag\n> > + * \\param[in] flag The second operand\n> > + * \\return A Flags containing the result of the OR operation\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags Flags::operator|(Flags other) const\n> > + * \\brief Compute the bitwise OR of this Flags and the \\a other Flags\n> > + * \\param[in] other The second operand\n> > + * \\return A Flags containing the result of the OR operation\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags Flags::operator^(E flag) const\n> > + * \\brief Compute the bitwise XOR of this Flags and the \\a flag\n> > + * \\param[in] flag The second operand\n> > + * \\return A Flags containing the result of the XOR operation\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags Flags::operator^(Flags other) const\n> > + * \\brief Compute the bitwise XOR of this Flags and the \\a other Flags\n> > + * \\param[in] other The second operand\n> > + * \\return A Flags containing the result of the XOR operation\n> > + */\n> > +\n> > +/**\n> > + * \\fn Flags Flags::operator~() const\n> > + * \\brief Compute the bitwise NOT of this Flags\n> > + * \\return A Flags containing the result of the NOT operation\n> > + */\n> > +\n> > +/**\n> > + * \\fn bool Flags::operator!() const\n> > + * \\brief Check if flags are set\n> > + * \\return True if no flags is set, false otherwise\n> > + */\n> > +\n> > +/**\n> > + * \\def LIBCAMERA_FLAGS_ENABLE_OPERATORS(enum)\n> > + * \\brief Enable bitwise operations on the \\a enum enumeration\n> > + *\n> > + * This macro enables the bitwise AND, OR, XOR and NOT operators on the given\n> > + * \\a enum. This allows the enum values to be safely used in bitwise operations\n> > + * with the Flags<> class.\n> > + */\n> > +\n> > +} /* namespace libcamera */\n> > diff --git a/src/libcamera/base/meson.build b/src/libcamera/base/meson.build\n> > index 871721571e98..d799c66d8b3a 100644\n> > --- a/src/libcamera/base/meson.build\n> > +++ b/src/libcamera/base/meson.build\n> > @@ -7,6 +7,7 @@ libcamera_base_sources = files([\n> >      'event_dispatcher_poll.cpp',\n> >      'event_notifier.cpp',\n> >      'file.cpp',\n> > +    'flags.cpp',\n> >      'log.cpp',\n> >      'message.cpp',\n> >      'object.cpp',\n> \n> Great!\n> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 99EBBC322C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 26 Jul 2021 09:50:16 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0F3D2687BA;\n\tMon, 26 Jul 2021 11:50:16 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id AA5D060272\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 26 Jul 2021 11:50:14 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1E193332;\n\tMon, 26 Jul 2021 11:50:14 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"oa4MjttS\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1627293014;\n\tbh=RQ5VynmO/suMyd2d7ekuABG6nRQanBBH7HAsgOvyUi0=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=oa4MjttSN1ecpS/zpXw0MrK+u/viODeeaxZYM1MITlgkckXxx0IEDPGJAnqILbh+b\n\tarGhdVtWQZhoOJAzM2X85N1pDc6uNUar1/rQnhqe5WmZAHGq4wL4b4bIdLhwDfK4DP\n\t0SP8sqSqpAyuaJjt4KUcn43wFv2fDm/wravgp6YE=","Date":"Mon, 26 Jul 2021 12:50:10 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<YP6FUmSl9nnG99cH@pendragon.ideasonboard.com>","References":"<20210725171827.23643-1-laurent.pinchart@ideasonboard.com>\n\t<20210725171827.23643-2-laurent.pinchart@ideasonboard.com>\n\t<20210726094223.iudsqfk4crawvvmn@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20210726094223.iudsqfk4crawvvmn@uno.localdomain>","Subject":"Re: [libcamera-devel] [PATCH v2 1/5] libcamera: flags: Add\n\ttype-safe enum-based flags","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>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]