Message ID | 20200120173816.31829-2-laurent.pinchart@ideasonboard.com |
---|---|
State | RFC |
Delegated to: | Laurent Pinchart |
Headers | show |
Series |
|
Related | show |
Hi Laurent, Thanks for your work. On 2020-01-20 19:38:14 +0200, Laurent Pinchart wrote: > Add a custom implementation of std::make_array() as defined by the > library fundamentals TS v2 ([1]). The function is useful to initialize > static arrays without requiring manually specifying the number of > elements, which could lead to bugs when the specified size is larger > than the number of initializers. > > This is an experimental feature in the C++ standard, and while available > in <experimental/array> in stdlibc++ from g++-6 onwards, it is not > provided by libc++. > > [1] https://en.cppreference.com/w/cpp/experimental/make_array > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> > --- > Documentation/Doxyfile.in | 1 + > src/libcamera/include/utils.h | 42 +++++++++++++++++++++++++++++++++++ > src/libcamera/utils.cpp | 14 ++++++++++++ > 3 files changed, 57 insertions(+) > > diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in > index 8e6fbdbb92b6..6de59d407e7b 100644 > --- a/Documentation/Doxyfile.in > +++ b/Documentation/Doxyfile.in > @@ -877,6 +877,7 @@ EXCLUDE_SYMBOLS = libcamera::BoundMethodArgs \ > libcamera::BoundMethodPackBase \ > libcamera::BoundMethodStatic \ > libcamera::SignalBase \ > + *::details::* \ > std::* > > # The EXAMPLE_PATH tag can be used to specify one or more files or directories > diff --git a/src/libcamera/include/utils.h b/src/libcamera/include/utils.h > index e467eb21c518..6e9b9259456a 100644 > --- a/src/libcamera/include/utils.h > +++ b/src/libcamera/include/utils.h > @@ -8,12 +8,15 @@ > #define __LIBCAMERA_UTILS_H__ > > #include <algorithm> > +#include <array> > #include <chrono> > +#include <functional> > #include <memory> > #include <ostream> > #include <string> > #include <string.h> > #include <sys/time.h> > +#include <type_traits> > > #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) > > @@ -108,6 +111,45 @@ inline _hex hex<uint64_t>(uint64_t value, unsigned int width) > > size_t strlcpy(char *dst, const char *src, size_t size); > > +namespace details { > + > +namespace make_array { > + > + template<class B> > + struct negation : std::integral_constant<bool, !bool(B::value)> {}; > + > + template<class...> struct conjunction : std::true_type {}; > + template<class B1> struct conjunction<B1> : B1 {}; > + template<class B1, class... Bn> > + struct conjunction<B1, Bn...> > + : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {}; > + > + template<class> struct is_ref_wrapper : std::false_type {}; > + template<class T> struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {}; > + > + template<class D, class...> > + struct return_type_helper { > + using type = D; > + }; > + template <class... Types> > + struct return_type_helper<void, Types...> : std::common_type<Types...> { > + static_assert(conjunction<negation<is_ref_wrapper<std::decay_t<Types>>>...>::value, > + "Types cannot contain reference_wrappers when D is void"); > + }; > + > + template<class D, class... Types> > + using return_type = std::array<typename return_type_helper<D, Types...>::type, > + sizeof...(Types)>; > +} /* namespace make_array */ > + > +} /* namespace details */ > + > +template<class D = void, class... Types> > +constexpr details::make_array::return_type<D, Types...> make_array(Types&&... t) > +{ > + return {std::forward<Types>(t)... }; > +} > + > } /* namespace utils */ > > } /* namespace libcamera */ > diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp > index 4beffdab5eb6..b639cfa83d0c 100644 > --- a/src/libcamera/utils.cpp > +++ b/src/libcamera/utils.cpp > @@ -199,6 +199,20 @@ size_t strlcpy(char *dst, const char *src, size_t size) > return strlen(src); > } > > +/** > + * \fn template<class D, class... Types> libcamera::utils::make_array(Types&&... t) > + * \brief Create a std::array with automatic deduction of element type and count > + * \param[in] t The initialization values for the array elements > + * > + * This function creates and returns an instance of std::array whose size is > + * equal to the number of arguments. If the template argument \a D is void, the > + * array element type is deduced from the elements through > + * std::common_types_t<Types...>. Otherwise it is set to D. The elements are > + * initialized from the corresponding arguments. > + * > + * \return A std::array initialized from the arguments > + */ > + > } /* namespace utils */ > > } /* namespace libcamera */ > -- > Regards, > > Laurent Pinchart > > _______________________________________________ > libcamera-devel mailing list > libcamera-devel@lists.libcamera.org > https://lists.libcamera.org/listinfo/libcamera-devel
diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index 8e6fbdbb92b6..6de59d407e7b 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -877,6 +877,7 @@ EXCLUDE_SYMBOLS = libcamera::BoundMethodArgs \ libcamera::BoundMethodPackBase \ libcamera::BoundMethodStatic \ libcamera::SignalBase \ + *::details::* \ std::* # The EXAMPLE_PATH tag can be used to specify one or more files or directories diff --git a/src/libcamera/include/utils.h b/src/libcamera/include/utils.h index e467eb21c518..6e9b9259456a 100644 --- a/src/libcamera/include/utils.h +++ b/src/libcamera/include/utils.h @@ -8,12 +8,15 @@ #define __LIBCAMERA_UTILS_H__ #include <algorithm> +#include <array> #include <chrono> +#include <functional> #include <memory> #include <ostream> #include <string> #include <string.h> #include <sys/time.h> +#include <type_traits> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) @@ -108,6 +111,45 @@ inline _hex hex<uint64_t>(uint64_t value, unsigned int width) size_t strlcpy(char *dst, const char *src, size_t size); +namespace details { + +namespace make_array { + + template<class B> + struct negation : std::integral_constant<bool, !bool(B::value)> {}; + + template<class...> struct conjunction : std::true_type {}; + template<class B1> struct conjunction<B1> : B1 {}; + template<class B1, class... Bn> + struct conjunction<B1, Bn...> + : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {}; + + template<class> struct is_ref_wrapper : std::false_type {}; + template<class T> struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {}; + + template<class D, class...> + struct return_type_helper { + using type = D; + }; + template <class... Types> + struct return_type_helper<void, Types...> : std::common_type<Types...> { + static_assert(conjunction<negation<is_ref_wrapper<std::decay_t<Types>>>...>::value, + "Types cannot contain reference_wrappers when D is void"); + }; + + template<class D, class... Types> + using return_type = std::array<typename return_type_helper<D, Types...>::type, + sizeof...(Types)>; +} /* namespace make_array */ + +} /* namespace details */ + +template<class D = void, class... Types> +constexpr details::make_array::return_type<D, Types...> make_array(Types&&... t) +{ + return {std::forward<Types>(t)... }; +} + } /* namespace utils */ } /* namespace libcamera */ diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp index 4beffdab5eb6..b639cfa83d0c 100644 --- a/src/libcamera/utils.cpp +++ b/src/libcamera/utils.cpp @@ -199,6 +199,20 @@ size_t strlcpy(char *dst, const char *src, size_t size) return strlen(src); } +/** + * \fn template<class D, class... Types> libcamera::utils::make_array(Types&&... t) + * \brief Create a std::array with automatic deduction of element type and count + * \param[in] t The initialization values for the array elements + * + * This function creates and returns an instance of std::array whose size is + * equal to the number of arguments. If the template argument \a D is void, the + * array element type is deduced from the elements through + * std::common_types_t<Types...>. Otherwise it is set to D. The elements are + * initialized from the corresponding arguments. + * + * \return A std::array initialized from the arguments + */ + } /* namespace utils */ } /* namespace libcamera */
Add a custom implementation of std::make_array() as defined by the library fundamentals TS v2 ([1]). The function is useful to initialize static arrays without requiring manually specifying the number of elements, which could lead to bugs when the specified size is larger than the number of initializers. This is an experimental feature in the C++ standard, and while available in <experimental/array> in stdlibc++ from g++-6 onwards, it is not provided by libc++. [1] https://en.cppreference.com/w/cpp/experimental/make_array Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> --- Documentation/Doxyfile.in | 1 + src/libcamera/include/utils.h | 42 +++++++++++++++++++++++++++++++++++ src/libcamera/utils.cpp | 14 ++++++++++++ 3 files changed, 57 insertions(+)