[{"id":2894,"web_url":"https://patchwork.libcamera.org/comment/2894/","msgid":"<20191013200220.GZ23166@bigcity.dyn.berto.se>","date":"2019-10-13T20:02:20","subject":"Re: [libcamera-devel] [PATCH] libcamera: utils: Add hex stream\n\toutput helper","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Laurent,\n\nThanks for your work.\n\nOn 2019-10-13 22:23:46 +0300, Laurent Pinchart wrote:\n> Add a utils::hex() function that simplifies writing hexadecimal values\n> to an ostream. The function handles the '0x' prefix, the field width and\n> the fill character automatically. Use it through the libcamera code\n> base, and add a test.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nI really like this patch!\n\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\n> ---\n>  src/android/camera_device.cpp      |  2 +-\n>  src/libcamera/camera_sensor.cpp    |  6 ++--\n>  src/libcamera/controls.cpp         |  6 ++--\n>  src/libcamera/include/utils.h      | 40 ++++++++++++++++++++++\n>  src/libcamera/stream.cpp           |  7 ++--\n>  src/libcamera/utils.cpp            | 39 ++++++++++++++++++++++\n>  src/libcamera/v4l2_subdevice.cpp   |  6 ++--\n>  src/libcamera/v4l2_videodevice.cpp |  6 ++--\n>  test/camera-sensor.cpp             |  3 +-\n>  test/meson.build                   |  1 +\n>  test/utils.cpp                     | 53 ++++++++++++++++++++++++++++++\n>  11 files changed, 147 insertions(+), 22 deletions(-)\n>  create mode 100644 test/utils.cpp\n> \n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index bf991d5933cd..c7c9b3fd1724 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -640,7 +640,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n>  \t\t\t       << \", direction: \" << stream->stream_type\n>  \t\t\t       << \", width: \" << stream->width\n>  \t\t\t       << \", height: \" << stream->height\n> -\t\t\t       << \", format: \" << std::hex << stream->format;\n> +\t\t\t       << \", format: \" << utils::hex(stream->format);\n>  \t}\n>  \n>  \t/* Hardcode viewfinder role, collecting sizes from the stream config. */\n> diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp\n> index 9e8b44a23850..1b8e8c0e07da 100644\n> --- a/src/libcamera/camera_sensor.cpp\n> +++ b/src/libcamera/camera_sensor.cpp\n> @@ -14,6 +14,7 @@\n>  #include <math.h>\n>  \n>  #include \"formats.h\"\n> +#include \"utils.h\"\n>  #include \"v4l2_subdevice.h\"\n>  \n>  /**\n> @@ -79,9 +80,8 @@ int CameraSensor::init()\n>  \n>  \tif (entity_->function() != MEDIA_ENT_F_CAM_SENSOR) {\n>  \t\tLOG(CameraSensor, Error)\n> -\t\t\t<< \"Invalid sensor function 0x\"\n> -\t\t\t<< std::hex << std::setfill('0') << std::setw(8)\n> -\t\t\t<< entity_->function();\n> +\t\t\t<< \"Invalid sensor function \"\n> +\t\t\t<< utils::hex(entity_->function());\n>  \t\treturn -EINVAL;\n>  \t}\n>  \n> diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp\n> index e46aa438a06e..6a0301f3a2ae 100644\n> --- a/src/libcamera/controls.cpp\n> +++ b/src/libcamera/controls.cpp\n> @@ -549,8 +549,7 @@ const ControlValue &ControlList::get(unsigned int id) const\n>  \tconst auto ctrl = idmap_->find(id);\n>  \tif (ctrl == idmap_->end()) {\n>  \t\tLOG(Controls, Error)\n> -\t\t\t<< std::hex << std::setfill('0')\n> -\t\t\t<< \"Control 0x\" << std::setw(8) << id\n> +\t\t\t<< \"Control \" << utils::hex(id)\n>  \t\t\t<< \" is not supported\";\n>  \t\treturn zero;\n>  \t}\n> @@ -579,8 +578,7 @@ void ControlList::set(unsigned int id, const ControlValue &value)\n>  \tconst auto ctrl = idmap_->find(id);\n>  \tif (ctrl == idmap_->end()) {\n>  \t\tLOG(Controls, Error)\n> -\t\t\t<< std::hex << std::setfill('0')\n> -\t\t\t<< \"Control 0x\" << std::setw(8) << id\n> +\t\t\t<< \"Control 0x\" << utils::hex(id)\n>  \t\t\t<< \" is not supported\";\n>  \t\treturn;\n>  \t}\n> diff --git a/src/libcamera/include/utils.h b/src/libcamera/include/utils.h\n> index 52eee8ac2804..3efb11c119c2 100644\n> --- a/src/libcamera/include/utils.h\n> +++ b/src/libcamera/include/utils.h\n> @@ -10,6 +10,7 @@\n>  #include <algorithm>\n>  #include <chrono>\n>  #include <memory>\n> +#include <ostream>\n>  #include <string>\n>  #include <sys/time.h>\n>  \n> @@ -63,6 +64,45 @@ using time_point = std::chrono::steady_clock::time_point;\n>  struct timespec duration_to_timespec(const duration &value);\n>  std::string time_point_to_string(const time_point &time);\n>  \n> +#ifndef __DOXYGEN__\n> +struct _hex {\n> +\tuint64_t v;\n> +\tunsigned int w;\n> +};\n> +\n> +std::basic_ostream<char, std::char_traits<char>> &\n> +operator<<(std::basic_ostream<char, std::char_traits<char>> &stream, const _hex &h);\n> +#endif\n> +\n> +template<typename T>\n> +_hex hex(T value, unsigned int width = 0);\n> +\n> +#ifndef __DOXYGEN__\n> +template<>\n> +inline _hex hex<int32_t>(int32_t value, unsigned int width)\n> +{\n> +\treturn { static_cast<uint64_t>(value), width ? width : 8 };\n> +}\n> +\n> +template<>\n> +inline _hex hex<uint32_t>(uint32_t value, unsigned int width)\n> +{\n> +\treturn { static_cast<uint64_t>(value), width ? width : 8 };\n> +}\n> +\n> +template<>\n> +inline _hex hex<int64_t>(int64_t value, unsigned int width)\n> +{\n> +\treturn { static_cast<uint64_t>(value), width ? width : 16 };\n> +}\n> +\n> +template<>\n> +inline _hex hex<uint64_t>(uint64_t value, unsigned int width)\n> +{\n> +\treturn { static_cast<uint64_t>(value), width ? width : 16 };\n> +}\n> +#endif\n> +\n>  } /* namespace utils */\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp\n> index c28b4cd669b2..610920d1e5b3 100644\n> --- a/src/libcamera/stream.cpp\n> +++ b/src/libcamera/stream.cpp\n> @@ -16,6 +16,7 @@\n>  #include <libcamera/request.h>\n>  \n>  #include \"log.h\"\n> +#include \"utils.h\"\n>  \n>  /**\n>   * \\file stream.h\n> @@ -367,11 +368,7 @@ StreamConfiguration::StreamConfiguration(const StreamFormats &formats)\n>  std::string StreamConfiguration::toString() const\n>  {\n>  \tstd::stringstream ss;\n> -\n> -\tss.fill(0);\n> -\tss << size.toString() << \"-0x\" << std::hex << std::setw(8)\n> -\t   << pixelFormat;\n> -\n> +\tss << size.toString() << \"-\" << utils::hex(pixelFormat);\n>  \treturn ss.str();\n>  }\n>  \n> diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp\n> index 928db254ec67..d632f6e66638 100644\n> --- a/src/libcamera/utils.cpp\n> +++ b/src/libcamera/utils.cpp\n> @@ -143,6 +143,45 @@ std::string time_point_to_string(const time_point &time)\n>  \treturn ossTimestamp.str();\n>  }\n>  \n> +std::basic_ostream<char, std::char_traits<char>> &\n> +operator<<(std::basic_ostream<char, std::char_traits<char>> &stream, const _hex &h)\n> +{\n> +\tstream << \"0x\";\n> +\n> +\tstd::ostream::fmtflags flags = stream.setf(std::ios_base::hex,\n> +\t\t\t\t\t\t   std::ios_base::basefield);\n> +\tstd::streamsize width = stream.width(h.w);\n> +\tchar fill = stream.fill('0');\n> +\n> +\tstream << h.v;\n> +\n> +\tstream.flags(flags);\n> +\tstream.width(width);\n> +\tstream.fill(fill);\n> +\n> +\treturn stream;\n> +}\n> +\n> +/**\n> + * \\fn hex(T value, unsigned int width)\n> + * \\brief Write an hexadecimal value to an output string\n> + * \\param value The value\n> + * \\param width The width\n> + *\n> + * Return an object of unspecified type such that, if \\a os is the name of an\n> + * output stream of type std::ostream, and T is an integer type, then the\n> + * expression\n> + *\n> + * \\code{.cpp}\n> + * os << utils::hex(value)\n> + * \\endcode\n> + *\n> + * will output the \\a value to the stream in hexadecimal form with the base\n> + * prefix and the filling character set to '0'. The field width is set to \\a\n> + * width if specified to a non-zero value, or to the native width of type T\n> + * otherwise. The \\a os stream configuration is not modified.\n> + */\n> +\n>  } /* namespace utils */\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\n> index a188298de34c..f2bcd7f73c5c 100644\n> --- a/src/libcamera/v4l2_subdevice.cpp\n> +++ b/src/libcamera/v4l2_subdevice.cpp\n> @@ -21,6 +21,7 @@\n>  #include \"log.h\"\n>  #include \"media_device.h\"\n>  #include \"media_object.h\"\n> +#include \"utils.h\"\n>  \n>  /**\n>   * \\file v4l2_subdevice.h\n> @@ -76,10 +77,7 @@ LOG_DECLARE_CATEGORY(V4L2)\n>  const std::string V4L2SubdeviceFormat::toString() const\n>  {\n>  \tstd::stringstream ss;\n> -\n> -\tss.fill(0);\n> -\tss << size.toString() << \"-0x\" << std::hex << std::setw(4) << mbus_code;\n> -\n> +\tss << size.toString() << \"-\" << utils::hex(mbus_code, 4);\n>  \treturn ss.str();\n>  }\n>  \n> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\n> index eb4e44deb4a5..208ab54199b1 100644\n> --- a/src/libcamera/v4l2_videodevice.cpp\n> +++ b/src/libcamera/v4l2_videodevice.cpp\n> @@ -23,6 +23,7 @@\n>  #include \"log.h\"\n>  #include \"media_device.h\"\n>  #include \"media_object.h\"\n> +#include \"utils.h\"\n>  \n>  /**\n>   * \\file v4l2_videodevice.h\n> @@ -239,10 +240,7 @@ LOG_DECLARE_CATEGORY(V4L2)\n>  const std::string V4L2DeviceFormat::toString() const\n>  {\n>  \tstd::stringstream ss;\n> -\n> -\tss.fill(0);\n> -\tss << size.toString() << \"-0x\" << std::hex << std::setw(8) << fourcc;\n> -\n> +\tss << size.toString() << \"-\" << utils::hex(fourcc);\n>  \treturn ss.str();\n>  }\n>  \n> diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp\n> index 9fe59cc98d79..27c190fe7ace 100644\n> --- a/test/camera-sensor.cpp\n> +++ b/test/camera-sensor.cpp\n> @@ -13,6 +13,7 @@\n>  #include \"camera_sensor.h\"\n>  #include \"device_enumerator.h\"\n>  #include \"media_device.h\"\n> +#include \"utils.h\"\n>  #include \"v4l2_subdevice.h\"\n>  \n>  #include \"test.h\"\n> @@ -91,7 +92,7 @@ protected:\n>  \t\tif (format.mbus_code != MEDIA_BUS_FMT_SBGGR10_1X10 ||\n>  \t\t    format.size != Size(4096, 2160)) {\n>  \t\t\tcerr << \"Failed to get a suitable format, expected 4096x2160-0x\"\n> -\t\t\t     << std::hex << MEDIA_BUS_FMT_SBGGR10_1X10\n> +\t\t\t     << utils::hex(MEDIA_BUS_FMT_SBGGR10_1X10)\n>  \t\t\t     << \", got \" << format.toString() << endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> diff --git a/test/meson.build b/test/meson.build\n> index 84722cceb35d..cf5eb84d20b2 100644\n> --- a/test/meson.build\n> +++ b/test/meson.build\n> @@ -30,6 +30,7 @@ internal_tests = [\n>      ['threads',                         'threads.cpp'],\n>      ['timer',                           'timer.cpp'],\n>      ['timer-thread',                    'timer-thread.cpp'],\n> +    ['utils',                           'utils.cpp'],\n>  ]\n>  \n>  foreach t : public_tests\n> diff --git a/test/utils.cpp b/test/utils.cpp\n> new file mode 100644\n> index 000000000000..9fe0d4775b73\n> --- /dev/null\n> +++ b/test/utils.cpp\n> @@ -0,0 +1,53 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2018, Google Inc.\n> + *\n> + * utils.cpp - Miscellaneous utility tests\n> + */\n> +\n> +#include <iostream>\n> +#include <sstream>\n> +\n> +#include \"test.h\"\n> +#include \"utils.h\"\n> +\n> +using namespace std;\n> +using namespace libcamera;\n> +\n> +class UtilsTest : public Test\n> +{\n> +protected:\n> +\tint run()\n> +\t{\n> +\t\tstd::ostringstream os;\n> +\t\tstd::string ref;\n> +\n> +\t\tos << utils::hex(static_cast<int32_t>(0x42)) << \" \";\n> +\t\tref += \"0x00000042 \";\n> +\t\tos << utils::hex(static_cast<uint32_t>(0x42)) << \" \";\n> +\t\tref += \"0x00000042 \";\n> +\t\tos << utils::hex(static_cast<int64_t>(0x42)) << \" \";\n> +\t\tref += \"0x0000000000000042 \";\n> +\t\tos << utils::hex(static_cast<uint64_t>(0x42)) << \" \";\n> +\t\tref += \"0x0000000000000042 \";\n> +\t\tos << utils::hex(static_cast<int32_t>(0x42), 4) << \" \";\n> +\t\tref += \"0x0042 \";\n> +\t\tos << utils::hex(static_cast<uint32_t>(0x42), 1) << \" \";\n> +\t\tref += \"0x42 \";\n> +\t\tos << utils::hex(static_cast<int64_t>(0x42), 4) << \" \";\n> +\t\tref += \"0x0042 \";\n> +\t\tos << utils::hex(static_cast<uint64_t>(0x42), 1) << \" \";\n> +\t\tref += \"0x42 \";\n> +\n> +\t\tstd::string s = os.str();\n> +\t\tif (s != ref) {\n> +\t\t\tcerr << \"utils::hex() test failed, expected '\" << ref\n> +\t\t\t     << \"', got '\" << s << \"'\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +};\n> +\n> +TEST_REGISTER(UtilsTest)\n> -- \n> Regards,\n> \n> Laurent Pinchart\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lf1-x143.google.com (mail-lf1-x143.google.com\n\t[IPv6:2a00:1450:4864:20::143])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 31770600F9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 13 Oct 2019 22:02:23 +0200 (CEST)","by mail-lf1-x143.google.com with SMTP id x80so10343159lff.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 13 Oct 2019 13:02:23 -0700 (PDT)","from localhost (h-93-159.A463.priv.bahnhof.se. [46.59.93.159])\n\tby smtp.gmail.com with ESMTPSA id\n\tq66sm3544323ljq.101.2019.10.13.13.02.20\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tSun, 13 Oct 2019 13:02:21 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to\n\t:user-agent; bh=qW2ZuYlAnm/Lkm4bJ+DzfGNEWRLNQEQqCnEq94g3aCI=;\n\tb=qya98x0XduCY0J0W4gq09u7MWnHYPsg256yhSMuvzVIFGex5+E9ajrnitKo8MVYATE\n\tyXk4CrW3QT/AIXT6vwWuY1DyZazdRJdQjZN0fpnmN23PT1RTimNtBhHbKL0RMXidLhRm\n\tupN/IcmFM4+D0gi/c0Kd9g8xJcGYDNZ1O6b5ji1uzXO4f7FpNwVIKd6coznasojYwE3a\n\tqN1Hwf+SayNB2akIVQ+GewNf2Q8oa1yLs8TwaKM5xXqxUpB4Rgce5FwqIQtgzYJWfoyx\n\t+GLz89XniC3mRPGztfxs1thIoMFV6Ln7Pgm1c8EbS0VmRD/dTpSlvdumJrIQ3xMFMyRW\n\t0/dg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to:user-agent;\n\tbh=qW2ZuYlAnm/Lkm4bJ+DzfGNEWRLNQEQqCnEq94g3aCI=;\n\tb=RkUKmJCJNe171MsURmBYeuBSqQNiZYIX1nDq0GahStb032u70q/4G0xN7sylgAQJQF\n\tPehwUgmgj0YJzCZrqD53EThYxu+BsWPBWaF+9Xc5y5lZznTPQHYM71/HdOUEfY4n4TXA\n\t7bRHphi0ZsRLo2awsJhkoLAGAzx54H7PrFrZjXgJlcCGiEyrKgodf83V06yeVWxXwAN3\n\tSrCQXa/5r7GysM5HrTAUzC+XBltktzyI/knCsU2MaV1Bzyd7352cspprgdEde4EqQndb\n\tXFKDtaFzmNXC5yW2hrCr5mv/caWI8YjO3QbGN/0Wc7FoqfNHK/bLGQxuupg5mZNAVnWk\n\t7NJg==","X-Gm-Message-State":"APjAAAVVFq1YzGEST9Sk9VNljT05gxuQ/ejKaNL6p1wmkUXHoI4/vip5\n\tjCZaehwTjBzSDMUZZFAk64M0FsPcD7c=","X-Google-Smtp-Source":"APXvYqwTkEjQ0B28coRABPZp1F7A3VTkolU/uDIs3iQd7tiQhxbwSCEMJvEc8SXPsKDhlXQglk86YQ==","X-Received":"by 2002:a19:5204:: with SMTP id\n\tm4mr14883786lfb.121.1570996942252; \n\tSun, 13 Oct 2019 13:02:22 -0700 (PDT)","Date":"Sun, 13 Oct 2019 22:02:20 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20191013200220.GZ23166@bigcity.dyn.berto.se>","References":"<20191013192346.8270-1-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20191013192346.8270-1-laurent.pinchart@ideasonboard.com>","User-Agent":"Mutt/1.12.1 (2019-06-15)","Subject":"Re: [libcamera-devel] [PATCH] libcamera: utils: Add hex stream\n\toutput helper","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>","X-List-Received-Date":"Sun, 13 Oct 2019 20:02:23 -0000"}},{"id":2905,"web_url":"https://patchwork.libcamera.org/comment/2905/","msgid":"<20191015074618.4q33aj6mygp7xydn@uno.localdomain>","date":"2019-10-15T07:46:18","subject":"Re: [libcamera-devel] [PATCH] libcamera: utils: Add hex stream\n\toutput helper","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Sun, Oct 13, 2019 at 10:23:46PM +0300, Laurent Pinchart wrote:\n> Add a utils::hex() function that simplifies writing hexadecimal values\n> to an ostream. The function handles the '0x' prefix, the field width and\n> the fill character automatically. Use it through the libcamera code\n> base, and add a test.\n>\n\nThanks, very nice to shorten the streams handling\n\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\n\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  src/android/camera_device.cpp      |  2 +-\n>  src/libcamera/camera_sensor.cpp    |  6 ++--\n>  src/libcamera/controls.cpp         |  6 ++--\n>  src/libcamera/include/utils.h      | 40 ++++++++++++++++++++++\n>  src/libcamera/stream.cpp           |  7 ++--\n>  src/libcamera/utils.cpp            | 39 ++++++++++++++++++++++\n>  src/libcamera/v4l2_subdevice.cpp   |  6 ++--\n>  src/libcamera/v4l2_videodevice.cpp |  6 ++--\n>  test/camera-sensor.cpp             |  3 +-\n>  test/meson.build                   |  1 +\n>  test/utils.cpp                     | 53 ++++++++++++++++++++++++++++++\n>  11 files changed, 147 insertions(+), 22 deletions(-)\n>  create mode 100644 test/utils.cpp\n>\n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index bf991d5933cd..c7c9b3fd1724 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -640,7 +640,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n>  \t\t\t       << \", direction: \" << stream->stream_type\n>  \t\t\t       << \", width: \" << stream->width\n>  \t\t\t       << \", height: \" << stream->height\n> -\t\t\t       << \", format: \" << std::hex << stream->format;\n> +\t\t\t       << \", format: \" << utils::hex(stream->format);\n>  \t}\n>\n>  \t/* Hardcode viewfinder role, collecting sizes from the stream config. */\n> diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp\n> index 9e8b44a23850..1b8e8c0e07da 100644\n> --- a/src/libcamera/camera_sensor.cpp\n> +++ b/src/libcamera/camera_sensor.cpp\n> @@ -14,6 +14,7 @@\n>  #include <math.h>\n>\n>  #include \"formats.h\"\n> +#include \"utils.h\"\n>  #include \"v4l2_subdevice.h\"\n>\n>  /**\n> @@ -79,9 +80,8 @@ int CameraSensor::init()\n>\n>  \tif (entity_->function() != MEDIA_ENT_F_CAM_SENSOR) {\n>  \t\tLOG(CameraSensor, Error)\n> -\t\t\t<< \"Invalid sensor function 0x\"\n> -\t\t\t<< std::hex << std::setfill('0') << std::setw(8)\n> -\t\t\t<< entity_->function();\n> +\t\t\t<< \"Invalid sensor function \"\n> +\t\t\t<< utils::hex(entity_->function());\n>  \t\treturn -EINVAL;\n>  \t}\n>\n> diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp\n> index e46aa438a06e..6a0301f3a2ae 100644\n> --- a/src/libcamera/controls.cpp\n> +++ b/src/libcamera/controls.cpp\n> @@ -549,8 +549,7 @@ const ControlValue &ControlList::get(unsigned int id) const\n>  \tconst auto ctrl = idmap_->find(id);\n>  \tif (ctrl == idmap_->end()) {\n>  \t\tLOG(Controls, Error)\n> -\t\t\t<< std::hex << std::setfill('0')\n> -\t\t\t<< \"Control 0x\" << std::setw(8) << id\n> +\t\t\t<< \"Control \" << utils::hex(id)\n>  \t\t\t<< \" is not supported\";\n>  \t\treturn zero;\n>  \t}\n> @@ -579,8 +578,7 @@ void ControlList::set(unsigned int id, const ControlValue &value)\n>  \tconst auto ctrl = idmap_->find(id);\n>  \tif (ctrl == idmap_->end()) {\n>  \t\tLOG(Controls, Error)\n> -\t\t\t<< std::hex << std::setfill('0')\n> -\t\t\t<< \"Control 0x\" << std::setw(8) << id\n> +\t\t\t<< \"Control 0x\" << utils::hex(id)\n>  \t\t\t<< \" is not supported\";\n>  \t\treturn;\n>  \t}\n> diff --git a/src/libcamera/include/utils.h b/src/libcamera/include/utils.h\n> index 52eee8ac2804..3efb11c119c2 100644\n> --- a/src/libcamera/include/utils.h\n> +++ b/src/libcamera/include/utils.h\n> @@ -10,6 +10,7 @@\n>  #include <algorithm>\n>  #include <chrono>\n>  #include <memory>\n> +#include <ostream>\n>  #include <string>\n>  #include <sys/time.h>\n>\n> @@ -63,6 +64,45 @@ using time_point = std::chrono::steady_clock::time_point;\n>  struct timespec duration_to_timespec(const duration &value);\n>  std::string time_point_to_string(const time_point &time);\n>\n> +#ifndef __DOXYGEN__\n> +struct _hex {\n> +\tuint64_t v;\n> +\tunsigned int w;\n> +};\n> +\n> +std::basic_ostream<char, std::char_traits<char>> &\n> +operator<<(std::basic_ostream<char, std::char_traits<char>> &stream, const _hex &h);\n> +#endif\n> +\n> +template<typename T>\n> +_hex hex(T value, unsigned int width = 0);\n> +\n> +#ifndef __DOXYGEN__\n> +template<>\n> +inline _hex hex<int32_t>(int32_t value, unsigned int width)\n> +{\n> +\treturn { static_cast<uint64_t>(value), width ? width : 8 };\n> +}\n> +\n> +template<>\n> +inline _hex hex<uint32_t>(uint32_t value, unsigned int width)\n> +{\n> +\treturn { static_cast<uint64_t>(value), width ? width : 8 };\n> +}\n> +\n> +template<>\n> +inline _hex hex<int64_t>(int64_t value, unsigned int width)\n> +{\n> +\treturn { static_cast<uint64_t>(value), width ? width : 16 };\n> +}\n> +\n> +template<>\n> +inline _hex hex<uint64_t>(uint64_t value, unsigned int width)\n> +{\n> +\treturn { static_cast<uint64_t>(value), width ? width : 16 };\n> +}\n> +#endif\n> +\n>  } /* namespace utils */\n>\n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp\n> index c28b4cd669b2..610920d1e5b3 100644\n> --- a/src/libcamera/stream.cpp\n> +++ b/src/libcamera/stream.cpp\n> @@ -16,6 +16,7 @@\n>  #include <libcamera/request.h>\n>\n>  #include \"log.h\"\n> +#include \"utils.h\"\n>\n>  /**\n>   * \\file stream.h\n> @@ -367,11 +368,7 @@ StreamConfiguration::StreamConfiguration(const StreamFormats &formats)\n>  std::string StreamConfiguration::toString() const\n>  {\n>  \tstd::stringstream ss;\n> -\n> -\tss.fill(0);\n> -\tss << size.toString() << \"-0x\" << std::hex << std::setw(8)\n> -\t   << pixelFormat;\n> -\n> +\tss << size.toString() << \"-\" << utils::hex(pixelFormat);\n>  \treturn ss.str();\n>  }\n>\n> diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp\n> index 928db254ec67..d632f6e66638 100644\n> --- a/src/libcamera/utils.cpp\n> +++ b/src/libcamera/utils.cpp\n> @@ -143,6 +143,45 @@ std::string time_point_to_string(const time_point &time)\n>  \treturn ossTimestamp.str();\n>  }\n>\n> +std::basic_ostream<char, std::char_traits<char>> &\n> +operator<<(std::basic_ostream<char, std::char_traits<char>> &stream, const _hex &h)\n> +{\n> +\tstream << \"0x\";\n> +\n> +\tstd::ostream::fmtflags flags = stream.setf(std::ios_base::hex,\n> +\t\t\t\t\t\t   std::ios_base::basefield);\n> +\tstd::streamsize width = stream.width(h.w);\n> +\tchar fill = stream.fill('0');\n> +\n> +\tstream << h.v;\n> +\n> +\tstream.flags(flags);\n> +\tstream.width(width);\n> +\tstream.fill(fill);\n> +\n> +\treturn stream;\n> +}\n> +\n> +/**\n> + * \\fn hex(T value, unsigned int width)\n> + * \\brief Write an hexadecimal value to an output string\n> + * \\param value The value\n> + * \\param width The width\n> + *\n> + * Return an object of unspecified type such that, if \\a os is the name of an\n> + * output stream of type std::ostream, and T is an integer type, then the\n> + * expression\n> + *\n> + * \\code{.cpp}\n> + * os << utils::hex(value)\n> + * \\endcode\n> + *\n> + * will output the \\a value to the stream in hexadecimal form with the base\n> + * prefix and the filling character set to '0'. The field width is set to \\a\n> + * width if specified to a non-zero value, or to the native width of type T\n> + * otherwise. The \\a os stream configuration is not modified.\n> + */\n> +\n>  } /* namespace utils */\n>\n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\n> index a188298de34c..f2bcd7f73c5c 100644\n> --- a/src/libcamera/v4l2_subdevice.cpp\n> +++ b/src/libcamera/v4l2_subdevice.cpp\n> @@ -21,6 +21,7 @@\n>  #include \"log.h\"\n>  #include \"media_device.h\"\n>  #include \"media_object.h\"\n> +#include \"utils.h\"\n>\n>  /**\n>   * \\file v4l2_subdevice.h\n> @@ -76,10 +77,7 @@ LOG_DECLARE_CATEGORY(V4L2)\n>  const std::string V4L2SubdeviceFormat::toString() const\n>  {\n>  \tstd::stringstream ss;\n> -\n> -\tss.fill(0);\n> -\tss << size.toString() << \"-0x\" << std::hex << std::setw(4) << mbus_code;\n> -\n> +\tss << size.toString() << \"-\" << utils::hex(mbus_code, 4);\n>  \treturn ss.str();\n>  }\n>\n> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\n> index eb4e44deb4a5..208ab54199b1 100644\n> --- a/src/libcamera/v4l2_videodevice.cpp\n> +++ b/src/libcamera/v4l2_videodevice.cpp\n> @@ -23,6 +23,7 @@\n>  #include \"log.h\"\n>  #include \"media_device.h\"\n>  #include \"media_object.h\"\n> +#include \"utils.h\"\n>\n>  /**\n>   * \\file v4l2_videodevice.h\n> @@ -239,10 +240,7 @@ LOG_DECLARE_CATEGORY(V4L2)\n>  const std::string V4L2DeviceFormat::toString() const\n>  {\n>  \tstd::stringstream ss;\n> -\n> -\tss.fill(0);\n> -\tss << size.toString() << \"-0x\" << std::hex << std::setw(8) << fourcc;\n> -\n> +\tss << size.toString() << \"-\" << utils::hex(fourcc);\n>  \treturn ss.str();\n>  }\n>\n> diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp\n> index 9fe59cc98d79..27c190fe7ace 100644\n> --- a/test/camera-sensor.cpp\n> +++ b/test/camera-sensor.cpp\n> @@ -13,6 +13,7 @@\n>  #include \"camera_sensor.h\"\n>  #include \"device_enumerator.h\"\n>  #include \"media_device.h\"\n> +#include \"utils.h\"\n>  #include \"v4l2_subdevice.h\"\n>\n>  #include \"test.h\"\n> @@ -91,7 +92,7 @@ protected:\n>  \t\tif (format.mbus_code != MEDIA_BUS_FMT_SBGGR10_1X10 ||\n>  \t\t    format.size != Size(4096, 2160)) {\n>  \t\t\tcerr << \"Failed to get a suitable format, expected 4096x2160-0x\"\n> -\t\t\t     << std::hex << MEDIA_BUS_FMT_SBGGR10_1X10\n> +\t\t\t     << utils::hex(MEDIA_BUS_FMT_SBGGR10_1X10)\n>  \t\t\t     << \", got \" << format.toString() << endl;\n>  \t\t\treturn TestFail;\n>  \t\t}\n> diff --git a/test/meson.build b/test/meson.build\n> index 84722cceb35d..cf5eb84d20b2 100644\n> --- a/test/meson.build\n> +++ b/test/meson.build\n> @@ -30,6 +30,7 @@ internal_tests = [\n>      ['threads',                         'threads.cpp'],\n>      ['timer',                           'timer.cpp'],\n>      ['timer-thread',                    'timer-thread.cpp'],\n> +    ['utils',                           'utils.cpp'],\n>  ]\n>\n>  foreach t : public_tests\n> diff --git a/test/utils.cpp b/test/utils.cpp\n> new file mode 100644\n> index 000000000000..9fe0d4775b73\n> --- /dev/null\n> +++ b/test/utils.cpp\n> @@ -0,0 +1,53 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2018, Google Inc.\n> + *\n> + * utils.cpp - Miscellaneous utility tests\n> + */\n> +\n> +#include <iostream>\n> +#include <sstream>\n> +\n> +#include \"test.h\"\n> +#include \"utils.h\"\n> +\n> +using namespace std;\n> +using namespace libcamera;\n> +\n> +class UtilsTest : public Test\n> +{\n> +protected:\n> +\tint run()\n> +\t{\n> +\t\tstd::ostringstream os;\n> +\t\tstd::string ref;\n> +\n> +\t\tos << utils::hex(static_cast<int32_t>(0x42)) << \" \";\n> +\t\tref += \"0x00000042 \";\n> +\t\tos << utils::hex(static_cast<uint32_t>(0x42)) << \" \";\n> +\t\tref += \"0x00000042 \";\n> +\t\tos << utils::hex(static_cast<int64_t>(0x42)) << \" \";\n> +\t\tref += \"0x0000000000000042 \";\n> +\t\tos << utils::hex(static_cast<uint64_t>(0x42)) << \" \";\n> +\t\tref += \"0x0000000000000042 \";\n> +\t\tos << utils::hex(static_cast<int32_t>(0x42), 4) << \" \";\n> +\t\tref += \"0x0042 \";\n> +\t\tos << utils::hex(static_cast<uint32_t>(0x42), 1) << \" \";\n> +\t\tref += \"0x42 \";\n> +\t\tos << utils::hex(static_cast<int64_t>(0x42), 4) << \" \";\n> +\t\tref += \"0x0042 \";\n> +\t\tos << utils::hex(static_cast<uint64_t>(0x42), 1) << \" \";\n> +\t\tref += \"0x42 \";\n> +\n> +\t\tstd::string s = os.str();\n> +\t\tif (s != ref) {\n> +\t\t\tcerr << \"utils::hex() test failed, expected '\" << ref\n> +\t\t\t     << \"', got '\" << s << \"'\";\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +};\n> +\n> +TEST_REGISTER(UtilsTest)\n> --\n> Regards,\n>\n> Laurent Pinchart\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net\n\t[217.70.183.197])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9271760E1A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 15 Oct 2019 09:44:29 +0200 (CEST)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 1A5581C0004;\n\tTue, 15 Oct 2019 07:44:28 +0000 (UTC)"],"X-Originating-IP":"2.224.242.101","Date":"Tue, 15 Oct 2019 09:46:18 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20191015074618.4q33aj6mygp7xydn@uno.localdomain>","References":"<20191013192346.8270-1-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"mkpj5jc7yrb325je\"","Content-Disposition":"inline","In-Reply-To":"<20191013192346.8270-1-laurent.pinchart@ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH] libcamera: utils: Add hex stream\n\toutput helper","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>","X-List-Received-Date":"Tue, 15 Oct 2019 07:44:29 -0000"}}]