Merge 5a110847a19e4a758c2f06dab04c21b5e2d844c0 into 60ba92928e8af3441f2a4eea5f18fd2563d98ad0

This commit is contained in:
Roland Reichwein 2026-10-19 11:09:20 +00:00 committed by GitHub
commit 8a20befca4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 4069 additions and 0 deletions

View File

@ -0,0 +1,57 @@
# Pinned by digest for reproducible builds.
# To update: docker buildx imagetools inspect debian:sid-slim
FROM debian:sid-slim@sha256:ec3fa4e0b2987ae47be353f56854191e300261915470e40165b1c906d22a65db
# Pin the package archive to a snapshot.debian.org timestamp so that
# `apt-get install` resolves the same package versions on every build.
# This is the snapshot the base image itself was built from - see the comment
# in /etc/apt/sources.list.d/debian.sources of the pinned image above.
ARG DEBIAN_SNAPSHOT=20260918T000000Z
# snapshot.debian.org serves archived Release files whose Valid-Until has long
# since passed, so that check has to be disabled.
# http is used rather than https because the slim base image has no
# ca-certificates; integrity is guaranteed by the archive's GPG signature.
RUN printf '%s\n' \
'Types: deb' \
"URIs: http://snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT}/" \
'Suites: sid' \
'Components: main' \
'Check-Valid-Until: no' \
'Signed-By: /usr/share/keyrings/debian-archive-keyring.pgp' \
> /etc/apt/sources.list.d/debian.sources
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
git \
ninja-build \
python3 \
python3-cogapp \
gcc-16 \
g++-16 \
&& rm -rf /var/lib/apt/lists/*
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-16 100 \
--slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-16 \
--slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-16 \
--slave /usr/bin/gcc-ranlib gcc-ranlib /usr/bin/gcc-ranlib-16 \
&& update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-16 100
# Create non-root user with stable UID/GID
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=1000
RUN groupadd --gid ${USER_GID} ${USERNAME} && \
useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home ${USERNAME}
# Ensure workspace directory ownership for non-root user
RUN mkdir -p /etl && chown -R ${USERNAME}:${USERNAME} /etl
WORKDIR /etl
# Switch to non-root user
USER ${USERNAME}
CMD ["/bin/bash"]

View File

@ -0,0 +1,12 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
//
// GCC 16 is the reference toolchain for the C++26 static reflection support in
// etl/meta.h. It cannot use the shared ../Dockerfile because there is no
// 'gcc:16' base image yet, so gcc-16 is taken from Debian sid instead.
{
"name": "Gcc 16",
"build": {
"dockerfile": "./Dockerfile"
}
}

View File

@ -0,0 +1,78 @@
name: gcc16-c++26-reflection
on:
push:
branches: [ master, development, pull-request/* ]
paths:
- '.github/workflows/**'
- 'include/**'
- 'test/**'
- 'CMakeLists.txt'
- 'cmake/**'
- '.devcontainer/**'
pull_request:
branches: [ master, development, pull-request/* ]
types: [opened, synchronize, reopened]
paths:
- '.github/workflows/**'
- 'include/**'
- 'test/**'
- 'CMakeLists.txt'
- 'cmake/**'
- '.devcontainer/**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build-gcc16-cpp26-reflection-stl:
name: GCC 16 C++26 Reflection - STL
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6.0.3
with:
persist-credentials: false
- name: Build Docker image
run: docker build -t etl-gcc16 -f .devcontainer/gcc16/Dockerfile .
- name: Build and run tests
run: |
docker run --rm --user root -v ${{ github.workspace }}:/etl etl-gcc16 bash -c "\
cd /etl && \
export CC=gcc-16 && \
export CXX=g++-16 && \
g++-16 --version && \
cmake -G Ninja -B /tmp/build-stl -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 -DETL_OPTIMISATION=-O0 /etl/test && \
grep -q 'ETL_GNU_HAS_FREFLECTION:INTERNAL=1' /tmp/build-stl/CMakeCache.txt || (echo 'ERROR: -freflection was not detected - C++26 reflection is not being tested.' && exit 1) && \
cmake --build /tmp/build-stl -j \$(getconf _NPROCESSORS_ONLN) && \
ctest --test-dir /tmp/build-stl --output-on-failure"
build-gcc16-cpp26-reflection-no-stl:
name: GCC 16 C++26 Reflection - No STL
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6.0.3
with:
persist-credentials: false
- name: Build Docker image
run: docker build -t etl-gcc16 -f .devcontainer/gcc16/Dockerfile .
- name: Build and run tests
run: |
docker run --rm --user root -v ${{ github.workspace }}:/etl etl-gcc16 bash -c "\
cd /etl && \
export CC=gcc-16 && \
export CXX=g++-16 && \
g++-16 --version && \
cmake -G Ninja -B /tmp/build-no-stl -DBUILD_TESTS=ON -DNO_STL=ON -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=26 -DETL_OPTIMISATION=-O0 /etl/test && \
grep -q 'ETL_GNU_HAS_FREFLECTION:INTERNAL=1' /tmp/build-no-stl/CMakeCache.txt || (echo 'ERROR: -freflection was not detected - C++26 reflection is not being tested.' && exit 1) && \
cmake --build /tmp/build-no-stl -j \$(getconf _NPROCESSORS_ONLN) && \
ctest --test-dir /tmp/build-no-stl --output-on-failure"

View File

@ -103,6 +103,7 @@ These may be defined in the project settings or the user created `etl_profile.h`
| `ETL_HAS_IDEQUE_REPAIR` | Set to `1` if the repair functionality for `etl::ideque` is enabled, otherwise `0`.|
| `ETL_IS_DEBUG_BUILD` | Set to `1` if in a debug build, otherwise `0`.|
| `ETL_HAS_POLYMORPHIC_MESSAGES` | Set to `1` if messages are polymorphic, otherwise `0`.|
| `ETL_HAS_REFLECTION` | Defined by `etl/meta.h`. Set to `1` if the compiler supports C++26 static reflection (P2996) and `etl::meta` is available, otherwise `0`.|
| `ETL_HAS_ERROR_ON_STRING_TRUNCATION` | Set to `1` if truncated strings are an error, otherwise `0`.|
| `ETL_USING_LIBC_WCHAR_H` | These macros will be defined as `0` & `1` depending on whether `ETL_NO_LIBC_WCHAR_H` is defined or not.|
| `ETL_NOT_USING_LIBC_WCHAR_H` | Inversion of `ETL_USING_LIBC_WCHAR_H`.|

97
docs/types/meta.md Normal file
View File

@ -0,0 +1,97 @@
---
title: "meta"
---
{{< callout type="info">}}
Header: `meta.h`
From: `20.50.0`
Similar to: `std::meta`
{{< /callout >}}
C++26 static reflection (P2996) in namespace `etl::meta`.
`etl::meta` mirrors `std::meta`, but is usable in both STL and non-STL builds.
In an STL build it is a thin layer of using-declarations over `std::meta`.
In a non-STL build ETL supplies the minimal declarations that the compiler's
reflection builtins require, so no standard library is needed.
```cpp
#include "etl/meta.h"
```
## Compiler support
Static reflection is a very new language feature, and at the time of writing
**GCC 16** is the only compiler that implements enough of P2996 to be usable.
Clang (including the Bloomberg `clang-p2996` fork) and MSVC are not supported.
`etl/meta.h` may always be included. It defines a single macro,
`ETL_HAS_REFLECTION`, as `1` or `0`; when it is `0` the header defines nothing
else. This is the only reflection feature switch in the ETL, and user code
should test it before using anything in `etl::meta`.
```cpp
#include "etl/meta.h"
#if ETL_HAS_REFLECTION
static_assert(etl::meta::identifier_of(^^my_type) == "my_type");
#endif
```
GCC requires the `-freflection` option in addition to `-std=c++26`.
The reference toolchain is defined in `.devcontainer/gcc16`.
## Usage
Names are used exactly as their `std::meta` equivalents.
```cpp
struct point
{
int x;
int y;
};
constexpr auto members =
etl::meta::nonstatic_data_members_of(^^point,
etl::meta::access_context::unchecked());
static_assert(etl::meta::identifier_of(members[0]) == "x");
static_assert(etl::meta::type_of(members[0]) == ^^int);
static_assert(etl::meta::size_of(^^point) == 2 * sizeof(int));
```
`identifier_of`, `display_string_of` and `symbol_of` return `std::string_view`
in an STL build and `etl::string_view` in a non-STL build.
## info_array
GCC cannot keep the heap allocation of a `std::vector<info>` alive across a
constant evaluation, so a `template for` over the result of `members_of` does
not compile. `etl::meta::info_array` is a fixed-size, allocation-free array of
`info` that can be iterated instead.
```cpp
constexpr auto ctx = etl::meta::access_context::unchecked();
constexpr auto count = etl::meta::nonstatic_data_members_of(^^point, ctx).size();
constexpr auto members =
etl::meta::to_info_array<count>(etl::meta::nonstatic_data_members_of(^^point, ctx));
template for (constexpr auto member : members)
{
// ...
}
```
| Member | Description |
|--------|-------------|
| `begin()` | Pointer to the first element. |
| `end()` | Pointer past the last element. |
| `size()` | The number of elements. |
| `operator[](size_t)` | The element at the index. |
All members are `consteval`.
## Tests
`test_meta.cpp`

73
include/etl/meta.h Normal file
View File

@ -0,0 +1,73 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2026 BMW AG
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_META_INCLUDED
#define ETL_META_INCLUDED
#include "platform.h"
//*****************************************************************************
/// \defgroup meta meta
/// C++26 static reflection (P2996).
/// \ingroup etl
//*****************************************************************************
//*****************************************************************************
// This is the one and only place where reflection support is detected.
//
// GCC 16 is currently the only compiler that implements enough of P2996 for
// etl::meta, and it does so for both STL and non-STL builds.
// See .devcontainer/gcc16 for the reference toolchain.
//
// Clang (including the Bloomberg p2996 fork) and MSVC are not supported yet.
//
// ETL_HAS_REFLECTION is always defined, as 1 or 0.
// When it is 0 this header defines nothing else, so user code can include
// etl/meta.h unconditionally and test ETL_HAS_REFLECTION.
//*****************************************************************************
#if defined(ETL_COMPILER_GCC) && defined(__cpp_impl_reflection) && (__cpp_impl_reflection >= 202506L)
#define ETL_HAS_REFLECTION 1
#else
#define ETL_HAS_REFLECTION 0
#endif
#if ETL_HAS_REFLECTION
#if ETL_USING_STL
// The full standard library is available, so etl::meta is a thin
// using-declaration layer over std::meta.
#include "private/meta/stl.h"
#else
// No standard library: etl::meta supplies the minimal std declarations
// that the reflection builtins require.
#include "private/meta/gcc.h"
#endif
#endif
#endif // ETL_META_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,117 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2026 BMW AG
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_PRIVATE_META_STL_H_INCLUDED
#define ETL_PRIVATE_META_STL_H_INCLUDED
#include <cstddef>
#include <initializer_list>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include <meta>
#include <source_location> // Workaround for GCC 16: <meta> depends on <source_location> but does not include it.
///\defgroup meta meta
///\ingroup etl
namespace etl
{
namespace meta
{
//*************************************************************************
// Standard <meta> path, used when the full standard library is available.
//
// A using-directive is sufficient here: qualified lookup for
// etl::meta::foo also searches the namespaces nominated by the
// using-directives of etl::meta ([namespace.qual]), so every std::meta
// name - including the function templates such as extract<> - is
// reachable as etl::meta::name. This mirrors the non-STL implementation
// in gcc.h, which uses the same mechanism.
//*************************************************************************
using namespace std::meta;
// Enumerators of std::meta::operators (op_equals_equals, etc.) are scoped,
// so they need a using-enum-declaration rather than the using-directive.
using enum std::meta::operators;
//*************************************************************************
/// info_array — fixed-size, zero-allocation array of info values.
///
/// GCC limitation: template-for over a std::vector<info> fails because the
/// vector's heap allocation cannot persist in a constant expression. The
/// workaround is to copy the elements into a plain aggregate array (no
/// allocation) and iterate that instead.
///
/// Usage pattern:
/// constexpr auto N = std::meta::members_of(^^T, ctx).size();
/// constexpr auto arr = etl::meta::to_info_array<N>(
/// std::meta::members_of(^^T, ctx));
/// template for (constexpr auto m : arr) { ... }
//*************************************************************************
template <size_t N>
struct info_array
{
info elems[N > 0 ? N : 1]{};
consteval const info* begin() const
{
return elems;
}
consteval const info* end() const
{
return elems + N;
}
consteval size_t size() const
{
return N;
}
consteval const info& operator[](size_t i) const
{
return elems[i];
}
};
template <size_t N>
consteval info_array<N> to_info_array(const std::vector<info>& v)
{
info_array<N> a{};
for (size_t i = 0; i < N; ++i)
{
a.elems[i] = v[i];
}
return a;
}
} // namespace meta
} // namespace etl
#endif // ETL_PRIVATE_META_STL_H_INCLUDED

View File

@ -3808,9 +3808,14 @@ namespace etl
template <typename T>
struct is_nothrow_relocatable
{
#if ETL_USING_CPP11
static ETL_CONSTANT bool value = etl::is_trivially_relocatable<T>::value
|| (etl::is_nothrow_move_constructible<typename etl::remove_all_extents<T>::type>::value
&& etl::is_nothrow_destructible<typename etl::remove_all_extents<T>::type>::value);
#else
// No move semantics: only trivially relocatable types are known to be nothrow relocatable.
static ETL_CONSTANT bool value = etl::is_trivially_relocatable<T>::value;
#endif
};
#elif defined(ETL_USER_DEFINED_TYPE_TRAITS) && !defined(ETL_USE_TYPE_TRAITS_BUILTINS)

View File

@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.10)
project(etl_unit_tests LANGUAGES CXX)
include(CheckCXXCompilerFlag)
#include(FetchContent)
#FetchContent_Declare(
# googletest
@ -232,6 +234,7 @@ add_executable(etl_tests
test_map.cpp
test_math.cpp
test_math_functions.cpp
test_meta.cpp
test_mean.cpp
test_memory.cpp
test_mem_cast.cpp
@ -513,6 +516,16 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
${EXTRA_COMPILE_OPTIONS}
)
target_link_options(etl_tests PRIVATE ${EXTRA_LINK_OPTIONS})
if (ETL_CXX_STANDARD MATCHES "26")
# -freflection is only accepted when compiling as C++26, so probe with that standard.
set(CMAKE_REQUIRED_FLAGS "-std=c++26")
check_cxx_compiler_flag(-freflection ETL_GNU_HAS_FREFLECTION)
unset(CMAKE_REQUIRED_FLAGS)
if (ETL_GNU_HAS_FREFLECTION)
target_compile_options(etl_tests PRIVATE -freflection)
endif ()
endif ()
endif ()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")

View File

@ -234,6 +234,7 @@ etl_test_sources = files(
'test_message_timer_atomic.cpp',
'test_message_timer_interrupt.cpp',
'test_message_timer_locked.cpp',
'test_meta.cpp',
'test_multi_array.cpp',
'test_multi_range.cpp',
'test_multi_span.cpp',

View File

@ -289,6 +289,7 @@ target_sources(tests PRIVATE
message_timer_interrupt.h.t.cpp
message_timer_locked.h.t.cpp
message_types.h.t.cpp
meta.h.t.cpp
multimap.h.t.cpp
multiset.h.t.cpp
multi_array.h.t.cpp

View File

@ -0,0 +1,40 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2026 BMW AG
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include <etl/meta.h>
// etl/meta.h must be includable unconditionally, on every compiler and every
// language standard. Where reflection is unavailable it defines nothing
// except ETL_HAS_REFLECTION, which is always defined as either 1 or 0.
#if !defined(ETL_HAS_REFLECTION)
#error ETL_HAS_REFLECTION is not defined by etl/meta.h
#endif
#if (ETL_HAS_REFLECTION != 0) && (ETL_HAS_REFLECTION != 1)
#error ETL_HAS_REFLECTION must be defined as 0 or 1
#endif

2391
test/test_meta.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10447,6 +10447,7 @@
<ClCompile Include="..\test_message_timer_atomic.cpp" />
<ClCompile Include="..\test_message_timer_interrupt.cpp" />
<ClCompile Include="..\test_message_timer_locked.cpp" />
<ClCompile Include="..\test_meta.cpp" />
<ClCompile Include="..\test_multi_array.cpp" />
<ClCompile Include="..\test_array.cpp">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../../unittest-cpp</AdditionalIncludeDirectories>

View File

@ -1664,6 +1664,9 @@
<ClCompile Include="..\test_message_timer_locked.cpp">
<Filter>Tests\Messaging</Filter>
</ClCompile>
<ClCompile Include="..\test_meta.cpp">
<Filter>Tests\Types</Filter>
</ClCompile>
<ClCompile Include="..\test_shared_message.cpp">
<Filter>Tests\Messaging</Filter>
</ClCompile>