std::from_chars(), introduced in C++17, is a fast, locale-independent
string-to-arithmetic conversion function. The C++ standard library
provides overloads for all integer types, making it a prime candidate to
replace the manual handling of integer sizes in the YamlParser string to
integer conversion.
Compared to std::strtol(), std::from_chars() doesn't recognize the '0x'
prefix or '+' prefix, and doesn't ignore leading white space. As the
YamlParser doesn't require those features, std::from_chars() can be used
safely, reducing the amount of code.
C++17 also requires the standard C++ library to provide overloads for
floating-point types, but libc++ does not implement those. The float and
bool implementations of YamlParser::Getter::get() are therefore kept
as-is.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
In many cases a static string literal is used as key. Thus
having the argument type be `const std::string&` is suboptimal
since an `std::string` object needs to be constructed before
the call.
C++17 introduced `std::string_view`, using which the call
can be done with less overhead, as the `std::string_view`
is non-owning and may be passed in registers entirely.
So make `YamlObject::{contains,operator[]}` take the string keys
in `std::string_view`s.
Unfortunately, that is not sufficient yet, because `std::map::find()`
takes an reference to `const key_type`, which would be `const std::string&`
in the case of `YamlParser`. However, with a transparent comparator
such as `std::less<>` `std::map::find()` is able to accept any
object as the argument, and it forwards it to the comparator.
So make `YamlParser::dictionary_` use `std::less<>` as the comparator
to enable the use of `std::map::find()` with any type of argument.
Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
When accessing a nonexistent key on a dict the YamlObject returns an
empty element. This element can happily be cast to a string which is
unexpected. For example the following statement:
yamlDict["nonexistent"].get<string>("default")
is expected to return "default" but actually returns "". Fix this by
introducing an empty type to distinguish between an empty YamlObject and
a YamlObject of type value containing an empty string. For completeness
add an isEmpty() function and an explicit cast to bool to be able to
test for that type.
Extend the tests accordingly.
Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Without the change the build fails on upcoming `gcc-15` as:
In file included from ../src/libcamera/yaml_parser.cpp:8:
../include/libcamera/internal/yaml_parser.h:183:41: error: 'uint8_t' was not declared in this scope
183 | std::is_same_v<uint8_t, T> ||
| ^~~~~~~
Signed-off-by: Sergei Trofimovich <slyich@gmail.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
The YamlObject::get<T>() function template has a specialization for
double but not for float. When used in an IPA module, the issue is
caught at module load time only, when dynamic links are resolved,
causing errors such as
Failed to open IPA module shared object: /usr/lib/libcamera/ipa_rkisp1.so: undefined symbol: _ZNK9libcamera10YamlObject6GetterIfE3getERK_
Fix it by adding a float specialization. The alternative would be to use
double only in IPA modules, but the lack of enforcement at compile time
makes this dangerous.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>
The YamlObject::get() function is a function template that gets fully
specialized for various types. This works fine for non-template types,
but specializing it for template types (e.g. a std::vector<U>) would
require partial template specialization, which C++ allows for classes
and variables but not functions.
To work around this problem, delegate the implementation to a new
YamlObject::Getter structure template, which will support partial
specialization.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
The YamlObject::get() function template is implemented for a set of
basic types through template specializations. The function declaration
uses std::enable_if_t<> guards to signal incorrect usage at compilation
time. This however prevents the API to be extended with additional
specializations in other compilation units.
To prepare for new specializations of the function for the ipa::Vector
and ipa::Pwl classes types, implemented in their respective compilation
units, drop the std::enable_it_t<> guards. Incorrect usage will still be
reported as link errors.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This way the construction of the default value of type `T`
can be delayed until it is really needed, which is useful,
for example when `T == std::string` and the default value comes
from a string literal, as the default value string would always
be constructed otherwise, even if not needed.
Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Source files in libcamera start by a comment block header, which
includes the file name and a one-line description of the file contents.
While the latter is useful to get a quick overview of the file contents
at a glance, the former is mostly a source of inconvenience. The name in
the comments can easily get out of sync with the file name when files
are renamed, and copy & paste during development have often lead to
incorrect names being used to start with.
Readers of the source code are expected to know which file they're
looking it. Drop the file name from the header comment block.
The change was generated with the following script:
----------------------------------------
dirs="include/libcamera src test utils"
declare -rA patterns=(
['c']=' \* '
['cpp']=' \* '
['h']=' \* '
['py']='# '
['sh']='# '
)
for ext in ${!patterns[@]} ; do
files=$(for dir in $dirs ; do find $dir -name "*.${ext}" ; done)
pattern=${patterns[${ext}]}
for file in $files ; do
name=$(basename ${file})
sed -i "s/^\(${pattern}\)${name} - /\1/" "$file"
done
done
----------------------------------------
This misses several files that are out of sync with the comment block
header. Those will be addressed separately and manually.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
The YamlObject::get() function template is implemented for 16-bit and
32-bit integers. Add an 8-bit specialization that will be used in the
rkisp1 IPA module, and extend the unit tests accordingly.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Usage of the std::enable_if_t type doesn't need to be prefixed by
typename. Drop the unnecessary keyword.
Reported-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Allow to retrieve a YAML list of any already supported types in a
std::vector.
Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
The std::map container used to store dictionary items in YamlObject
doesn't preserve the YAML data order, as maps are ordered by key, not by
insertion order. While this is compliant with the YAML specification
which doesn't guarantee ordering of mappings, the Raspberry Pi IPA
relies on elements being ordered as in the YAML data. To replace the
dependency on boost with the YamlParser class, we thus need to guarantee
that the order is preserved.
Preserve the order by storing items in list_ unconditionally. Turn the
list_ vector from storing YamlObject unique pointers to storing
key-value pairs, with the key being absent when the object is a list,
not a dictionary.
The YamlObject implementation is updated to preserve the existing API,
with the only difference being that YamlObject::memberNames() now
returns member names in the same order as in the YAML file.
The ordering is an implementation detail, so changing it doesn't violate
the YAML specification. The documentation is not updated to reflect
this, as we don't want any new user to rely on a particular ordering.
This commit could be reverted if desired when the Raspberry Pi IPA
updates to a new tuning data format and drops support for the old
format.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
The YamlObject::get() function takes a default value and an optional
bool ok flag to handle parsing errors. This ad-hoc mechanism complicates
error handling in callers.
A better API is possible by dropping the default value and ok flag and
returning an std::optional. Not only does it simplify the calls, it also
lets callers handle errors through the standard std::optional class
instead of the current ad-hoc mechanism.
Provide a get() wrapper around std::optional::value_or() to further
simplify callers that don't need any specific error handling.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Tested-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Now that YamlObject supports iteration, the memberNames() function isn't
useful anymore as it can be implemented using utils::map_keys() if
really needed. Drop it.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Han-Lin Chen <hanlinchen@chromium.org>
Allow using range-based for loops over YamlObject instances by
implementing iterators. New YamlObject::DictAdapter and
YamlObject::ListAdapter adapter classes are introduced to provide
different iterators depending on the object type.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Han-Lin Chen <hanlinchen@chromium.org>
As the YamlObject class is internal to libcamera, it can use the full
C++17 API. Replace std::is_same<>::value with std::is_same_v<>.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Han-Lin Chen <hanlinchen@chromium.org>
THe FILE object isn't very user-friendly as it requires manual close.
Replace it with File to provide RAII-style resource management in the
YamlParser API.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Dictionaries have a size too, extend the size() function to support
them.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Turn the Type enum into an enum class to force qualifying 'List' and
'Dictionary' in the YamlObject namespace scope. This will help avoiding
ambiguities when adding iterator support.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Introduce YamlParser as a helper to convert contents of a yaml file to
a tree based structure for easier reading, and to avoid writing parser
with raw yaml tokens. The class is based on libyaml, and only support
reading but not writing a yaml file.
The interface is inspired by Json::Value class from jsoncpp:
http://jsoncpp.sourceforge.net/class_json_1_1_value.html
Signed-off-by: Han-Lin Chen <hanlinchen@chromium.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>