[{"id":24201,"web_url":"https://patchwork.libcamera.org/comment/24201/","msgid":"<165896215823.973512.5533745328591341164@Monstersaurus>","date":"2022-07-27T22:49:18","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Laurent Pinchart via libcamera-devel (2022-07-27 23:21:42)\n> The YamlObject::get() function takes a default value and an optional\n> bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> error handling in callers.\n> \n> A better API is possible by dropping the default value and ok flag and\n> returning an std::optional. Not only does it simplify the calls, it also\n> lets callers handle errors through the standard std::optional class\n> instead of the current ad-hoc mechanism.\n> \n> Provide a get() wrapper around std::optional::value_or() to further\n> simplify callers that don't need any specific error handling.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> Tested-by: Naushir Patuck <naush@raspberrypi.com>\n> ---\n>  include/libcamera/internal/yaml_parser.h |   9 +-\n>  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n>  test/yaml-parser.cpp                     |  71 ++++++------\n>  3 files changed, 96 insertions(+), 122 deletions(-)\n> \n> diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> index 064cf44381d7..61f2223223a7 100644\n> --- a/include/libcamera/internal/yaml_parser.h\n> +++ b/include/libcamera/internal/yaml_parser.h\n> @@ -9,6 +9,7 @@\n>  \n\n<snip>\n\n> --- a/test/yaml-parser.cpp\n> +++ b/test/yaml-parser.cpp\n> @@ -148,7 +148,6 @@ protected:\n>                 }\n>  \n>                 /* Test string object */\n> -               bool ok;\n>                 auto &strObj = (*root)[\"string\"];\n>  \n>                 if (strObj.isDictionary()) {\n> @@ -161,27 +160,27 @@ protected:\n>                         return TestFail;\n>                 }\n>  \n> -               if (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> +               if (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n\nDoes this series mean we can now (safely?) do:\n\n\t\t  if (strObj.get<string>() != \"libcamera\") {\n\t\t  }\n\nOr perhaps the previous patch means we could do:\n\n\n\t\t  if (strObj.get<string>().value_or(utils::defopt) != \"libcamera\") {\n\t\t  }\n\nThough, that's not shorter here, hence using the \"\" instead?\n\n\n\n\n>                         cerr << \"String object parse as wrong content\" << std::endl;\n>                         return TestFail;\n>                 }\n>  \n> -               if (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +               if (strObj.get<int32_t>()) {\n>                         cerr << \"String object parse as integer\" << std::endl;\n>                         return TestFail;\n>                 }\n>  \n> -               if (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +               if (strObj.get<uint32_t>()) {\n>                         cerr << \"String object parse as unsigned integer\" << std::endl;\n>                         return TestFail;\n>                 }\n>  \n> -               if (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +               if (strObj.get<double>()) {\n>                         cerr << \"String object parse as double\" << std::endl;\n>                         return TestFail;\n>                 }\n>  \n> -               if (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +               if (strObj.get<Size>()) {\n>                         cerr << \"String object parse as Size\" << std::endl;\n>                         return TestFail;\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 EE4ECC3275\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 27 Jul 2022 22:49:22 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5A66D63311;\n\tThu, 28 Jul 2022 00:49:22 +0200 (CEST)","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 DD139603E7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 Jul 2022 00:49:20 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 5A32B6D4;\n\tThu, 28 Jul 2022 00:49:20 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1658962162;\n\tbh=sx6aBLG5cNsZ2qTCYcvasYMAqFj4/81x6pqtoqQVUIA=;\n\th=In-Reply-To:References:To:Date:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=OMdMCHJycsK1qhT+/98DScSw3+fr/uM94lzVpVPpabiiwDfwGuH6xes+pYj0TRI+L\n\toTHQPXW+ywUsx0XE7R/WDnzABSEIDZfrMJ97WkL7dyQt8TwZ3KkqobUX6OUuuxvyx8\n\tHgLNZln1IR7HqBGXVJBK1+qYE/avWM7Oi+DYAJdywzZoo+6oVqWfyvjmL+oPUaGvCj\n\tXZRmMJn6qzXEgYZtYy4ytw7jJOXRQHP11qU1G4fYKYJaW1WwrvCJbSR4jjhfrRqRc3\n\tFYSurtC+a1pMSr99REoCudB/l0LTVDL1miV92EWwj0W9CtO7cio0OBDP4CvZnNvhZF\n\t45bePFyzFrTfA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1658962160;\n\tbh=sx6aBLG5cNsZ2qTCYcvasYMAqFj4/81x6pqtoqQVUIA=;\n\th=In-Reply-To:References:Subject:From:To:Date:From;\n\tb=tImkvKPMzvIzmMs0ElYmuz0rrfquSXstCGjc5SC/cxZLMPv2CJ1/j3miKxXC6t+dU\n\tfx0rFkcBwQY4McKRxJ6dFmFg4jwdDXmE7X2TQPTK3HOtJte7tqibhPA8gBMv/RuKfq\n\tG5L7CHHL5VkH5F5HL7Z8X4kLsPlP36hqrvIdUJmk="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"tImkvKPM\"; dkim-atps=neutral","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Wed, 27 Jul 2022 23:49:18 +0100","Message-ID":"<165896215823.973512.5533745328591341164@Monstersaurus>","User-Agent":"alot/0.10","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Kieran Bingham via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24202,"web_url":"https://patchwork.libcamera.org/comment/24202/","msgid":"<YuHDDPx8ocBhB6qf@pendragon.ideasonboard.com>","date":"2022-07-27T22:58:20","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nOn Wed, Jul 27, 2022 at 11:49:18PM +0100, Kieran Bingham wrote:\n> Quoting Laurent Pinchart via libcamera-devel (2022-07-27 23:21:42)\n> > The YamlObject::get() function takes a default value and an optional\n> > bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> > error handling in callers.\n> > \n> > A better API is possible by dropping the default value and ok flag and\n> > returning an std::optional. Not only does it simplify the calls, it also\n> > lets callers handle errors through the standard std::optional class\n> > instead of the current ad-hoc mechanism.\n> > \n> > Provide a get() wrapper around std::optional::value_or() to further\n> > simplify callers that don't need any specific error handling.\n> > \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> > Tested-by: Naushir Patuck <naush@raspberrypi.com>\n> > ---\n> >  include/libcamera/internal/yaml_parser.h |   9 +-\n> >  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n> >  test/yaml-parser.cpp                     |  71 ++++++------\n> >  3 files changed, 96 insertions(+), 122 deletions(-)\n> > \n> > diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> > index 064cf44381d7..61f2223223a7 100644\n> > --- a/include/libcamera/internal/yaml_parser.h\n> > +++ b/include/libcamera/internal/yaml_parser.h\n> > @@ -9,6 +9,7 @@\n> \n> <snip>\n> \n> > --- a/test/yaml-parser.cpp\n> > +++ b/test/yaml-parser.cpp\n> > @@ -148,7 +148,6 @@ protected:\n> >                 }\n> >  \n> >                 /* Test string object */\n> > -               bool ok;\n> >                 auto &strObj = (*root)[\"string\"];\n> >  \n> >                 if (strObj.isDictionary()) {\n> > @@ -161,27 +160,27 @@ protected:\n> >                         return TestFail;\n> >                 }\n> >  \n> > -               if (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> > +               if (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n> \n> Does this series mean we can now (safely?) do:\n> \n> \t\t  if (strObj.get<string>() != \"libcamera\") {\n> \t\t  }\n\nThis is safe, and the condition will be true of strObj doesn't contain a\nstring or if it contains a string other than \"libcamera\".\n\n> \n> Or perhaps the previous patch means we could do:\n> \n> \n> \t\t  if (strObj.get<string>().value_or(utils::defopt) != \"libcamera\") {\n> \t\t  }\n\nThis is fine too.\n\n> Though, that's not shorter here, hence using the \"\" instead?\n\nYou can indeed write\n\n \t\t  if (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n \t\t  }\n\nat the cost of an unnecessary construction and destruction of a\nstd::string(\"\") if strObj.get<string> has a value.\n\n> >                         cerr << \"String object parse as wrong content\" << std::endl;\n> >                         return TestFail;\n> >                 }\n> >  \n> > -               if (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +               if (strObj.get<int32_t>()) {\n> >                         cerr << \"String object parse as integer\" << std::endl;\n> >                         return TestFail;\n> >                 }\n> >  \n> > -               if (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +               if (strObj.get<uint32_t>()) {\n> >                         cerr << \"String object parse as unsigned integer\" << std::endl;\n> >                         return TestFail;\n> >                 }\n> >  \n> > -               if (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > +               if (strObj.get<double>()) {\n> >                         cerr << \"String object parse as double\" << std::endl;\n> >                         return TestFail;\n> >                 }\n> >  \n> > -               if (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +               if (strObj.get<Size>()) {\n> >                         cerr << \"String object parse as Size\" << std::endl;\n> >                         return TestFail;\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 0D9D3BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 27 Jul 2022 22:58:25 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7840463311;\n\tThu, 28 Jul 2022 00:58:24 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 251C2603E7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 Jul 2022 00:58:23 +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 8CE1A6D4;\n\tThu, 28 Jul 2022 00:58:22 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1658962704;\n\tbh=ZyPGSQindCFwlZwGCedodCZydHaUSSGXLKlKQyipd7w=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=vgY7nxJBM9nCznzuBliTpLAFLc5scY4z/qKhFnHhmsS4wXxj2sCupfA7SRWhRD0g2\n\tUZK5j2MinRGbBW6/5Hd6ZuP3dmgpUdUzvCwsiLxa2HomQmB5u0HLzHmQFyD3umy38c\n\tZnevWzeaZkkwwAZgKL5Ho/4yJcmIO2F3H8lJU88F/qE3SpSv7OwfFV5fXuzq8dh5Wv\n\tVZYYh3RtFJ1V8y9VtbQCCaYNjT31H1noMU4kSgKX8dmcOmD771QYRi6FlCCD4BhvYQ\n\t22GYuyx2A5sOmfDEpQdP6hF/UnAg5PGHz07xicdaSwqG74osd36+QRTpihxrjmLfin\n\tBa1Nq6LnR8npA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1658962702;\n\tbh=ZyPGSQindCFwlZwGCedodCZydHaUSSGXLKlKQyipd7w=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=euZPIdKJVdj1vorzn+0hgT9aP+eDhuv7edOlX86wmMsSBncZu3aWJdKmK74f4OBdi\n\trzkjmeMvfcYOVMKHgeRsq5mvfyjZ6QMkjrDDhSg7L1RCgR8uTBLiHVtYihpEjxfE1C\n\trqglTYx3bZbBsZPplWaRSHnp0xyYIn8mWl8U78BA="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"euZPIdKJ\"; dkim-atps=neutral","Date":"Thu, 28 Jul 2022 01:58:20 +0300","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Message-ID":"<YuHDDPx8ocBhB6qf@pendragon.ideasonboard.com>","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>\n\t<165896215823.973512.5533745328591341164@Monstersaurus>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<165896215823.973512.5533745328591341164@Monstersaurus>","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24205,"web_url":"https://patchwork.libcamera.org/comment/24205/","msgid":"<20220728070025.tl6n3ieauhb24bfe@uno.localdomain>","date":"2022-07-28T07:00:25","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent\n\nOn Thu, Jul 28, 2022 at 01:21:42AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> The YamlObject::get() function takes a default value and an optional\n> bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> error handling in callers.\n>\n> A better API is possible by dropping the default value and ok flag and\n> returning an std::optional. Not only does it simplify the calls, it also\n> lets callers handle errors through the standard std::optional class\n> instead of the current ad-hoc mechanism.\n>\n> Provide a get() wrapper around std::optional::value_or() to further\n> simplify callers that don't need any specific error handling.\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> Tested-by: Naushir Patuck <naush@raspberrypi.com>\n\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\nThanks\n   j\n\n> ---\n>  include/libcamera/internal/yaml_parser.h |   9 +-\n>  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n>  test/yaml-parser.cpp                     |  71 ++++++------\n>  3 files changed, 96 insertions(+), 122 deletions(-)\n>\n> diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> index 064cf44381d7..61f2223223a7 100644\n> --- a/include/libcamera/internal/yaml_parser.h\n> +++ b/include/libcamera/internal/yaml_parser.h\n> @@ -9,6 +9,7 @@\n>\n>  #include <iterator>\n>  #include <map>\n> +#include <optional>\n>  #include <string>\n>  #include <vector>\n>\n> @@ -165,7 +166,13 @@ public:\n>  #else\n>  \ttemplate<typename T>\n>  #endif\n> -\tT get(const T &defaultValue, bool *ok = nullptr) const;\n> +\tstd::optional<T> get() const;\n> +\n> +\ttemplate<typename T>\n> +\tT get(const T &defaultValue) const\n> +\t{\n> +\t\treturn get<T>().value_or(defaultValue);\n> +\t}\n>\n>  \tDictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n>  \tListAdapter asList() const { return ListAdapter{ list_ }; }\n> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> index 5c45e44e49c3..4299f5abd38a 100644\n> --- a/src/libcamera/yaml_parser.cpp\n> +++ b/src/libcamera/yaml_parser.cpp\n> @@ -31,12 +31,6 @@ namespace {\n>  /* Empty static YamlObject as a safe result for invalid operations */\n>  static const YamlObject empty;\n>\n> -void setOk(bool *ok, bool result)\n> -{\n> -\tif (ok)\n> -\t\t*ok = result;\n> -}\n> -\n>  } /* namespace */\n>\n>  /**\n> @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n>  }\n>\n>  /**\n> - * \\fn template<typename T> YamlObject::get<T>(\n> - *\tconst T &defaultValue, bool *ok) const\n> + * \\fn template<typename T> YamlObject::get<T>() const\n> + * \\brief Parse the YamlObject as a \\a T value\n> + *\n> + * This function parses the value of the YamlObject as a \\a T object, and\n> + * returns the value. If parsing fails (usually because the YamlObject doesn't\n> + * store a \\a T value), std::nullopt is returned.\n> + *\n> + * \\return The YamlObject value, or std::nullopt if parsing failed\n> + */\n> +\n> +/**\n> + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n>   * \\brief Parse the YamlObject as a \\a T value\n>   * \\param[in] defaultValue The default value when failing to parse\n> - * \\param[out] ok The result of whether the parse succeeded\n>   *\n>   * This function parses the value of the YamlObject as a \\a T object, and\n>   * returns the value. If parsing fails (usually because the YamlObject doesn't\n> - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n> - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n> + * store a \\a T value), the \\a defaultValue is returned.\n>   *\n> - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n> - * need to know if parsing succeeded.\n> - *\n> - * \\return Value as a bool type\n> + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n>   */\n>\n>  #ifndef __DOXYGEN__\n>\n>  template<>\n> -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n> +std::optional<bool> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tif (value_ == \"true\") {\n> -\t\tsetOk(ok, true);\n> +\tif (value_ == \"true\")\n>  \t\treturn true;\n> -\t} else if (value_ == \"false\") {\n> -\t\tsetOk(ok, true);\n> +\telse if (value_ == \"false\")\n>  \t\treturn false;\n> -\t}\n>\n> -\treturn defaultValue;\n> +\treturn {};\n>  }\n>\n>  template<>\n> -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> +std::optional<int16_t> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<int16_t>::min() ||\n>  \t    value > std::numeric_limits<int16_t>::max())\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> +std::optional<uint16_t> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \t/*\n>  \t * libyaml parses all scalar values as strings. When a string has\n> @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>  \t */\n>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>  \tif (found != std::string::npos && value_[found] == '-')\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<uint16_t>::min() ||\n>  \t    value > std::numeric_limits<uint16_t>::max())\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> +std::optional<int32_t> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<int32_t>::min() ||\n>  \t    value > std::numeric_limits<int32_t>::max())\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> +std::optional<uint32_t> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \t/*\n>  \t * libyaml parses all scalar values as strings. When a string has\n> @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>  \t */\n>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>  \tif (found != std::string::npos && value_[found] == '-')\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<uint32_t>::min() ||\n>  \t    value > std::numeric_limits<uint32_t>::max())\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -double YamlObject::get(const double &defaultValue, bool *ok) const\n> +std::optional<double> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n>  \tdouble value = std::strtod(value_.c_str(), &end);\n>\n>  \tif ('\\0' != *end || errno == ERANGE)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n> +std::optional<std::string> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value_;\n>  }\n>\n>  template<>\n> -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n> +std::optional<Size> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::List)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (list_.size() != 2)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\t/*\n> -\t * Add a local variable to validate each dimension in case\n> -\t * that ok == nullptr.\n> -\t */\n> -\tbool valid;\n> -\tuint32_t width = list_[0]->get<uint32_t>(0, &valid);\n> -\tif (!valid)\n> -\t\treturn defaultValue;\n> +\tauto width = list_[0]->get<uint32_t>();\n> +\tif (!width)\n> +\t\treturn {};\n>\n> -\tuint32_t height = list_[1]->get<uint32_t>(0, &valid);\n> -\tif (!valid)\n> -\t\treturn defaultValue;\n> +\tauto height = list_[1]->get<uint32_t>();\n> +\tif (!height)\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n> -\treturn Size(width, height);\n> +\treturn Size(*width, *height);\n>  }\n>\n>  #endif /* __DOXYGEN__ */\n> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> index 38f848232fa6..ebb654f2ef9c 100644\n> --- a/test/yaml-parser.cpp\n> +++ b/test/yaml-parser.cpp\n> @@ -148,7 +148,6 @@ protected:\n>  \t\t}\n>\n>  \t\t/* Test string object */\n> -\t\tbool ok;\n>  \t\tauto &strObj = (*root)[\"string\"];\n>\n>  \t\tif (strObj.isDictionary()) {\n> @@ -161,27 +160,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> +\t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n>  \t\t\tcerr << \"String object parse as wrong content\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (strObj.get<int32_t>()) {\n>  \t\t\tcerr << \"String object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (strObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\tif (strObj.get<double>()) {\n>  \t\t\tcerr << \"String object parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (strObj.get<Size>()) {\n>  \t\t\tcerr << \"String object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -199,27 +198,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n> +\t\tif (int32Obj.get<int32_t>().value_or(0) != -100) {\n>  \t\t\tcerr << \"Integer object parse as wrong value\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n> +\t\tif (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n>  \t\t\tcerr << \"Integer object fail to parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n> +\t\tif (int32Obj.get<double>().value_or(0.0) != -100.0) {\n>  \t\t\tcerr << \"Integer object fail to parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (int32Obj.get<uint32_t>()) {\n>  \t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (int32Obj.get<Size>()) {\n>  \t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -237,27 +236,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n> +\t\tif (uint32Obj.get<int32_t>().value_or(0) != 100) {\n>  \t\t\tcerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n> +\t\tif (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n>  \t\t\tcerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n> +\t\tif (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n>  \t\t\tcerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n> +\t\tif (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n>  \t\t\tcerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (uint32Obj.get<Size>()) {\n>  \t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -275,27 +274,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n> +\t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n>  \t\t\tcerr << \"Double object fail to parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n> +\t\tif (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n>  \t\t\tcerr << \"Double object parse as wrong value\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (doubleObj.get<int32_t>()) {\n>  \t\t\tcerr << \"Double object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (doubleObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (doubleObj.get<Size>()) {\n>  \t\t\tcerr << \"Double object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -313,27 +312,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n> +\t\tif (sizeObj.get<string>()) {\n>  \t\t\tcerr << \"Size object parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\tif (sizeObj.get<double>()) {\n>  \t\t\tcerr << \"Size object parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (sizeObj.get<int32_t>()) {\n>  \t\t\tcerr << \"Size object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (sizeObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n> +\t\tif (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n>  \t\t\tcerr << \"Size object parse as wrong value\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -351,27 +350,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n> +\t\tif (listObj.get<string>()) {\n>  \t\t\tcerr << \"List object parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\tif (listObj.get<double>()) {\n>  \t\t\tcerr << \"List object parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (listObj.get<int32_t>()) {\n>  \t\t\tcerr << \"List object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (listObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (listObj.get<Size>()) {\n>  \t\t\tcerr << \"String list object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -424,27 +423,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n> +\t\tif (dictObj.get<string>()) {\n>  \t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\tif (dictObj.get<double>()) {\n>  \t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (dictObj.get<int32_t>()) {\n>  \t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (dictObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (dictObj.get<Size>()) {\n>  \t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\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 9DA39BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 28 Jul 2022 07:00:30 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1D03C603EB;\n\tThu, 28 Jul 2022 09:00:30 +0200 (CEST)","from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net\n\t[IPv6:2001:4b98:dc4:8::225])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 798A8603EB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 Jul 2022 09:00:28 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id 1C3791C000D;\n\tThu, 28 Jul 2022 07:00:26 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1658991630;\n\tbh=jM+Szqm2P3/Kqfb9687PUMJUGJ+bKoB7ClSbg3qTLdk=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=aMEWhilwTMLWMRjH4vagoX2kZy3uboqrtKE8tE2doszeUYv7Et8XCjVUADkU5qgjL\n\t2adb8wA6oT9/QYngbzORlLaj6TZx4jgjJis87dn8F+0yAmH6rwdpKRMxkqp3oOG3Ii\n\tDiJpU1/0uVrGDYwhAykxBW4FqAEDwgrgZsjO3SPU8Ux4aCTXS99TNZ7uL4eDWbLpIy\n\tXthOCXfF8c8V42dHfCrQd9EI7fhHOljJRdWubY1vRqdTZTGUePeBlUnzeQ4uVUwtFt\n\tigscymVeiU45q/wYqei+LpSj6Xp0SFvNL/cgOJS7QjKhwRVBHnXpwQFGcQnsQeVC2E\n\t/6zQ0VzRxOdKA==","Date":"Thu, 28 Jul 2022 09:00:25 +0200","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20220728070025.tl6n3ieauhb24bfe@uno.localdomain>","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Jacopo Mondi via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24235,"web_url":"https://patchwork.libcamera.org/comment/24235/","msgid":"<CALzBHU6kCD+o6+v5NQuBxRZiuWnRkTh1DVHVqhXbASUQv+pwhg@mail.gmail.com>","date":"2022-07-29T07:03:19","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":123,"url":"https://patchwork.libcamera.org/api/people/123/","name":"Florian Sylvestre","email":"fsylvestre@baylibre.com"},"content":"Hi Laurent,\n\nOn Thu, 28 Jul 2022 at 09:00, Jacopo Mondi via libcamera-devel\n<libcamera-devel@lists.libcamera.org> wrote:\n>\n> Hi Laurent\n>\n> On Thu, Jul 28, 2022 at 01:21:42AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> > The YamlObject::get() function takes a default value and an optional\n> > bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> > error handling in callers.\n> >\n> > A better API is possible by dropping the default value and ok flag and\n> > returning an std::optional. Not only does it simplify the calls, it also\n> > lets callers handle errors through the standard std::optional class\n> > instead of the current ad-hoc mechanism.\n> >\n> > Provide a get() wrapper around std::optional::value_or() to further\n> > simplify callers that don't need any specific error handling.\n> >\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> > Tested-by: Naushir Patuck <naush@raspberrypi.com>\n>\n> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n>\n> Thanks\n>    j\n>\n> > ---\n> >  include/libcamera/internal/yaml_parser.h |   9 +-\n> >  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n> >  test/yaml-parser.cpp                     |  71 ++++++------\n> >  3 files changed, 96 insertions(+), 122 deletions(-)\n> >\n> > diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> > index 064cf44381d7..61f2223223a7 100644\n> > --- a/include/libcamera/internal/yaml_parser.h\n> > +++ b/include/libcamera/internal/yaml_parser.h\n> > @@ -9,6 +9,7 @@\n> >\n> >  #include <iterator>\n> >  #include <map>\n> > +#include <optional>\n> >  #include <string>\n> >  #include <vector>\n> >\n> > @@ -165,7 +166,13 @@ public:\n> >  #else\n> >       template<typename T>\n> >  #endif\n> > -     T get(const T &defaultValue, bool *ok = nullptr) const;\n> > +     std::optional<T> get() const;\n> > +\n> > +     template<typename T>\n> > +     T get(const T &defaultValue) const\n> > +     {\n> > +             return get<T>().value_or(defaultValue);\n> > +     }\n> >\nI have not seen any test for this specific part (it could be great at\nleast as an example).\n\nAlso, do you see any added value to add it to the getList() function\nlater on this series?\nI find more readable to have something like that:\n        std::vector<uint16_t> table = tuningData[prop].getList<uint16_t>({});\nthan:\n        std::vector<uint16_t> table =\ntuningData[prop].getList<uint16_t>().value_or(utils::defopt);\nin case an empty vector is not expected (and we can do check on size)\n\n> >       DictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n> >       ListAdapter asList() const { return ListAdapter{ list_ }; }\n> > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> > index 5c45e44e49c3..4299f5abd38a 100644\n> > --- a/src/libcamera/yaml_parser.cpp\n> > +++ b/src/libcamera/yaml_parser.cpp\n> > @@ -31,12 +31,6 @@ namespace {\n> >  /* Empty static YamlObject as a safe result for invalid operations */\n> >  static const YamlObject empty;\n> >\n> > -void setOk(bool *ok, bool result)\n> > -{\n> > -     if (ok)\n> > -             *ok = result;\n> > -}\n> > -\n> >  } /* namespace */\n> >\n> >  /**\n> > @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n> >  }\n> >\n> >  /**\n> > - * \\fn template<typename T> YamlObject::get<T>(\n> > - *   const T &defaultValue, bool *ok) const\n> > + * \\fn template<typename T> YamlObject::get<T>() const\n> > + * \\brief Parse the YamlObject as a \\a T value\n> > + *\n> > + * This function parses the value of the YamlObject as a \\a T object, and\n> > + * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > + * store a \\a T value), std::nullopt is returned.\n> > + *\n> > + * \\return The YamlObject value, or std::nullopt if parsing failed\n> > + */\n> > +\n> > +/**\n> > + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n> >   * \\brief Parse the YamlObject as a \\a T value\n> >   * \\param[in] defaultValue The default value when failing to parse\n> > - * \\param[out] ok The result of whether the parse succeeded\n> >   *\n> >   * This function parses the value of the YamlObject as a \\a T object, and\n> >   * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n> > - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n> > + * store a \\a T value), the \\a defaultValue is returned.\n> >   *\n> > - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n> > - * need to know if parsing succeeded.\n> > - *\n> > - * \\return Value as a bool type\n> > + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n> >   */\n> >\n> >  #ifndef __DOXYGEN__\n> >\n> >  template<>\n> > -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n> > +std::optional<bool> YamlObject::get() const\n> >  {\n> > -     setOk(ok, false);\n> > -\n> >       if (type_ != Type::Value)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> > -     if (value_ == \"true\") {\n> > -             setOk(ok, true);\n> > +     if (value_ == \"true\")\n> >               return true;\n> > -     } else if (value_ == \"false\") {\n> > -             setOk(ok, true);\n> > +     else if (value_ == \"false\")\n> >               return false;\n> > -     }\n> >\n> > -     return defaultValue;\n> > +     return {};\n> >  }\n> >\n> >  template<>\n> > -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> > +std::optional<int16_t> YamlObject::get() const\n> >  {\n> > -     setOk(ok, false);\n> > -\n> >       if (type_ != Type::Value)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       if (value_ == \"\")\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       char *end;\n> >\n> > @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> >       if ('\\0' != *end || errno == ERANGE ||\n> >           value < std::numeric_limits<int16_t>::min() ||\n> >           value > std::numeric_limits<int16_t>::max())\n> > -             return defaultValue;\n> > +             return {};\n> >\n> > -     setOk(ok, true);\n> >       return value;\n> >  }\n> >\n> >  template<>\n> > -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > +std::optional<uint16_t> YamlObject::get() const\n> >  {\n> > -     setOk(ok, false);\n> > -\n> >       if (type_ != Type::Value)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       if (value_ == \"\")\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       /*\n> >        * libyaml parses all scalar values as strings. When a string has\n> > @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> >        */\n> >       std::size_t found = value_.find_first_not_of(\" \\t\");\n> >       if (found != std::string::npos && value_[found] == '-')\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       char *end;\n> >\n> > @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> >       if ('\\0' != *end || errno == ERANGE ||\n> >           value < std::numeric_limits<uint16_t>::min() ||\n> >           value > std::numeric_limits<uint16_t>::max())\n> > -             return defaultValue;\n> > +             return {};\n> >\n> > -     setOk(ok, true);\n> >       return value;\n> >  }\n> >\n> >  template<>\n> > -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> > +std::optional<int32_t> YamlObject::get() const\n> >  {\n> > -     setOk(ok, false);\n> > -\n> >       if (type_ != Type::Value)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       if (value_ == \"\")\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       char *end;\n> >\n> > @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> >       if ('\\0' != *end || errno == ERANGE ||\n> >           value < std::numeric_limits<int32_t>::min() ||\n> >           value > std::numeric_limits<int32_t>::max())\n> > -             return defaultValue;\n> > +             return {};\n> >\n> > -     setOk(ok, true);\n> >       return value;\n> >  }\n> >\n> >  template<>\n> > -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > +std::optional<uint32_t> YamlObject::get() const\n> >  {\n> > -     setOk(ok, false);\n> > -\n> >       if (type_ != Type::Value)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       if (value_ == \"\")\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       /*\n> >        * libyaml parses all scalar values as strings. When a string has\n> > @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> >        */\n> >       std::size_t found = value_.find_first_not_of(\" \\t\");\n> >       if (found != std::string::npos && value_[found] == '-')\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       char *end;\n> >\n> > @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> >       if ('\\0' != *end || errno == ERANGE ||\n> >           value < std::numeric_limits<uint32_t>::min() ||\n> >           value > std::numeric_limits<uint32_t>::max())\n> > -             return defaultValue;\n> > +             return {};\n> >\n> > -     setOk(ok, true);\n> >       return value;\n> >  }\n> >\n> >  template<>\n> > -double YamlObject::get(const double &defaultValue, bool *ok) const\n> > +std::optional<double> YamlObject::get() const\n> >  {\n> > -     setOk(ok, false);\n> > -\n> >       if (type_ != Type::Value)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       if (value_ == \"\")\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       char *end;\n> >\n> > @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n> >       double value = std::strtod(value_.c_str(), &end);\n> >\n> >       if ('\\0' != *end || errno == ERANGE)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> > -     setOk(ok, true);\n> >       return value;\n> >  }\n> >\n> >  template<>\n> > -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n> > +std::optional<std::string> YamlObject::get() const\n> >  {\n> > -     setOk(ok, false);\n> > -\n> >       if (type_ != Type::Value)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> > -     setOk(ok, true);\n> >       return value_;\n> >  }\n> >\n> >  template<>\n> > -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n> > +std::optional<Size> YamlObject::get() const\n> >  {\n> > -     setOk(ok, false);\n> > -\n> >       if (type_ != Type::List)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> >       if (list_.size() != 2)\n> > -             return defaultValue;\n> > +             return {};\n> >\n> > -     /*\n> > -      * Add a local variable to validate each dimension in case\n> > -      * that ok == nullptr.\n> > -      */\n> > -     bool valid;\n> > -     uint32_t width = list_[0]->get<uint32_t>(0, &valid);\n> > -     if (!valid)\n> > -             return defaultValue;\n> > +     auto width = list_[0]->get<uint32_t>();\n> > +     if (!width)\n> > +             return {};\n> >\n> > -     uint32_t height = list_[1]->get<uint32_t>(0, &valid);\n> > -     if (!valid)\n> > -             return defaultValue;\n> > +     auto height = list_[1]->get<uint32_t>();\n> > +     if (!height)\n> > +             return {};\n> >\n> > -     setOk(ok, true);\n> > -     return Size(width, height);\n> > +     return Size(*width, *height);\n> >  }\n> >\n> >  #endif /* __DOXYGEN__ */\n> > diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> > index 38f848232fa6..ebb654f2ef9c 100644\n> > --- a/test/yaml-parser.cpp\n> > +++ b/test/yaml-parser.cpp\n> > @@ -148,7 +148,6 @@ protected:\n> >               }\n> >\n> >               /* Test string object */\n> > -             bool ok;\n> >               auto &strObj = (*root)[\"string\"];\n> >\n> >               if (strObj.isDictionary()) {\n> > @@ -161,27 +160,27 @@ protected:\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> > +             if (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n> >                       cerr << \"String object parse as wrong content\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +             if (strObj.get<int32_t>()) {\n> >                       cerr << \"String object parse as integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +             if (strObj.get<uint32_t>()) {\n> >                       cerr << \"String object parse as unsigned integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > +             if (strObj.get<double>()) {\n> >                       cerr << \"String object parse as double\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +             if (strObj.get<Size>()) {\n> >                       cerr << \"String object parse as Size\" << std::endl;\n> >                       return TestFail;\n> >               }\n> > @@ -199,27 +198,27 @@ protected:\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n> > +             if (int32Obj.get<int32_t>().value_or(0) != -100) {\n> >                       cerr << \"Integer object parse as wrong value\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n> > +             if (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n> >                       cerr << \"Integer object fail to parse as string\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n> > +             if (int32Obj.get<double>().value_or(0.0) != -100.0) {\n> >                       cerr << \"Integer object fail to parse as double\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +             if (int32Obj.get<uint32_t>()) {\n> >                       cerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +             if (int32Obj.get<Size>()) {\n> >                       cerr << \"Integer object parse as Size\" << std::endl;\n> >                       return TestFail;\n> >               }\n> > @@ -237,27 +236,27 @@ protected:\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n> > +             if (uint32Obj.get<int32_t>().value_or(0) != 100) {\n> >                       cerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n> > +             if (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n> >                       cerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n> > +             if (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n> >                       cerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n> > +             if (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n> >                       cerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +             if (uint32Obj.get<Size>()) {\n> >                       cerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> >                       return TestFail;\n> >               }\n> > @@ -275,27 +274,27 @@ protected:\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n> > +             if (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n> >                       cerr << \"Double object fail to parse as string\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n> > +             if (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n> >                       cerr << \"Double object parse as wrong value\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +             if (doubleObj.get<int32_t>()) {\n> >                       cerr << \"Double object parse as integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +             if (doubleObj.get<uint32_t>()) {\n> >                       cerr << \"Double object parse as unsigned integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +             if (doubleObj.get<Size>()) {\n> >                       cerr << \"Double object parse as Size\" << std::endl;\n> >                       return TestFail;\n> >               }\n> > @@ -313,27 +312,27 @@ protected:\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > +             if (sizeObj.get<string>()) {\n> >                       cerr << \"Size object parse as string\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > +             if (sizeObj.get<double>()) {\n> >                       cerr << \"Size object parse as double\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +             if (sizeObj.get<int32_t>()) {\n> >                       cerr << \"Size object parse as integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +             if (sizeObj.get<uint32_t>()) {\n> >                       cerr << \"Size object parse as unsigned integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n> > +             if (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n> >                       cerr << \"Size object parse as wrong value\" << std::endl;\n> >                       return TestFail;\n> >               }\n> > @@ -351,27 +350,27 @@ protected:\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > +             if (listObj.get<string>()) {\n> >                       cerr << \"List object parse as string\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > +             if (listObj.get<double>()) {\n> >                       cerr << \"List object parse as double\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +             if (listObj.get<int32_t>()) {\n> >                       cerr << \"List object parse as integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +             if (listObj.get<uint32_t>()) {\n> >                       cerr << \"List object parse as unsigne integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +             if (listObj.get<Size>()) {\n> >                       cerr << \"String list object parse as Size\" << std::endl;\n> >                       return TestFail;\n> >               }\n> > @@ -424,27 +423,27 @@ protected:\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > +             if (dictObj.get<string>()) {\n> >                       cerr << \"Dictionary object parse as string\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > +             if (dictObj.get<double>()) {\n> >                       cerr << \"Dictionary object parse as double\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +             if (dictObj.get<int32_t>()) {\n> >                       cerr << \"Dictionary object parse as integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +             if (dictObj.get<uint32_t>()) {\n> >                       cerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> >                       return TestFail;\n> >               }\n> >\n> > -             if (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +             if (dictObj.get<Size>()) {\n> >                       cerr << \"Dictionary object parse as Size\" << std::endl;\n> >                       return TestFail;\n> >               }\n> > --\n> > Regards,\n> >\n> > Laurent Pinchart\n> >\n\nReviewed-by: Florian Sylvestre <fsylvestre@baylibre.com>","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 C4F89BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 29 Jul 2022 07:03:35 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 38E2063312;\n\tFri, 29 Jul 2022 09:03:35 +0200 (CEST)","from mail-pj1-x1032.google.com (mail-pj1-x1032.google.com\n\t[IPv6:2607:f8b0:4864:20::1032])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 48B8860486\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 29 Jul 2022 09:03:33 +0200 (CEST)","by mail-pj1-x1032.google.com with SMTP id ha11so4059480pjb.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 29 Jul 2022 00:03:33 -0700 (PDT)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659078215;\n\tbh=hDxVp8HqzsdJEL2XvQpIrSaFWabw+EPjXZXy+jBnslQ=;\n\th=References:In-Reply-To:Date:To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=GHMqlBOAvvV8QvErUHAMsyMio054dZnsprLEluYtrsQ56Xd1H+WmWK387S0nAj6Ev\n\turpUZ/kqfw+Cm/f1MJK0e1mq7hsRYjwdRsYm1HeUWshE1mkbfYY1cUQede11+SvN1p\n\tvXZFX7K5+H3slnrEJohPzJmBoX252YjY/ZLUOEXdZvbzPAli46oOAfxeomZ5yIv+mq\n\tSzFhUXoS0q4mCzHQkrhZBidkDk5hKB4ZXmGHxhqhsGsWN0PMeKS/pIEMp/wg8kh9T9\n\tdcYSeY0VFPx5HNQr6neKD95jysnMY7yrpYn4qcZUcJDJfC060lXl8+vlHcq03xGqF6\n\tN8rwRbBHGsRrQ==","v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=baylibre-com.20210112.gappssmtp.com; s=20210112;\n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=xgC6Fvy/kg3CZwc++zXFXyN3srzBMNts7nLPc0HuEkM=;\n\tb=0jnpukBr9kB9/VQmIFAuAdEQ8L05ifDGjBsiG7beqIF0s8f5WYLS9fvBtyYxVftUuC\n\t11M61Nn2K9OHlBd26DT4nVbz4yho6icGToXGnODO2j0M++aDsCo+fd3thhhAP7FNUVT/\n\t6HqSKbP3ys5uVTUe/FD4vG6aekgiXeYwD3YqG6W7on4vPdCqnotPr7rRAQO3tmsfNvfz\n\tsXxdKhTmgL+wXpgrYd1MB4OhO55FptJDZ0mgSOEIdvXt6RrLnrEJOorsiC5sc+kUm37a\n\tqWt3S1btjhp973Zge97iOC/zvVA8ybro4c+jmuYCiwGE7jN7Qz7VIKdgxF/LWEQ8uFW9\n\tqknA=="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected)\n\theader.d=baylibre-com.20210112.gappssmtp.com\n\theader.i=@baylibre-com.20210112.gappssmtp.com header.b=\"0jnpukBr\"; \n\tdkim-atps=neutral","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20210112;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=xgC6Fvy/kg3CZwc++zXFXyN3srzBMNts7nLPc0HuEkM=;\n\tb=ciqVCiqKZCMTSGF9e4YewTL0mgT2Q0Ny766hnENdntxlrdrQRbIFQkZn0vZI0sBEFs\n\tkD5o36oCqRQF9oswk6iFBbSW2NQodY/9787D9mS7nnHrAyeMlCxDYX6vgWEW6xC0Icy6\n\tBbVbCTR1oq+PwFVeO7xb5kWu6p8qrO5Et9URGPPx1AhF/YPADLTgSfWS1gwPDFvHho2c\n\tje6njnewSlNc7Hi+wL5x2mpHgUMfH/JAFF67nLI8uWXYQoXSRE1DXLnmZA3ccU4qXaIu\n\tAqEaLV5QoRA+3eRWKLOKA48FORUV5miOA34af16rIR5KxpLSbhtiuu+Gu2XrP3/a5Pa7\n\tmALg==","X-Gm-Message-State":"ACgBeo2mqDSX+Zn2sZUV7e3WRkFmRWzc9o2PHXKOItc4jAueyiWQWYy9\n\tnrfORnNLbujGLYVjqOeaOstHxq2B88aAdORZOmzQTULx8bua4Z4/","X-Google-Smtp-Source":"AA6agR6/m1OJlW8J8KOFd8EO2aMgENxMy/7OuBc3H4OhOt6pJ7wgVR1LjMc9ZVpB0UxJCQXM3lZOPLfF2kW3nIJ1yWg=","X-Received":"by 2002:a17:902:704b:b0:16d:d2c2:9942 with SMTP id\n\th11-20020a170902704b00b0016dd2c29942mr1427881plt.85.1659078211274;\n\tFri, 29 Jul 2022 00:03:31 -0700 (PDT)","MIME-Version":"1.0","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>\n\t<20220728070025.tl6n3ieauhb24bfe@uno.localdomain>","In-Reply-To":"<20220728070025.tl6n3ieauhb24bfe@uno.localdomain>","Date":"Fri, 29 Jul 2022 09:03:19 +0200","Message-ID":"<CALzBHU6kCD+o6+v5NQuBxRZiuWnRkTh1DVHVqhXbASUQv+pwhg@mail.gmail.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Content-Type":"text/plain; charset=\"UTF-8\"","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Florian Sylvestre via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Florian Sylvestre <fsylvestre@baylibre.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24253,"web_url":"https://patchwork.libcamera.org/comment/24253/","msgid":"<YuUwEFZYXKwPFZXp@pendragon.ideasonboard.com>","date":"2022-07-30T13:20:16","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Florian,\n\nOn Fri, Jul 29, 2022 at 09:03:19AM +0200, Florian Sylvestre wrote:\n> On Thu, 28 Jul 2022 at 09:00, Jacopo Mondi via libcamera-devel wrote:\n> > On Thu, Jul 28, 2022 at 01:21:42AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> > > The YamlObject::get() function takes a default value and an optional\n> > > bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> > > error handling in callers.\n> > >\n> > > A better API is possible by dropping the default value and ok flag and\n> > > returning an std::optional. Not only does it simplify the calls, it also\n> > > lets callers handle errors through the standard std::optional class\n> > > instead of the current ad-hoc mechanism.\n> > >\n> > > Provide a get() wrapper around std::optional::value_or() to further\n> > > simplify callers that don't need any specific error handling.\n> > >\n> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > > Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> > > Tested-by: Naushir Patuck <naush@raspberrypi.com>\n> >\n> > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> >\n> > > ---\n> > >  include/libcamera/internal/yaml_parser.h |   9 +-\n> > >  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n> > >  test/yaml-parser.cpp                     |  71 ++++++------\n> > >  3 files changed, 96 insertions(+), 122 deletions(-)\n> > >\n> > > diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> > > index 064cf44381d7..61f2223223a7 100644\n> > > --- a/include/libcamera/internal/yaml_parser.h\n> > > +++ b/include/libcamera/internal/yaml_parser.h\n> > > @@ -9,6 +9,7 @@\n> > >\n> > >  #include <iterator>\n> > >  #include <map>\n> > > +#include <optional>\n> > >  #include <string>\n> > >  #include <vector>\n> > >\n> > > @@ -165,7 +166,13 @@ public:\n> > >  #else\n> > >       template<typename T>\n> > >  #endif\n> > > -     T get(const T &defaultValue, bool *ok = nullptr) const;\n> > > +     std::optional<T> get() const;\n> > > +\n> > > +     template<typename T>\n> > > +     T get(const T &defaultValue) const\n> > > +     {\n> > > +             return get<T>().value_or(defaultValue);\n> > > +     }\n> \n> I have not seen any test for this specific part (it could be great at\n> least as an example).\n\nGood point. I'll add tests.\n\n> Also, do you see any added value to add it to the getList() function\n> later on this series?\n> I find more readable to have something like that:\n>         std::vector<uint16_t> table = tuningData[prop].getList<uint16_t>({});\n> than:\n>         std::vector<uint16_t> table =\n> tuningData[prop].getList<uint16_t>().value_or(utils::defopt);\n> in case an empty vector is not expected (and we can do check on size)\n\nDo you mean something along the lines of\n\n\ttemplate<typename T>\n\tstd::vector<T> getList(const std::vector<T> &defaultValue);\n\n?\n\n> > >       DictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n> > >       ListAdapter asList() const { return ListAdapter{ list_ }; }\n> > > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> > > index 5c45e44e49c3..4299f5abd38a 100644\n> > > --- a/src/libcamera/yaml_parser.cpp\n> > > +++ b/src/libcamera/yaml_parser.cpp\n> > > @@ -31,12 +31,6 @@ namespace {\n> > >  /* Empty static YamlObject as a safe result for invalid operations */\n> > >  static const YamlObject empty;\n> > >\n> > > -void setOk(bool *ok, bool result)\n> > > -{\n> > > -     if (ok)\n> > > -             *ok = result;\n> > > -}\n> > > -\n> > >  } /* namespace */\n> > >\n> > >  /**\n> > > @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n> > >  }\n> > >\n> > >  /**\n> > > - * \\fn template<typename T> YamlObject::get<T>(\n> > > - *   const T &defaultValue, bool *ok) const\n> > > + * \\fn template<typename T> YamlObject::get<T>() const\n> > > + * \\brief Parse the YamlObject as a \\a T value\n> > > + *\n> > > + * This function parses the value of the YamlObject as a \\a T object, and\n> > > + * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > > + * store a \\a T value), std::nullopt is returned.\n> > > + *\n> > > + * \\return The YamlObject value, or std::nullopt if parsing failed\n> > > + */\n> > > +\n> > > +/**\n> > > + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n> > >   * \\brief Parse the YamlObject as a \\a T value\n> > >   * \\param[in] defaultValue The default value when failing to parse\n> > > - * \\param[out] ok The result of whether the parse succeeded\n> > >   *\n> > >   * This function parses the value of the YamlObject as a \\a T object, and\n> > >   * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > > - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n> > > - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n> > > + * store a \\a T value), the \\a defaultValue is returned.\n> > >   *\n> > > - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n> > > - * need to know if parsing succeeded.\n> > > - *\n> > > - * \\return Value as a bool type\n> > > + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n> > >   */\n> > >\n> > >  #ifndef __DOXYGEN__\n> > >\n> > >  template<>\n> > > -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n> > > +std::optional<bool> YamlObject::get() const\n> > >  {\n> > > -     setOk(ok, false);\n> > > -\n> > >       if (type_ != Type::Value)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > > -     if (value_ == \"true\") {\n> > > -             setOk(ok, true);\n> > > +     if (value_ == \"true\")\n> > >               return true;\n> > > -     } else if (value_ == \"false\") {\n> > > -             setOk(ok, true);\n> > > +     else if (value_ == \"false\")\n> > >               return false;\n> > > -     }\n> > >\n> > > -     return defaultValue;\n> > > +     return {};\n> > >  }\n> > >\n> > >  template<>\n> > > -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> > > +std::optional<int16_t> YamlObject::get() const\n> > >  {\n> > > -     setOk(ok, false);\n> > > -\n> > >       if (type_ != Type::Value)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       if (value_ == \"\")\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       char *end;\n> > >\n> > > @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> > >       if ('\\0' != *end || errno == ERANGE ||\n> > >           value < std::numeric_limits<int16_t>::min() ||\n> > >           value > std::numeric_limits<int16_t>::max())\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > > -     setOk(ok, true);\n> > >       return value;\n> > >  }\n> > >\n> > >  template<>\n> > > -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > > +std::optional<uint16_t> YamlObject::get() const\n> > >  {\n> > > -     setOk(ok, false);\n> > > -\n> > >       if (type_ != Type::Value)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       if (value_ == \"\")\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       /*\n> > >        * libyaml parses all scalar values as strings. When a string has\n> > > @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > >        */\n> > >       std::size_t found = value_.find_first_not_of(\" \\t\");\n> > >       if (found != std::string::npos && value_[found] == '-')\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       char *end;\n> > >\n> > > @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > >       if ('\\0' != *end || errno == ERANGE ||\n> > >           value < std::numeric_limits<uint16_t>::min() ||\n> > >           value > std::numeric_limits<uint16_t>::max())\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > > -     setOk(ok, true);\n> > >       return value;\n> > >  }\n> > >\n> > >  template<>\n> > > -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> > > +std::optional<int32_t> YamlObject::get() const\n> > >  {\n> > > -     setOk(ok, false);\n> > > -\n> > >       if (type_ != Type::Value)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       if (value_ == \"\")\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       char *end;\n> > >\n> > > @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> > >       if ('\\0' != *end || errno == ERANGE ||\n> > >           value < std::numeric_limits<int32_t>::min() ||\n> > >           value > std::numeric_limits<int32_t>::max())\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > > -     setOk(ok, true);\n> > >       return value;\n> > >  }\n> > >\n> > >  template<>\n> > > -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > > +std::optional<uint32_t> YamlObject::get() const\n> > >  {\n> > > -     setOk(ok, false);\n> > > -\n> > >       if (type_ != Type::Value)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       if (value_ == \"\")\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       /*\n> > >        * libyaml parses all scalar values as strings. When a string has\n> > > @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > >        */\n> > >       std::size_t found = value_.find_first_not_of(\" \\t\");\n> > >       if (found != std::string::npos && value_[found] == '-')\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       char *end;\n> > >\n> > > @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > >       if ('\\0' != *end || errno == ERANGE ||\n> > >           value < std::numeric_limits<uint32_t>::min() ||\n> > >           value > std::numeric_limits<uint32_t>::max())\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > > -     setOk(ok, true);\n> > >       return value;\n> > >  }\n> > >\n> > >  template<>\n> > > -double YamlObject::get(const double &defaultValue, bool *ok) const\n> > > +std::optional<double> YamlObject::get() const\n> > >  {\n> > > -     setOk(ok, false);\n> > > -\n> > >       if (type_ != Type::Value)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       if (value_ == \"\")\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       char *end;\n> > >\n> > > @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n> > >       double value = std::strtod(value_.c_str(), &end);\n> > >\n> > >       if ('\\0' != *end || errno == ERANGE)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > > -     setOk(ok, true);\n> > >       return value;\n> > >  }\n> > >\n> > >  template<>\n> > > -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n> > > +std::optional<std::string> YamlObject::get() const\n> > >  {\n> > > -     setOk(ok, false);\n> > > -\n> > >       if (type_ != Type::Value)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > > -     setOk(ok, true);\n> > >       return value_;\n> > >  }\n> > >\n> > >  template<>\n> > > -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n> > > +std::optional<Size> YamlObject::get() const\n> > >  {\n> > > -     setOk(ok, false);\n> > > -\n> > >       if (type_ != Type::List)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > >       if (list_.size() != 2)\n> > > -             return defaultValue;\n> > > +             return {};\n> > >\n> > > -     /*\n> > > -      * Add a local variable to validate each dimension in case\n> > > -      * that ok == nullptr.\n> > > -      */\n> > > -     bool valid;\n> > > -     uint32_t width = list_[0]->get<uint32_t>(0, &valid);\n> > > -     if (!valid)\n> > > -             return defaultValue;\n> > > +     auto width = list_[0]->get<uint32_t>();\n> > > +     if (!width)\n> > > +             return {};\n> > >\n> > > -     uint32_t height = list_[1]->get<uint32_t>(0, &valid);\n> > > -     if (!valid)\n> > > -             return defaultValue;\n> > > +     auto height = list_[1]->get<uint32_t>();\n> > > +     if (!height)\n> > > +             return {};\n> > >\n> > > -     setOk(ok, true);\n> > > -     return Size(width, height);\n> > > +     return Size(*width, *height);\n> > >  }\n> > >\n> > >  #endif /* __DOXYGEN__ */\n> > > diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> > > index 38f848232fa6..ebb654f2ef9c 100644\n> > > --- a/test/yaml-parser.cpp\n> > > +++ b/test/yaml-parser.cpp\n> > > @@ -148,7 +148,6 @@ protected:\n> > >               }\n> > >\n> > >               /* Test string object */\n> > > -             bool ok;\n> > >               auto &strObj = (*root)[\"string\"];\n> > >\n> > >               if (strObj.isDictionary()) {\n> > > @@ -161,27 +160,27 @@ protected:\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> > > +             if (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n> > >                       cerr << \"String object parse as wrong content\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > +             if (strObj.get<int32_t>()) {\n> > >                       cerr << \"String object parse as integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > +             if (strObj.get<uint32_t>()) {\n> > >                       cerr << \"String object parse as unsigned integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > +             if (strObj.get<double>()) {\n> > >                       cerr << \"String object parse as double\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > +             if (strObj.get<Size>()) {\n> > >                       cerr << \"String object parse as Size\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > > @@ -199,27 +198,27 @@ protected:\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n> > > +             if (int32Obj.get<int32_t>().value_or(0) != -100) {\n> > >                       cerr << \"Integer object parse as wrong value\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n> > > +             if (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n> > >                       cerr << \"Integer object fail to parse as string\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n> > > +             if (int32Obj.get<double>().value_or(0.0) != -100.0) {\n> > >                       cerr << \"Integer object fail to parse as double\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > +             if (int32Obj.get<uint32_t>()) {\n> > >                       cerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > +             if (int32Obj.get<Size>()) {\n> > >                       cerr << \"Integer object parse as Size\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > > @@ -237,27 +236,27 @@ protected:\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n> > > +             if (uint32Obj.get<int32_t>().value_or(0) != 100) {\n> > >                       cerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n> > > +             if (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n> > >                       cerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n> > > +             if (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n> > >                       cerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n> > > +             if (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n> > >                       cerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > +             if (uint32Obj.get<Size>()) {\n> > >                       cerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > > @@ -275,27 +274,27 @@ protected:\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n> > > +             if (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n> > >                       cerr << \"Double object fail to parse as string\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n> > > +             if (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n> > >                       cerr << \"Double object parse as wrong value\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > +             if (doubleObj.get<int32_t>()) {\n> > >                       cerr << \"Double object parse as integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > +             if (doubleObj.get<uint32_t>()) {\n> > >                       cerr << \"Double object parse as unsigned integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > +             if (doubleObj.get<Size>()) {\n> > >                       cerr << \"Double object parse as Size\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > > @@ -313,27 +312,27 @@ protected:\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > > +             if (sizeObj.get<string>()) {\n> > >                       cerr << \"Size object parse as string\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > +             if (sizeObj.get<double>()) {\n> > >                       cerr << \"Size object parse as double\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > +             if (sizeObj.get<int32_t>()) {\n> > >                       cerr << \"Size object parse as integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > +             if (sizeObj.get<uint32_t>()) {\n> > >                       cerr << \"Size object parse as unsigned integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n> > > +             if (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n> > >                       cerr << \"Size object parse as wrong value\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > > @@ -351,27 +350,27 @@ protected:\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > > +             if (listObj.get<string>()) {\n> > >                       cerr << \"List object parse as string\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > +             if (listObj.get<double>()) {\n> > >                       cerr << \"List object parse as double\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > +             if (listObj.get<int32_t>()) {\n> > >                       cerr << \"List object parse as integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > +             if (listObj.get<uint32_t>()) {\n> > >                       cerr << \"List object parse as unsigne integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > +             if (listObj.get<Size>()) {\n> > >                       cerr << \"String list object parse as Size\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > > @@ -424,27 +423,27 @@ protected:\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > > +             if (dictObj.get<string>()) {\n> > >                       cerr << \"Dictionary object parse as string\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > +             if (dictObj.get<double>()) {\n> > >                       cerr << \"Dictionary object parse as double\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > +             if (dictObj.get<int32_t>()) {\n> > >                       cerr << \"Dictionary object parse as integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > +             if (dictObj.get<uint32_t>()) {\n> > >                       cerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> > >\n> > > -             if (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > +             if (dictObj.get<Size>()) {\n> > >                       cerr << \"Dictionary object parse as Size\" << std::endl;\n> > >                       return TestFail;\n> > >               }\n> \n> Reviewed-by: Florian Sylvestre <fsylvestre@baylibre.com>","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 E3F6EC3275\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 30 Jul 2022 13:20:21 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5E23263312;\n\tSat, 30 Jul 2022 15:20:21 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B7289603EB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 30 Jul 2022 15:20:19 +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 1E39A480;\n\tSat, 30 Jul 2022 15:20:19 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659187221;\n\tbh=i7NPVyDzcKOF2L25NYEboD6YB5z16D3TrFS1sznkgAw=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=cWkJu/uebJSeKZm0YXT9YYPyW9HtXjjfvKVU75KQiZj9seBHDgX+YvRxWmfAcme/a\n\tGqdwPB62sAUN9Qy3osdMuRUj5hdnxesR47dpYU/1kpcETfN+1aiWCCyMkPVE08zpVZ\n\tOOJrTDGGP+z4XrY1JNotOoGUsxEPTGKuwPvVoRR27NiyUvS1z+p/DNDk//7Z9OYN3q\n\tOGHhtkiIEuhCV6iWMbJJVTWW0d4X1AFtE/CkTcT9dBG8Wb1Bsg4ClvyOXThw2jrP14\n\tzak1g8ODBo+Lv/siM9jEjvK6yvFmKdCBmpAWkIZpouHfT8A8uJN946HMpj2qb7R3Yd\n\taxo5dwaLL6yiw==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1659187219;\n\tbh=i7NPVyDzcKOF2L25NYEboD6YB5z16D3TrFS1sznkgAw=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=aeOYh97GmFMG9o+YLcxLZi8Xasw0DzQ5PdxP8mou/Qss6mFOo4Jy05+Z966bXQraE\n\twxflOVxTx0geZJcVIB8w8QN4ITLS3ntyNFu86p5kWqnZYieJw4ngbWBlmADLWZktpB\n\tFRAByjtJhQImxA40rhOh0Arq5tmdar8oSJ7KyOYI="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"aeOYh97G\"; dkim-atps=neutral","Date":"Sat, 30 Jul 2022 16:20:16 +0300","To":"Florian Sylvestre <fsylvestre@baylibre.com>","Message-ID":"<YuUwEFZYXKwPFZXp@pendragon.ideasonboard.com>","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>\n\t<20220728070025.tl6n3ieauhb24bfe@uno.localdomain>\n\t<CALzBHU6kCD+o6+v5NQuBxRZiuWnRkTh1DVHVqhXbASUQv+pwhg@mail.gmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<CALzBHU6kCD+o6+v5NQuBxRZiuWnRkTh1DVHVqhXbASUQv+pwhg@mail.gmail.com>","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24278,"web_url":"https://patchwork.libcamera.org/comment/24278/","msgid":"<CALzBHU4x5chAUR-yryUH1kmHnqSbGthjL9TuNSjvBtH40NR1CQ@mail.gmail.com>","date":"2022-08-01T20:32:53","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":123,"url":"https://patchwork.libcamera.org/api/people/123/","name":"Florian Sylvestre","email":"fsylvestre@baylibre.com"},"content":"Hello Laurent,\n\nOn Sat, 30 Jul 2022 at 15:20, Laurent Pinchart\n<laurent.pinchart@ideasonboard.com> wrote:\n>\n> Hi Florian,\n>\n> On Fri, Jul 29, 2022 at 09:03:19AM +0200, Florian Sylvestre wrote:\n> > On Thu, 28 Jul 2022 at 09:00, Jacopo Mondi via libcamera-devel wrote:\n> > > On Thu, Jul 28, 2022 at 01:21:42AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> > > > The YamlObject::get() function takes a default value and an optional\n> > > > bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> > > > error handling in callers.\n> > > >\n> > > > A better API is possible by dropping the default value and ok flag and\n> > > > returning an std::optional. Not only does it simplify the calls, it also\n> > > > lets callers handle errors through the standard std::optional class\n> > > > instead of the current ad-hoc mechanism.\n> > > >\n> > > > Provide a get() wrapper around std::optional::value_or() to further\n> > > > simplify callers that don't need any specific error handling.\n> > > >\n> > > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > > > Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> > > > Tested-by: Naushir Patuck <naush@raspberrypi.com>\n> > >\n> > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> > >\n> > > > ---\n> > > >  include/libcamera/internal/yaml_parser.h |   9 +-\n> > > >  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n> > > >  test/yaml-parser.cpp                     |  71 ++++++------\n> > > >  3 files changed, 96 insertions(+), 122 deletions(-)\n> > > >\n> > > > diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> > > > index 064cf44381d7..61f2223223a7 100644\n> > > > --- a/include/libcamera/internal/yaml_parser.h\n> > > > +++ b/include/libcamera/internal/yaml_parser.h\n> > > > @@ -9,6 +9,7 @@\n> > > >\n> > > >  #include <iterator>\n> > > >  #include <map>\n> > > > +#include <optional>\n> > > >  #include <string>\n> > > >  #include <vector>\n> > > >\n> > > > @@ -165,7 +166,13 @@ public:\n> > > >  #else\n> > > >       template<typename T>\n> > > >  #endif\n> > > > -     T get(const T &defaultValue, bool *ok = nullptr) const;\n> > > > +     std::optional<T> get() const;\n> > > > +\n> > > > +     template<typename T>\n> > > > +     T get(const T &defaultValue) const\n> > > > +     {\n> > > > +             return get<T>().value_or(defaultValue);\n> > > > +     }\n> >\n> > I have not seen any test for this specific part (it could be great at\n> > least as an example).\n>\n> Good point. I'll add tests.\n>\n> > Also, do you see any added value to add it to the getList() function\n> > later on this series?\n> > I find more readable to have something like that:\n> >         std::vector<uint16_t> table = tuningData[prop].getList<uint16_t>({});\n> > than:\n> >         std::vector<uint16_t> table =\n> > tuningData[prop].getList<uint16_t>().value_or(utils::defopt);\n> > in case an empty vector is not expected (and we can do check on size)\n>\n> Do you mean something along the lines of\n>\n>         template<typename T>\n>         std::vector<T> getList(const std::vector<T> &defaultValue);\n>\n> ?\nI was thinking of adding:\n        template<typename T>\n        std::vector<T> getList(const std::vector<T> &defaultValue) const\n        {\n                return getList<T>().value_or(defaultValue);\n        }\n\nTo allow the following call:\n        std::vector<uint16_t> x = tuningData[\"x\"].getList<uint16_t>({});\nthat seems more readable than:\n        std::vector<uint16_t> x =\ntuningData[\"x\"].getList<uint16_t>().value_or(utils::defopt);\n\n> > > >       DictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n> > > >       ListAdapter asList() const { return ListAdapter{ list_ }; }\n> > > > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> > > > index 5c45e44e49c3..4299f5abd38a 100644\n> > > > --- a/src/libcamera/yaml_parser.cpp\n> > > > +++ b/src/libcamera/yaml_parser.cpp\n> > > > @@ -31,12 +31,6 @@ namespace {\n> > > >  /* Empty static YamlObject as a safe result for invalid operations */\n> > > >  static const YamlObject empty;\n> > > >\n> > > > -void setOk(bool *ok, bool result)\n> > > > -{\n> > > > -     if (ok)\n> > > > -             *ok = result;\n> > > > -}\n> > > > -\n> > > >  } /* namespace */\n> > > >\n> > > >  /**\n> > > > @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n> > > >  }\n> > > >\n> > > >  /**\n> > > > - * \\fn template<typename T> YamlObject::get<T>(\n> > > > - *   const T &defaultValue, bool *ok) const\n> > > > + * \\fn template<typename T> YamlObject::get<T>() const\n> > > > + * \\brief Parse the YamlObject as a \\a T value\n> > > > + *\n> > > > + * This function parses the value of the YamlObject as a \\a T object, and\n> > > > + * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > > > + * store a \\a T value), std::nullopt is returned.\n> > > > + *\n> > > > + * \\return The YamlObject value, or std::nullopt if parsing failed\n> > > > + */\n> > > > +\n> > > > +/**\n> > > > + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n> > > >   * \\brief Parse the YamlObject as a \\a T value\n> > > >   * \\param[in] defaultValue The default value when failing to parse\n> > > > - * \\param[out] ok The result of whether the parse succeeded\n> > > >   *\n> > > >   * This function parses the value of the YamlObject as a \\a T object, and\n> > > >   * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > > > - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n> > > > - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n> > > > + * store a \\a T value), the \\a defaultValue is returned.\n> > > >   *\n> > > > - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n> > > > - * need to know if parsing succeeded.\n> > > > - *\n> > > > - * \\return Value as a bool type\n> > > > + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n> > > >   */\n> > > >\n> > > >  #ifndef __DOXYGEN__\n> > > >\n> > > >  template<>\n> > > > -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n> > > > +std::optional<bool> YamlObject::get() const\n> > > >  {\n> > > > -     setOk(ok, false);\n> > > > -\n> > > >       if (type_ != Type::Value)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > > -     if (value_ == \"true\") {\n> > > > -             setOk(ok, true);\n> > > > +     if (value_ == \"true\")\n> > > >               return true;\n> > > > -     } else if (value_ == \"false\") {\n> > > > -             setOk(ok, true);\n> > > > +     else if (value_ == \"false\")\n> > > >               return false;\n> > > > -     }\n> > > >\n> > > > -     return defaultValue;\n> > > > +     return {};\n> > > >  }\n> > > >\n> > > >  template<>\n> > > > -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> > > > +std::optional<int16_t> YamlObject::get() const\n> > > >  {\n> > > > -     setOk(ok, false);\n> > > > -\n> > > >       if (type_ != Type::Value)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       if (value_ == \"\")\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       char *end;\n> > > >\n> > > > @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> > > >       if ('\\0' != *end || errno == ERANGE ||\n> > > >           value < std::numeric_limits<int16_t>::min() ||\n> > > >           value > std::numeric_limits<int16_t>::max())\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > > -     setOk(ok, true);\n> > > >       return value;\n> > > >  }\n> > > >\n> > > >  template<>\n> > > > -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > > > +std::optional<uint16_t> YamlObject::get() const\n> > > >  {\n> > > > -     setOk(ok, false);\n> > > > -\n> > > >       if (type_ != Type::Value)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       if (value_ == \"\")\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       /*\n> > > >        * libyaml parses all scalar values as strings. When a string has\n> > > > @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > > >        */\n> > > >       std::size_t found = value_.find_first_not_of(\" \\t\");\n> > > >       if (found != std::string::npos && value_[found] == '-')\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       char *end;\n> > > >\n> > > > @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > > >       if ('\\0' != *end || errno == ERANGE ||\n> > > >           value < std::numeric_limits<uint16_t>::min() ||\n> > > >           value > std::numeric_limits<uint16_t>::max())\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > > -     setOk(ok, true);\n> > > >       return value;\n> > > >  }\n> > > >\n> > > >  template<>\n> > > > -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> > > > +std::optional<int32_t> YamlObject::get() const\n> > > >  {\n> > > > -     setOk(ok, false);\n> > > > -\n> > > >       if (type_ != Type::Value)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       if (value_ == \"\")\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       char *end;\n> > > >\n> > > > @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> > > >       if ('\\0' != *end || errno == ERANGE ||\n> > > >           value < std::numeric_limits<int32_t>::min() ||\n> > > >           value > std::numeric_limits<int32_t>::max())\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > > -     setOk(ok, true);\n> > > >       return value;\n> > > >  }\n> > > >\n> > > >  template<>\n> > > > -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > > > +std::optional<uint32_t> YamlObject::get() const\n> > > >  {\n> > > > -     setOk(ok, false);\n> > > > -\n> > > >       if (type_ != Type::Value)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       if (value_ == \"\")\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       /*\n> > > >        * libyaml parses all scalar values as strings. When a string has\n> > > > @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > > >        */\n> > > >       std::size_t found = value_.find_first_not_of(\" \\t\");\n> > > >       if (found != std::string::npos && value_[found] == '-')\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       char *end;\n> > > >\n> > > > @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > > >       if ('\\0' != *end || errno == ERANGE ||\n> > > >           value < std::numeric_limits<uint32_t>::min() ||\n> > > >           value > std::numeric_limits<uint32_t>::max())\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > > -     setOk(ok, true);\n> > > >       return value;\n> > > >  }\n> > > >\n> > > >  template<>\n> > > > -double YamlObject::get(const double &defaultValue, bool *ok) const\n> > > > +std::optional<double> YamlObject::get() const\n> > > >  {\n> > > > -     setOk(ok, false);\n> > > > -\n> > > >       if (type_ != Type::Value)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       if (value_ == \"\")\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       char *end;\n> > > >\n> > > > @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n> > > >       double value = std::strtod(value_.c_str(), &end);\n> > > >\n> > > >       if ('\\0' != *end || errno == ERANGE)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > > -     setOk(ok, true);\n> > > >       return value;\n> > > >  }\n> > > >\n> > > >  template<>\n> > > > -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n> > > > +std::optional<std::string> YamlObject::get() const\n> > > >  {\n> > > > -     setOk(ok, false);\n> > > > -\n> > > >       if (type_ != Type::Value)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > > -     setOk(ok, true);\n> > > >       return value_;\n> > > >  }\n> > > >\n> > > >  template<>\n> > > > -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n> > > > +std::optional<Size> YamlObject::get() const\n> > > >  {\n> > > > -     setOk(ok, false);\n> > > > -\n> > > >       if (type_ != Type::List)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > >       if (list_.size() != 2)\n> > > > -             return defaultValue;\n> > > > +             return {};\n> > > >\n> > > > -     /*\n> > > > -      * Add a local variable to validate each dimension in case\n> > > > -      * that ok == nullptr.\n> > > > -      */\n> > > > -     bool valid;\n> > > > -     uint32_t width = list_[0]->get<uint32_t>(0, &valid);\n> > > > -     if (!valid)\n> > > > -             return defaultValue;\n> > > > +     auto width = list_[0]->get<uint32_t>();\n> > > > +     if (!width)\n> > > > +             return {};\n> > > >\n> > > > -     uint32_t height = list_[1]->get<uint32_t>(0, &valid);\n> > > > -     if (!valid)\n> > > > -             return defaultValue;\n> > > > +     auto height = list_[1]->get<uint32_t>();\n> > > > +     if (!height)\n> > > > +             return {};\n> > > >\n> > > > -     setOk(ok, true);\n> > > > -     return Size(width, height);\n> > > > +     return Size(*width, *height);\n> > > >  }\n> > > >\n> > > >  #endif /* __DOXYGEN__ */\n> > > > diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> > > > index 38f848232fa6..ebb654f2ef9c 100644\n> > > > --- a/test/yaml-parser.cpp\n> > > > +++ b/test/yaml-parser.cpp\n> > > > @@ -148,7 +148,6 @@ protected:\n> > > >               }\n> > > >\n> > > >               /* Test string object */\n> > > > -             bool ok;\n> > > >               auto &strObj = (*root)[\"string\"];\n> > > >\n> > > >               if (strObj.isDictionary()) {\n> > > > @@ -161,27 +160,27 @@ protected:\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> > > > +             if (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n> > > >                       cerr << \"String object parse as wrong content\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > +             if (strObj.get<int32_t>()) {\n> > > >                       cerr << \"String object parse as integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > +             if (strObj.get<uint32_t>()) {\n> > > >                       cerr << \"String object parse as unsigned integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > > +             if (strObj.get<double>()) {\n> > > >                       cerr << \"String object parse as double\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > +             if (strObj.get<Size>()) {\n> > > >                       cerr << \"String object parse as Size\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > > @@ -199,27 +198,27 @@ protected:\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n> > > > +             if (int32Obj.get<int32_t>().value_or(0) != -100) {\n> > > >                       cerr << \"Integer object parse as wrong value\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n> > > > +             if (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n> > > >                       cerr << \"Integer object fail to parse as string\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n> > > > +             if (int32Obj.get<double>().value_or(0.0) != -100.0) {\n> > > >                       cerr << \"Integer object fail to parse as double\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > +             if (int32Obj.get<uint32_t>()) {\n> > > >                       cerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > +             if (int32Obj.get<Size>()) {\n> > > >                       cerr << \"Integer object parse as Size\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > > @@ -237,27 +236,27 @@ protected:\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n> > > > +             if (uint32Obj.get<int32_t>().value_or(0) != 100) {\n> > > >                       cerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n> > > > +             if (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n> > > >                       cerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n> > > > +             if (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n> > > >                       cerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n> > > > +             if (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n> > > >                       cerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > +             if (uint32Obj.get<Size>()) {\n> > > >                       cerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > > @@ -275,27 +274,27 @@ protected:\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n> > > > +             if (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n> > > >                       cerr << \"Double object fail to parse as string\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n> > > > +             if (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n> > > >                       cerr << \"Double object parse as wrong value\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > +             if (doubleObj.get<int32_t>()) {\n> > > >                       cerr << \"Double object parse as integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > +             if (doubleObj.get<uint32_t>()) {\n> > > >                       cerr << \"Double object parse as unsigned integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > +             if (doubleObj.get<Size>()) {\n> > > >                       cerr << \"Double object parse as Size\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > > @@ -313,27 +312,27 @@ protected:\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > > > +             if (sizeObj.get<string>()) {\n> > > >                       cerr << \"Size object parse as string\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > > +             if (sizeObj.get<double>()) {\n> > > >                       cerr << \"Size object parse as double\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > +             if (sizeObj.get<int32_t>()) {\n> > > >                       cerr << \"Size object parse as integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > +             if (sizeObj.get<uint32_t>()) {\n> > > >                       cerr << \"Size object parse as unsigned integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n> > > > +             if (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n> > > >                       cerr << \"Size object parse as wrong value\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > > @@ -351,27 +350,27 @@ protected:\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > > > +             if (listObj.get<string>()) {\n> > > >                       cerr << \"List object parse as string\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > > +             if (listObj.get<double>()) {\n> > > >                       cerr << \"List object parse as double\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > +             if (listObj.get<int32_t>()) {\n> > > >                       cerr << \"List object parse as integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > +             if (listObj.get<uint32_t>()) {\n> > > >                       cerr << \"List object parse as unsigne integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > +             if (listObj.get<Size>()) {\n> > > >                       cerr << \"String list object parse as Size\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > > @@ -424,27 +423,27 @@ protected:\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > > > +             if (dictObj.get<string>()) {\n> > > >                       cerr << \"Dictionary object parse as string\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > > +             if (dictObj.get<double>()) {\n> > > >                       cerr << \"Dictionary object parse as double\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > +             if (dictObj.get<int32_t>()) {\n> > > >                       cerr << \"Dictionary object parse as integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > +             if (dictObj.get<uint32_t>()) {\n> > > >                       cerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> > > >\n> > > > -             if (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > +             if (dictObj.get<Size>()) {\n> > > >                       cerr << \"Dictionary object parse as Size\" << std::endl;\n> > > >                       return TestFail;\n> > > >               }\n> >\n> > Reviewed-by: Florian Sylvestre <fsylvestre@baylibre.com>\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","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 E6BB6BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  1 Aug 2022 20:33:08 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4BB5A6330F;\n\tMon,  1 Aug 2022 22:33:08 +0200 (CEST)","from mail-pg1-x531.google.com (mail-pg1-x531.google.com\n\t[IPv6:2607:f8b0:4864:20::531])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1D9F2603E8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  1 Aug 2022 22:33:06 +0200 (CEST)","by mail-pg1-x531.google.com with SMTP id e132so10650595pgc.5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 01 Aug 2022 13:33:06 -0700 (PDT)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659385988;\n\tbh=HJAnQ46esNfqtZb379uuaj9MuQkbY++PqtGM2OeFFU0=;\n\th=References:In-Reply-To:Date:To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=kDuHNCeJXMaxutZa8Idg3EJluDx7i/km0Habb0eDH/CJb0/M76jgewlE0pqBW5EqN\n\tbebtc9vXOSdcdKCTxDWFeSLN9JYOcrq8ooWCn14BoTDPdLQ/rfE1J3d57DuTtls8KY\n\t8dDfhyRKEM7Qac5aL46ZRXwGjfjl7zp7Ub7Ti5a8PCz1my+JqueOJnsa8H2hNeVV/s\n\t8N0iU5VRN3ib3KJQIfliX/GMW24YxqhX5rGrbtRkphrQlMyrXwEXe/ZT2qNmgvCr57\n\tsrBAQMq5BBKeSZu7tV9Pv6my5GIjFTD+2lkzvcIpBVIuxXc6co9cpMQvW7Zb8eY0IN\n\tvOORFDxHnMVZg==","v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=baylibre-com.20210112.gappssmtp.com; s=20210112;\n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=Gglklf6PV7/ZCzhWP2DeMZ+4uGJwh/BfNtbFkFyAZKk=;\n\tb=Nb6hq/kFkpaXqz4XgPGJ7rBy2ahrdZfyDHdcDzlRJm5ovwEf1OGciFL4ILTeQzDaiF\n\tB6AxervLKRQU4OI9qkIVDhwrpNslNOq6297XAzSL+aQQvIYGe6oD379lRMS+KDN7aXT5\n\tyh4wtyZRBTaNu4maBCRTVCRgCizzSu2mWJPMCQEzX6RN53DXIo5BOEa2kUSmY7f8TUkA\n\tyYDuxinzi1eIhsoQEvRkYCAAxjtp2+vs6adHKlXsZnNluFdsl7+/oMdI6fEPZHKZsJ1T\n\tMNRFcf75y73xN/SYePxEwI1usmeWwNiYxLkz9jdGg5fsqb1hFdNs63h2L9yzFop0JUXu\n\tBwpA=="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected)\n\theader.d=baylibre-com.20210112.gappssmtp.com\n\theader.i=@baylibre-com.20210112.gappssmtp.com header.b=\"Nb6hq/kF\"; \n\tdkim-atps=neutral","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20210112;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=Gglklf6PV7/ZCzhWP2DeMZ+4uGJwh/BfNtbFkFyAZKk=;\n\tb=czU/9IUDeRgjsW6mDu/cOIi6yDlBe2nYNF/F6E9NOD+ZEbpWtO8iXlSz0XDJPjm7hJ\n\tzhVNQNQJEdXEqm2pnu0xnyKG8ZW4o2V8GITCJ+HIbgcITFY1yCXT1hxNeyjena2hYZWg\n\t8Uzcf9UtBIETAy9MSv1FaCQ3CN7xmUhdWfHt0aGG9Nepw+0KSlvM50wB4WtuzeyqHRvB\n\tmTVQyRj7MvEoELcblay6TQUfsDjnQ1KMNZmtOv97yUhtdtwllU5lYZznpwiE0whM0PVu\n\tzTRmQyflBBwndBfr02ILJ0j4OF0xQxJ4YQPitGqHqg1xYnWb19mX0VmRPKkfc9exOsYS\n\tJrOA==","X-Gm-Message-State":"AJIora94Udk8+FyvJ5tiSF+ooPaqYhxH26wU8mT3/f3cRF9jIm/PhjDb\n\tTHUrbcMnwEzJGrrf6lRHqaVRH8qQSNQm59eMULlnhukgU9cX9zUb","X-Google-Smtp-Source":"AGRyM1vRV/e4bNNWpacdTzGM7qIS3nPG7ECwjLdoj71Np+WgGaWX3/eD/twsOGaMITH1iRIAChJa1yZ2YA7X2HMmqfk=","X-Received":"by 2002:a05:6a00:e8f:b0:528:a1c7:3d00 with SMTP id\n\tbo15-20020a056a000e8f00b00528a1c73d00mr17261256pfb.25.1659385984075;\n\tMon, 01 Aug 2022 13:33:04 -0700 (PDT)","MIME-Version":"1.0","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>\n\t<20220728070025.tl6n3ieauhb24bfe@uno.localdomain>\n\t<CALzBHU6kCD+o6+v5NQuBxRZiuWnRkTh1DVHVqhXbASUQv+pwhg@mail.gmail.com>\n\t<YuUwEFZYXKwPFZXp@pendragon.ideasonboard.com>","In-Reply-To":"<YuUwEFZYXKwPFZXp@pendragon.ideasonboard.com>","Date":"Mon, 1 Aug 2022 22:32:53 +0200","Message-ID":"<CALzBHU4x5chAUR-yryUH1kmHnqSbGthjL9TuNSjvBtH40NR1CQ@mail.gmail.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=\"UTF-8\"","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Florian Sylvestre via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Florian Sylvestre <fsylvestre@baylibre.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24283,"web_url":"https://patchwork.libcamera.org/comment/24283/","msgid":"<YuhCKePeAPJ+k69n@pendragon.ideasonboard.com>","date":"2022-08-01T21:14:17","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Florian,\n\nOn Mon, Aug 01, 2022 at 10:32:53PM +0200, Florian Sylvestre wrote:\n> On Sat, 30 Jul 2022 at 15:20, Laurent Pinchart wrote:\n> > On Fri, Jul 29, 2022 at 09:03:19AM +0200, Florian Sylvestre wrote:\n> > > On Thu, 28 Jul 2022 at 09:00, Jacopo Mondi via libcamera-devel wrote:\n> > > > On Thu, Jul 28, 2022 at 01:21:42AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> > > > > The YamlObject::get() function takes a default value and an optional\n> > > > > bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> > > > > error handling in callers.\n> > > > >\n> > > > > A better API is possible by dropping the default value and ok flag and\n> > > > > returning an std::optional. Not only does it simplify the calls, it also\n> > > > > lets callers handle errors through the standard std::optional class\n> > > > > instead of the current ad-hoc mechanism.\n> > > > >\n> > > > > Provide a get() wrapper around std::optional::value_or() to further\n> > > > > simplify callers that don't need any specific error handling.\n> > > > >\n> > > > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > > > > Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> > > > > Tested-by: Naushir Patuck <naush@raspberrypi.com>\n> > > >\n> > > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> > > >\n> > > > > ---\n> > > > >  include/libcamera/internal/yaml_parser.h |   9 +-\n> > > > >  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n> > > > >  test/yaml-parser.cpp                     |  71 ++++++------\n> > > > >  3 files changed, 96 insertions(+), 122 deletions(-)\n> > > > >\n> > > > > diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> > > > > index 064cf44381d7..61f2223223a7 100644\n> > > > > --- a/include/libcamera/internal/yaml_parser.h\n> > > > > +++ b/include/libcamera/internal/yaml_parser.h\n> > > > > @@ -9,6 +9,7 @@\n> > > > >\n> > > > >  #include <iterator>\n> > > > >  #include <map>\n> > > > > +#include <optional>\n> > > > >  #include <string>\n> > > > >  #include <vector>\n> > > > >\n> > > > > @@ -165,7 +166,13 @@ public:\n> > > > >  #else\n> > > > >       template<typename T>\n> > > > >  #endif\n> > > > > -     T get(const T &defaultValue, bool *ok = nullptr) const;\n> > > > > +     std::optional<T> get() const;\n> > > > > +\n> > > > > +     template<typename T>\n> > > > > +     T get(const T &defaultValue) const\n> > > > > +     {\n> > > > > +             return get<T>().value_or(defaultValue);\n> > > > > +     }\n> > >\n> > > I have not seen any test for this specific part (it could be great at\n> > > least as an example).\n> >\n> > Good point. I'll add tests.\n\nDone and merged btw.\n\n> > > Also, do you see any added value to add it to the getList() function\n> > > later on this series?\n> > > I find more readable to have something like that:\n> > >         std::vector<uint16_t> table = tuningData[prop].getList<uint16_t>({});\n> > > than:\n> > >         std::vector<uint16_t> table =\n> > > tuningData[prop].getList<uint16_t>().value_or(utils::defopt);\n> > > in case an empty vector is not expected (and we can do check on size)\n> >\n> > Do you mean something along the lines of\n> >\n> >         template<typename T>\n> >         std::vector<T> getList(const std::vector<T> &defaultValue);\n> >\n> > ?\n> \n> I was thinking of adding:\n>         template<typename T>\n>         std::vector<T> getList(const std::vector<T> &defaultValue) const\n>         {\n>                 return getList<T>().value_or(defaultValue);\n>         }\n> \n> To allow the following call:\n>         std::vector<uint16_t> x = tuningData[\"x\"].getList<uint16_t>({});\n> that seems more readable than:\n>         std::vector<uint16_t> x = tuningData[\"x\"].getList<uint16_t>().value_or(utils::defopt);\n\nutils::defopt is meant as an optimization to avoid the construction of a\ndefault value passed to the function in the case the list is not empty.\nIt's probably not that costly in this specific case for an empty\nstd::vector, but I don't like this quite ad-hoc API to be honest. It\npushes callers towards inefficient constructs.\n\n> > > > >       DictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n> > > > >       ListAdapter asList() const { return ListAdapter{ list_ }; }\n> > > > > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> > > > > index 5c45e44e49c3..4299f5abd38a 100644\n> > > > > --- a/src/libcamera/yaml_parser.cpp\n> > > > > +++ b/src/libcamera/yaml_parser.cpp\n> > > > > @@ -31,12 +31,6 @@ namespace {\n> > > > >  /* Empty static YamlObject as a safe result for invalid operations */\n> > > > >  static const YamlObject empty;\n> > > > >\n> > > > > -void setOk(bool *ok, bool result)\n> > > > > -{\n> > > > > -     if (ok)\n> > > > > -             *ok = result;\n> > > > > -}\n> > > > > -\n> > > > >  } /* namespace */\n> > > > >\n> > > > >  /**\n> > > > > @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n> > > > >  }\n> > > > >\n> > > > >  /**\n> > > > > - * \\fn template<typename T> YamlObject::get<T>(\n> > > > > - *   const T &defaultValue, bool *ok) const\n> > > > > + * \\fn template<typename T> YamlObject::get<T>() const\n> > > > > + * \\brief Parse the YamlObject as a \\a T value\n> > > > > + *\n> > > > > + * This function parses the value of the YamlObject as a \\a T object, and\n> > > > > + * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > > > > + * store a \\a T value), std::nullopt is returned.\n> > > > > + *\n> > > > > + * \\return The YamlObject value, or std::nullopt if parsing failed\n> > > > > + */\n> > > > > +\n> > > > > +/**\n> > > > > + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n> > > > >   * \\brief Parse the YamlObject as a \\a T value\n> > > > >   * \\param[in] defaultValue The default value when failing to parse\n> > > > > - * \\param[out] ok The result of whether the parse succeeded\n> > > > >   *\n> > > > >   * This function parses the value of the YamlObject as a \\a T object, and\n> > > > >   * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > > > > - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n> > > > > - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n> > > > > + * store a \\a T value), the \\a defaultValue is returned.\n> > > > >   *\n> > > > > - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n> > > > > - * need to know if parsing succeeded.\n> > > > > - *\n> > > > > - * \\return Value as a bool type\n> > > > > + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n> > > > >   */\n> > > > >\n> > > > >  #ifndef __DOXYGEN__\n> > > > >\n> > > > >  template<>\n> > > > > -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n> > > > > +std::optional<bool> YamlObject::get() const\n> > > > >  {\n> > > > > -     setOk(ok, false);\n> > > > > -\n> > > > >       if (type_ != Type::Value)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > > -     if (value_ == \"true\") {\n> > > > > -             setOk(ok, true);\n> > > > > +     if (value_ == \"true\")\n> > > > >               return true;\n> > > > > -     } else if (value_ == \"false\") {\n> > > > > -             setOk(ok, true);\n> > > > > +     else if (value_ == \"false\")\n> > > > >               return false;\n> > > > > -     }\n> > > > >\n> > > > > -     return defaultValue;\n> > > > > +     return {};\n> > > > >  }\n> > > > >\n> > > > >  template<>\n> > > > > -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> > > > > +std::optional<int16_t> YamlObject::get() const\n> > > > >  {\n> > > > > -     setOk(ok, false);\n> > > > > -\n> > > > >       if (type_ != Type::Value)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       if (value_ == \"\")\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       char *end;\n> > > > >\n> > > > > @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> > > > >       if ('\\0' != *end || errno == ERANGE ||\n> > > > >           value < std::numeric_limits<int16_t>::min() ||\n> > > > >           value > std::numeric_limits<int16_t>::max())\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > > -     setOk(ok, true);\n> > > > >       return value;\n> > > > >  }\n> > > > >\n> > > > >  template<>\n> > > > > -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > > > > +std::optional<uint16_t> YamlObject::get() const\n> > > > >  {\n> > > > > -     setOk(ok, false);\n> > > > > -\n> > > > >       if (type_ != Type::Value)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       if (value_ == \"\")\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       /*\n> > > > >        * libyaml parses all scalar values as strings. When a string has\n> > > > > @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > > > >        */\n> > > > >       std::size_t found = value_.find_first_not_of(\" \\t\");\n> > > > >       if (found != std::string::npos && value_[found] == '-')\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       char *end;\n> > > > >\n> > > > > @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > > > >       if ('\\0' != *end || errno == ERANGE ||\n> > > > >           value < std::numeric_limits<uint16_t>::min() ||\n> > > > >           value > std::numeric_limits<uint16_t>::max())\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > > -     setOk(ok, true);\n> > > > >       return value;\n> > > > >  }\n> > > > >\n> > > > >  template<>\n> > > > > -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> > > > > +std::optional<int32_t> YamlObject::get() const\n> > > > >  {\n> > > > > -     setOk(ok, false);\n> > > > > -\n> > > > >       if (type_ != Type::Value)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       if (value_ == \"\")\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       char *end;\n> > > > >\n> > > > > @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> > > > >       if ('\\0' != *end || errno == ERANGE ||\n> > > > >           value < std::numeric_limits<int32_t>::min() ||\n> > > > >           value > std::numeric_limits<int32_t>::max())\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > > -     setOk(ok, true);\n> > > > >       return value;\n> > > > >  }\n> > > > >\n> > > > >  template<>\n> > > > > -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > > > > +std::optional<uint32_t> YamlObject::get() const\n> > > > >  {\n> > > > > -     setOk(ok, false);\n> > > > > -\n> > > > >       if (type_ != Type::Value)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       if (value_ == \"\")\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       /*\n> > > > >        * libyaml parses all scalar values as strings. When a string has\n> > > > > @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > > > >        */\n> > > > >       std::size_t found = value_.find_first_not_of(\" \\t\");\n> > > > >       if (found != std::string::npos && value_[found] == '-')\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       char *end;\n> > > > >\n> > > > > @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > > > >       if ('\\0' != *end || errno == ERANGE ||\n> > > > >           value < std::numeric_limits<uint32_t>::min() ||\n> > > > >           value > std::numeric_limits<uint32_t>::max())\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > > -     setOk(ok, true);\n> > > > >       return value;\n> > > > >  }\n> > > > >\n> > > > >  template<>\n> > > > > -double YamlObject::get(const double &defaultValue, bool *ok) const\n> > > > > +std::optional<double> YamlObject::get() const\n> > > > >  {\n> > > > > -     setOk(ok, false);\n> > > > > -\n> > > > >       if (type_ != Type::Value)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       if (value_ == \"\")\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       char *end;\n> > > > >\n> > > > > @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n> > > > >       double value = std::strtod(value_.c_str(), &end);\n> > > > >\n> > > > >       if ('\\0' != *end || errno == ERANGE)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > > -     setOk(ok, true);\n> > > > >       return value;\n> > > > >  }\n> > > > >\n> > > > >  template<>\n> > > > > -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n> > > > > +std::optional<std::string> YamlObject::get() const\n> > > > >  {\n> > > > > -     setOk(ok, false);\n> > > > > -\n> > > > >       if (type_ != Type::Value)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > > -     setOk(ok, true);\n> > > > >       return value_;\n> > > > >  }\n> > > > >\n> > > > >  template<>\n> > > > > -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n> > > > > +std::optional<Size> YamlObject::get() const\n> > > > >  {\n> > > > > -     setOk(ok, false);\n> > > > > -\n> > > > >       if (type_ != Type::List)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > >       if (list_.size() != 2)\n> > > > > -             return defaultValue;\n> > > > > +             return {};\n> > > > >\n> > > > > -     /*\n> > > > > -      * Add a local variable to validate each dimension in case\n> > > > > -      * that ok == nullptr.\n> > > > > -      */\n> > > > > -     bool valid;\n> > > > > -     uint32_t width = list_[0]->get<uint32_t>(0, &valid);\n> > > > > -     if (!valid)\n> > > > > -             return defaultValue;\n> > > > > +     auto width = list_[0]->get<uint32_t>();\n> > > > > +     if (!width)\n> > > > > +             return {};\n> > > > >\n> > > > > -     uint32_t height = list_[1]->get<uint32_t>(0, &valid);\n> > > > > -     if (!valid)\n> > > > > -             return defaultValue;\n> > > > > +     auto height = list_[1]->get<uint32_t>();\n> > > > > +     if (!height)\n> > > > > +             return {};\n> > > > >\n> > > > > -     setOk(ok, true);\n> > > > > -     return Size(width, height);\n> > > > > +     return Size(*width, *height);\n> > > > >  }\n> > > > >\n> > > > >  #endif /* __DOXYGEN__ */\n> > > > > diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> > > > > index 38f848232fa6..ebb654f2ef9c 100644\n> > > > > --- a/test/yaml-parser.cpp\n> > > > > +++ b/test/yaml-parser.cpp\n> > > > > @@ -148,7 +148,6 @@ protected:\n> > > > >               }\n> > > > >\n> > > > >               /* Test string object */\n> > > > > -             bool ok;\n> > > > >               auto &strObj = (*root)[\"string\"];\n> > > > >\n> > > > >               if (strObj.isDictionary()) {\n> > > > > @@ -161,27 +160,27 @@ protected:\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> > > > > +             if (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n> > > > >                       cerr << \"String object parse as wrong content\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > > +             if (strObj.get<int32_t>()) {\n> > > > >                       cerr << \"String object parse as integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > > +             if (strObj.get<uint32_t>()) {\n> > > > >                       cerr << \"String object parse as unsigned integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > > > +             if (strObj.get<double>()) {\n> > > > >                       cerr << \"String object parse as double\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > > +             if (strObj.get<Size>()) {\n> > > > >                       cerr << \"String object parse as Size\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > > @@ -199,27 +198,27 @@ protected:\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n> > > > > +             if (int32Obj.get<int32_t>().value_or(0) != -100) {\n> > > > >                       cerr << \"Integer object parse as wrong value\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n> > > > > +             if (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n> > > > >                       cerr << \"Integer object fail to parse as string\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n> > > > > +             if (int32Obj.get<double>().value_or(0.0) != -100.0) {\n> > > > >                       cerr << \"Integer object fail to parse as double\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > > +             if (int32Obj.get<uint32_t>()) {\n> > > > >                       cerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > > +             if (int32Obj.get<Size>()) {\n> > > > >                       cerr << \"Integer object parse as Size\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > > @@ -237,27 +236,27 @@ protected:\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n> > > > > +             if (uint32Obj.get<int32_t>().value_or(0) != 100) {\n> > > > >                       cerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n> > > > > +             if (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n> > > > >                       cerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n> > > > > +             if (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n> > > > >                       cerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n> > > > > +             if (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n> > > > >                       cerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > > +             if (uint32Obj.get<Size>()) {\n> > > > >                       cerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > > @@ -275,27 +274,27 @@ protected:\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n> > > > > +             if (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n> > > > >                       cerr << \"Double object fail to parse as string\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n> > > > > +             if (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n> > > > >                       cerr << \"Double object parse as wrong value\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > > +             if (doubleObj.get<int32_t>()) {\n> > > > >                       cerr << \"Double object parse as integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > > +             if (doubleObj.get<uint32_t>()) {\n> > > > >                       cerr << \"Double object parse as unsigned integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > > +             if (doubleObj.get<Size>()) {\n> > > > >                       cerr << \"Double object parse as Size\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > > @@ -313,27 +312,27 @@ protected:\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > > > > +             if (sizeObj.get<string>()) {\n> > > > >                       cerr << \"Size object parse as string\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > > > +             if (sizeObj.get<double>()) {\n> > > > >                       cerr << \"Size object parse as double\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > > +             if (sizeObj.get<int32_t>()) {\n> > > > >                       cerr << \"Size object parse as integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > > +             if (sizeObj.get<uint32_t>()) {\n> > > > >                       cerr << \"Size object parse as unsigned integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n> > > > > +             if (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n> > > > >                       cerr << \"Size object parse as wrong value\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > > @@ -351,27 +350,27 @@ protected:\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > > > > +             if (listObj.get<string>()) {\n> > > > >                       cerr << \"List object parse as string\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > > > +             if (listObj.get<double>()) {\n> > > > >                       cerr << \"List object parse as double\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > > +             if (listObj.get<int32_t>()) {\n> > > > >                       cerr << \"List object parse as integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > > +             if (listObj.get<uint32_t>()) {\n> > > > >                       cerr << \"List object parse as unsigne integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > > +             if (listObj.get<Size>()) {\n> > > > >                       cerr << \"String list object parse as Size\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > > @@ -424,27 +423,27 @@ protected:\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > > > > +             if (dictObj.get<string>()) {\n> > > > >                       cerr << \"Dictionary object parse as string\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > > > > +             if (dictObj.get<double>()) {\n> > > > >                       cerr << \"Dictionary object parse as double\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > > > > +             if (dictObj.get<int32_t>()) {\n> > > > >                       cerr << \"Dictionary object parse as integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > > > > +             if (dictObj.get<uint32_t>()) {\n> > > > >                       cerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > > > >\n> > > > > -             if (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > > > > +             if (dictObj.get<Size>()) {\n> > > > >                       cerr << \"Dictionary object parse as Size\" << std::endl;\n> > > > >                       return TestFail;\n> > > > >               }\n> > >\n> > > Reviewed-by: Florian Sylvestre <fsylvestre@baylibre.com>","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 78DF6C3275\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  1 Aug 2022 21:14:24 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E5CF0603E8;\n\tMon,  1 Aug 2022 23:14:23 +0200 (CEST)","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 0D7EA603E8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  1 Aug 2022 23:14:23 +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 5A1F448F;\n\tMon,  1 Aug 2022 23:14:22 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659388463;\n\tbh=lDdqN7G9hAG3dvyd5qrvELVw0lAj8PezduyL6kSVXVI=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=tR+1bfTL/AhiR9xP0Jdis8RGGRQiXgtUHJ/74phBVEA56/w5V+UV+VYdeMMuv3dB4\n\t7Y9hY9IPhHJfyaPSyDUmauzfmq63/wnMUIqiBXDlpNmplcecPiGcsIfy0iRSjdrdV5\n\tWVVhYyt4WBH6AjQqzJxqtrXiZNcJChkvjy6LUmMDqg2qs9slR6OOLwi78r+Y0Sj7pW\n\tzVCrjCQP0By3CxQsDGWwmo+5LC8S7HZBcap68p5bjizOX5liGrQK0Q1S2r5XKfRwD9\n\tujxfZQ3hD/24MP4kveLq7FeGlAyyrl4ARd4JepCElI5lO8lcyMl6AmBWfMIRYNoFrh\n\tCBbOhOgDNjYdw==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1659388462;\n\tbh=lDdqN7G9hAG3dvyd5qrvELVw0lAj8PezduyL6kSVXVI=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=DUXScJ8TX6KnfELUv399aev54hcJfMWiIDOzxvfeb8i6uuYMJ59TCLJ+6TAhAktxH\n\tKHoJWrWvnTgD15eVOvSfpFT3DsDbLZlBFl0hzRRL1NT9WKDevqN3UB42jq4LOC+MEs\n\tSigRz8CGlicPUj2Yz7t8PyvHKElZQNZOdltKmGwI="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"DUXScJ8T\"; dkim-atps=neutral","Date":"Tue, 2 Aug 2022 00:14:17 +0300","To":"Florian Sylvestre <fsylvestre@baylibre.com>","Message-ID":"<YuhCKePeAPJ+k69n@pendragon.ideasonboard.com>","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>\n\t<20220728070025.tl6n3ieauhb24bfe@uno.localdomain>\n\t<CALzBHU6kCD+o6+v5NQuBxRZiuWnRkTh1DVHVqhXbASUQv+pwhg@mail.gmail.com>\n\t<YuUwEFZYXKwPFZXp@pendragon.ideasonboard.com>\n\t<CALzBHU4x5chAUR-yryUH1kmHnqSbGthjL9TuNSjvBtH40NR1CQ@mail.gmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<CALzBHU4x5chAUR-yryUH1kmHnqSbGthjL9TuNSjvBtH40NR1CQ@mail.gmail.com>","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24315,"web_url":"https://patchwork.libcamera.org/comment/24315/","msgid":"<791711aa-0211-72d5-f5d7-377e77661efd@gmx.de>","date":"2022-08-02T20:47:52","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":111,"url":"https://patchwork.libcamera.org/api/people/111/","name":"Christian Rauch","email":"Rauch.Christian@gmx.de"},"content":"Dear Laurent,\n\nThe \"return {};\" in this patch cause \"maybe-uninitialized\" warnings in\nmy CI pipeline:\n\n../src/libcamera/yaml_parser.cpp: In member function ‘std::optional<_Tp>\nlibcamera::YamlObject::get() const [with T = short unsigned int;\nstd::enable_if_t<(((((((is_same_v<bool, T> || is_same_v<double, T>) ||\nis_same_v<short int, T>) || is_same_v<short unsigned int, T>) ||\nis_same_v<int, T>) || is_same_v<unsigned int, T>) ||\nis_same_v<std::__cxx11::basic_string<char, std::char_traits<char>,\nstd::allocator<char> >, T>) || is_same_v<libcamera::Size, T>)>*\n<anonymous> = 0]’:\n../src/libcamera/yaml_parser.cpp:184:11: error: ‘<anonymous>’ may be\nused uninitialized in this function [-Werror=maybe-uninitialized]\n  184 |   return {};\n      |           ^\n\n... and a couple more in \"yaml_parser.cpp\".\n\nSince your intention is here to notify the user of invalid values,\nwouldn't it be better to \"return nullptr;\" instead?\n\nBest,\nChristian\n\n\nAm 28.07.22 um 00:21 schrieb Laurent Pinchart via libcamera-devel:\n> The YamlObject::get() function takes a default value and an optional\n> bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> error handling in callers.\n>\n> A better API is possible by dropping the default value and ok flag and\n> returning an std::optional. Not only does it simplify the calls, it also\n> lets callers handle errors through the standard std::optional class\n> instead of the current ad-hoc mechanism.\n>\n> Provide a get() wrapper around std::optional::value_or() to further\n> simplify callers that don't need any specific error handling.\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> Tested-by: Naushir Patuck <naush@raspberrypi.com>\n> ---\n>  include/libcamera/internal/yaml_parser.h |   9 +-\n>  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n>  test/yaml-parser.cpp                     |  71 ++++++------\n>  3 files changed, 96 insertions(+), 122 deletions(-)\n>\n> diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> index 064cf44381d7..61f2223223a7 100644\n> --- a/include/libcamera/internal/yaml_parser.h\n> +++ b/include/libcamera/internal/yaml_parser.h\n> @@ -9,6 +9,7 @@\n>\n>  #include <iterator>\n>  #include <map>\n> +#include <optional>\n>  #include <string>\n>  #include <vector>\n>\n> @@ -165,7 +166,13 @@ public:\n>  #else\n>  \ttemplate<typename T>\n>  #endif\n> -\tT get(const T &defaultValue, bool *ok = nullptr) const;\n> +\tstd::optional<T> get() const;\n> +\n> +\ttemplate<typename T>\n> +\tT get(const T &defaultValue) const\n> +\t{\n> +\t\treturn get<T>().value_or(defaultValue);\n> +\t}\n>\n>  \tDictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n>  \tListAdapter asList() const { return ListAdapter{ list_ }; }\n> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> index 5c45e44e49c3..4299f5abd38a 100644\n> --- a/src/libcamera/yaml_parser.cpp\n> +++ b/src/libcamera/yaml_parser.cpp\n> @@ -31,12 +31,6 @@ namespace {\n>  /* Empty static YamlObject as a safe result for invalid operations */\n>  static const YamlObject empty;\n>\n> -void setOk(bool *ok, bool result)\n> -{\n> -\tif (ok)\n> -\t\t*ok = result;\n> -}\n> -\n>  } /* namespace */\n>\n>  /**\n> @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n>  }\n>\n>  /**\n> - * \\fn template<typename T> YamlObject::get<T>(\n> - *\tconst T &defaultValue, bool *ok) const\n> + * \\fn template<typename T> YamlObject::get<T>() const\n> + * \\brief Parse the YamlObject as a \\a T value\n> + *\n> + * This function parses the value of the YamlObject as a \\a T object, and\n> + * returns the value. If parsing fails (usually because the YamlObject doesn't\n> + * store a \\a T value), std::nullopt is returned.\n> + *\n> + * \\return The YamlObject value, or std::nullopt if parsing failed\n> + */\n> +\n> +/**\n> + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n>   * \\brief Parse the YamlObject as a \\a T value\n>   * \\param[in] defaultValue The default value when failing to parse\n> - * \\param[out] ok The result of whether the parse succeeded\n>   *\n>   * This function parses the value of the YamlObject as a \\a T object, and\n>   * returns the value. If parsing fails (usually because the YamlObject doesn't\n> - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n> - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n> + * store a \\a T value), the \\a defaultValue is returned.\n>   *\n> - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n> - * need to know if parsing succeeded.\n> - *\n> - * \\return Value as a bool type\n> + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n>   */\n>\n>  #ifndef __DOXYGEN__\n>\n>  template<>\n> -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n> +std::optional<bool> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tif (value_ == \"true\") {\n> -\t\tsetOk(ok, true);\n> +\tif (value_ == \"true\")\n>  \t\treturn true;\n> -\t} else if (value_ == \"false\") {\n> -\t\tsetOk(ok, true);\n> +\telse if (value_ == \"false\")\n>  \t\treturn false;\n> -\t}\n>\n> -\treturn defaultValue;\n> +\treturn {};\n>  }\n>\n>  template<>\n> -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> +std::optional<int16_t> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<int16_t>::min() ||\n>  \t    value > std::numeric_limits<int16_t>::max())\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> +std::optional<uint16_t> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \t/*\n>  \t * libyaml parses all scalar values as strings. When a string has\n> @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>  \t */\n>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>  \tif (found != std::string::npos && value_[found] == '-')\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<uint16_t>::min() ||\n>  \t    value > std::numeric_limits<uint16_t>::max())\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> +std::optional<int32_t> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<int32_t>::min() ||\n>  \t    value > std::numeric_limits<int32_t>::max())\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> +std::optional<uint32_t> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \t/*\n>  \t * libyaml parses all scalar values as strings. When a string has\n> @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>  \t */\n>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>  \tif (found != std::string::npos && value_[found] == '-')\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<uint32_t>::min() ||\n>  \t    value > std::numeric_limits<uint32_t>::max())\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -double YamlObject::get(const double &defaultValue, bool *ok) const\n> +std::optional<double> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (value_ == \"\")\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tchar *end;\n>\n> @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n>  \tdouble value = std::strtod(value_.c_str(), &end);\n>\n>  \tif ('\\0' != *end || errno == ERANGE)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value;\n>  }\n>\n>  template<>\n> -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n> +std::optional<std::string> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::Value)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n>  \treturn value_;\n>  }\n>\n>  template<>\n> -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n> +std::optional<Size> YamlObject::get() const\n>  {\n> -\tsetOk(ok, false);\n> -\n>  \tif (type_ != Type::List)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n>  \tif (list_.size() != 2)\n> -\t\treturn defaultValue;\n> +\t\treturn {};\n>\n> -\t/*\n> -\t * Add a local variable to validate each dimension in case\n> -\t * that ok == nullptr.\n> -\t */\n> -\tbool valid;\n> -\tuint32_t width = list_[0]->get<uint32_t>(0, &valid);\n> -\tif (!valid)\n> -\t\treturn defaultValue;\n> +\tauto width = list_[0]->get<uint32_t>();\n> +\tif (!width)\n> +\t\treturn {};\n>\n> -\tuint32_t height = list_[1]->get<uint32_t>(0, &valid);\n> -\tif (!valid)\n> -\t\treturn defaultValue;\n> +\tauto height = list_[1]->get<uint32_t>();\n> +\tif (!height)\n> +\t\treturn {};\n>\n> -\tsetOk(ok, true);\n> -\treturn Size(width, height);\n> +\treturn Size(*width, *height);\n>  }\n>\n>  #endif /* __DOXYGEN__ */\n> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> index 38f848232fa6..ebb654f2ef9c 100644\n> --- a/test/yaml-parser.cpp\n> +++ b/test/yaml-parser.cpp\n> @@ -148,7 +148,6 @@ protected:\n>  \t\t}\n>\n>  \t\t/* Test string object */\n> -\t\tbool ok;\n>  \t\tauto &strObj = (*root)[\"string\"];\n>\n>  \t\tif (strObj.isDictionary()) {\n> @@ -161,27 +160,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> +\t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n>  \t\t\tcerr << \"String object parse as wrong content\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (strObj.get<int32_t>()) {\n>  \t\t\tcerr << \"String object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (strObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\tif (strObj.get<double>()) {\n>  \t\t\tcerr << \"String object parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (strObj.get<Size>()) {\n>  \t\t\tcerr << \"String object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -199,27 +198,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n> +\t\tif (int32Obj.get<int32_t>().value_or(0) != -100) {\n>  \t\t\tcerr << \"Integer object parse as wrong value\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n> +\t\tif (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n>  \t\t\tcerr << \"Integer object fail to parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n> +\t\tif (int32Obj.get<double>().value_or(0.0) != -100.0) {\n>  \t\t\tcerr << \"Integer object fail to parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (int32Obj.get<uint32_t>()) {\n>  \t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (int32Obj.get<Size>()) {\n>  \t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -237,27 +236,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n> +\t\tif (uint32Obj.get<int32_t>().value_or(0) != 100) {\n>  \t\t\tcerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n> +\t\tif (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n>  \t\t\tcerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n> +\t\tif (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n>  \t\t\tcerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n> +\t\tif (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n>  \t\t\tcerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (uint32Obj.get<Size>()) {\n>  \t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -275,27 +274,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n> +\t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n>  \t\t\tcerr << \"Double object fail to parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n> +\t\tif (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n>  \t\t\tcerr << \"Double object parse as wrong value\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (doubleObj.get<int32_t>()) {\n>  \t\t\tcerr << \"Double object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (doubleObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (doubleObj.get<Size>()) {\n>  \t\t\tcerr << \"Double object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -313,27 +312,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n> +\t\tif (sizeObj.get<string>()) {\n>  \t\t\tcerr << \"Size object parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\tif (sizeObj.get<double>()) {\n>  \t\t\tcerr << \"Size object parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (sizeObj.get<int32_t>()) {\n>  \t\t\tcerr << \"Size object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (sizeObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n> +\t\tif (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n>  \t\t\tcerr << \"Size object parse as wrong value\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -351,27 +350,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n> +\t\tif (listObj.get<string>()) {\n>  \t\t\tcerr << \"List object parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\tif (listObj.get<double>()) {\n>  \t\t\tcerr << \"List object parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (listObj.get<int32_t>()) {\n>  \t\t\tcerr << \"List object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (listObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (listObj.get<Size>()) {\n>  \t\t\tcerr << \"String list object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> @@ -424,27 +423,27 @@ protected:\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n> +\t\tif (dictObj.get<string>()) {\n>  \t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> +\t\tif (dictObj.get<double>()) {\n>  \t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> +\t\tif (dictObj.get<int32_t>()) {\n>  \t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> +\t\tif (dictObj.get<uint32_t>()) {\n>  \t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n>\n> -\t\tif (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> +\t\tif (dictObj.get<Size>()) {\n>  \t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n>  \t\t\treturn TestFail;\n>  \t\t}","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 342ABC3275\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  2 Aug 2022 20:47:56 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5041E63313;\n\tTue,  2 Aug 2022 22:47:55 +0200 (CEST)","from mout.gmx.net (mout.gmx.net [212.227.17.22])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 859B4603E7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  2 Aug 2022 22:47:53 +0200 (CEST)","from [192.168.0.158] ([88.152.184.103]) by mail.gmx.net (mrgmx104\n\t[212.227.17.168]) with ESMTPSA (Nemesis) id\n\t1MvK4f-1nRq3N3UDx-00rHsy for\n\t<libcamera-devel@lists.libcamera.org>; Tue, 02 Aug 2022 22:47:52 +0200"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659473275;\n\tbh=PxD1i46vWesZ9YIFr00CS/n3R7fYQYQisbJlCzUc+fE=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=0iBOOJI/K9wZ/evMxDXgF96e4uKRMsT5DffKPt8Il3VnEhk2gbD6688l5ZUE6Lnds\n\tw72lazLtq90SDfUQPUpGeG/n3qLKiUZBkLQ1aX+G8HcVzz7VU7jXXUBIR+zvWVnnP0\n\tveEwQZDuueo3+NW1nneqxeOOE5UXEbRnC4z0u/45+2j14UipgHE90gGaBmYmk00+5e\n\tEXSPQIrd/uo8/qJhnIywxYxuPjU3BlslTYhxZEfibDex96IWAhxBQmy8XOxO4/5H8u\n\t8b5JzW7W48FHRJGzHXOU7V31Wogh4qMuEYRrYYM2cPLqTESUO/3nKXIe81fd/+8TOo\n\tHwjV8htGoLO4Q==","v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net;\n\ts=badeba3b8450; t=1659473273;\n\tbh=PxD1i46vWesZ9YIFr00CS/n3R7fYQYQisbJlCzUc+fE=;\n\th=X-UI-Sender-Class:Date:Subject:To:References:From:In-Reply-To;\n\tb=l07Hrw8/zuR7DtQu2R1mlNHgRC6i82KNiFUKUhU+vKOUN0QO/KcQ4DeSXsZSMuOUD\n\ta/43KEdVsKvHBSdADlxEaIVlWlNOIo0tzgQg0SyCcAmhs6lCSxjc+DXff6O6EYosXU\n\taghv2/0HgIJeZzcZkU60fcAOAvbzXOv0kiD3YBAA="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=gmx.net header.i=@gmx.net\n\theader.b=\"l07Hrw8/\"; dkim-atps=neutral","X-UI-Sender-Class":"01bb95c1-4bf8-414a-932a-4f6e2808ef9c","Message-ID":"<791711aa-0211-72d5-f5d7-377e77661efd@gmx.de>","Date":"Tue, 2 Aug 2022 22:47:52 +0200","MIME-Version":"1.0","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101\n\tThunderbird/91.11.0","Content-Language":"en-GB","To":"libcamera-devel@lists.libcamera.org","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>","In-Reply-To":"<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"quoted-printable","X-Provags-ID":"V03:K1:WDWwC9dqvvs/zPP++3HGjnFQdMbbGJlf2+Qt4kIk3FnBOwhJjAE\n\taJC+06lsDAXRIxbglueFWc/AQQ/vJ3UuNUobpx8Oi1nV6vCz8yXoCqtrPDl9vawuLJzess0\n\tXjO3BEYMyZXn+H/fFWGL8nck2Qf0Z03VUtjXZzFY2S+8Z3aNFluTuZKjEzDz7fvlbtRDavC\n\tcbKAR6LkkF3SjXZPGC2Rg==","X-Spam-Flag":"NO","X-UI-Out-Filterresults":"notjunk:1; V03:K0:j2i+34ONcFc=:xjIpF+oDrcvWeU/z9q0HbC\n\th3Zlh5IyaCYankFTWV97JqvQUroAnMg4koH2GpIT/oHAL3nKgYqXPHWN59C5fvZ9L6wcZyW46\n\tYrpx/IxImedEV5USzbi+wSIIuUexCckTfIJ+orubda7+/rcNO8Vc+Z+S6P6GnpbiDgd/LtPti\n\tBdqpIzsL+w90qtwhWh5BhKcAdN/6pl44pD8SSqigZ1yvD5dIqNuqbqDW9dTAAMeYFqTvRCRRW\n\thCIvjm5aXNaQbfSnQMOC54c/+QergfqBS/b3sETkPUMc3d2Je8W1fEik+ysWqAKyZXsy5VHap\n\t+rr0+u9jGJMWBK1uCiktan5Kcd97OvKarfitKfsqGUCBBNPK1aH6ctD8ckGb32NkeI/1gsKVW\n\tVCcdeTZLYPx7vdVHJY5bAUi2o3zVAuHJa+wvkKCPbo5jbs88MD5oAdqwKKhTJbBtmiIyLk50D\n\tyOW3BpPwkaxBoLmKHpR8jXEZ1hSVCVwvOyetUiOYVwWHrmYKe7NorQZYRCw7axHjcOuH39x5j\n\t55m86eizZV+yT1FgJHF+O4x1NuNKee/j9jLZH1XhMTcQDvzhgmeE4Sr1/2RGpNPyXCaBBjmMI\n\tpQvc9hMSXEQAOSx/AAG4fw2TTi4wN0Dwvoo6U5MK6aAc9eGKCrWqOEdmWVzqeq84sSGWZiNYa\n\tZjfX+9oDyWvkSl14QQHPgkyW6MoMMmNxDulW5iR+gS9G01NSzBeX2sDiXJ8igJg6U6iwjEWtT\n\tIbrvrFCNQizPAo+B4D/uWR66o+/1c3Lpb/iJeaxw1BpPEyFQKzAzZOYGeYaS/9foyTHleILGH\n\tSLHDo72CNm45thtj/U6ntsyvAxsGARnCfbWxW3kL5RYpOWO+RZrzAUzhroUrk/0yXJBHpqNF9\n\t7gf9QzoLryvjpyrnE0ghn4dKTEphHl233W4QF6DLHNAiAgWZviKRsPSgpgIgyKOBhhk+yn2HD\n\tF4ZKyJfB1qWmfJ4rPi4sHKiUkbwZFJryLA8rL89AlfGFfFvri8/adRQW0/VLmP3GshgfuH6UT\n\t1LnhpZ3ANsAh2gOqgIW48V1WKp+Q0nd2fq21UCi88UBgWSfeFpuXYuMvDoWqGeReYfWu+S83V\n\tztPASJnbPgM9QbxBUhFQ5wsjwKt2/MHItHgcvjlsNI17HYCfgsaeZbmcQ==","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Christian Rauch via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Christian Rauch <Rauch.Christian@gmx.de>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24317,"web_url":"https://patchwork.libcamera.org/comment/24317/","msgid":"<YumevpvF8wO0PpxL@pendragon.ideasonboard.com>","date":"2022-08-02T22:01:34","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Christian,\n\nOn Tue, Aug 02, 2022 at 10:47:52PM +0200, Christian Rauch via libcamera-devel wrote:\n> Dear Laurent,\n> \n> The \"return {};\" in this patch cause \"maybe-uninitialized\" warnings in\n> my CI pipeline:\n\nThank you for the report. We have CI pipelines too, but clearly, there\nare way more compiler/platform combinations out there that we test at\nthe moment :-)\n\nCould you report the compiler, compiler version and platform, for my\ninformation ?\n\n> ../src/libcamera/yaml_parser.cpp: In member function ‘std::optional<_Tp>\n> libcamera::YamlObject::get() const [with T = short unsigned int;\n> std::enable_if_t<(((((((is_same_v<bool, T> || is_same_v<double, T>) ||\n> is_same_v<short int, T>) || is_same_v<short unsigned int, T>) ||\n> is_same_v<int, T>) || is_same_v<unsigned int, T>) ||\n> is_same_v<std::__cxx11::basic_string<char, std::char_traits<char>,\n> std::allocator<char> >, T>) || is_same_v<libcamera::Size, T>)>*\n> <anonymous> = 0]’:\n> ../src/libcamera/yaml_parser.cpp:184:11: error: ‘<anonymous>’ may be\n> used uninitialized in this function [-Werror=maybe-uninitialized]\n>   184 |   return {};\n>       |           ^\n> \n> ... and a couple more in \"yaml_parser.cpp\".\n> \n> Since your intention is here to notify the user of invalid values,\n> wouldn't it be better to \"return nullptr;\" instead?\n\nThe would be std::nullopt as the function returns a std::optional<>, but\nyes, that would make sense. I was expecting {} to do the same.\n\nAs I can't test if this would fix the compilation warning given that I\ncan't reproduce them, would you be able to test that change with your CI\npipeline ? If std::nullopt fixes the errors, I can send a patch, or you\ncan send one directly if you prefer.\n\n> Am 28.07.22 um 00:21 schrieb Laurent Pinchart via libcamera-devel:\n> > The YamlObject::get() function takes a default value and an optional\n> > bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> > error handling in callers.\n> >\n> > A better API is possible by dropping the default value and ok flag and\n> > returning an std::optional. Not only does it simplify the calls, it also\n> > lets callers handle errors through the standard std::optional class\n> > instead of the current ad-hoc mechanism.\n> >\n> > Provide a get() wrapper around std::optional::value_or() to further\n> > simplify callers that don't need any specific error handling.\n> >\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> > Tested-by: Naushir Patuck <naush@raspberrypi.com>\n> > ---\n> >  include/libcamera/internal/yaml_parser.h |   9 +-\n> >  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n> >  test/yaml-parser.cpp                     |  71 ++++++------\n> >  3 files changed, 96 insertions(+), 122 deletions(-)\n> >\n> > diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> > index 064cf44381d7..61f2223223a7 100644\n> > --- a/include/libcamera/internal/yaml_parser.h\n> > +++ b/include/libcamera/internal/yaml_parser.h\n> > @@ -9,6 +9,7 @@\n> >\n> >  #include <iterator>\n> >  #include <map>\n> > +#include <optional>\n> >  #include <string>\n> >  #include <vector>\n> >\n> > @@ -165,7 +166,13 @@ public:\n> >  #else\n> >  \ttemplate<typename T>\n> >  #endif\n> > -\tT get(const T &defaultValue, bool *ok = nullptr) const;\n> > +\tstd::optional<T> get() const;\n> > +\n> > +\ttemplate<typename T>\n> > +\tT get(const T &defaultValue) const\n> > +\t{\n> > +\t\treturn get<T>().value_or(defaultValue);\n> > +\t}\n> >\n> >  \tDictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n> >  \tListAdapter asList() const { return ListAdapter{ list_ }; }\n> > diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> > index 5c45e44e49c3..4299f5abd38a 100644\n> > --- a/src/libcamera/yaml_parser.cpp\n> > +++ b/src/libcamera/yaml_parser.cpp\n> > @@ -31,12 +31,6 @@ namespace {\n> >  /* Empty static YamlObject as a safe result for invalid operations */\n> >  static const YamlObject empty;\n> >\n> > -void setOk(bool *ok, bool result)\n> > -{\n> > -\tif (ok)\n> > -\t\t*ok = result;\n> > -}\n> > -\n> >  } /* namespace */\n> >\n> >  /**\n> > @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n> >  }\n> >\n> >  /**\n> > - * \\fn template<typename T> YamlObject::get<T>(\n> > - *\tconst T &defaultValue, bool *ok) const\n> > + * \\fn template<typename T> YamlObject::get<T>() const\n> > + * \\brief Parse the YamlObject as a \\a T value\n> > + *\n> > + * This function parses the value of the YamlObject as a \\a T object, and\n> > + * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > + * store a \\a T value), std::nullopt is returned.\n> > + *\n> > + * \\return The YamlObject value, or std::nullopt if parsing failed\n> > + */\n> > +\n> > +/**\n> > + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n> >   * \\brief Parse the YamlObject as a \\a T value\n> >   * \\param[in] defaultValue The default value when failing to parse\n> > - * \\param[out] ok The result of whether the parse succeeded\n> >   *\n> >   * This function parses the value of the YamlObject as a \\a T object, and\n> >   * returns the value. If parsing fails (usually because the YamlObject doesn't\n> > - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n> > - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n> > + * store a \\a T value), the \\a defaultValue is returned.\n> >   *\n> > - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n> > - * need to know if parsing succeeded.\n> > - *\n> > - * \\return Value as a bool type\n> > + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n> >   */\n> >\n> >  #ifndef __DOXYGEN__\n> >\n> >  template<>\n> > -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n> > +std::optional<bool> YamlObject::get() const\n> >  {\n> > -\tsetOk(ok, false);\n> > -\n> >  \tif (type_ != Type::Value)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> > -\tif (value_ == \"true\") {\n> > -\t\tsetOk(ok, true);\n> > +\tif (value_ == \"true\")\n> >  \t\treturn true;\n> > -\t} else if (value_ == \"false\") {\n> > -\t\tsetOk(ok, true);\n> > +\telse if (value_ == \"false\")\n> >  \t\treturn false;\n> > -\t}\n> >\n> > -\treturn defaultValue;\n> > +\treturn {};\n> >  }\n> >\n> >  template<>\n> > -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> > +std::optional<int16_t> YamlObject::get() const\n> >  {\n> > -\tsetOk(ok, false);\n> > -\n> >  \tif (type_ != Type::Value)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tif (value_ == \"\")\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tchar *end;\n> >\n> > @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> >  \tif ('\\0' != *end || errno == ERANGE ||\n> >  \t    value < std::numeric_limits<int16_t>::min() ||\n> >  \t    value > std::numeric_limits<int16_t>::max())\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> > -\tsetOk(ok, true);\n> >  \treturn value;\n> >  }\n> >\n> >  template<>\n> > -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> > +std::optional<uint16_t> YamlObject::get() const\n> >  {\n> > -\tsetOk(ok, false);\n> > -\n> >  \tif (type_ != Type::Value)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tif (value_ == \"\")\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \t/*\n> >  \t * libyaml parses all scalar values as strings. When a string has\n> > @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> >  \t */\n> >  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n> >  \tif (found != std::string::npos && value_[found] == '-')\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tchar *end;\n> >\n> > @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> >  \tif ('\\0' != *end || errno == ERANGE ||\n> >  \t    value < std::numeric_limits<uint16_t>::min() ||\n> >  \t    value > std::numeric_limits<uint16_t>::max())\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> > -\tsetOk(ok, true);\n> >  \treturn value;\n> >  }\n> >\n> >  template<>\n> > -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> > +std::optional<int32_t> YamlObject::get() const\n> >  {\n> > -\tsetOk(ok, false);\n> > -\n> >  \tif (type_ != Type::Value)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tif (value_ == \"\")\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tchar *end;\n> >\n> > @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> >  \tif ('\\0' != *end || errno == ERANGE ||\n> >  \t    value < std::numeric_limits<int32_t>::min() ||\n> >  \t    value > std::numeric_limits<int32_t>::max())\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> > -\tsetOk(ok, true);\n> >  \treturn value;\n> >  }\n> >\n> >  template<>\n> > -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> > +std::optional<uint32_t> YamlObject::get() const\n> >  {\n> > -\tsetOk(ok, false);\n> > -\n> >  \tif (type_ != Type::Value)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tif (value_ == \"\")\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \t/*\n> >  \t * libyaml parses all scalar values as strings. When a string has\n> > @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> >  \t */\n> >  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n> >  \tif (found != std::string::npos && value_[found] == '-')\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tchar *end;\n> >\n> > @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> >  \tif ('\\0' != *end || errno == ERANGE ||\n> >  \t    value < std::numeric_limits<uint32_t>::min() ||\n> >  \t    value > std::numeric_limits<uint32_t>::max())\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> > -\tsetOk(ok, true);\n> >  \treturn value;\n> >  }\n> >\n> >  template<>\n> > -double YamlObject::get(const double &defaultValue, bool *ok) const\n> > +std::optional<double> YamlObject::get() const\n> >  {\n> > -\tsetOk(ok, false);\n> > -\n> >  \tif (type_ != Type::Value)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tif (value_ == \"\")\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tchar *end;\n> >\n> > @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n> >  \tdouble value = std::strtod(value_.c_str(), &end);\n> >\n> >  \tif ('\\0' != *end || errno == ERANGE)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> > -\tsetOk(ok, true);\n> >  \treturn value;\n> >  }\n> >\n> >  template<>\n> > -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n> > +std::optional<std::string> YamlObject::get() const\n> >  {\n> > -\tsetOk(ok, false);\n> > -\n> >  \tif (type_ != Type::Value)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> > -\tsetOk(ok, true);\n> >  \treturn value_;\n> >  }\n> >\n> >  template<>\n> > -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n> > +std::optional<Size> YamlObject::get() const\n> >  {\n> > -\tsetOk(ok, false);\n> > -\n> >  \tif (type_ != Type::List)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> >  \tif (list_.size() != 2)\n> > -\t\treturn defaultValue;\n> > +\t\treturn {};\n> >\n> > -\t/*\n> > -\t * Add a local variable to validate each dimension in case\n> > -\t * that ok == nullptr.\n> > -\t */\n> > -\tbool valid;\n> > -\tuint32_t width = list_[0]->get<uint32_t>(0, &valid);\n> > -\tif (!valid)\n> > -\t\treturn defaultValue;\n> > +\tauto width = list_[0]->get<uint32_t>();\n> > +\tif (!width)\n> > +\t\treturn {};\n> >\n> > -\tuint32_t height = list_[1]->get<uint32_t>(0, &valid);\n> > -\tif (!valid)\n> > -\t\treturn defaultValue;\n> > +\tauto height = list_[1]->get<uint32_t>();\n> > +\tif (!height)\n> > +\t\treturn {};\n> >\n> > -\tsetOk(ok, true);\n> > -\treturn Size(width, height);\n> > +\treturn Size(*width, *height);\n> >  }\n> >\n> >  #endif /* __DOXYGEN__ */\n> > diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> > index 38f848232fa6..ebb654f2ef9c 100644\n> > --- a/test/yaml-parser.cpp\n> > +++ b/test/yaml-parser.cpp\n> > @@ -148,7 +148,6 @@ protected:\n> >  \t\t}\n> >\n> >  \t\t/* Test string object */\n> > -\t\tbool ok;\n> >  \t\tauto &strObj = (*root)[\"string\"];\n> >\n> >  \t\tif (strObj.isDictionary()) {\n> > @@ -161,27 +160,27 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> > +\t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n> >  \t\t\tcerr << \"String object parse as wrong content\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +\t\tif (strObj.get<int32_t>()) {\n> >  \t\t\tcerr << \"String object parse as integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +\t\tif (strObj.get<uint32_t>()) {\n> >  \t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > +\t\tif (strObj.get<double>()) {\n> >  \t\t\tcerr << \"String object parse as double\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +\t\tif (strObj.get<Size>()) {\n> >  \t\t\tcerr << \"String object parse as Size\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> > @@ -199,27 +198,27 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n> > +\t\tif (int32Obj.get<int32_t>().value_or(0) != -100) {\n> >  \t\t\tcerr << \"Integer object parse as wrong value\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n> > +\t\tif (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n> >  \t\t\tcerr << \"Integer object fail to parse as string\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n> > +\t\tif (int32Obj.get<double>().value_or(0.0) != -100.0) {\n> >  \t\t\tcerr << \"Integer object fail to parse as double\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +\t\tif (int32Obj.get<uint32_t>()) {\n> >  \t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +\t\tif (int32Obj.get<Size>()) {\n> >  \t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> > @@ -237,27 +236,27 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n> > +\t\tif (uint32Obj.get<int32_t>().value_or(0) != 100) {\n> >  \t\t\tcerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n> > +\t\tif (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n> >  \t\t\tcerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n> > +\t\tif (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n> >  \t\t\tcerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n> > +\t\tif (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n> >  \t\t\tcerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +\t\tif (uint32Obj.get<Size>()) {\n> >  \t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> > @@ -275,27 +274,27 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n> > +\t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n> >  \t\t\tcerr << \"Double object fail to parse as string\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n> > +\t\tif (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n> >  \t\t\tcerr << \"Double object parse as wrong value\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +\t\tif (doubleObj.get<int32_t>()) {\n> >  \t\t\tcerr << \"Double object parse as integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +\t\tif (doubleObj.get<uint32_t>()) {\n> >  \t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +\t\tif (doubleObj.get<Size>()) {\n> >  \t\t\tcerr << \"Double object parse as Size\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> > @@ -313,27 +312,27 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > +\t\tif (sizeObj.get<string>()) {\n> >  \t\t\tcerr << \"Size object parse as string\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > +\t\tif (sizeObj.get<double>()) {\n> >  \t\t\tcerr << \"Size object parse as double\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +\t\tif (sizeObj.get<int32_t>()) {\n> >  \t\t\tcerr << \"Size object parse as integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +\t\tif (sizeObj.get<uint32_t>()) {\n> >  \t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n> > +\t\tif (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n> >  \t\t\tcerr << \"Size object parse as wrong value\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> > @@ -351,27 +350,27 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > +\t\tif (listObj.get<string>()) {\n> >  \t\t\tcerr << \"List object parse as string\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > +\t\tif (listObj.get<double>()) {\n> >  \t\t\tcerr << \"List object parse as double\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +\t\tif (listObj.get<int32_t>()) {\n> >  \t\t\tcerr << \"List object parse as integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +\t\tif (listObj.get<uint32_t>()) {\n> >  \t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +\t\tif (listObj.get<Size>()) {\n> >  \t\t\tcerr << \"String list object parse as Size\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> > @@ -424,27 +423,27 @@ protected:\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n> > +\t\tif (dictObj.get<string>()) {\n> >  \t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> > +\t\tif (dictObj.get<double>()) {\n> >  \t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> > +\t\tif (dictObj.get<int32_t>()) {\n> >  \t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> > +\t\tif (dictObj.get<uint32_t>()) {\n> >  \t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}\n> >\n> > -\t\tif (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> > +\t\tif (dictObj.get<Size>()) {\n> >  \t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n> >  \t\t\treturn TestFail;\n> >  \t\t}","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 950E6BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  2 Aug 2022 22:01:43 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id BCE3263313;\n\tWed,  3 Aug 2022 00:01:42 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1DDAB603E8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Aug 2022 00:01:41 +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 5809325B;\n\tWed,  3 Aug 2022 00:01:40 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659477702;\n\tbh=zF99uiD95tyGdsXaipTPA2VZSYDQaKp3vGaRqKCJVi4=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=DNt/rwbob5kCBWfCqtPtQ97xDujtJurNKbANCQa1NhvXZn7Z48zAu7EvnPAFt0giC\n\thLj7jnIF9Jwg6MTGqeD6OGnSTQ8LyUSrBEnaBYjoiTWFqV1yMlSuR+vifo063+q9c9\n\tN1qVFjoTtPMTW+Sc8cHCezOVuaOAudByLF+ia4eUB9jH+EUk7WiHQJzVw09/lXhnBk\n\tcXLLRyHFjHFPnzmG2+V946ZaruCAWTF4cVU3ZKVj3aZaFfmTfEiYdX84qsHk6Fc9gx\n\tmE9e19ZsK7VeTmPZxqfbh3bPj1FcasMcVF3vrqQ8shwEW3/n0KV1parUyzUAH56GbD\n\tiEwnICCERodMA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1659477700;\n\tbh=zF99uiD95tyGdsXaipTPA2VZSYDQaKp3vGaRqKCJVi4=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=JgrZXc/cIY7o1HOGjHmrN9Eur9rZtFYKcT0Q8tfpXuaEqxfyUnvhpER3AIRDgue3/\n\tsfOZMafrCY2qeI+dIBijoDZYMTAkSWU1gULdpJLXaBgjijQNj621wZGVMUfcPqFREF\n\tNrHxlGb7EHlatMFQJ9CvMmSoBWMeMyu2fbjwhWkI="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"JgrZXc/c\"; dkim-atps=neutral","Date":"Wed, 3 Aug 2022 01:01:34 +0300","To":"Christian Rauch <Rauch.Christian@gmx.de>","Message-ID":"<YumevpvF8wO0PpxL@pendragon.ideasonboard.com>","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>\n\t<791711aa-0211-72d5-f5d7-377e77661efd@gmx.de>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<791711aa-0211-72d5-f5d7-377e77661efd@gmx.de>","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24359,"web_url":"https://patchwork.libcamera.org/comment/24359/","msgid":"<8660cbbf-71e0-b2b6-7e15-d872912367ab@gmx.de>","date":"2022-08-03T19:10:19","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":111,"url":"https://patchwork.libcamera.org/api/people/111/","name":"Christian Rauch","email":"Rauch.Christian@gmx.de"},"content":"Hi Laurent,\n\nAm 03.08.22 um 00:01 schrieb Laurent Pinchart:\n> Hi Christian,\n>\n> On Tue, Aug 02, 2022 at 10:47:52PM +0200, Christian Rauch via libcamera-devel wrote:\n>> Dear Laurent,\n>>\n>> The \"return {};\" in this patch cause \"maybe-uninitialized\" warnings in\n>> my CI pipeline:\n>\n> Thank you for the report. We have CI pipelines too, but clearly, there\n> are way more compiler/platform combinations out there that we test at\n> the moment :-)\n>\n> Could you report the compiler, compiler version and platform, for my\n> information ?\n\nIt's an arm64 corss compile workflow with gcc 9 [1]. See the full log at\n[2].\n\n[1]\nhttps://github.com/christianrauch/libcamera-ci/blob/ci/.github/workflows/main_cross.yml\n[2]\nhttps://github.com/christianrauch/libcamera-ci/runs/7639256594?check_suite_focus=true\n\n>\n>> ../src/libcamera/yaml_parser.cpp: In member function ‘std::optional<_Tp>\n>> libcamera::YamlObject::get() const [with T = short unsigned int;\n>> std::enable_if_t<(((((((is_same_v<bool, T> || is_same_v<double, T>) ||\n>> is_same_v<short int, T>) || is_same_v<short unsigned int, T>) ||\n>> is_same_v<int, T>) || is_same_v<unsigned int, T>) ||\n>> is_same_v<std::__cxx11::basic_string<char, std::char_traits<char>,\n>> std::allocator<char> >, T>) || is_same_v<libcamera::Size, T>)>*\n>> <anonymous> = 0]’:\n>> ../src/libcamera/yaml_parser.cpp:184:11: error: ‘<anonymous>’ may be\n>> used uninitialized in this function [-Werror=maybe-uninitialized]\n>>   184 |   return {};\n>>       |           ^\n>>\n>> ... and a couple more in \"yaml_parser.cpp\".\n>>\n>> Since your intention is here to notify the user of invalid values,\n>> wouldn't it be better to \"return nullptr;\" instead?\n>\n> The would be std::nullopt as the function returns a std::optional<>, but\n> yes, that would make sense. I was expecting {} to do the same.\n>\n> As I can't test if this would fix the compilation warning given that I\n> can't reproduce them, would you be able to test that change with your CI\n> pipeline ? If std::nullopt fixes the errors, I can send a patch, or you\n> can send one directly if you prefer.\n>\n>> Am 28.07.22 um 00:21 schrieb Laurent Pinchart via libcamera-devel:\n>>> The YamlObject::get() function takes a default value and an optional\n>>> bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n>>> error handling in callers.\n>>>\n>>> A better API is possible by dropping the default value and ok flag and\n>>> returning an std::optional. Not only does it simplify the calls, it also\n>>> lets callers handle errors through the standard std::optional class\n>>> instead of the current ad-hoc mechanism.\n>>>\n>>> Provide a get() wrapper around std::optional::value_or() to further\n>>> simplify callers that don't need any specific error handling.\n>>>\n>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>>> Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n>>> Tested-by: Naushir Patuck <naush@raspberrypi.com>\n>>> ---\n>>>  include/libcamera/internal/yaml_parser.h |   9 +-\n>>>  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n>>>  test/yaml-parser.cpp                     |  71 ++++++------\n>>>  3 files changed, 96 insertions(+), 122 deletions(-)\n>>>\n>>> diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n>>> index 064cf44381d7..61f2223223a7 100644\n>>> --- a/include/libcamera/internal/yaml_parser.h\n>>> +++ b/include/libcamera/internal/yaml_parser.h\n>>> @@ -9,6 +9,7 @@\n>>>\n>>>  #include <iterator>\n>>>  #include <map>\n>>> +#include <optional>\n>>>  #include <string>\n>>>  #include <vector>\n>>>\n>>> @@ -165,7 +166,13 @@ public:\n>>>  #else\n>>>  \ttemplate<typename T>\n>>>  #endif\n>>> -\tT get(const T &defaultValue, bool *ok = nullptr) const;\n>>> +\tstd::optional<T> get() const;\n>>> +\n>>> +\ttemplate<typename T>\n>>> +\tT get(const T &defaultValue) const\n>>> +\t{\n>>> +\t\treturn get<T>().value_or(defaultValue);\n>>> +\t}\n>>>\n>>>  \tDictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n>>>  \tListAdapter asList() const { return ListAdapter{ list_ }; }\n>>> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n>>> index 5c45e44e49c3..4299f5abd38a 100644\n>>> --- a/src/libcamera/yaml_parser.cpp\n>>> +++ b/src/libcamera/yaml_parser.cpp\n>>> @@ -31,12 +31,6 @@ namespace {\n>>>  /* Empty static YamlObject as a safe result for invalid operations */\n>>>  static const YamlObject empty;\n>>>\n>>> -void setOk(bool *ok, bool result)\n>>> -{\n>>> -\tif (ok)\n>>> -\t\t*ok = result;\n>>> -}\n>>> -\n>>>  } /* namespace */\n>>>\n>>>  /**\n>>> @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n>>>  }\n>>>\n>>>  /**\n>>> - * \\fn template<typename T> YamlObject::get<T>(\n>>> - *\tconst T &defaultValue, bool *ok) const\n>>> + * \\fn template<typename T> YamlObject::get<T>() const\n>>> + * \\brief Parse the YamlObject as a \\a T value\n>>> + *\n>>> + * This function parses the value of the YamlObject as a \\a T object, and\n>>> + * returns the value. If parsing fails (usually because the YamlObject doesn't\n>>> + * store a \\a T value), std::nullopt is returned.\n>>> + *\n>>> + * \\return The YamlObject value, or std::nullopt if parsing failed\n>>> + */\n>>> +\n>>> +/**\n>>> + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n>>>   * \\brief Parse the YamlObject as a \\a T value\n>>>   * \\param[in] defaultValue The default value when failing to parse\n>>> - * \\param[out] ok The result of whether the parse succeeded\n>>>   *\n>>>   * This function parses the value of the YamlObject as a \\a T object, and\n>>>   * returns the value. If parsing fails (usually because the YamlObject doesn't\n>>> - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n>>> - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n>>> + * store a \\a T value), the \\a defaultValue is returned.\n>>>   *\n>>> - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n>>> - * need to know if parsing succeeded.\n>>> - *\n>>> - * \\return Value as a bool type\n>>> + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n>>>   */\n>>>\n>>>  #ifndef __DOXYGEN__\n>>>\n>>>  template<>\n>>> -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n>>> +std::optional<bool> YamlObject::get() const\n>>>  {\n>>> -\tsetOk(ok, false);\n>>> -\n>>>  \tif (type_ != Type::Value)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>> -\tif (value_ == \"true\") {\n>>> -\t\tsetOk(ok, true);\n>>> +\tif (value_ == \"true\")\n>>>  \t\treturn true;\n>>> -\t} else if (value_ == \"false\") {\n>>> -\t\tsetOk(ok, true);\n>>> +\telse if (value_ == \"false\")\n>>>  \t\treturn false;\n>>> -\t}\n>>>\n>>> -\treturn defaultValue;\n>>> +\treturn {};\n>>>  }\n>>>\n>>>  template<>\n>>> -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n>>> +std::optional<int16_t> YamlObject::get() const\n>>>  {\n>>> -\tsetOk(ok, false);\n>>> -\n>>>  \tif (type_ != Type::Value)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tif (value_ == \"\")\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tchar *end;\n>>>\n>>> @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n>>>  \tif ('\\0' != *end || errno == ERANGE ||\n>>>  \t    value < std::numeric_limits<int16_t>::min() ||\n>>>  \t    value > std::numeric_limits<int16_t>::max())\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>> -\tsetOk(ok, true);\n>>>  \treturn value;\n>>>  }\n>>>\n>>>  template<>\n>>> -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>>> +std::optional<uint16_t> YamlObject::get() const\n>>>  {\n>>> -\tsetOk(ok, false);\n>>> -\n>>>  \tif (type_ != Type::Value)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tif (value_ == \"\")\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \t/*\n>>>  \t * libyaml parses all scalar values as strings. When a string has\n>>> @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>>>  \t */\n>>>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>>>  \tif (found != std::string::npos && value_[found] == '-')\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tchar *end;\n>>>\n>>> @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>>>  \tif ('\\0' != *end || errno == ERANGE ||\n>>>  \t    value < std::numeric_limits<uint16_t>::min() ||\n>>>  \t    value > std::numeric_limits<uint16_t>::max())\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>> -\tsetOk(ok, true);\n>>>  \treturn value;\n>>>  }\n>>>\n>>>  template<>\n>>> -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n>>> +std::optional<int32_t> YamlObject::get() const\n>>>  {\n>>> -\tsetOk(ok, false);\n>>> -\n>>>  \tif (type_ != Type::Value)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tif (value_ == \"\")\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tchar *end;\n>>>\n>>> @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n>>>  \tif ('\\0' != *end || errno == ERANGE ||\n>>>  \t    value < std::numeric_limits<int32_t>::min() ||\n>>>  \t    value > std::numeric_limits<int32_t>::max())\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>> -\tsetOk(ok, true);\n>>>  \treturn value;\n>>>  }\n>>>\n>>>  template<>\n>>> -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>>> +std::optional<uint32_t> YamlObject::get() const\n>>>  {\n>>> -\tsetOk(ok, false);\n>>> -\n>>>  \tif (type_ != Type::Value)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tif (value_ == \"\")\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \t/*\n>>>  \t * libyaml parses all scalar values as strings. When a string has\n>>> @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>>>  \t */\n>>>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>>>  \tif (found != std::string::npos && value_[found] == '-')\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tchar *end;\n>>>\n>>> @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>>>  \tif ('\\0' != *end || errno == ERANGE ||\n>>>  \t    value < std::numeric_limits<uint32_t>::min() ||\n>>>  \t    value > std::numeric_limits<uint32_t>::max())\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>> -\tsetOk(ok, true);\n>>>  \treturn value;\n>>>  }\n>>>\n>>>  template<>\n>>> -double YamlObject::get(const double &defaultValue, bool *ok) const\n>>> +std::optional<double> YamlObject::get() const\n>>>  {\n>>> -\tsetOk(ok, false);\n>>> -\n>>>  \tif (type_ != Type::Value)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tif (value_ == \"\")\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tchar *end;\n>>>\n>>> @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n>>>  \tdouble value = std::strtod(value_.c_str(), &end);\n>>>\n>>>  \tif ('\\0' != *end || errno == ERANGE)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>> -\tsetOk(ok, true);\n>>>  \treturn value;\n>>>  }\n>>>\n>>>  template<>\n>>> -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n>>> +std::optional<std::string> YamlObject::get() const\n>>>  {\n>>> -\tsetOk(ok, false);\n>>> -\n>>>  \tif (type_ != Type::Value)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>> -\tsetOk(ok, true);\n>>>  \treturn value_;\n>>>  }\n>>>\n>>>  template<>\n>>> -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n>>> +std::optional<Size> YamlObject::get() const\n>>>  {\n>>> -\tsetOk(ok, false);\n>>> -\n>>>  \tif (type_ != Type::List)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>>  \tif (list_.size() != 2)\n>>> -\t\treturn defaultValue;\n>>> +\t\treturn {};\n>>>\n>>> -\t/*\n>>> -\t * Add a local variable to validate each dimension in case\n>>> -\t * that ok == nullptr.\n>>> -\t */\n>>> -\tbool valid;\n>>> -\tuint32_t width = list_[0]->get<uint32_t>(0, &valid);\n>>> -\tif (!valid)\n>>> -\t\treturn defaultValue;\n>>> +\tauto width = list_[0]->get<uint32_t>();\n>>> +\tif (!width)\n>>> +\t\treturn {};\n>>>\n>>> -\tuint32_t height = list_[1]->get<uint32_t>(0, &valid);\n>>> -\tif (!valid)\n>>> -\t\treturn defaultValue;\n>>> +\tauto height = list_[1]->get<uint32_t>();\n>>> +\tif (!height)\n>>> +\t\treturn {};\n>>>\n>>> -\tsetOk(ok, true);\n>>> -\treturn Size(width, height);\n>>> +\treturn Size(*width, *height);\n>>>  }\n>>>\n>>>  #endif /* __DOXYGEN__ */\n>>> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n>>> index 38f848232fa6..ebb654f2ef9c 100644\n>>> --- a/test/yaml-parser.cpp\n>>> +++ b/test/yaml-parser.cpp\n>>> @@ -148,7 +148,6 @@ protected:\n>>>  \t\t}\n>>>\n>>>  \t\t/* Test string object */\n>>> -\t\tbool ok;\n>>>  \t\tauto &strObj = (*root)[\"string\"];\n>>>\n>>>  \t\tif (strObj.isDictionary()) {\n>>> @@ -161,27 +160,27 @@ protected:\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n>>> +\t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n>>>  \t\t\tcerr << \"String object parse as wrong content\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>> +\t\tif (strObj.get<int32_t>()) {\n>>>  \t\t\tcerr << \"String object parse as integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>> +\t\tif (strObj.get<uint32_t>()) {\n>>>  \t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n>>> +\t\tif (strObj.get<double>()) {\n>>>  \t\t\tcerr << \"String object parse as double\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>> +\t\tif (strObj.get<Size>()) {\n>>>  \t\t\tcerr << \"String object parse as Size\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>> @@ -199,27 +198,27 @@ protected:\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n>>> +\t\tif (int32Obj.get<int32_t>().value_or(0) != -100) {\n>>>  \t\t\tcerr << \"Integer object parse as wrong value\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n>>> +\t\tif (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n>>>  \t\t\tcerr << \"Integer object fail to parse as string\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n>>> +\t\tif (int32Obj.get<double>().value_or(0.0) != -100.0) {\n>>>  \t\t\tcerr << \"Integer object fail to parse as double\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>> +\t\tif (int32Obj.get<uint32_t>()) {\n>>>  \t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>> +\t\tif (int32Obj.get<Size>()) {\n>>>  \t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>> @@ -237,27 +236,27 @@ protected:\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n>>> +\t\tif (uint32Obj.get<int32_t>().value_or(0) != 100) {\n>>>  \t\t\tcerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n>>> +\t\tif (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n>>>  \t\t\tcerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n>>> +\t\tif (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n>>>  \t\t\tcerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n>>> +\t\tif (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n>>>  \t\t\tcerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>> +\t\tif (uint32Obj.get<Size>()) {\n>>>  \t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>> @@ -275,27 +274,27 @@ protected:\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n>>> +\t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n>>>  \t\t\tcerr << \"Double object fail to parse as string\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n>>> +\t\tif (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n>>>  \t\t\tcerr << \"Double object parse as wrong value\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>> +\t\tif (doubleObj.get<int32_t>()) {\n>>>  \t\t\tcerr << \"Double object parse as integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>> +\t\tif (doubleObj.get<uint32_t>()) {\n>>>  \t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>> +\t\tif (doubleObj.get<Size>()) {\n>>>  \t\t\tcerr << \"Double object parse as Size\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>> @@ -313,27 +312,27 @@ protected:\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n>>> +\t\tif (sizeObj.get<string>()) {\n>>>  \t\t\tcerr << \"Size object parse as string\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n>>> +\t\tif (sizeObj.get<double>()) {\n>>>  \t\t\tcerr << \"Size object parse as double\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>> +\t\tif (sizeObj.get<int32_t>()) {\n>>>  \t\t\tcerr << \"Size object parse as integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>> +\t\tif (sizeObj.get<uint32_t>()) {\n>>>  \t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n>>> +\t\tif (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n>>>  \t\t\tcerr << \"Size object parse as wrong value\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>> @@ -351,27 +350,27 @@ protected:\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n>>> +\t\tif (listObj.get<string>()) {\n>>>  \t\t\tcerr << \"List object parse as string\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n>>> +\t\tif (listObj.get<double>()) {\n>>>  \t\t\tcerr << \"List object parse as double\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>> +\t\tif (listObj.get<int32_t>()) {\n>>>  \t\t\tcerr << \"List object parse as integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>> +\t\tif (listObj.get<uint32_t>()) {\n>>>  \t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>> +\t\tif (listObj.get<Size>()) {\n>>>  \t\t\tcerr << \"String list object parse as Size\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>> @@ -424,27 +423,27 @@ protected:\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n>>> +\t\tif (dictObj.get<string>()) {\n>>>  \t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n>>> +\t\tif (dictObj.get<double>()) {\n>>>  \t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>> +\t\tif (dictObj.get<int32_t>()) {\n>>>  \t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>> +\t\tif (dictObj.get<uint32_t>()) {\n>>>  \t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\t}\n>>>\n>>> -\t\tif (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>> +\t\tif (dictObj.get<Size>()) {\n>>>  \t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n>>>  \t\t\treturn TestFail;\n>>>  \t\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 C7867BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  3 Aug 2022 19:10:22 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E6B4163310;\n\tWed,  3 Aug 2022 21:10:21 +0200 (CEST)","from mout.gmx.net (mout.gmx.net [212.227.15.15])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0ECF6603E6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Aug 2022 21:10:20 +0200 (CEST)","from [192.168.0.158] ([88.152.184.103]) by mail.gmx.net (mrgmx005\n\t[212.227.17.190]) with ESMTPSA (Nemesis) id\n\t1Mirna-1npVJX1gvc-00etlk for\n\t<libcamera-devel@lists.libcamera.org>; Wed, 03 Aug 2022 21:10:19 +0200"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659553821;\n\tbh=TKi4RuN+y4JepAikAmDKhAd2UNtKXpDQWaKAL8X6LRg=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=qaVuBDQvjk8BKwp+rfFY5w2vLG5bKXJD2cR6OS+E033Ubmu0vCt3qkl6syxqRQS2p\n\to9wx9iEbDFejQpuUBkgiZ+ZGX/hNQ8+t+5KNztqP2mOU4brbn9O1F7sZ39Je/B9C6G\n\tJYWp/nNZx5rF51evZHQ+v4qHCCGkwqog3aK82CV2liQjdGgQuV8TsYLTT8z+GbdeAO\n\tLWXNmQbdm4D/mqbdj6/vNrp2j/iEJ4fGFu882OSg9kl1AQq9ZiYyuKU3zOePYqaGQB\n\tEzrIj9T3uontyHr/caQD/sY1kG9KfMjhR3mw3tEBD9s2rCwDv6a5j6L/giVtppIbbp\n\tjgQNI/xceiWIQ==","v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net;\n\ts=badeba3b8450; t=1659553819;\n\tbh=TKi4RuN+y4JepAikAmDKhAd2UNtKXpDQWaKAL8X6LRg=;\n\th=X-UI-Sender-Class:Date:Subject:To:References:From:In-Reply-To;\n\tb=ivDZatTtfqJYoU7turKxFkYJlBx3IlgDJDEI2XgRH8dFi1vysX7wnVQfeOB2noMgz\n\tMF/9FBkHDjf5YLyXPBhOpaQfrA5sAqBWAIwi1lYIHDsPe8RHD/B9OobkyqjnCw9wKf\n\tYtbxrbTY2KnSdlEMrat7lWBg0/2dPmhseXPLM6Lw="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=gmx.net header.i=@gmx.net\n\theader.b=\"ivDZatTt\"; dkim-atps=neutral","X-UI-Sender-Class":"01bb95c1-4bf8-414a-932a-4f6e2808ef9c","Message-ID":"<8660cbbf-71e0-b2b6-7e15-d872912367ab@gmx.de>","Date":"Wed, 3 Aug 2022 21:10:19 +0200","MIME-Version":"1.0","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101\n\tThunderbird/91.11.0","Content-Language":"en-GB","To":"libcamera-devel@lists.libcamera.org","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>\n\t<791711aa-0211-72d5-f5d7-377e77661efd@gmx.de>\n\t<YumevpvF8wO0PpxL@pendragon.ideasonboard.com>","In-Reply-To":"<YumevpvF8wO0PpxL@pendragon.ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"quoted-printable","X-Provags-ID":"V03:K1:vWIsOGFls//zXtmR1ZPhcLneUZI3vPU/XD+5NfanPr995gUh3hV\n\tQECVlWWcjf2CV58vxVi1ZGv/kHraLCuPIsGYPHw/h/EFBxHgZ7Nt95kP+uxArzEgZweeczO\n\tbWcm/gUzyN6nX/dK2d0mNVzG4kMR7BeX+NDT6cCyp3ZEJHBN/Enh41LR3leSN7oRxLRoaOh\n\t+kf3VQ+eA8VyrDfx26rgA==","X-Spam-Flag":"NO","X-UI-Out-Filterresults":"notjunk:1; V03:K0:zySIEepNcaE=:dqaLR5Dzt4UN6v/GSD3Lvp\n\tTT+MBRZHx38+rH7/FkgKNLJS6Vvv/rQu5hrT9KdLJD/U7xRWG/exUWOz3SlM8LoTLEklHO1Tq\n\tuv2WYrqkusuHX2ZK33EpskWVsbhFYqOWxREsPKDgvfD99fDbOKKSpssZzpTFRzNU5oNcC5gBI\n\tWNdXIHn9TZGPfT4q3vlA1yf/Ioue/UELXRTDFzLmdWUxo68F6unz4X8ffAzqmty1Qigw9KMO4\n\t7NnE6JAGe5nJw76rA8ofObe973X/DgeDCWywEq9ux3AAMqYDQp49JBJg/XB0Zefe9he0/dWVA\n\tw1jQ4PZUF12xaiNoxzVBLeOlJlplKoCrlwtDxDCTQWiwUY9sI+rLojTQh9DAlUfXnJrg6qGmi\n\tQ6YDqq9ADEFAgYGaMLXenogXbCeXKLOojnJWiYb7Ih3895tuKLs4yxygd4iXljvSbKgJTV+dU\n\tVPR7EfIxl8rxa3v3uhFmTNEorUiFNCARp385pVoAZs718icQIttS40ojZyKN+NawuVAbRTzay\n\tdV1BjfOfp/N7xlmE7D2l32s9VxSpX7p56gwVFTzSW36wdzVFIlBS8FcgLRxrM2v7HTrVqjMHX\n\thrycTENMTtjaeLRVJmqvV1CmDb73zrs4v836jcaKF6DLMJLyYr6F9lR4BqMUu5hRdbNaqca0L\n\t7kw7cWkgCTl8d36Dx6e4TszDp9eguo+9VcDZvMvJ4O5MHGH454ibXKVoAMPbLGIfhFUdrCElP\n\teg5jZXOMvo/YCbhQsUfLs6j8CAHg8dgapn2vYvbxzyhDokpTuo5HBTic37p2kw682MN4mJOvi\n\tAis2x9xSbFz1p/ZnysbbcvCrHsTEZ2fTqF7PuuUtDxC5zlbVjfvjMCnftesLoLKtOnerc8Hfr\n\tsp31IyHaPU3X8qivwSp8rbHB31uvgahN3wTJZ79lCxRWGc6/YIvEv/ymlRk2RLQ8v3IO+vRGd\n\teLHu0k0oAtlkd8N5wjc65SnaVySqDjpuzydb5r0fNaZIbU9WFDKtDv4W9uN3Y5KcB0g6ntWh+\n\tcvRw0o68i9stwOIFrd+0BUcPegWPo/IjWUl/yQWHgR91KKOwAAi6wy96EKObamnD30ISK9gTT\n\tV1SV8mNHt065P6xwu6MM9pt5qkNGNAyl9u6yRC4RB/oLX9coDecEj271A==","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Christian Rauch via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Christian Rauch <Rauch.Christian@gmx.de>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24361,"web_url":"https://patchwork.libcamera.org/comment/24361/","msgid":"<YurywHQzAKDGBA1Z@pendragon.ideasonboard.com>","date":"2022-08-03T22:12:16","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Christian,\n\nOn Wed, Aug 03, 2022 at 09:10:19PM +0200, Christian Rauch via libcamera-devel wrote:\n> Am 03.08.22 um 00:01 schrieb Laurent Pinchart:\n> > On Tue, Aug 02, 2022 at 10:47:52PM +0200, Christian Rauch via libcamera-devel wrote:\n> >> Dear Laurent,\n> >>\n> >> The \"return {};\" in this patch cause \"maybe-uninitialized\" warnings in\n> >> my CI pipeline:\n> >\n> > Thank you for the report. We have CI pipelines too, but clearly, there\n> > are way more compiler/platform combinations out there that we test at\n> > the moment :-)\n> >\n> > Could you report the compiler, compiler version and platform, for my\n> > information ?\n> \n> It's an arm64 corss compile workflow with gcc 9 [1]. See the full log at\n> [2].\n> \n> [1] https://github.com/christianrauch/libcamera-ci/blob/ci/.github/workflows/main_cross.yml\n> [2] https://github.com/christianrauch/libcamera-ci/runs/7639256594?check_suite_focus=true\n\nCould you test the following patch to see if it fixes the problem ? If\nso I'll send it with a proper commit message.\n\ndiff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\nindex c96e99e1317c..9162e2250ed4 100644\n--- a/src/libcamera/yaml_parser.cpp\n+++ b/src/libcamera/yaml_parser.cpp\n@@ -121,24 +121,24 @@ template<>\n std::optional<bool> YamlObject::get() const\n {\n \tif (type_ != Type::Value)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tif (value_ == \"true\")\n \t\treturn true;\n \telse if (value_ == \"false\")\n \t\treturn false;\n\n-\treturn {};\n+\treturn std::nullopt;\n }\n\n template<>\n std::optional<int16_t> YamlObject::get() const\n {\n \tif (type_ != Type::Value)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tif (value_ == \"\")\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tchar *end;\n\n@@ -148,7 +148,7 @@ std::optional<int16_t> YamlObject::get() const\n \tif ('\\0' != *end || errno == ERANGE ||\n \t    value < std::numeric_limits<int16_t>::min() ||\n \t    value > std::numeric_limits<int16_t>::max())\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \treturn value;\n }\n@@ -157,10 +157,10 @@ template<>\n std::optional<uint16_t> YamlObject::get() const\n {\n \tif (type_ != Type::Value)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tif (value_ == \"\")\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \t/*\n \t * libyaml parses all scalar values as strings. When a string has\n@@ -171,7 +171,7 @@ std::optional<uint16_t> YamlObject::get() const\n \t */\n \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n \tif (found != std::string::npos && value_[found] == '-')\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tchar *end;\n\n@@ -181,7 +181,7 @@ std::optional<uint16_t> YamlObject::get() const\n \tif ('\\0' != *end || errno == ERANGE ||\n \t    value < std::numeric_limits<uint16_t>::min() ||\n \t    value > std::numeric_limits<uint16_t>::max())\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \treturn value;\n }\n@@ -190,10 +190,10 @@ template<>\n std::optional<int32_t> YamlObject::get() const\n {\n \tif (type_ != Type::Value)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tif (value_ == \"\")\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tchar *end;\n\n@@ -203,7 +203,7 @@ std::optional<int32_t> YamlObject::get() const\n \tif ('\\0' != *end || errno == ERANGE ||\n \t    value < std::numeric_limits<int32_t>::min() ||\n \t    value > std::numeric_limits<int32_t>::max())\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \treturn value;\n }\n@@ -212,10 +212,10 @@ template<>\n std::optional<uint32_t> YamlObject::get() const\n {\n \tif (type_ != Type::Value)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tif (value_ == \"\")\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \t/*\n \t * libyaml parses all scalar values as strings. When a string has\n@@ -226,7 +226,7 @@ std::optional<uint32_t> YamlObject::get() const\n \t */\n \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n \tif (found != std::string::npos && value_[found] == '-')\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tchar *end;\n\n@@ -236,7 +236,7 @@ std::optional<uint32_t> YamlObject::get() const\n \tif ('\\0' != *end || errno == ERANGE ||\n \t    value < std::numeric_limits<uint32_t>::min() ||\n \t    value > std::numeric_limits<uint32_t>::max())\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \treturn value;\n }\n@@ -245,10 +245,10 @@ template<>\n std::optional<double> YamlObject::get() const\n {\n \tif (type_ != Type::Value)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tif (value_ == \"\")\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tchar *end;\n\n@@ -256,7 +256,7 @@ std::optional<double> YamlObject::get() const\n \tdouble value = std::strtod(value_.c_str(), &end);\n\n \tif ('\\0' != *end || errno == ERANGE)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \treturn value;\n }\n@@ -265,7 +265,7 @@ template<>\n std::optional<std::string> YamlObject::get() const\n {\n \tif (type_ != Type::Value)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \treturn value_;\n }\n@@ -274,18 +274,18 @@ template<>\n std::optional<Size> YamlObject::get() const\n {\n \tif (type_ != Type::List)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tif (list_.size() != 2)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tauto width = list_[0].value->get<uint32_t>();\n \tif (!width)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \tauto height = list_[1].value->get<uint32_t>();\n \tif (!height)\n-\t\treturn {};\n+\t\treturn std::nullopt;\n\n \treturn Size(*width, *height);\n }\n\n\n> >> ../src/libcamera/yaml_parser.cpp: In member function ‘std::optional<_Tp>\n> >> libcamera::YamlObject::get() const [with T = short unsigned int;\n> >> std::enable_if_t<(((((((is_same_v<bool, T> || is_same_v<double, T>) ||\n> >> is_same_v<short int, T>) || is_same_v<short unsigned int, T>) ||\n> >> is_same_v<int, T>) || is_same_v<unsigned int, T>) ||\n> >> is_same_v<std::__cxx11::basic_string<char, std::char_traits<char>,\n> >> std::allocator<char> >, T>) || is_same_v<libcamera::Size, T>)>*\n> >> <anonymous> = 0]’:\n> >> ../src/libcamera/yaml_parser.cpp:184:11: error: ‘<anonymous>’ may be\n> >> used uninitialized in this function [-Werror=maybe-uninitialized]\n> >>   184 |   return {};\n> >>       |           ^\n> >>\n> >> ... and a couple more in \"yaml_parser.cpp\".\n> >>\n> >> Since your intention is here to notify the user of invalid values,\n> >> wouldn't it be better to \"return nullptr;\" instead?\n> >\n> > The would be std::nullopt as the function returns a std::optional<>, but\n> > yes, that would make sense. I was expecting {} to do the same.\n> >\n> > As I can't test if this would fix the compilation warning given that I\n> > can't reproduce them, would you be able to test that change with your CI\n> > pipeline ? If std::nullopt fixes the errors, I can send a patch, or you\n> > can send one directly if you prefer.\n> >\n> >> Am 28.07.22 um 00:21 schrieb Laurent Pinchart via libcamera-devel:\n> >>> The YamlObject::get() function takes a default value and an optional\n> >>> bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n> >>> error handling in callers.\n> >>>\n> >>> A better API is possible by dropping the default value and ok flag and\n> >>> returning an std::optional. Not only does it simplify the calls, it also\n> >>> lets callers handle errors through the standard std::optional class\n> >>> instead of the current ad-hoc mechanism.\n> >>>\n> >>> Provide a get() wrapper around std::optional::value_or() to further\n> >>> simplify callers that don't need any specific error handling.\n> >>>\n> >>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> >>> Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n> >>> Tested-by: Naushir Patuck <naush@raspberrypi.com>\n> >>> ---\n> >>>  include/libcamera/internal/yaml_parser.h |   9 +-\n> >>>  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n> >>>  test/yaml-parser.cpp                     |  71 ++++++------\n> >>>  3 files changed, 96 insertions(+), 122 deletions(-)\n> >>>\n> >>> diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n> >>> index 064cf44381d7..61f2223223a7 100644\n> >>> --- a/include/libcamera/internal/yaml_parser.h\n> >>> +++ b/include/libcamera/internal/yaml_parser.h\n> >>> @@ -9,6 +9,7 @@\n> >>>\n> >>>  #include <iterator>\n> >>>  #include <map>\n> >>> +#include <optional>\n> >>>  #include <string>\n> >>>  #include <vector>\n> >>>\n> >>> @@ -165,7 +166,13 @@ public:\n> >>>  #else\n> >>>  \ttemplate<typename T>\n> >>>  #endif\n> >>> -\tT get(const T &defaultValue, bool *ok = nullptr) const;\n> >>> +\tstd::optional<T> get() const;\n> >>> +\n> >>> +\ttemplate<typename T>\n> >>> +\tT get(const T &defaultValue) const\n> >>> +\t{\n> >>> +\t\treturn get<T>().value_or(defaultValue);\n> >>> +\t}\n> >>>\n> >>>  \tDictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n> >>>  \tListAdapter asList() const { return ListAdapter{ list_ }; }\n> >>> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> >>> index 5c45e44e49c3..4299f5abd38a 100644\n> >>> --- a/src/libcamera/yaml_parser.cpp\n> >>> +++ b/src/libcamera/yaml_parser.cpp\n> >>> @@ -31,12 +31,6 @@ namespace {\n> >>>  /* Empty static YamlObject as a safe result for invalid operations */\n> >>>  static const YamlObject empty;\n> >>>\n> >>> -void setOk(bool *ok, bool result)\n> >>> -{\n> >>> -\tif (ok)\n> >>> -\t\t*ok = result;\n> >>> -}\n> >>> -\n> >>>  } /* namespace */\n> >>>\n> >>>  /**\n> >>> @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n> >>>  }\n> >>>\n> >>>  /**\n> >>> - * \\fn template<typename T> YamlObject::get<T>(\n> >>> - *\tconst T &defaultValue, bool *ok) const\n> >>> + * \\fn template<typename T> YamlObject::get<T>() const\n> >>> + * \\brief Parse the YamlObject as a \\a T value\n> >>> + *\n> >>> + * This function parses the value of the YamlObject as a \\a T object, and\n> >>> + * returns the value. If parsing fails (usually because the YamlObject doesn't\n> >>> + * store a \\a T value), std::nullopt is returned.\n> >>> + *\n> >>> + * \\return The YamlObject value, or std::nullopt if parsing failed\n> >>> + */\n> >>> +\n> >>> +/**\n> >>> + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n> >>>   * \\brief Parse the YamlObject as a \\a T value\n> >>>   * \\param[in] defaultValue The default value when failing to parse\n> >>> - * \\param[out] ok The result of whether the parse succeeded\n> >>>   *\n> >>>   * This function parses the value of the YamlObject as a \\a T object, and\n> >>>   * returns the value. If parsing fails (usually because the YamlObject doesn't\n> >>> - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n> >>> - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n> >>> + * store a \\a T value), the \\a defaultValue is returned.\n> >>>   *\n> >>> - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n> >>> - * need to know if parsing succeeded.\n> >>> - *\n> >>> - * \\return Value as a bool type\n> >>> + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n> >>>   */\n> >>>\n> >>>  #ifndef __DOXYGEN__\n> >>>\n> >>>  template<>\n> >>> -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n> >>> +std::optional<bool> YamlObject::get() const\n> >>>  {\n> >>> -\tsetOk(ok, false);\n> >>> -\n> >>>  \tif (type_ != Type::Value)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>> -\tif (value_ == \"true\") {\n> >>> -\t\tsetOk(ok, true);\n> >>> +\tif (value_ == \"true\")\n> >>>  \t\treturn true;\n> >>> -\t} else if (value_ == \"false\") {\n> >>> -\t\tsetOk(ok, true);\n> >>> +\telse if (value_ == \"false\")\n> >>>  \t\treturn false;\n> >>> -\t}\n> >>>\n> >>> -\treturn defaultValue;\n> >>> +\treturn {};\n> >>>  }\n> >>>\n> >>>  template<>\n> >>> -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> >>> +std::optional<int16_t> YamlObject::get() const\n> >>>  {\n> >>> -\tsetOk(ok, false);\n> >>> -\n> >>>  \tif (type_ != Type::Value)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tif (value_ == \"\")\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tchar *end;\n> >>>\n> >>> @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n> >>>  \tif ('\\0' != *end || errno == ERANGE ||\n> >>>  \t    value < std::numeric_limits<int16_t>::min() ||\n> >>>  \t    value > std::numeric_limits<int16_t>::max())\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>> -\tsetOk(ok, true);\n> >>>  \treturn value;\n> >>>  }\n> >>>\n> >>>  template<>\n> >>> -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> >>> +std::optional<uint16_t> YamlObject::get() const\n> >>>  {\n> >>> -\tsetOk(ok, false);\n> >>> -\n> >>>  \tif (type_ != Type::Value)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tif (value_ == \"\")\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \t/*\n> >>>  \t * libyaml parses all scalar values as strings. When a string has\n> >>> @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> >>>  \t */\n> >>>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n> >>>  \tif (found != std::string::npos && value_[found] == '-')\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tchar *end;\n> >>>\n> >>> @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n> >>>  \tif ('\\0' != *end || errno == ERANGE ||\n> >>>  \t    value < std::numeric_limits<uint16_t>::min() ||\n> >>>  \t    value > std::numeric_limits<uint16_t>::max())\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>> -\tsetOk(ok, true);\n> >>>  \treturn value;\n> >>>  }\n> >>>\n> >>>  template<>\n> >>> -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> >>> +std::optional<int32_t> YamlObject::get() const\n> >>>  {\n> >>> -\tsetOk(ok, false);\n> >>> -\n> >>>  \tif (type_ != Type::Value)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tif (value_ == \"\")\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tchar *end;\n> >>>\n> >>> @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n> >>>  \tif ('\\0' != *end || errno == ERANGE ||\n> >>>  \t    value < std::numeric_limits<int32_t>::min() ||\n> >>>  \t    value > std::numeric_limits<int32_t>::max())\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>> -\tsetOk(ok, true);\n> >>>  \treturn value;\n> >>>  }\n> >>>\n> >>>  template<>\n> >>> -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> >>> +std::optional<uint32_t> YamlObject::get() const\n> >>>  {\n> >>> -\tsetOk(ok, false);\n> >>> -\n> >>>  \tif (type_ != Type::Value)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tif (value_ == \"\")\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \t/*\n> >>>  \t * libyaml parses all scalar values as strings. When a string has\n> >>> @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> >>>  \t */\n> >>>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n> >>>  \tif (found != std::string::npos && value_[found] == '-')\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tchar *end;\n> >>>\n> >>> @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n> >>>  \tif ('\\0' != *end || errno == ERANGE ||\n> >>>  \t    value < std::numeric_limits<uint32_t>::min() ||\n> >>>  \t    value > std::numeric_limits<uint32_t>::max())\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>> -\tsetOk(ok, true);\n> >>>  \treturn value;\n> >>>  }\n> >>>\n> >>>  template<>\n> >>> -double YamlObject::get(const double &defaultValue, bool *ok) const\n> >>> +std::optional<double> YamlObject::get() const\n> >>>  {\n> >>> -\tsetOk(ok, false);\n> >>> -\n> >>>  \tif (type_ != Type::Value)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tif (value_ == \"\")\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tchar *end;\n> >>>\n> >>> @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n> >>>  \tdouble value = std::strtod(value_.c_str(), &end);\n> >>>\n> >>>  \tif ('\\0' != *end || errno == ERANGE)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>> -\tsetOk(ok, true);\n> >>>  \treturn value;\n> >>>  }\n> >>>\n> >>>  template<>\n> >>> -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n> >>> +std::optional<std::string> YamlObject::get() const\n> >>>  {\n> >>> -\tsetOk(ok, false);\n> >>> -\n> >>>  \tif (type_ != Type::Value)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>> -\tsetOk(ok, true);\n> >>>  \treturn value_;\n> >>>  }\n> >>>\n> >>>  template<>\n> >>> -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n> >>> +std::optional<Size> YamlObject::get() const\n> >>>  {\n> >>> -\tsetOk(ok, false);\n> >>> -\n> >>>  \tif (type_ != Type::List)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>>  \tif (list_.size() != 2)\n> >>> -\t\treturn defaultValue;\n> >>> +\t\treturn {};\n> >>>\n> >>> -\t/*\n> >>> -\t * Add a local variable to validate each dimension in case\n> >>> -\t * that ok == nullptr.\n> >>> -\t */\n> >>> -\tbool valid;\n> >>> -\tuint32_t width = list_[0]->get<uint32_t>(0, &valid);\n> >>> -\tif (!valid)\n> >>> -\t\treturn defaultValue;\n> >>> +\tauto width = list_[0]->get<uint32_t>();\n> >>> +\tif (!width)\n> >>> +\t\treturn {};\n> >>>\n> >>> -\tuint32_t height = list_[1]->get<uint32_t>(0, &valid);\n> >>> -\tif (!valid)\n> >>> -\t\treturn defaultValue;\n> >>> +\tauto height = list_[1]->get<uint32_t>();\n> >>> +\tif (!height)\n> >>> +\t\treturn {};\n> >>>\n> >>> -\tsetOk(ok, true);\n> >>> -\treturn Size(width, height);\n> >>> +\treturn Size(*width, *height);\n> >>>  }\n> >>>\n> >>>  #endif /* __DOXYGEN__ */\n> >>> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n> >>> index 38f848232fa6..ebb654f2ef9c 100644\n> >>> --- a/test/yaml-parser.cpp\n> >>> +++ b/test/yaml-parser.cpp\n> >>> @@ -148,7 +148,6 @@ protected:\n> >>>  \t\t}\n> >>>\n> >>>  \t\t/* Test string object */\n> >>> -\t\tbool ok;\n> >>>  \t\tauto &strObj = (*root)[\"string\"];\n> >>>\n> >>>  \t\tif (strObj.isDictionary()) {\n> >>> @@ -161,27 +160,27 @@ protected:\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n> >>> +\t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n> >>>  \t\t\tcerr << \"String object parse as wrong content\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> >>> +\t\tif (strObj.get<int32_t>()) {\n> >>>  \t\t\tcerr << \"String object parse as integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> >>> +\t\tif (strObj.get<uint32_t>()) {\n> >>>  \t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> >>> +\t\tif (strObj.get<double>()) {\n> >>>  \t\t\tcerr << \"String object parse as double\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> >>> +\t\tif (strObj.get<Size>()) {\n> >>>  \t\t\tcerr << \"String object parse as Size\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>> @@ -199,27 +198,27 @@ protected:\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n> >>> +\t\tif (int32Obj.get<int32_t>().value_or(0) != -100) {\n> >>>  \t\t\tcerr << \"Integer object parse as wrong value\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n> >>> +\t\tif (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n> >>>  \t\t\tcerr << \"Integer object fail to parse as string\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n> >>> +\t\tif (int32Obj.get<double>().value_or(0.0) != -100.0) {\n> >>>  \t\t\tcerr << \"Integer object fail to parse as double\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n> >>> +\t\tif (int32Obj.get<uint32_t>()) {\n> >>>  \t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> >>> +\t\tif (int32Obj.get<Size>()) {\n> >>>  \t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>> @@ -237,27 +236,27 @@ protected:\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n> >>> +\t\tif (uint32Obj.get<int32_t>().value_or(0) != 100) {\n> >>>  \t\t\tcerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n> >>> +\t\tif (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n> >>>  \t\t\tcerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n> >>> +\t\tif (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n> >>>  \t\t\tcerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n> >>> +\t\tif (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n> >>>  \t\t\tcerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> >>> +\t\tif (uint32Obj.get<Size>()) {\n> >>>  \t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>> @@ -275,27 +274,27 @@ protected:\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n> >>> +\t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n> >>>  \t\t\tcerr << \"Double object fail to parse as string\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n> >>> +\t\tif (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n> >>>  \t\t\tcerr << \"Double object parse as wrong value\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> >>> +\t\tif (doubleObj.get<int32_t>()) {\n> >>>  \t\t\tcerr << \"Double object parse as integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> >>> +\t\tif (doubleObj.get<uint32_t>()) {\n> >>>  \t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> >>> +\t\tif (doubleObj.get<Size>()) {\n> >>>  \t\t\tcerr << \"Double object parse as Size\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>> @@ -313,27 +312,27 @@ protected:\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n> >>> +\t\tif (sizeObj.get<string>()) {\n> >>>  \t\t\tcerr << \"Size object parse as string\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> >>> +\t\tif (sizeObj.get<double>()) {\n> >>>  \t\t\tcerr << \"Size object parse as double\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> >>> +\t\tif (sizeObj.get<int32_t>()) {\n> >>>  \t\t\tcerr << \"Size object parse as integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> >>> +\t\tif (sizeObj.get<uint32_t>()) {\n> >>>  \t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n> >>> +\t\tif (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n> >>>  \t\t\tcerr << \"Size object parse as wrong value\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>> @@ -351,27 +350,27 @@ protected:\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n> >>> +\t\tif (listObj.get<string>()) {\n> >>>  \t\t\tcerr << \"List object parse as string\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> >>> +\t\tif (listObj.get<double>()) {\n> >>>  \t\t\tcerr << \"List object parse as double\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> >>> +\t\tif (listObj.get<int32_t>()) {\n> >>>  \t\t\tcerr << \"List object parse as integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> >>> +\t\tif (listObj.get<uint32_t>()) {\n> >>>  \t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> >>> +\t\tif (listObj.get<Size>()) {\n> >>>  \t\t\tcerr << \"String list object parse as Size\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>> @@ -424,27 +423,27 @@ protected:\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n> >>> +\t\tif (dictObj.get<string>()) {\n> >>>  \t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n> >>> +\t\tif (dictObj.get<double>()) {\n> >>>  \t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n> >>> +\t\tif (dictObj.get<int32_t>()) {\n> >>>  \t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n> >>> +\t\tif (dictObj.get<uint32_t>()) {\n> >>>  \t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}\n> >>>\n> >>> -\t\tif (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n> >>> +\t\tif (dictObj.get<Size>()) {\n> >>>  \t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n> >>>  \t\t\treturn TestFail;\n> >>>  \t\t}","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 15E0EC3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  3 Aug 2022 22:12:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D367A63310;\n\tThu,  4 Aug 2022 00:12:24 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0CC4E603E7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  4 Aug 2022 00:12:23 +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 5C0458B;\n\tThu,  4 Aug 2022 00:12:22 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659564744;\n\tbh=E7jH7dT7aJSTXFbgWBzL1iuOObpSg0RrtvxnVh53sB0=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=IfRKNkj8frOtuNNoaEga3274F0tV5KWKISccBEBcflL7z6Bv/eF+AVw11qhU6fHxN\n\tCLPUVuwHqiu0+GHN0QBOFJAO566SmyJG0syhFaOMB6SXSDuYQaCEk7tmZWgJ5uNAwN\n\ts4MGXa/pXweRajmmyYGDUruz6aEg/GP0EiaqzxmTgvfj/WPkyjP3YYd2Is/77V3LE2\n\tYqDgALHkRCiC/dWQtA1J/hTCzng9f9mfrg16hhoTvQfP4yKxSJoxBJLxv4/TizitVY\n\tZ687xqIhO3G2bcmFsU1dgJ7wsBd/XitwJQ8ASNyRu1EkCAsktUk8F/QCYLchVtlzyc\n\tAeZQ9QAT9vyuQ==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1659564742;\n\tbh=E7jH7dT7aJSTXFbgWBzL1iuOObpSg0RrtvxnVh53sB0=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=SqLNMzlp6uVsd9pTJas1Tt9Y7wzxMS/Lo+ri6BJsXeBQI+lV4ZupTc55RHGXIGK7Y\n\tYg2siMckblP5SGAyX1rbW7UcBfsEOW4xSBlK93df6XqBN0fg3Q4KsivokWorsc47NC\n\toYm+RMWvErYAqdTzrLmxbub/h9ODGSXKBscysCsI="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"SqLNMzlp\"; dkim-atps=neutral","Date":"Thu, 4 Aug 2022 01:12:16 +0300","To":"Christian Rauch <Rauch.Christian@gmx.de>","Message-ID":"<YurywHQzAKDGBA1Z@pendragon.ideasonboard.com>","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>\n\t<791711aa-0211-72d5-f5d7-377e77661efd@gmx.de>\n\t<YumevpvF8wO0PpxL@pendragon.ideasonboard.com>\n\t<8660cbbf-71e0-b2b6-7e15-d872912367ab@gmx.de>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<8660cbbf-71e0-b2b6-7e15-d872912367ab@gmx.de>","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24383,"web_url":"https://patchwork.libcamera.org/comment/24383/","msgid":"<51e9ae7c-d91b-37e1-4d8a-4034519be67f@gmx.de>","date":"2022-08-04T22:06:30","subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","submitter":{"id":111,"url":"https://patchwork.libcamera.org/api/people/111/","name":"Christian Rauch","email":"Rauch.Christian@gmx.de"},"content":"Thanks Laurent, the patch seems to work [1].\n\n[1] https://github.com/christianrauch/libcamera-ci/actions/runs/2799422430\n\nAm 04.08.22 um 00:12 schrieb Laurent Pinchart:\n> Hi Christian,\n>\n> On Wed, Aug 03, 2022 at 09:10:19PM +0200, Christian Rauch via libcamera-devel wrote:\n>> Am 03.08.22 um 00:01 schrieb Laurent Pinchart:\n>>> On Tue, Aug 02, 2022 at 10:47:52PM +0200, Christian Rauch via libcamera-devel wrote:\n>>>> Dear Laurent,\n>>>>\n>>>> The \"return {};\" in this patch cause \"maybe-uninitialized\" warnings in\n>>>> my CI pipeline:\n>>>\n>>> Thank you for the report. We have CI pipelines too, but clearly, there\n>>> are way more compiler/platform combinations out there that we test at\n>>> the moment :-)\n>>>\n>>> Could you report the compiler, compiler version and platform, for my\n>>> information ?\n>>\n>> It's an arm64 corss compile workflow with gcc 9 [1]. See the full log at\n>> [2].\n>>\n>> [1] https://github.com/christianrauch/libcamera-ci/blob/ci/.github/workflows/main_cross.yml\n>> [2] https://github.com/christianrauch/libcamera-ci/runs/7639256594?check_suite_focus=true\n>\n> Could you test the following patch to see if it fixes the problem ? If\n> so I'll send it with a proper commit message.\n>\n> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n> index c96e99e1317c..9162e2250ed4 100644\n> --- a/src/libcamera/yaml_parser.cpp\n> +++ b/src/libcamera/yaml_parser.cpp\n> @@ -121,24 +121,24 @@ template<>\n>  std::optional<bool> YamlObject::get() const\n>  {\n>  \tif (type_ != Type::Value)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tif (value_ == \"true\")\n>  \t\treturn true;\n>  \telse if (value_ == \"false\")\n>  \t\treturn false;\n>\n> -\treturn {};\n> +\treturn std::nullopt;\n>  }\n>\n>  template<>\n>  std::optional<int16_t> YamlObject::get() const\n>  {\n>  \tif (type_ != Type::Value)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tif (value_ == \"\")\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tchar *end;\n>\n> @@ -148,7 +148,7 @@ std::optional<int16_t> YamlObject::get() const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<int16_t>::min() ||\n>  \t    value > std::numeric_limits<int16_t>::max())\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \treturn value;\n>  }\n> @@ -157,10 +157,10 @@ template<>\n>  std::optional<uint16_t> YamlObject::get() const\n>  {\n>  \tif (type_ != Type::Value)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tif (value_ == \"\")\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \t/*\n>  \t * libyaml parses all scalar values as strings. When a string has\n> @@ -171,7 +171,7 @@ std::optional<uint16_t> YamlObject::get() const\n>  \t */\n>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>  \tif (found != std::string::npos && value_[found] == '-')\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tchar *end;\n>\n> @@ -181,7 +181,7 @@ std::optional<uint16_t> YamlObject::get() const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<uint16_t>::min() ||\n>  \t    value > std::numeric_limits<uint16_t>::max())\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \treturn value;\n>  }\n> @@ -190,10 +190,10 @@ template<>\n>  std::optional<int32_t> YamlObject::get() const\n>  {\n>  \tif (type_ != Type::Value)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tif (value_ == \"\")\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tchar *end;\n>\n> @@ -203,7 +203,7 @@ std::optional<int32_t> YamlObject::get() const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<int32_t>::min() ||\n>  \t    value > std::numeric_limits<int32_t>::max())\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \treturn value;\n>  }\n> @@ -212,10 +212,10 @@ template<>\n>  std::optional<uint32_t> YamlObject::get() const\n>  {\n>  \tif (type_ != Type::Value)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tif (value_ == \"\")\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \t/*\n>  \t * libyaml parses all scalar values as strings. When a string has\n> @@ -226,7 +226,7 @@ std::optional<uint32_t> YamlObject::get() const\n>  \t */\n>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>  \tif (found != std::string::npos && value_[found] == '-')\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tchar *end;\n>\n> @@ -236,7 +236,7 @@ std::optional<uint32_t> YamlObject::get() const\n>  \tif ('\\0' != *end || errno == ERANGE ||\n>  \t    value < std::numeric_limits<uint32_t>::min() ||\n>  \t    value > std::numeric_limits<uint32_t>::max())\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \treturn value;\n>  }\n> @@ -245,10 +245,10 @@ template<>\n>  std::optional<double> YamlObject::get() const\n>  {\n>  \tif (type_ != Type::Value)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tif (value_ == \"\")\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tchar *end;\n>\n> @@ -256,7 +256,7 @@ std::optional<double> YamlObject::get() const\n>  \tdouble value = std::strtod(value_.c_str(), &end);\n>\n>  \tif ('\\0' != *end || errno == ERANGE)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \treturn value;\n>  }\n> @@ -265,7 +265,7 @@ template<>\n>  std::optional<std::string> YamlObject::get() const\n>  {\n>  \tif (type_ != Type::Value)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \treturn value_;\n>  }\n> @@ -274,18 +274,18 @@ template<>\n>  std::optional<Size> YamlObject::get() const\n>  {\n>  \tif (type_ != Type::List)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tif (list_.size() != 2)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tauto width = list_[0].value->get<uint32_t>();\n>  \tif (!width)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \tauto height = list_[1].value->get<uint32_t>();\n>  \tif (!height)\n> -\t\treturn {};\n> +\t\treturn std::nullopt;\n>\n>  \treturn Size(*width, *height);\n>  }\n>\n>\n>>>> ../src/libcamera/yaml_parser.cpp: In member function ‘std::optional<_Tp>\n>>>> libcamera::YamlObject::get() const [with T = short unsigned int;\n>>>> std::enable_if_t<(((((((is_same_v<bool, T> || is_same_v<double, T>) ||\n>>>> is_same_v<short int, T>) || is_same_v<short unsigned int, T>) ||\n>>>> is_same_v<int, T>) || is_same_v<unsigned int, T>) ||\n>>>> is_same_v<std::__cxx11::basic_string<char, std::char_traits<char>,\n>>>> std::allocator<char> >, T>) || is_same_v<libcamera::Size, T>)>*\n>>>> <anonymous> = 0]’:\n>>>> ../src/libcamera/yaml_parser.cpp:184:11: error: ‘<anonymous>’ may be\n>>>> used uninitialized in this function [-Werror=maybe-uninitialized]\n>>>>   184 |   return {};\n>>>>       |           ^\n>>>>\n>>>> ... and a couple more in \"yaml_parser.cpp\".\n>>>>\n>>>> Since your intention is here to notify the user of invalid values,\n>>>> wouldn't it be better to \"return nullptr;\" instead?\n>>>\n>>> The would be std::nullopt as the function returns a std::optional<>, but\n>>> yes, that would make sense. I was expecting {} to do the same.\n>>>\n>>> As I can't test if this would fix the compilation warning given that I\n>>> can't reproduce them, would you be able to test that change with your CI\n>>> pipeline ? If std::nullopt fixes the errors, I can send a patch, or you\n>>> can send one directly if you prefer.\n>>>\n>>>> Am 28.07.22 um 00:21 schrieb Laurent Pinchart via libcamera-devel:\n>>>>> The YamlObject::get() function takes a default value and an optional\n>>>>> bool ok flag to handle parsing errors. This ad-hoc mechanism complicates\n>>>>> error handling in callers.\n>>>>>\n>>>>> A better API is possible by dropping the default value and ok flag and\n>>>>> returning an std::optional. Not only does it simplify the calls, it also\n>>>>> lets callers handle errors through the standard std::optional class\n>>>>> instead of the current ad-hoc mechanism.\n>>>>>\n>>>>> Provide a get() wrapper around std::optional::value_or() to further\n>>>>> simplify callers that don't need any specific error handling.\n>>>>>\n>>>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>>>>> Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n>>>>> Tested-by: Naushir Patuck <naush@raspberrypi.com>\n>>>>> ---\n>>>>>  include/libcamera/internal/yaml_parser.h |   9 +-\n>>>>>  src/libcamera/yaml_parser.cpp            | 138 +++++++++--------------\n>>>>>  test/yaml-parser.cpp                     |  71 ++++++------\n>>>>>  3 files changed, 96 insertions(+), 122 deletions(-)\n>>>>>\n>>>>> diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h\n>>>>> index 064cf44381d7..61f2223223a7 100644\n>>>>> --- a/include/libcamera/internal/yaml_parser.h\n>>>>> +++ b/include/libcamera/internal/yaml_parser.h\n>>>>> @@ -9,6 +9,7 @@\n>>>>>\n>>>>>  #include <iterator>\n>>>>>  #include <map>\n>>>>> +#include <optional>\n>>>>>  #include <string>\n>>>>>  #include <vector>\n>>>>>\n>>>>> @@ -165,7 +166,13 @@ public:\n>>>>>  #else\n>>>>>  \ttemplate<typename T>\n>>>>>  #endif\n>>>>> -\tT get(const T &defaultValue, bool *ok = nullptr) const;\n>>>>> +\tstd::optional<T> get() const;\n>>>>> +\n>>>>> +\ttemplate<typename T>\n>>>>> +\tT get(const T &defaultValue) const\n>>>>> +\t{\n>>>>> +\t\treturn get<T>().value_or(defaultValue);\n>>>>> +\t}\n>>>>>\n>>>>>  \tDictAdapter asDict() const { return DictAdapter{ dictionary_ }; }\n>>>>>  \tListAdapter asList() const { return ListAdapter{ list_ }; }\n>>>>> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp\n>>>>> index 5c45e44e49c3..4299f5abd38a 100644\n>>>>> --- a/src/libcamera/yaml_parser.cpp\n>>>>> +++ b/src/libcamera/yaml_parser.cpp\n>>>>> @@ -31,12 +31,6 @@ namespace {\n>>>>>  /* Empty static YamlObject as a safe result for invalid operations */\n>>>>>  static const YamlObject empty;\n>>>>>\n>>>>> -void setOk(bool *ok, bool result)\n>>>>> -{\n>>>>> -\tif (ok)\n>>>>> -\t\t*ok = result;\n>>>>> -}\n>>>>> -\n>>>>>  } /* namespace */\n>>>>>\n>>>>>  /**\n>>>>> @@ -100,54 +94,52 @@ std::size_t YamlObject::size() const\n>>>>>  }\n>>>>>\n>>>>>  /**\n>>>>> - * \\fn template<typename T> YamlObject::get<T>(\n>>>>> - *\tconst T &defaultValue, bool *ok) const\n>>>>> + * \\fn template<typename T> YamlObject::get<T>() const\n>>>>> + * \\brief Parse the YamlObject as a \\a T value\n>>>>> + *\n>>>>> + * This function parses the value of the YamlObject as a \\a T object, and\n>>>>> + * returns the value. If parsing fails (usually because the YamlObject doesn't\n>>>>> + * store a \\a T value), std::nullopt is returned.\n>>>>> + *\n>>>>> + * \\return The YamlObject value, or std::nullopt if parsing failed\n>>>>> + */\n>>>>> +\n>>>>> +/**\n>>>>> + * \\fn template<typename T> YamlObject::get<T>(const T &defaultValue) const\n>>>>>   * \\brief Parse the YamlObject as a \\a T value\n>>>>>   * \\param[in] defaultValue The default value when failing to parse\n>>>>> - * \\param[out] ok The result of whether the parse succeeded\n>>>>>   *\n>>>>>   * This function parses the value of the YamlObject as a \\a T object, and\n>>>>>   * returns the value. If parsing fails (usually because the YamlObject doesn't\n>>>>> - * store a \\a T value), the \\a defaultValue is returned, and \\a ok is set to\n>>>>> - * false. Otherwise, the YamlObject value is returned, and \\a ok is set to true.\n>>>>> + * store a \\a T value), the \\a defaultValue is returned.\n>>>>>   *\n>>>>> - * The \\a ok pointer is optional and can be a nullptr if the caller doesn't\n>>>>> - * need to know if parsing succeeded.\n>>>>> - *\n>>>>> - * \\return Value as a bool type\n>>>>> + * \\return The YamlObject value, or \\a defaultValue if parsing failed\n>>>>>   */\n>>>>>\n>>>>>  #ifndef __DOXYGEN__\n>>>>>\n>>>>>  template<>\n>>>>> -bool YamlObject::get(const bool &defaultValue, bool *ok) const\n>>>>> +std::optional<bool> YamlObject::get() const\n>>>>>  {\n>>>>> -\tsetOk(ok, false);\n>>>>> -\n>>>>>  \tif (type_ != Type::Value)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\tif (value_ == \"true\") {\n>>>>> -\t\tsetOk(ok, true);\n>>>>> +\tif (value_ == \"true\")\n>>>>>  \t\treturn true;\n>>>>> -\t} else if (value_ == \"false\") {\n>>>>> -\t\tsetOk(ok, true);\n>>>>> +\telse if (value_ == \"false\")\n>>>>>  \t\treturn false;\n>>>>> -\t}\n>>>>>\n>>>>> -\treturn defaultValue;\n>>>>> +\treturn {};\n>>>>>  }\n>>>>>\n>>>>>  template<>\n>>>>> -int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n>>>>> +std::optional<int16_t> YamlObject::get() const\n>>>>>  {\n>>>>> -\tsetOk(ok, false);\n>>>>> -\n>>>>>  \tif (type_ != Type::Value)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tif (value_ == \"\")\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tchar *end;\n>>>>>\n>>>>> @@ -157,22 +149,19 @@ int16_t YamlObject::get(const int16_t &defaultValue, bool *ok) const\n>>>>>  \tif ('\\0' != *end || errno == ERANGE ||\n>>>>>  \t    value < std::numeric_limits<int16_t>::min() ||\n>>>>>  \t    value > std::numeric_limits<int16_t>::max())\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\tsetOk(ok, true);\n>>>>>  \treturn value;\n>>>>>  }\n>>>>>\n>>>>>  template<>\n>>>>> -uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>>>>> +std::optional<uint16_t> YamlObject::get() const\n>>>>>  {\n>>>>> -\tsetOk(ok, false);\n>>>>> -\n>>>>>  \tif (type_ != Type::Value)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tif (value_ == \"\")\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \t/*\n>>>>>  \t * libyaml parses all scalar values as strings. When a string has\n>>>>> @@ -183,7 +172,7 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>>>>>  \t */\n>>>>>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>>>>>  \tif (found != std::string::npos && value_[found] == '-')\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tchar *end;\n>>>>>\n>>>>> @@ -193,22 +182,19 @@ uint16_t YamlObject::get(const uint16_t &defaultValue, bool *ok) const\n>>>>>  \tif ('\\0' != *end || errno == ERANGE ||\n>>>>>  \t    value < std::numeric_limits<uint16_t>::min() ||\n>>>>>  \t    value > std::numeric_limits<uint16_t>::max())\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\tsetOk(ok, true);\n>>>>>  \treturn value;\n>>>>>  }\n>>>>>\n>>>>>  template<>\n>>>>> -int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n>>>>> +std::optional<int32_t> YamlObject::get() const\n>>>>>  {\n>>>>> -\tsetOk(ok, false);\n>>>>> -\n>>>>>  \tif (type_ != Type::Value)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tif (value_ == \"\")\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tchar *end;\n>>>>>\n>>>>> @@ -218,22 +204,19 @@ int32_t YamlObject::get(const int32_t &defaultValue, bool *ok) const\n>>>>>  \tif ('\\0' != *end || errno == ERANGE ||\n>>>>>  \t    value < std::numeric_limits<int32_t>::min() ||\n>>>>>  \t    value > std::numeric_limits<int32_t>::max())\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\tsetOk(ok, true);\n>>>>>  \treturn value;\n>>>>>  }\n>>>>>\n>>>>>  template<>\n>>>>> -uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>>>>> +std::optional<uint32_t> YamlObject::get() const\n>>>>>  {\n>>>>> -\tsetOk(ok, false);\n>>>>> -\n>>>>>  \tif (type_ != Type::Value)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tif (value_ == \"\")\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \t/*\n>>>>>  \t * libyaml parses all scalar values as strings. When a string has\n>>>>> @@ -244,7 +227,7 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>>>>>  \t */\n>>>>>  \tstd::size_t found = value_.find_first_not_of(\" \\t\");\n>>>>>  \tif (found != std::string::npos && value_[found] == '-')\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tchar *end;\n>>>>>\n>>>>> @@ -254,22 +237,19 @@ uint32_t YamlObject::get(const uint32_t &defaultValue, bool *ok) const\n>>>>>  \tif ('\\0' != *end || errno == ERANGE ||\n>>>>>  \t    value < std::numeric_limits<uint32_t>::min() ||\n>>>>>  \t    value > std::numeric_limits<uint32_t>::max())\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\tsetOk(ok, true);\n>>>>>  \treturn value;\n>>>>>  }\n>>>>>\n>>>>>  template<>\n>>>>> -double YamlObject::get(const double &defaultValue, bool *ok) const\n>>>>> +std::optional<double> YamlObject::get() const\n>>>>>  {\n>>>>> -\tsetOk(ok, false);\n>>>>> -\n>>>>>  \tif (type_ != Type::Value)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tif (value_ == \"\")\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tchar *end;\n>>>>>\n>>>>> @@ -277,50 +257,38 @@ double YamlObject::get(const double &defaultValue, bool *ok) const\n>>>>>  \tdouble value = std::strtod(value_.c_str(), &end);\n>>>>>\n>>>>>  \tif ('\\0' != *end || errno == ERANGE)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\tsetOk(ok, true);\n>>>>>  \treturn value;\n>>>>>  }\n>>>>>\n>>>>>  template<>\n>>>>> -std::string YamlObject::get(const std::string &defaultValue, bool *ok) const\n>>>>> +std::optional<std::string> YamlObject::get() const\n>>>>>  {\n>>>>> -\tsetOk(ok, false);\n>>>>> -\n>>>>>  \tif (type_ != Type::Value)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\tsetOk(ok, true);\n>>>>>  \treturn value_;\n>>>>>  }\n>>>>>\n>>>>>  template<>\n>>>>> -Size YamlObject::get(const Size &defaultValue, bool *ok) const\n>>>>> +std::optional<Size> YamlObject::get() const\n>>>>>  {\n>>>>> -\tsetOk(ok, false);\n>>>>> -\n>>>>>  \tif (type_ != Type::List)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>>  \tif (list_.size() != 2)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\t/*\n>>>>> -\t * Add a local variable to validate each dimension in case\n>>>>> -\t * that ok == nullptr.\n>>>>> -\t */\n>>>>> -\tbool valid;\n>>>>> -\tuint32_t width = list_[0]->get<uint32_t>(0, &valid);\n>>>>> -\tif (!valid)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\tauto width = list_[0]->get<uint32_t>();\n>>>>> +\tif (!width)\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\tuint32_t height = list_[1]->get<uint32_t>(0, &valid);\n>>>>> -\tif (!valid)\n>>>>> -\t\treturn defaultValue;\n>>>>> +\tauto height = list_[1]->get<uint32_t>();\n>>>>> +\tif (!height)\n>>>>> +\t\treturn {};\n>>>>>\n>>>>> -\tsetOk(ok, true);\n>>>>> -\treturn Size(width, height);\n>>>>> +\treturn Size(*width, *height);\n>>>>>  }\n>>>>>\n>>>>>  #endif /* __DOXYGEN__ */\n>>>>> diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp\n>>>>> index 38f848232fa6..ebb654f2ef9c 100644\n>>>>> --- a/test/yaml-parser.cpp\n>>>>> +++ b/test/yaml-parser.cpp\n>>>>> @@ -148,7 +148,6 @@ protected:\n>>>>>  \t\t}\n>>>>>\n>>>>>  \t\t/* Test string object */\n>>>>> -\t\tbool ok;\n>>>>>  \t\tauto &strObj = (*root)[\"string\"];\n>>>>>\n>>>>>  \t\tif (strObj.isDictionary()) {\n>>>>> @@ -161,27 +160,27 @@ protected:\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (strObj.get<string>(\"\", &ok) != \"libcamera\" || !ok) {\n>>>>> +\t\tif (strObj.get<string>().value_or(\"\") != \"libcamera\") {\n>>>>>  \t\t\tcerr << \"String object parse as wrong content\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (strObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>>>> +\t\tif (strObj.get<int32_t>()) {\n>>>>>  \t\t\tcerr << \"String object parse as integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (strObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>>>> +\t\tif (strObj.get<uint32_t>()) {\n>>>>>  \t\t\tcerr << \"String object parse as unsigned integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (strObj.get<double>(1.0, &ok) != 1.0 || ok) {\n>>>>> +\t\tif (strObj.get<double>()) {\n>>>>>  \t\t\tcerr << \"String object parse as double\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (strObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>>>> +\t\tif (strObj.get<Size>()) {\n>>>>>  \t\t\tcerr << \"String object parse as Size\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>> @@ -199,27 +198,27 @@ protected:\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (int32Obj.get<int32_t>(-100, &ok) != -100 || !ok) {\n>>>>> +\t\tif (int32Obj.get<int32_t>().value_or(0) != -100) {\n>>>>>  \t\t\tcerr << \"Integer object parse as wrong value\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (int32Obj.get<string>(\"\", &ok) != \"-100\" || !ok) {\n>>>>> +\t\tif (int32Obj.get<string>().value_or(\"\") != \"-100\") {\n>>>>>  \t\t\tcerr << \"Integer object fail to parse as string\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (int32Obj.get<double>(1.0, &ok) != -100.0 || !ok) {\n>>>>> +\t\tif (int32Obj.get<double>().value_or(0.0) != -100.0) {\n>>>>>  \t\t\tcerr << \"Integer object fail to parse as double\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (int32Obj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>>>> +\t\tif (int32Obj.get<uint32_t>()) {\n>>>>>  \t\t\tcerr << \"Negative integer object parse as unsigned integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (int32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>>>> +\t\tif (int32Obj.get<Size>()) {\n>>>>>  \t\t\tcerr << \"Integer object parse as Size\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>> @@ -237,27 +236,27 @@ protected:\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (uint32Obj.get<int32_t>(-1, &ok) != 100 || !ok) {\n>>>>> +\t\tif (uint32Obj.get<int32_t>().value_or(0) != 100) {\n>>>>>  \t\t\tcerr << \"Unsigned integer object fail to parse as integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (uint32Obj.get<string>(\"\", &ok) != \"100\" || !ok) {\n>>>>> +\t\tif (uint32Obj.get<string>().value_or(\"\") != \"100\") {\n>>>>>  \t\t\tcerr << \"Unsigned integer object fail to parse as string\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (uint32Obj.get<double>(1.0, &ok) != 100.0 || !ok) {\n>>>>> +\t\tif (uint32Obj.get<double>().value_or(0.0) != 100.0) {\n>>>>>  \t\t\tcerr << \"Unsigned integer object fail to parse as double\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (uint32Obj.get<uint32_t>(100, &ok) != 100 || !ok) {\n>>>>> +\t\tif (uint32Obj.get<uint32_t>().value_or(0) != 100) {\n>>>>>  \t\t\tcerr << \"Unsigned integer object parsed as wrong value\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (uint32Obj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>>>> +\t\tif (uint32Obj.get<Size>()) {\n>>>>>  \t\t\tcerr << \"Unsigned integer object parsed as Size\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>> @@ -275,27 +274,27 @@ protected:\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (doubleObj.get<string>(\"\", &ok) != \"3.14159\" || !ok) {\n>>>>> +\t\tif (doubleObj.get<string>().value_or(\"\") != \"3.14159\") {\n>>>>>  \t\t\tcerr << \"Double object fail to parse as string\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (doubleObj.get<double>(1.0, &ok) != 3.14159 || !ok) {\n>>>>> +\t\tif (doubleObj.get<double>().value_or(0.0) != 3.14159) {\n>>>>>  \t\t\tcerr << \"Double object parse as wrong value\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (doubleObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>>>> +\t\tif (doubleObj.get<int32_t>()) {\n>>>>>  \t\t\tcerr << \"Double object parse as integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (doubleObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>>>> +\t\tif (doubleObj.get<uint32_t>()) {\n>>>>>  \t\t\tcerr << \"Double object parse as unsigned integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (doubleObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>>>> +\t\tif (doubleObj.get<Size>()) {\n>>>>>  \t\t\tcerr << \"Double object parse as Size\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>> @@ -313,27 +312,27 @@ protected:\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (sizeObj.get<string>(\"\", &ok) != \"\" || ok) {\n>>>>> +\t\tif (sizeObj.get<string>()) {\n>>>>>  \t\t\tcerr << \"Size object parse as string\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (sizeObj.get<double>(1.0, &ok) != 1.0 || ok) {\n>>>>> +\t\tif (sizeObj.get<double>()) {\n>>>>>  \t\t\tcerr << \"Size object parse as double\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (sizeObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>>>> +\t\tif (sizeObj.get<int32_t>()) {\n>>>>>  \t\t\tcerr << \"Size object parse as integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (sizeObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>>>> +\t\tif (sizeObj.get<uint32_t>()) {\n>>>>>  \t\t\tcerr << \"Size object parse as unsigned integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (sizeObj.get<Size>(Size(0, 0), &ok) != Size(1920, 1080) || !ok) {\n>>>>> +\t\tif (sizeObj.get<Size>().value_or(Size(0, 0)) != Size(1920, 1080)) {\n>>>>>  \t\t\tcerr << \"Size object parse as wrong value\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>> @@ -351,27 +350,27 @@ protected:\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (listObj.get<string>(\"\", &ok) != \"\" || ok) {\n>>>>> +\t\tif (listObj.get<string>()) {\n>>>>>  \t\t\tcerr << \"List object parse as string\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (listObj.get<double>(1.0, &ok) != 1.0 || ok) {\n>>>>> +\t\tif (listObj.get<double>()) {\n>>>>>  \t\t\tcerr << \"List object parse as double\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (listObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>>>> +\t\tif (listObj.get<int32_t>()) {\n>>>>>  \t\t\tcerr << \"List object parse as integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (listObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>>>> +\t\tif (listObj.get<uint32_t>()) {\n>>>>>  \t\t\tcerr << \"List object parse as unsigne integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (listObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>>>> +\t\tif (listObj.get<Size>()) {\n>>>>>  \t\t\tcerr << \"String list object parse as Size\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>> @@ -424,27 +423,27 @@ protected:\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (dictObj.get<string>(\"\", &ok) != \"\" || ok) {\n>>>>> +\t\tif (dictObj.get<string>()) {\n>>>>>  \t\t\tcerr << \"Dictionary object parse as string\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (dictObj.get<double>(1.0, &ok) != 1.0 || ok) {\n>>>>> +\t\tif (dictObj.get<double>()) {\n>>>>>  \t\t\tcerr << \"Dictionary object parse as double\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (dictObj.get<int32_t>(-1, &ok) != -1 || ok) {\n>>>>> +\t\tif (dictObj.get<int32_t>()) {\n>>>>>  \t\t\tcerr << \"Dictionary object parse as integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (dictObj.get<uint32_t>(1, &ok) != 1 || ok) {\n>>>>> +\t\tif (dictObj.get<uint32_t>()) {\n>>>>>  \t\t\tcerr << \"Dictionary object parse as unsigned integer\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\t}\n>>>>>\n>>>>> -\t\tif (dictObj.get<Size>(Size(0, 0), &ok) != Size(0, 0) || ok) {\n>>>>> +\t\tif (dictObj.get<Size>()) {\n>>>>>  \t\t\tcerr << \"Dictionary object parse as Size\" << std::endl;\n>>>>>  \t\t\treturn TestFail;\n>>>>>  \t\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 9CD03C3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  4 Aug 2022 22:06:34 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7885E6332B;\n\tFri,  5 Aug 2022 00:06:33 +0200 (CEST)","from mout.gmx.net (mout.gmx.net [212.227.17.22])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9A910603E6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  5 Aug 2022 00:06:31 +0200 (CEST)","from [192.168.0.158] ([88.152.184.103]) by mail.gmx.net (mrgmx104\n\t[212.227.17.168]) with ESMTPSA (Nemesis) id\n\t1M1HZi-1oI55o3KFm-002keC for\n\t<libcamera-devel@lists.libcamera.org>; Fri, 05 Aug 2022 00:06:30 +0200"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659650793;\n\tbh=Bv/BBDHbZIpeZ2KJEH/G3b/03MP7OSdfZnmbklNSjsM=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=DG6cDtcmafamphbdeV6QsuSNvE+KRng616EWmuKyJ7nnLbibgKs2WhPJOQYXVV6Vf\n\t2YH6GOrKDI+5XN9cI3srcdGDS0sAFhCw5x6yksWNhHq6haSa4BHVRXS8MfMCu9WeNg\n\tJH2hbRAO4NuUXtFOuXxWAH5IPHqe3D2qZ3MrgwbvwmorExY90XttqOmqv7gqNRgGN9\n\tuS4J2K8FHSaH7etKrKVuQOrBS5jyJ1mxitVqw6owC7uosRu9GRiamWmoE5VNJBGnn6\n\tBJp41cZ85dIzZG3aVHX9woWBzppruHXz3TD82/M3E5hP/FJhbX8WvNPBl275MFA5RP\n\tVlR05dzc21/cQ==","v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net;\n\ts=badeba3b8450; t=1659650791;\n\tbh=Bv/BBDHbZIpeZ2KJEH/G3b/03MP7OSdfZnmbklNSjsM=;\n\th=X-UI-Sender-Class:Date:Subject:To:References:From:In-Reply-To;\n\tb=TsDxJ4Kx+bXKwY+45VNIo9YALF6LTcSY6GrxW/wcnCnFaK5ZovOAUugf+DT/6s5mi\n\teXCFR2LLwTjaHAzAiyUTygLokyTqji5CGOMlQ1Tkq8EHfaOGd1eN9oWkX0Oz+Z1cI4\n\teIvsDSOMe+X17WeXzQf4G1Sv9/m3n35b3CBggRsw="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=gmx.net header.i=@gmx.net\n\theader.b=\"TsDxJ4Kx\"; dkim-atps=neutral","X-UI-Sender-Class":"01bb95c1-4bf8-414a-932a-4f6e2808ef9c","Message-ID":"<51e9ae7c-d91b-37e1-4d8a-4034519be67f@gmx.de>","Date":"Fri, 5 Aug 2022 00:06:30 +0200","MIME-Version":"1.0","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101\n\tThunderbird/91.11.0","Content-Language":"en-GB","To":"libcamera-devel@lists.libcamera.org","References":"<20220727222149.30627-1-laurent.pinchart@ideasonboard.com>\n\t<20220727222149.30627-3-laurent.pinchart@ideasonboard.com>\n\t<791711aa-0211-72d5-f5d7-377e77661efd@gmx.de>\n\t<YumevpvF8wO0PpxL@pendragon.ideasonboard.com>\n\t<8660cbbf-71e0-b2b6-7e15-d872912367ab@gmx.de>\n\t<YurywHQzAKDGBA1Z@pendragon.ideasonboard.com>","In-Reply-To":"<YurywHQzAKDGBA1Z@pendragon.ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"quoted-printable","X-Provags-ID":"V03:K1:ujxaST/7pPbOplIhQYP2zmWOug5CTzGb8TLOQrrzdHsROOxZ/L7\n\tudt/azrniTv2RhBwPR4HRw1OgzAj0ep/AzbJYlRULHhHDxN+1Tt0JyJ77kFJkFOdbk0ebAk\n\tAcZ1nZ0rtPCGVRLsSwbk7WtCTr9WXF4nyFPfHT633E32hNrXrTCu6taF8iM4X3+4dI1q9d+\n\tvbFddQFM0oo0dUhXejDhg==","X-Spam-Flag":"NO","X-UI-Out-Filterresults":"notjunk:1; V03:K0:KuahaFJckJ8=:YHbg/HNEgkBfCQU5W3YZad\n\taxgtim1idf1nU3jTca078e4hDGSc70jbRiivsxghTySE0Rvrybn1TDD/ooLXjNST0lbhG/BEd\n\tDSZcgFgXMp6mSVnVO9sd+naw1jalm833+1D8ACVx8BuB/7ABhWNQzoqix5X7vC3yfPsM0fFvp\n\trFA5boN3mc7dZrQzNLu9tLVJLxh6y3Z5ngxc/trG+rSd4MJHJyQk8osesVU09nqb6qQrbJaNX\n\tuWd30xUwuXf0r2Zh2lF80MGYDg09eLxKUxxmJEiKad+IVUQbz4HB0tRq3/xIsBNg/+VvZW2bz\n\tK1yxUpHQzgQHGi7OkYDt+rJu5QpZzFycwTPRZyY7aFJbWtCzyEMpC64Pbn4wfNlfug1Zo1H5C\n\te5Tx6fSMI4YgXlrCnQY9DLSH6aWXus+AfDjjvYMyCm/RIYKUGLLbhwQXoICtV0EdPjBC+kK1T\n\tWfEURBbPltiHJSsK3hNsT8lEjDuBbN7m+vGt+Ity9QlbfH5FA2yvF2oX/t5E/hWpqQfvhuVTg\n\trD35MtiGTR3WdnUAAmsQqOTicZPCNVoJceeU55QNWD2BbEITtRK3/dIHxNupTB4hHEq7my2pZ\n\tr5rAFSOKhd1I8x8f+6O3awfiftfUctUqCtklYxJpQr81pc2Egu5+3z2EfgEDb4hdQN0MkdYHb\n\tYA6mwsGiwT5F9ovtxCvEwuWNXyqxSsV2/+vXJAsoOx1UTOBeTOa7CcOjmZXuHaq1EIG/I0QRA\n\tuuAKha4JwXhqpqQZe9RJMcI925nXYWKutuvu11faeykmy2rNiBE9zy7Dfv6pc+8v1a/jLvKEo\n\tREKCYuCoXW/NT6IJw0gazwhNog1CpYXTlNv2RrecvdR7E1SAp0f5MaP91yt7HfFqrD2st6DlX\n\tWqskqkLA/KK0OkvYUwPZv8H3sHariPAhwRc3riOXu9Xurv61kgHhYOBcf8kFLrrcIzceqY1B7\n\tqc85kkgsPU1bgOlB7mUbpBvnr3uIovHEqJmxshBTePoWc2mHmmCR/CCvzOnnl4yOUSPdF34Ol\n\tkRyQtGcn9p7v0aoQMpJI6gr4KxuAIdYvKB/YEGd6oKz8l8i1rboo71eDg7NWE7rBu7enFUf5y\n\taEW7if8tl/yUNbNOCLdAyNag6m15aLD7N3EHiwaniJqt7jJid0lVYwGaw==","Subject":"Re: [libcamera-devel] [PATCH v5 2/9] libcamera: yaml_parser:\n\tReplace ok flag to get() with std::optional","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>","From":"Christian Rauch via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Christian Rauch <Rauch.Christian@gmx.de>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]