[{"id":37641,"web_url":"https://patchwork.libcamera.org/comment/37641/","msgid":"<b1bd8222-0429-4e3d-86fe-b11119e0bcc9@ideasonboard.com>","date":"2026-01-14T09:52:13","subject":"Re: [PATCH 28/36] libcamera: value_node: Add mutable children\n\taccessors","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2026. 01. 13. 1:08 keltezéssel, Laurent Pinchart írta:\n> At two at() functions that return mutable pointer to child nodes, based\n   Add\n\n\n> on an index for lists and a key for dictionaries.\n> \n> The API differs from const children accessors that use operator[] and\n> return a reference in order to allow better error handling: while the\n> const accessors return a reference to a global instance of an empty\n> ValueNode when the requested child doesn't exist, a mutable accessor\n> can't do the same without allowing modifying the empty global instance.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>   include/libcamera/internal/value_node.h |  2 ++\n>   src/libcamera/value_node.cpp            | 41 +++++++++++++++++++++++++\n>   2 files changed, 43 insertions(+)\n> \n> diff --git a/include/libcamera/internal/value_node.h b/include/libcamera/internal/value_node.h\n> index 56d200e1cf27..c285be4957ed 100644\n> --- a/include/libcamera/internal/value_node.h\n> +++ b/include/libcamera/internal/value_node.h\n> @@ -228,9 +228,11 @@ public:\n>   \tConstDictAdapter asDict() const { return ConstDictAdapter{ list_ }; }\n>   \tConstListAdapter asList() const { return ConstListAdapter{ list_ }; }\n>   \n> +\tValueNode *at(std::size_t index);\n>   \tconst ValueNode &operator[](std::size_t index) const;\n>   \n>   \tbool contains(std::string_view key) const;\n> +\tValueNode *at(std::string_view key);\n>   \tconst ValueNode &operator[](std::string_view key) const;\n>   \n>   \tValueNode *add(std::unique_ptr<ValueNode> child);\n> diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp\n> index 3c56b47bf79d..50b23284f930 100644\n> --- a/src/libcamera/value_node.cpp\n> +++ b/src/libcamera/value_node.cpp\n> @@ -384,6 +384,24 @@ template struct ValueNode::Accessor<std::vector<std::string>>;\n>    * \\return An adapter of unspecified type compatible with range-based for loops\n>    */\n>   \n> +/**\n> + * \\brief Retrieve the element from list ValueNode by index\n> + * \\param[in] index The element index\n> + *\n> + * This function retrieves an element of the ValueNode. Only ValueNode\n> + * instances of List type associate elements with index, calling this function\n                                                      an index / indices ?\n\n\n> + * on other types of instances or with an invalid index returns a null pointer.\n> + *\n> + * \\return The ValueNode as an element of the list\n\nI would write \"The ValueNode corresponding to \\a index\".\n\n\nReviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n\n> + */\n> +ValueNode *ValueNode::at(std::size_t index)\n> +{\n> +\tif (type_ != Type::List || index >= size())\n> +\t\treturn nullptr;\n> +\n> +\treturn list_[index].value.get();\n> +}\n> +\n>   /**\n>    * \\brief Retrieve the element from list ValueNode by index\n>    * \\param[in] index The element index\n> @@ -419,6 +437,29 @@ bool ValueNode::contains(std::string_view key) const\n>   \treturn dictionary_.find(key) != dictionary_.end();\n>   }\n>   \n> +/**\n> + * \\brief Retrieve a member by key from the dictionary\n> + * \\param[in] key The element key\n> + *\n> + * This function retrieves a member of a ValueNode by \\a key. Only ValueNode\n> + * instances of Dictionary type associate elements with keys, calling this\n> + * function on other types of instances or with a nonexistent key returns a null\n> + * pointer.\n> + *\n> + * \\return The ValueNode corresponding to the \\a key member\n> + */\n> +ValueNode *ValueNode::at(std::string_view key)\n> +{\n> +\tif (type_ != Type::Dictionary)\n> +\t\treturn nullptr;\n> +\n> +\tauto iter = dictionary_.find(key);\n> +\tif (iter == dictionary_.end())\n> +\t\treturn nullptr;\n> +\n> +\treturn iter->second;\n> +}\n> +\n>   /**\n>    * \\brief Retrieve a member by key from the dictionary\n>    * \\param[in] key The element key","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 A3551C3226\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 14 Jan 2026 09:52:17 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EFCE161FBC;\n\tWed, 14 Jan 2026 10:52:16 +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 58943615B2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 14 Jan 2026 10:52:16 +0100 (CET)","from [192.168.33.18] (185.221.143.114.nat.pool.zt.hu\n\t[185.221.143.114])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8AB0E316;\n\tWed, 14 Jan 2026 10:51:49 +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=\"vOU1aJEB\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1768384309;\n\tbh=lDymy8AuVzYzdAtpSuQMwXzoChRyG5LMktTxEWiClXI=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=vOU1aJEBSg5Zz+kdHuwNjQZXuV9f+a49sRnsss7elluQX4QUEmMXmBOiyNK3NJ2nf\n\ts67PLZerSRyFZLWD8hYuC/7DcYvOfGARw30uyHDQH+2+Llcx6+fSJWy1a9F9A1wWhr\n\tJU7cftYk5g+psvi/v8uvnmrgUYTKTvgxaIUSh3IE=","Message-ID":"<b1bd8222-0429-4e3d-86fe-b11119e0bcc9@ideasonboard.com>","Date":"Wed, 14 Jan 2026 10:52:13 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH 28/36] libcamera: value_node: Add mutable children\n\taccessors","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20260113000808.15395-1-laurent.pinchart@ideasonboard.com>\n\t<20260113000808.15395-29-laurent.pinchart@ideasonboard.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260113000808.15395-29-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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":37715,"web_url":"https://patchwork.libcamera.org/comment/37715/","msgid":"<20260118232010.GD27500@pendragon.ideasonboard.com>","date":"2026-01-18T23:20:10","subject":"Re: [PATCH 28/36] libcamera: value_node: Add mutable children\n\taccessors","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Wed, Jan 14, 2026 at 10:52:13AM +0100, Barnabás Pőcze wrote:\n> 2026. 01. 13. 1:08 keltezéssel, Laurent Pinchart írta:\n> > At two at() functions that return mutable pointer to child nodes, based\n>    Add\n> \n> > on an index for lists and a key for dictionaries.\n> > \n> > The API differs from const children accessors that use operator[] and\n> > return a reference in order to allow better error handling: while the\n> > const accessors return a reference to a global instance of an empty\n> > ValueNode when the requested child doesn't exist, a mutable accessor\n> > can't do the same without allowing modifying the empty global instance.\n> > \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >   include/libcamera/internal/value_node.h |  2 ++\n> >   src/libcamera/value_node.cpp            | 41 +++++++++++++++++++++++++\n> >   2 files changed, 43 insertions(+)\n> > \n> > diff --git a/include/libcamera/internal/value_node.h b/include/libcamera/internal/value_node.h\n> > index 56d200e1cf27..c285be4957ed 100644\n> > --- a/include/libcamera/internal/value_node.h\n> > +++ b/include/libcamera/internal/value_node.h\n> > @@ -228,9 +228,11 @@ public:\n> >   \tConstDictAdapter asDict() const { return ConstDictAdapter{ list_ }; }\n> >   \tConstListAdapter asList() const { return ConstListAdapter{ list_ }; }\n> >   \n> > +\tValueNode *at(std::size_t index);\n> >   \tconst ValueNode &operator[](std::size_t index) const;\n> >   \n> >   \tbool contains(std::string_view key) const;\n> > +\tValueNode *at(std::string_view key);\n> >   \tconst ValueNode &operator[](std::string_view key) const;\n> >   \n> >   \tValueNode *add(std::unique_ptr<ValueNode> child);\n> > diff --git a/src/libcamera/value_node.cpp b/src/libcamera/value_node.cpp\n> > index 3c56b47bf79d..50b23284f930 100644\n> > --- a/src/libcamera/value_node.cpp\n> > +++ b/src/libcamera/value_node.cpp\n> > @@ -384,6 +384,24 @@ template struct ValueNode::Accessor<std::vector<std::string>>;\n> >    * \\return An adapter of unspecified type compatible with range-based for loops\n> >    */\n> >   \n> > +/**\n> > + * \\brief Retrieve the element from list ValueNode by index\n> > + * \\param[in] index The element index\n> > + *\n> > + * This function retrieves an element of the ValueNode. Only ValueNode\n> > + * instances of List type associate elements with index, calling this function\n>                                                       an index / indices ?\n\n\"an index\" sounds good.\n\n> > + * on other types of instances or with an invalid index returns a null pointer.\n> > + *\n> > + * \\return The ValueNode as an element of the list\n> \n> I would write \"The ValueNode corresponding to \\a index\".\n\nAck, will address all three comments.\n\n> Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n> \n> > + */\n> > +ValueNode *ValueNode::at(std::size_t index)\n> > +{\n> > +\tif (type_ != Type::List || index >= size())\n> > +\t\treturn nullptr;\n> > +\n> > +\treturn list_[index].value.get();\n> > +}\n> > +\n> >   /**\n> >    * \\brief Retrieve the element from list ValueNode by index\n> >    * \\param[in] index The element index\n> > @@ -419,6 +437,29 @@ bool ValueNode::contains(std::string_view key) const\n> >   \treturn dictionary_.find(key) != dictionary_.end();\n> >   }\n> >   \n> > +/**\n> > + * \\brief Retrieve a member by key from the dictionary\n> > + * \\param[in] key The element key\n> > + *\n> > + * This function retrieves a member of a ValueNode by \\a key. Only ValueNode\n> > + * instances of Dictionary type associate elements with keys, calling this\n> > + * function on other types of instances or with a nonexistent key returns a null\n> > + * pointer.\n> > + *\n> > + * \\return The ValueNode corresponding to the \\a key member\n> > + */\n> > +ValueNode *ValueNode::at(std::string_view key)\n> > +{\n> > +\tif (type_ != Type::Dictionary)\n> > +\t\treturn nullptr;\n> > +\n> > +\tauto iter = dictionary_.find(key);\n> > +\tif (iter == dictionary_.end())\n> > +\t\treturn nullptr;\n> > +\n> > +\treturn iter->second;\n> > +}\n> > +\n> >   /**\n> >    * \\brief Retrieve a member by key from the dictionary\n> >    * \\param[in] key The element key","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 D3962BDCBF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 18 Jan 2026 23:20:33 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9D74B61FB9;\n\tMon, 19 Jan 2026 00:20:33 +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 5C84061F61\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 19 Jan 2026 00:20:32 +0100 (CET)","from pendragon.ideasonboard.com (81-175-209-152.bb.dnainternet.fi\n\t[81.175.209.152])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 518152D9;\n\tMon, 19 Jan 2026 00:20:02 +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=\"pwmYqbyE\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1768778402;\n\tbh=Cx19ouB7XDL2Gl+nM+QomVCcnbEEGvYVyfy8MokURec=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=pwmYqbyERAzjawp5RdjId4NJ5otfX3iZ+qa8oUYOwl0EiK69QJHa5dgqe4Cn1oJ6x\n\tzVWyeE2A8w7Oan9AitbxRx1s7YNOGULvCQ0XQV7SVePpQV0c8xgixWXqOg1kArLmjb\n\tZTnrbZ9xtH1pHZz9K3L5bBhx+27uASjz4HMKiJuw=","Date":"Mon, 19 Jan 2026 01:20:10 +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","Subject":"Re: [PATCH 28/36] libcamera: value_node: Add mutable children\n\taccessors","Message-ID":"<20260118232010.GD27500@pendragon.ideasonboard.com>","References":"<20260113000808.15395-1-laurent.pinchart@ideasonboard.com>\n\t<20260113000808.15395-29-laurent.pinchart@ideasonboard.com>\n\t<b1bd8222-0429-4e3d-86fe-b11119e0bcc9@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<b1bd8222-0429-4e3d-86fe-b11119e0bcc9@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>"}}]