Show a patch.

GET /api/patches/12299/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 12299,
    "url": "https://patchwork.libcamera.org/api/patches/12299/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/12299/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20210515040511.23294-2-laurent.pinchart@ideasonboard.com>",
    "date": "2021-05-15T04:05:08",
    "name": "[libcamera-devel,v2,1/4] libcamera: utils: Add enumerate view for range-based for loops",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "fae303a0f1944f3beb6bf729828bb621193566f8",
    "submitter": {
        "id": 2,
        "url": "https://patchwork.libcamera.org/api/people/2/?format=api",
        "name": "Laurent Pinchart",
        "email": "laurent.pinchart@ideasonboard.com"
    },
    "delegate": {
        "id": 14,
        "url": "https://patchwork.libcamera.org/api/users/14/?format=api",
        "username": "pinchartl",
        "first_name": "Laurent",
        "last_name": "Pinchart",
        "email": "laurent.pinchart@ideasonboard.com"
    },
    "mbox": "https://patchwork.libcamera.org/patch/12299/mbox/",
    "series": [
        {
            "id": 2032,
            "url": "https://patchwork.libcamera.org/api/series/2032/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=2032",
            "date": "2021-05-15T04:05:07",
            "name": "libcamera: Simplify range-based for loop counters",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/2032/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/12299/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/12299/checks/",
    "tags": {},
    "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 F1284C31F6\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 15 May 2021 04:05:27 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B1E0468922;\n\tSat, 15 May 2021 06:05:26 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7C1566890E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 15 May 2021 06:05:25 +0200 (CEST)",
            "from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id F2BCE6EE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 15 May 2021 06:05:24 +0200 (CEST)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"I3V98h+B\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1621051525;\n\tbh=9a7WHIyNzHJhF1vP7jYh9uigTP9HJd/ga9ckyToKuN0=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=I3V98h+Bz+DY0j/5jWP7KSUJY44hmA/pT1zuK5xukREIIYPSw2Ji4ZyzQld/tXJOt\n\teZ2Xi04s1W4eGQzkMPgiA87INfHNUJ1Xffz8xv9vxv4mKMEVVUh6X0OiJ3g4IG1ABC\n\twJP9ezNfmrK4uUSvOO9MDwczyJtqC0w+KoCxjG3M=",
        "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Sat, 15 May 2021 07:05:08 +0300",
        "Message-Id": "<20210515040511.23294-2-laurent.pinchart@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.28.1",
        "In-Reply-To": "<20210515040511.23294-1-laurent.pinchart@ideasonboard.com>",
        "References": "<20210515040511.23294-1-laurent.pinchart@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Subject": "[libcamera-devel] [PATCH v2 1/4] libcamera: utils: Add enumerate\n\tview for range-based for loops",
        "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>",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Range-based for loops are handy and widely preferred in C++, but are\nlimited in their ability to replace for loops that require access to a\nloop counter.  The enumerate() function solves this problem by wrapping\nthe \\a iterable in an adapter that, when used as a range-expression,\nwill provide iterators whose value_type is a pair of index and value\nreference.\n\nThe iterable must support std::begin() and std::end(). This includes all\ncontainers provided by the standard C++ library, as well as C-style\narrays.\n\nA typical usage pattern would use structured binding to store the index\nand value in two separate variables:\n\nstd::vector<int> values = ...;\n\nfor (auto [index, value] : utils::enumerate(values)) {\n     ...\n}\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\nChanges since v1:\n\n- Hardcoded enumerate_iterator::iterator_category to\n  std::input_iterator_tag\n- Made the enumerate_adapter begin(), end(), begin_ and end_ const\n---\n include/libcamera/internal/utils.h | 86 ++++++++++++++++++++++++++++++\n src/libcamera/utils.cpp            | 29 ++++++++++\n test/utils.cpp                     | 59 ++++++++++++++++++++\n 3 files changed, 174 insertions(+)",
    "diff": "diff --git a/include/libcamera/internal/utils.h b/include/libcamera/internal/utils.h\nindex d0146b71727d..83dada7cc16c 100644\n--- a/include/libcamera/internal/utils.h\n+++ b/include/libcamera/internal/utils.h\n@@ -9,12 +9,14 @@\n \n #include <algorithm>\n #include <chrono>\n+#include <iterator>\n #include <memory>\n #include <ostream>\n #include <sstream>\n #include <string>\n #include <string.h>\n #include <sys/time.h>\n+#include <utility>\n #include <vector>\n \n #ifndef __DOXYGEN__\n@@ -230,6 +232,90 @@ details::reverse_adapter<T> reverse(T &&iterable)\n \treturn { iterable };\n }\n \n+namespace details {\n+\n+template<typename Base>\n+class enumerate_iterator\n+{\n+private:\n+\tusing base_reference = typename std::iterator_traits<Base>::reference;\n+\n+public:\n+\tusing difference_type = typename std::iterator_traits<Base>::difference_type;\n+\tusing value_type = std::pair<const difference_type, base_reference>;\n+\tusing pointer = value_type *;\n+\tusing reference = value_type &;\n+\tusing iterator_category = std::input_iterator_tag;\n+\n+\texplicit enumerate_iterator(Base iter)\n+\t\t: current_(iter), pos_(0)\n+\t{\n+\t}\n+\n+\tenumerate_iterator &operator++()\n+\t{\n+\t\t++current_;\n+\t\t++pos_;\n+\t\treturn *this;\n+\t}\n+\n+\tbool operator!=(const enumerate_iterator &other) const\n+\t{\n+\t\treturn current_ != other.current_;\n+\t}\n+\n+\tvalue_type operator*() const\n+\t{\n+\t\treturn { pos_, *current_ };\n+\t}\n+\n+private:\n+\tBase current_;\n+\tdifference_type pos_;\n+};\n+\n+template<typename Base>\n+class enumerate_adapter\n+{\n+public:\n+\tusing iterator = enumerate_iterator<Base>;\n+\n+\tenumerate_adapter(Base begin, Base end)\n+\t\t: begin_(begin), end_(end)\n+\t{\n+\t}\n+\n+\titerator begin() const\n+\t{\n+\t\treturn iterator{ begin_ };\n+\t}\n+\n+\titerator end() const\n+\t{\n+\t\treturn iterator{ end_ };\n+\t}\n+\n+private:\n+\tconst Base begin_;\n+\tconst Base end_;\n+};\n+\n+} /* namespace details */\n+\n+template<typename T>\n+auto enumerate(T &iterable) -> details::enumerate_adapter<decltype(iterable.begin())>\n+{\n+\treturn { std::begin(iterable), std::end(iterable) };\n+}\n+\n+#ifndef __DOXYGEN__\n+template<typename T, size_t N>\n+auto enumerate(T (&iterable)[N]) -> details::enumerate_adapter<T *>\n+{\n+\treturn { std::begin(iterable), std::end(iterable) };\n+}\n+#endif\n+\n } /* namespace utils */\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp\nindex c4098a74e0ab..ff9a5832b10e 100644\n--- a/src/libcamera/utils.cpp\n+++ b/src/libcamera/utils.cpp\n@@ -472,6 +472,35 @@ std::string libcameraSourcePath()\n  * loop, will cause the loop to iterate over the \\a iterable in reverse order\n  */\n \n+/**\n+ * \\fn enumerate(T &iterable)\n+ * \\brief Wrap an iterable to enumerate index and value in a range-based loop\n+ * \\param[in] iterable The iterable\n+ *\n+ * Range-based for loops are handy and widely preferred in C++, but are limited\n+ * in their ability to replace for loops that require access to a loop counter.\n+ * The enumerate() function solves this problem by wrapping the \\a iterable in\n+ * an adapter that, when used as a range-expression, will provide iterators\n+ * whose value_type is a pair of index and value reference.\n+ *\n+ * The iterable must support std::begin() and std::end(). This includes all\n+ * containers provided by the standard C++ library, as well as C-style arrays.\n+ *\n+ * A typical usage pattern would use structured binding to store the index and\n+ * value in two separate variables:\n+ *\n+ * \\code{.cpp}\n+ * std::vector<int> values = ...;\n+ *\n+ * for (auto [index, value] : utils::enumerate(values)) {\n+ * \t...\n+ * }\n+ * \\endcode\n+ *\n+ * \\return A value of unspecified type that, when used in a range-based for\n+ * loop, iterates over an indexed view of the \\a iterable\n+ */\n+\n } /* namespace utils */\n \n } /* namespace libcamera */\ndiff --git a/test/utils.cpp b/test/utils.cpp\nindex 08f293898fd9..7e24c71e4775 100644\n--- a/test/utils.cpp\n+++ b/test/utils.cpp\n@@ -12,6 +12,7 @@\n #include <vector>\n \n #include <libcamera/geometry.h>\n+#include <libcamera/span.h>\n \n #include \"libcamera/internal/utils.h\"\n \n@@ -73,6 +74,60 @@ protected:\n \t\treturn TestPass;\n \t}\n \n+\tint testEnumerate()\n+\t{\n+\t\tstd::vector<int> integers{ 1, 2, 3, 4, 5 };\n+\t\tint i = 0;\n+\n+\t\tfor (auto [index, value] : utils::enumerate(integers)) {\n+\t\t\tif (index != i || value != i + 1) {\n+\t\t\t\tcerr << \"utils::enumerate(<vector>) test failed: i=\" << i\n+\t\t\t\t     << \", index=\" << index << \", value=\" << value\n+\t\t\t\t     << std::endl;\n+\t\t\t\treturn TestFail;\n+\t\t\t}\n+\n+\t\t\t/* Verify that we can modify the value. */\n+\t\t\t--value;\n+\t\t\t++i;\n+\t\t}\n+\n+\t\tif (integers != std::vector<int>{ 0, 1, 2, 3, 4 }) {\n+\t\t\tcerr << \"Failed to modify container in enumerated range loop\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\tSpan<const int> span{ integers };\n+\t\ti = 0;\n+\n+\t\tfor (auto [index, value] : utils::enumerate(span)) {\n+\t\t\tif (index != i || value != i) {\n+\t\t\t\tcerr << \"utils::enumerate(<span>) test failed: i=\" << i\n+\t\t\t\t     << \", index=\" << index << \", value=\" << value\n+\t\t\t\t     << std::endl;\n+\t\t\t\treturn TestFail;\n+\t\t\t}\n+\n+\t\t\t++i;\n+\t\t}\n+\n+\t\tconst int array[] = { 0, 2, 4, 6, 8 };\n+\t\ti = 0;\n+\n+\t\tfor (auto [index, value] : utils::enumerate(array)) {\n+\t\t\tif (index != i || value != i * 2) {\n+\t\t\t\tcerr << \"utils::enumerate(<array>) test failed: i=\" << i\n+\t\t\t\t     << \", index=\" << index << \", value=\" << value\n+\t\t\t\t     << std::endl;\n+\t\t\t\treturn TestFail;\n+\t\t\t}\n+\n+\t\t\t++i;\n+\t\t}\n+\n+\t\treturn TestPass;\n+\t}\n+\n \tint run()\n \t{\n \t\t/* utils::hex() test. */\n@@ -177,6 +232,10 @@ protected:\n \t\t\treturn TestFail;\n \t\t}\n \n+\t\t/* utils::enumerate() test. */\n+\t\tif (testEnumerate() != TestPass)\n+\t\t\treturn TestFail;\n+\n \t\treturn TestPass;\n \t}\n };\n",
    "prefixes": [
        "libcamera-devel",
        "v2",
        "1/4"
    ]
}