From patchwork Fri Jul 24 23:08:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 8992 X-Patchwork-Delegate: laurent.pinchart@ideasonboard.com Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id B856ABD878 for ; Fri, 24 Jul 2020 23:08:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 83457612F3; Sat, 25 Jul 2020 01:08:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="oRX65YH4"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AB7A160496 for ; Sat, 25 Jul 2020 01:08:55 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0D0F3585 for ; Sat, 25 Jul 2020 01:08:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1595632132; bh=mahSFIkd1bUlQaerddez9bd+4fMR5OX+MFXVHFSr3Bo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=oRX65YH4OoN6FHftO+tvQu8XePGSDuOc1ddP2bDIANGVzVaXHQYlA0XS5IZInUN1g Ef0s2OG6z3RgEF1+OC8z1J+DxMJBqvyUAi2xG1oGBs5Pjnetosqa6lkme2Npw6l1b+ cba1iPGbfoarldAGFg2UUqnEbJksvIfSW4JZ1xIw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 25 Jul 2020 02:08:40 +0300 Message-Id: <20200724230841.27838-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200724230841.27838-1-laurent.pinchart@ideasonboard.com> References: <20200724230841.27838-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/2] libcamera: flags: Add type-safe enum-based flags X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a Flags template class that provide type-safe bitwise operators on enum values. This allows using enum types for bit fields, without giving away type-safety as usually done when storing combined flags in integer variables. Signed-off-by: Laurent Pinchart --- include/libcamera/flags.h | 195 ++++++++++++++++++++++++++++++++++ include/libcamera/meson.build | 1 + src/libcamera/flags.cpp | 192 +++++++++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + 4 files changed, 389 insertions(+) create mode 100644 include/libcamera/flags.h create mode 100644 src/libcamera/flags.cpp diff --git a/include/libcamera/flags.h b/include/libcamera/flags.h new file mode 100644 index 000000000000..74525ccb1050 --- /dev/null +++ b/include/libcamera/flags.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * flags.h - Type-safe enum-based bitfields + */ +#ifndef __LIBCAMERA_FLAGS_H__ +#define __LIBCAMERA_FLAGS_H__ + +#include + +namespace libcamera { + +template +class Flags +{ +public: + static_assert(std::is_enum::value, + "Flags<> template parameter must be an enum"); + + using Type = std::underlying_type_t; + + constexpr Flags() + : value_(0) + { + } + + constexpr Flags(E flag) + : value_(static_cast(flag)) + { + } + + constexpr Flags &operator&=(E flag) + { + value_ &= static_cast(flag); + return *this; + } + + constexpr Flags &operator&=(Flags other) + { + value_ &= other.value_; + return *this; + } + + constexpr Flags &operator|=(E flag) + { + value_ |= static_cast(flag); + return *this; + } + + constexpr Flags &operator|=(Flags other) + { + value_ |= other.value_; + return *this; + } + + constexpr Flags &operator^=(E flag) + { + value_ ^= static_cast(flag); + return *this; + } + + constexpr Flags &operator^=(Flags other) + { + value_ ^= other.value_; + return *this; + } + + constexpr bool operator==(E flag) + { + return value_ == static_cast(flag); + } + + constexpr bool operator==(Flags other) + { + return value_ == static_cast(other); + } + + constexpr bool operator!=(E flag) + { + return value_ != static_cast(flag); + } + + constexpr bool operator!=(Flags other) + { + return value_ != static_cast(other); + } + + constexpr explicit operator Type() const + { + return value_; + } + + constexpr explicit operator bool() const + { + return !!value_; + } + + constexpr Flags operator&(E flag) const + { + return Flags(static_cast(value_ & static_cast(flag))); + } + + constexpr Flags operator&(Flags other) const + { + return Flags(static_cast(value_ & other.value_)); + } + + constexpr Flags operator|(E flag) const + { + return Flags(static_cast(value_ | static_cast(flag))); + } + + constexpr Flags operator|(Flags other) const + { + return Flags(static_cast(value_ | other.value_)); + } + + constexpr Flags operator^(E flag) const + { + return Flags(static_cast(value_ ^ static_cast(flag))); + } + + constexpr Flags operator^(Flags other) const + { + return Flags(static_cast(value_ ^ other.value_)); + } + + constexpr Flags operator~() const + { + return Flags(static_cast(~value_)); + } + + constexpr bool operator!() const + { + return !value_; + } + +private: + Type value_; +}; + +#ifndef __DOXYGEN__ +template +struct flags_enable_operators { + static const bool enable = false; +}; + +template +typename std::enable_if_t::enable, Flags> +operator|(E lhs, E rhs) +{ + using type = std::underlying_type_t; + return Flags(static_cast(static_cast(lhs) | static_cast(rhs))); +} + +template +typename std::enable_if_t::enable, Flags> +operator&(E lhs, E rhs) +{ + using type = std::underlying_type_t; + return Flags(static_cast(static_cast(lhs) & static_cast(rhs))); +} + +template +typename std::enable_if_t::enable, Flags> +operator^(E lhs, E rhs) +{ + using type = std::underlying_type_t; + return Flags(static_cast(static_cast(lhs) ^ static_cast(rhs))); +} + +template +typename std::enable_if_t::enable, Flags> +operator~(E rhs) +{ + using type = std::underlying_type_t; + return Flags(static_cast(~static_cast(rhs))); +} + +#define LIBCAMERA_FLAGS_ENABLE_OPERATORS(_enum) \ +template<> \ +struct flags_enable_operators<_enum> { \ + static const bool enable = true; \ +}; + +#else /* __DOXYGEN__ */ + +#define LIBCAMERA_FLAGS_ENABLE_OPERATORS(_enum) + +#endif /* __DOXYGEN__ */ + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_FLAGS_H__ */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index cdb8e0372e77..cd51a1f09ffb 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -9,6 +9,7 @@ libcamera_public_headers = files([ 'event_dispatcher.h', 'event_notifier.h', 'file_descriptor.h', + 'flags.h', 'framebuffer_allocator.h', 'geometry.h', 'logging.h', diff --git a/src/libcamera/flags.cpp b/src/libcamera/flags.cpp new file mode 100644 index 000000000000..d0521755a83e --- /dev/null +++ b/src/libcamera/flags.cpp @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * flags.cpp - Type-safe enum-based bitfields + */ + +#include + +/** + * \file flags.h + * \brief Enum-based bit fields + */ + +namespace libcamera { + +/** + * \class Flags + * \brief Type-safe container for enum-based bitfields + * + * The Flags template class provides type-safe bitwise operators on enum values. + * It allows using enum types for bitfields, while preventing unsafe casts from + * integer types and mixing of flags from different enum types. + * + * To use the Flags class, declare an enum containing the desired bit flags, and + * use the Flags class to store bitfields based on the enum. If bitwise + * operators on the underlying enum are also desired, they can be enabled with + * the LIBCAMERA_FLAGS_ENABLE_OPERATORS(enum) macro. + */ + +/** + * \typedef Flags::Type + * \brief The underlying data type of the enum + */ + +/** + * \fn Flags::Flags() + * \brief Construct a Flags instance with a zero value + */ + +/** + * \fn Flags::Flags(E flag) + * \brief Construct a Flags instance storing the \a flag + * \param[in] flag The initial value + */ + +/** + * \fn Flags &Flags::operator&=(E flag) + * \brief Store the bitwise AND of this Flags and the \a flag in this Flags + * \param[in] flag The second operand + * \return A reference to this Flags + */ + +/** + * \fn Flags &Flags::operator&=(Flags other) + * \brief Store the bitwise AND of this Flags and the \a other Flags in this Flags + * \param[in] other The second operand + * \return A reference to this Flags + */ + +/** + * \fn Flags &Flags::operator|=(E flag) + * \brief Store the bitwise OR of this Flags and the \a flag in this Flags + * \param[in] flag The second operand + * \return A reference to this Flags + */ + +/** + * \fn Flags &Flags::operator|=(Flags other) + * \brief Store the bitwise OR of this Flags and the \a other Flags in this Flags + * \param[in] other The second operand + * \return A reference to this Flags + */ + +/** + * \fn Flags &Flags::operator^=(E flag) + * \brief Store the bitwise XOR of this Flags and the \a flag in this Flags + * \param[in] flag The second operand + * \return A reference to this Flags + */ + +/** + * \fn Flags &Flags::operator^=(Flags other) + * \brief Store the bitwise XOR of this Flags and the \a other Flags in this Flags + * \param[in] other The second operand + * \return A reference to this Flags + */ + +/** + * \fn bool Flags::operator==(E flag) + * \brief Compare flags for equality + * \param[in] flag The second operand + * \return True if the Flags and \a flag are equal, false otherwise + */ + +/** + * \fn bool Flags::operator==(Flags other) + * \brief Compare flags for equality + * \param[in] other The second operand + * \return True if the Flags and \a other are equal, false otherwise + */ + +/** + * \fn bool Flags::operator!=(E flag) + * \brief Compare flags for non-equality + * \param[in] flag The second operand + * \return True if the Flags and \a flag are not equal, false otherwise + */ + +/** + * \fn bool Flags::operator!=(Flags other) + * \brief Compare flags for non-equality + * \param[in] other The second operand + * \return True if the Flags and \a other are not equal, false otherwise + */ + +/** + * \fn Flags::operator Type() const + * \brief Convert the Flags to the underlying integer type + * \return The Flags value as an integer + */ + +/** + * \fn Flags::operator bool() const + * \brief Convert the Flags to a boolean + * \return True if at least one flag is set, false otherwise + */ + +/** + * \fn Flags Flags::operator&(E flag) const + * \brief Compute the bitwise AND of this Flags and the \a flag + * \param[in] flag The second operand + * \return A Flags containing the result of the AND operation + */ + +/** + * \fn Flags Flags::operator&(Flags other) const + * \brief Compute the bitwise AND of this Flags and the \a other Flags + * \param[in] other The second operand + * \return A Flags containing the result of the AND operation + */ + +/** + * \fn Flags Flags::operator|(E flag) const + * \brief Compute the bitwise OR of this Flags and the \a flag + * \param[in] flag The second operand + * \return A Flags containing the result of the OR operation + */ + +/** + * \fn Flags Flags::operator|(Flags other) const + * \brief Compute the bitwise OR of this Flags and the \a other Flags + * \param[in] other The second operand + * \return A Flags containing the result of the OR operation + */ + +/** + * \fn Flags Flags::operator^(E flag) const + * \brief Compute the bitwise XOR of this Flags and the \a flag + * \param[in] flag The second operand + * \return A Flags containing the result of the XOR operation + */ + +/** + * \fn Flags Flags::operator^(Flags other) const + * \brief Compute the bitwise XOR of this Flags and the \a other Flags + * \param[in] other The second operand + * \return A Flags containing the result of the XOR operation + */ + +/** + * \fn Flags Flags::operator~() const + * \brief Compute the bitwise NOT of this Flags + * \return A Flags containing the result of the NOT operation + */ + +/** + * \fn bool Flags::operator!() const + * \brief Check if flags are set + * \return True if no flags is set, false otherwise + */ + +/** + * \def LIBCAMERA_FLAGS_ENABLE_OPERATORS(enum) + * \brief Enable bitwise operations on the \a enum enumeration + * + * This macro enables the bitwise AND, OR, XOR and NOT operators on the given + * \a enum. This allows the enum values to be safely used in bitwise operations + * with the Flags<> class. + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 3aad4386ffc2..2461200fa772 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -18,6 +18,7 @@ libcamera_sources = files([ 'event_notifier.cpp', 'file.cpp', 'file_descriptor.cpp', + 'flags.cpp', 'formats.cpp', 'framebuffer_allocator.cpp', 'geometry.cpp', From patchwork Fri Jul 24 23:08:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 8993 X-Patchwork-Delegate: laurent.pinchart@ideasonboard.com Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 59195BD878 for ; Fri, 24 Jul 2020 23:08:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D9B7661366; Sat, 25 Jul 2020 01:08:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="nfflp8g/"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D8D1260939 for ; Sat, 25 Jul 2020 01:08:55 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 711BD538 for ; Sat, 25 Jul 2020 01:08:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1595632132; bh=W9sXLdPHFJjTnt29uwOhGRc0ZoouWOc7dFyhBAWlX+M=; h=From:To:Subject:Date:In-Reply-To:References:From; b=nfflp8g/cvjLwAKN6fHw8dMxFrY5N5j0mW+RoZx6eMII1kp5NTqX2cKAEmWFWySDO bmdL0LBpshgJGSmfFGZQsYi2XnNED1CuvvR5/ZPmtRl+j9jw6d7gMC3R163W9GjdPk BVwTAsPGXLMbxOz65sz2z7si9ZlBlLsE2TvYwtA8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 25 Jul 2020 02:08:41 +0300 Message-Id: <20200724230841.27838-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200724230841.27838-1-laurent.pinchart@ideasonboard.com> References: <20200724230841.27838-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/2] test: Add tests for the Flags class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add tests that exercise the whole API of the Flags class. Signed-off-by: Laurent Pinchart --- test/flags.cpp | 204 +++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 205 insertions(+) create mode 100644 test/flags.cpp diff --git a/test/flags.cpp b/test/flags.cpp new file mode 100644 index 000000000000..82eca556f35e --- /dev/null +++ b/test/flags.cpp @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * flags.cpp - Flags tests + */ + +#include + +#include + +#include "test.h" + +using namespace libcamera; +using namespace std; + +class FlagsTest : public Test +{ +protected: + enum class Option { + First = (1 << 0), + Second = (1 << 1), + Third = (1 << 2), + }; + + using Options = Flags