[{"id":38366,"web_url":"https://patchwork.libcamera.org/comment/38366/","msgid":"<177392437753.1533536.13360225179930117088@ping.linuxembedded.co.uk>","date":"2026-03-19T12:46:17","subject":"Re: [PATCH v1] ipa: libipa: quantized: Enable `constexpr` operation","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Barnabás Pőcze (2026-03-19 08:00:05)\n> There is nothing inherently non-constexpr in the `Quantized` type. Whether\n> it can work in `constexpr` contexts depends on the traits type. There is\n> no reason to explicitly disallow `constexpr` operation. So mark all eligible\n> methods `constexpr`.\n> \n> In addition, add some `static_assert()`s to the \"quantized\" test to check\n> constexpr operation.\n> \n> For example, `FixedPointQTraits<...>::toFloat()` is `constexpr`, so this\n> enables the construction of `{U,}Q<...>` from the underlying quantized\n> value in `constexpr` contexts, which can be useful for example for\n> storing default values in e.g. `static constexpr` variables.\n> \n> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n\nGreat! I think I remember trying to make parts constexpr, but you were\nconcerned about needing a specific C++ revision?\n\nBut I assume that doesn't impact here so:\n\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> ---\n>  src/ipa/libipa/quantized.h    | 32 +++++++++++++++++++-------------\n>  test/ipa/libipa/quantized.cpp | 15 +++++++++++++--\n>  2 files changed, 32 insertions(+), 15 deletions(-)\n> \n> diff --git a/src/ipa/libipa/quantized.h b/src/ipa/libipa/quantized.h\n> index 6bd196c7d..8d7b06a2d 100644\n> --- a/src/ipa/libipa/quantized.h\n> +++ b/src/ipa/libipa/quantized.h\n> @@ -24,34 +24,40 @@ struct Quantized {\n>         static_assert(std::is_arithmetic_v<QuantizedType>,\n>                       \"Quantized: QuantizedType must be arithmetic\");\n>  \n> -       Quantized()\n> +       constexpr Quantized()\n>                 : Quantized(0.0f) {}\n> -       Quantized(float x) { *this = x; }\n> -       Quantized(QuantizedType x) { *this = x; }\n>  \n> -       Quantized &operator=(float x)\n> +       constexpr Quantized(float x)\n> +               : Quantized(Traits::fromFloat(x))\n>         {\n> -               quantized_ = Traits::fromFloat(x);\n> -               value_ = Traits::toFloat(quantized_);\n> +       }\n> +\n> +       constexpr Quantized(QuantizedType x)\n> +               : quantized_(x), value_(Traits::toFloat(x))\n> +       {\n> +       }\n> +\n> +       constexpr Quantized &operator=(float x)\n> +       {\n> +               *this = Quantized(x);\n>                 return *this;\n>         }\n>  \n> -       Quantized &operator=(QuantizedType x)\n> +       constexpr Quantized &operator=(QuantizedType x)\n>         {\n> -               value_ = Traits::toFloat(x);\n> -               quantized_ = x;\n> +               *this = Quantized(x);\n>                 return *this;\n>         }\n>  \n> -       float value() const { return value_; }\n> -       QuantizedType quantized() const { return quantized_; }\n> +       constexpr float value() const { return value_; }\n> +       constexpr QuantizedType quantized() const { return quantized_; }\n>  \n> -       bool operator==(const Quantized &other) const\n> +       constexpr bool operator==(const Quantized &other) const\n>         {\n>                 return quantized_ == other.quantized_;\n>         }\n>  \n> -       bool operator!=(const Quantized &other) const\n> +       constexpr bool operator!=(const Quantized &other) const\n>         {\n>                 return !(*this == other);\n>         }\n> diff --git a/test/ipa/libipa/quantized.cpp b/test/ipa/libipa/quantized.cpp\n> index f138597f2..18655dac5 100644\n> --- a/test/ipa/libipa/quantized.cpp\n> +++ b/test/ipa/libipa/quantized.cpp\n> @@ -25,7 +25,7 @@ struct BrightnessHueTraits {\n>                 int quantized = std::lround(v * 128.0f);\n>                 return std::clamp<int>(quantized, -128, 127);\n>         }\n> -       static float toFloat(QuantizedType v)\n> +       static constexpr float toFloat(QuantizedType v)\n>         {\n>                 return static_cast<float>(v) / 128.0f;\n>         }\n> @@ -40,7 +40,7 @@ struct ContrastSaturationTraits {\n>                 int quantized = std::lround(v * 128.0f);\n>                 return std::clamp<int>(quantized, 0, 255);\n>         }\n> -       static float toFloat(QuantizedType v)\n> +       static constexpr float toFloat(QuantizedType v)\n>         {\n>                 return static_cast<float>(v) / 128.0f;\n>         }\n> @@ -138,6 +138,17 @@ protected:\n>                                 return TestFail;\n>                 }\n>  \n> +               /* Test constexpr operation */\n> +               {\n> +                       constexpr BrightnessQ b1(uint8_t(1));\n> +                       constexpr BrightnessQ b2(uint8_t(2));\n> +\n> +                       static_assert(b1.quantized() == 1);\n> +                       static_assert(b2.quantized() == 2);\n> +                       static_assert(b1 != b2);\n> +                       static_assert(!(b1 == b2));\n> +               }\n> +\n>                 return TestPass;\n>         }\n>  };\n> -- \n> 2.53.0\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 A78BFBD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 19 Mar 2026 12:46:23 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B83AC62727;\n\tThu, 19 Mar 2026 13:46:22 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E8447620FA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 19 Mar 2026 13:46:20 +0100 (CET)","from monstersaurus.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 58925838;\n\tThu, 19 Mar 2026 13:45:07 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"WyvI7tCA\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1773924307;\n\tbh=dS8Op27yVeWj84PB3gx7zkCv+5bB6+HodBPcooU2FYY=;\n\th=In-Reply-To:References:Subject:From:To:Date:From;\n\tb=WyvI7tCA6nDadk+4hLW2h52ccLm9DdRNxgPGCgVkPjT+7XWHsAu0wku+JJilK1zwq\n\tCo+tJ+rOK79QiTW9S9xPRcqLbAhAjjE+pkZsKMH4ES4/zzP8kzpN8IVSxfvzhf1UJ7\n\tqPzCmXdYRQQPjuDiHr2BzuVYn8hB/ybRkA6WrhzM=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20260319080005.162571-1-barnabas.pocze@ideasonboard.com>","References":"<20260319080005.162571-1-barnabas.pocze@ideasonboard.com>","Subject":"Re: [PATCH v1] ipa: libipa: quantized: Enable `constexpr` operation","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Thu, 19 Mar 2026 12:46:17 +0000","Message-ID":"<177392437753.1533536.13360225179930117088@ping.linuxembedded.co.uk>","User-Agent":"alot/0.9.1","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":38369,"web_url":"https://patchwork.libcamera.org/comment/38369/","msgid":"<20260319162250.GE860715@killaraus.ideasonboard.com>","date":"2026-03-19T16:22:50","subject":"Re: [PATCH v1] ipa: libipa: quantized: Enable `constexpr` operation","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Thu, Mar 19, 2026 at 09:00:05AM +0100, Barnabás Pőcze wrote:\n> There is nothing inherently non-constexpr in the `Quantized` type. Whether\n> it can work in `constexpr` contexts depends on the traits type. There is\n> no reason to explicitly disallow `constexpr` operation. So mark all eligible\n> methods `constexpr`.\n> \n> In addition, add some `static_assert()`s to the \"quantized\" test to check\n> constexpr operation.\n> \n> For example, `FixedPointQTraits<...>::toFloat()` is `constexpr`, so this\n> enables the construction of `{U,}Q<...>` from the underlying quantized\n> value in `constexpr` contexts, which can be useful for example for\n> storing default values in e.g. `static constexpr` variables.\n> \n> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> ---\n>  src/ipa/libipa/quantized.h    | 32 +++++++++++++++++++-------------\n>  test/ipa/libipa/quantized.cpp | 15 +++++++++++++--\n>  2 files changed, 32 insertions(+), 15 deletions(-)\n> \n> diff --git a/src/ipa/libipa/quantized.h b/src/ipa/libipa/quantized.h\n> index 6bd196c7d..8d7b06a2d 100644\n> --- a/src/ipa/libipa/quantized.h\n> +++ b/src/ipa/libipa/quantized.h\n> @@ -24,34 +24,40 @@ struct Quantized {\n>  \tstatic_assert(std::is_arithmetic_v<QuantizedType>,\n>  \t\t      \"Quantized: QuantizedType must be arithmetic\");\n>  \n> -\tQuantized()\n> +\tconstexpr Quantized()\n>  \t\t: Quantized(0.0f) {}\n> -\tQuantized(float x) { *this = x; }\n> -\tQuantized(QuantizedType x) { *this = x; }\n>  \n> -\tQuantized &operator=(float x)\n> +\tconstexpr Quantized(float x)\n> +\t\t: Quantized(Traits::fromFloat(x))\n>  \t{\n> -\t\tquantized_ = Traits::fromFloat(x);\n> -\t\tvalue_ = Traits::toFloat(quantized_);\n> +\t}\n> +\n> +\tconstexpr Quantized(QuantizedType x)\n> +\t\t: quantized_(x), value_(Traits::toFloat(x))\n> +\t{\n> +\t}\n> +\n> +\tconstexpr Quantized &operator=(float x)\n> +\t{\n> +\t\t*this = Quantized(x);\n>  \t\treturn *this;\n>  \t}\n>  \n> -\tQuantized &operator=(QuantizedType x)\n> +\tconstexpr Quantized &operator=(QuantizedType x)\n>  \t{\n> -\t\tvalue_ = Traits::toFloat(x);\n> -\t\tquantized_ = x;\n> +\t\t*this = Quantized(x);\n>  \t\treturn *this;\n>  \t}\n>  \n> -\tfloat value() const { return value_; }\n> -\tQuantizedType quantized() const { return quantized_; }\n> +\tconstexpr float value() const { return value_; }\n> +\tconstexpr QuantizedType quantized() const { return quantized_; }\n>  \n> -\tbool operator==(const Quantized &other) const\n> +\tconstexpr bool operator==(const Quantized &other) const\n>  \t{\n>  \t\treturn quantized_ == other.quantized_;\n>  \t}\n>  \n> -\tbool operator!=(const Quantized &other) const\n> +\tconstexpr bool operator!=(const Quantized &other) const\n>  \t{\n>  \t\treturn !(*this == other);\n>  \t}\n> diff --git a/test/ipa/libipa/quantized.cpp b/test/ipa/libipa/quantized.cpp\n> index f138597f2..18655dac5 100644\n> --- a/test/ipa/libipa/quantized.cpp\n> +++ b/test/ipa/libipa/quantized.cpp\n> @@ -25,7 +25,7 @@ struct BrightnessHueTraits {\n>  \t\tint quantized = std::lround(v * 128.0f);\n>  \t\treturn std::clamp<int>(quantized, -128, 127);\n>  \t}\n> -\tstatic float toFloat(QuantizedType v)\n> +\tstatic constexpr float toFloat(QuantizedType v)\n>  \t{\n>  \t\treturn static_cast<float>(v) / 128.0f;\n>  \t}\n> @@ -40,7 +40,7 @@ struct ContrastSaturationTraits {\n>  \t\tint quantized = std::lround(v * 128.0f);\n>  \t\treturn std::clamp<int>(quantized, 0, 255);\n>  \t}\n> -\tstatic float toFloat(QuantizedType v)\n> +\tstatic constexpr float toFloat(QuantizedType v)\n>  \t{\n>  \t\treturn static_cast<float>(v) / 128.0f;\n>  \t}\n> @@ -138,6 +138,17 @@ protected:\n>  \t\t\t\treturn TestFail;\n>  \t\t}\n>  \n> +\t\t/* Test constexpr operation */\n> +\t\t{\n> +\t\t\tconstexpr BrightnessQ b1(uint8_t(1));\n> +\t\t\tconstexpr BrightnessQ b2(uint8_t(2));\n> +\n> +\t\t\tstatic_assert(b1.quantized() == 1);\n> +\t\t\tstatic_assert(b2.quantized() == 2);\n> +\t\t\tstatic_assert(b1 != b2);\n> +\t\t\tstatic_assert(!(b1 == b2));\n> +\t\t}\n> +\n>  \t\treturn TestPass;\n>  \t}\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 A9F8FBE086\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 19 Mar 2026 16:22:54 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0BA8262731;\n\tThu, 19 Mar 2026 17:22:54 +0100 (CET)","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 213FF620FA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 19 Mar 2026 17:22:52 +0100 (CET)","from killaraus.ideasonboard.com\n\t(2001-14ba-703d-e500--2a1.rev.dnainternet.fi\n\t[IPv6:2001:14ba:703d:e500::2a1])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 2F2CE838;\n\tThu, 19 Mar 2026 17:21:38 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Up0DCQNL\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1773937298;\n\tbh=hg8xdUaqmjjpQ7a2bYxUe16jakLm7cWM9Z6vFHBAgew=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=Up0DCQNLZGu9ktYd224r2S6IYEK+18w5DKm9n/+KualNTUdBlqaVGD8LyWqVrL6fi\n\t38J3Df9XlHfqHQt+NYb11bMbEWGWftYth5u0lCrKupMiF9Ao3yeZPiAL2cz5Cj7HXj\n\tDls0lS10pq5HlR8rO4xI24BO8NafXGUYBkBeg1QE=","Date":"Thu, 19 Mar 2026 18:22:50 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH v1] ipa: libipa: quantized: Enable `constexpr` operation","Message-ID":"<20260319162250.GE860715@killaraus.ideasonboard.com>","References":"<20260319080005.162571-1-barnabas.pocze@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20260319080005.162571-1-barnabas.pocze@ideasonboard.com>","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]