Skip to content

sarvex/tetl

 
 

Repository files navigation

TETL - Embedded Template Library

Tobante's embedded template library. A STL-like C++ template library designed for embedded devices with limited resources. Supports freestanding and hosted environments.

Quick Start

// main.cpp
#include "etl/algorithm.hpp"  // for count_if
#include "etl/array.hpp"      // for array

auto main() -> int
{
  auto const numbers = etl::array{1, 2, 3, 4, 5};
  auto const greater_two = [] (auto const v) { return v > 2; };
  return etl::count_if(begin(numbers), end(numbers), greater_two);
}
g++ -Wall -Wextra -Wpedantic -std=c++20 -I path/to/tetl/include main.cpp

For examples look at the examples subdirectory or the test files in tests. The API reference is currently work in progress. I'm switching from doxygen to standardese, which still has some bugs, so some parts of the docs may still be missing.

Status

License Lines of Code Progress Documentation
License LOC Spreadsheet API Reference

Hosted

x64

Platform Status Notes
Linux Linux X64 GCC 11/12 & Clang 12/13/14/15/16
macOS macOS X64 AppleClang 14
Windows Windows X64 Visual Studio 2022

Freestanding

Platform Status Notes
ARM ARM Freestanding GCC 12
AVR AVR Freestanding GCC 12
MSP430 MSP430 Freestanding GCC 12

Analysis

Type Status Notes
Coverage codecov GCC 11
Sanitizers Sanitizers (ASAN/UBSAN) Clang 16
Clang-Tidy Clang-Tidy Clang 16
Clang -Weverything Clang -Weverything Clang 16

NOTE: All test are compiled in debug and release mode with at least -Wall -Wextra -Wpedantic -Werror or /W3 /WX. The full list of warning flags can be found in the CMake configuration: cmake/compiler_warnings.cmake. Hosted platforms run all tests & examples, while freestanding builds only compile (ARM & AVR) and link (AVR) the example files.

Design Goals

  • 100% portable (no STL headers required, minimum of C headers)
  • Header only
  • C++20 and beyond (freestanding or hosted)
  • Similar API to the STL
  • No dynamic memory
  • constexpr all the things
  • Minimize undefined behavoir. See Error Handling
  • Easy desktop development (cmake)

It all started when I wanted to have a vector without dynamic memory. At that time I didn't know that proposals like github.com/gnzlbg/static_vector where in the making. My actual goal has turned into a mammoth project. A standard library for microcontrollers and other embedded environments. The API is, as far as it is technically feasible, identical to the STL. All algorithms work identically, pair and friend are available and containers like set, map and vector are also implemented, but with different names.

All containers work only with memory on the stack. This means that their size must be known at compile time. Furthermore I assume an environment in which exceptions and RTTI migth be disabled. This results in the problem that not all members of a container can be implemented the same way as they are in the STL. Any function that returns a reference to a sequence element has the ability to throw exceptions in a normal hosted environment if the index is out of bounds. If exceptions are disabled, this is not possible. For now, my solution to this problem is to delegate to the user. Unsafe methods like etl::static_vector::operator[] are still available (with asserts in debug builds), while throwing methods like etl::static_vector::at are not implemented. This is currently subject to change. See Error Handling for more details.

Unlike LLVMs SmallVector, etl::static_vector & friends do not have a base class which they can slice to. My plan is to add mutable view-like non-owning types for each container. A etl::static_vector we would have a vector_ref which would work mostly like a span, but would also provide the vector interface. I don't want to name the types *_view, since the word view implies non-mutable in standard containers like string_view. None of the container_ref types have been implemented yet.

The headers etl/algorithm.hpp and etl/numeric.hpp provide all algorithms from the standard. Unlike implementations found in libstdc++ or libc++, mine are primarily optimized for code size and not runtime performance. Overloads with an ExecutionPolicy are not implemented.

Headers like etl/chrono.hpp and etl/mutex.hpp only provide classes & functions that can be implemented in a portable way. Platform specific functionality like steady_clock or mutex can be provided by the user. The user provided types should meet the requirements listed in Named Requirements to work seamlessly with the types provided in the etl namespace.

The etl/experimental subdirectory includes libraries that use etl as their foundation. It can be thought of as a mini boost-like library collection. Everything is work in progress.

  • Networking (buffers, ntoh, ...)
  • Strong types
  • STM32 HAL
  • DSP DSL
  • FreeRTOS Abstraction
    • Stubs for unittests run on desktop machines

Error Handling

Since I assume that you might have exceptions disabled, I need a different way of reporting exceptional cases to you which occured deep inside the library. To keep the behavior of my library and actual STL implementations as close as possible, I've chosen to add a global assert/exception handler functions, which can be overriden by enabling the TETL_ENABLE_CUSTOM_ASSERT_HANDLER macro.

TODO

  • ASSERT macro for debug checks
  • EXCEPTION macro for debug & release checks

For more details about the global assertion handler etl::tetl_assert_handler & the assertion macro TETL_ASSERT see the examples/cassert.cpp file.

Near Future

  • Switch from doxygen to standardese as the documentation generator
  • Fix map, tuple, variant & format
  • Improve number <-> string conversions
  • Add fuzzing tests to CI
    • Check that etl and std implementations produce the same output

Far Future

  • Replace Catch2 with custom unit testing library
    • This depends on a working implementation of format for reporting errors.
  • Run unit test & examples on hardware or QEMU emulations.
    • Depends on the custom unit test library, since Catch2 is to big to fit onto most MCUs

Project Integration

The following steps explain how to add etl to your project. Embedded or desktop.

cd path/to/your/project
mkdir 3rd_party
git submodule add https://github.com/tobanteEmbedded/tetl.git 3rd_party/tetl

Command Line / Makefile

CXXFLAGS += -std=c++20 -I3rd_party/tetl

CMake

Add tetl as a git submodule, then add these lines to your CMakeLists.txt:

# tetl::etl is an interface target, so you can use it even if you
# have a custom toolchain in your CMake configuration. The target only sets the
# include path. No static library is created.

add_subdirectory(3rd_party/tetl/include EXCLUDE_FROM_ALL)
target_link_libraries(${YOUR_TARGET} tetl::etl)

PlatformIO

Add tetl as a git submodule, then add these lines to your platformio.ini:

; Most Arduino code does not compile unless you have GNU extensions enabled.
[env:yourenv]
build_unflags = -std=gnu++11
build_flags = -std=gnu++20 -Wno-register -I 3rd_party/tetl

Header Overview

Header Library Status Implementation Progress (Spreadsheet)
algorithm Algorithms ✔️ algorithm
any Utility ❌
array Containers ✔️ array
atomic Atomic ❌
barrier Thread ❌
bit Numeric ✔️ bit
bitset Utility ✔️ bitset
cassert Utility / Error Handling ✔️ cassert
cctype Strings ✔️ cctype
cerrno Utility / Error Handling ❌
cfenv Numeric ❌ TODO
cfloat Utility / Numeric Limits ✔️ cfloat
charconv Strings ✔️ charconv
chrono Utility ✔️ chrono
cinttypes Utility / Numeric Limits ❌ TODO
climits Utility / Numeric Limits ✔️ climits
clocale Localization ❌
cmath Numeric ✔️ cmath
compare Utility ❌ TODO
complex Numeric ✔️ complex
concepts Concepts ✔️ concepts
condition_variable Thread ❌
coroutine Coroutines ❌
csetjmp Utility ❌
csignal Utility ❌
cstdarg Utility ✔️ cstdarg
cstddef Utility ✔️ cstddef
cstdint Utility / Numeric Limits ✔️ cstdint
cstdio Input/Output ✔️ cstdio
cstdlib Utility ✔️ cstdlib
cstring Strings ✔️ cstring
ctime Utility ✔️ ctime
cuchar Strings ❌
cwchar Strings ✔️ cwchar
cwctype Strings ❌
deque Containers ❌ TODO
exception Utility / Error Handling ✔️ exception
execution Algorithms ❌
expected Utility / Error Handling ✔️ expected
filesystem Filesystem ❌
format Strings ✔️ format
forward_list Containers ❌
functional Utility ✔️ functional
future Thread ❌
fstream Input/Output ❌
ifstream Input/Output ❌
initializer_list Utility ❌
iomanip Input/Output ❌
ios Input/Output ✔️ ios
iosfwd Input/Output ❌
iostream Input/Output ❌
iterator Iterator ✔️ iterator
istream Input/Output ❌
latch Thread ❌
limits Utility / Numeric Limits ✔️ limits
list Containers ❌
locale Localization ❌
map Containers ✔️ map
memory Utility / Dynamic Memory ✔️ memory
memory_resource Utility / Dynamic Memory ❌
mutex Thread ✔️ mutex
new Utility / Dynamic Memory ✔️ new
numbers Numeric ✔️ numbers
numeric Numeric ✔️ numeric
optional Utility ✔️ optional
ostream Input/Output ❌
queue Containers ❌ TODO
random Numeric ✔️ random
ranges Ranges ✔️ TODO
regex Regular Expressions ❌
ratio Numeric ✔️ ratio
scoped_allocator Utility / Dynamic Memory ❌
scope Utility ✔️
semaphore Thread ❌
source_location Utility ✔️
set Containers ✔️ set
shared_mutex Thread ❌
span Containers ✔️ span
stack Containers ✔️ stack
stack_trace Utility ❌
stdexcept Utility / Error Handling ✔️ stdexcept
streambuf Input/Output ❌
string Strings ✔️ string
string_view Strings ✔️ string_view
stop_token Thread ❌
sstream Input/Output ❌
system_error Utility / Error Handling ✔️ system_error
sync_stream Input/Output ❌
thread Thread ❌
tuple Utility ✔️ tuple
type_index Utility ❌
type_info Utility ❌
type_traits Utility ✔️ type_traits
unordered_map Containers ❌ TODO
unordered_set Containers ❌ TODO
utility Utility ✔️ utility
valarray Numeric ❌
variant Utility ✔️ variant
vector Containers ✔️ vector
version Utility ✔️
warning Utility ✔️ Not standard.

Header Detail

algorithm

array

bit

bitset

cassert

  • Library: Utility / Error Handling
  • Include: etl/cassert.hpp
  • Example: cassert.cpp
  • Implementation Progress: cassert
  • Changes:
    • Added custom assertion macro TETL_ASSERT. The behavoir can be customized. The macro get's called every time an exceptional case has occurred inside the library. See the example file for more details.

cctype

  • Library: Strings
  • Include: etl/cctype.hpp
  • Example: TODO
  • Implementation Progress: cctype
  • Changes:
    • Locale independent

cfloat

  • Library: Utility / Numeric Limits
  • Include: etl/cfloat.hpp
  • Example: TODO
  • Implementation Progress: cfloat
  • Changes:
    • None

charconv

chrono

  • Library: Utility
  • Include: etl/chrono.hpp
  • Example: chrono.cpp
  • Implementation Progress: chrono
  • Changes:
    • No clocks are implemented. You have to provide your own, which must at least meet the requirements of Clock.

climits

  • Library: Utility / Numeric Limits
  • Include: etl/climits.hpp
  • Example: TODO
  • Implementation Progress: climits
  • Changes:
    • None

cmath

  • Library: Numeric
  • Include: etl/cmath.hpp
  • Example: TODO
  • Implementation Progress: cmath
  • Changes:
    • None

complex

concepts

cstdarg

cstddef

cstdint

  • Library: Utility / Numeric Limits
  • Include: etl/cstdint.hpp
  • Example: TODO
  • Implementation Progress: cstdint
  • Changes:
    • None

cstdio

  • Library: Input/Output
  • Include: etl/cstdio.hpp
  • Example: TODO
  • Implementation Progress: cstdio
  • Changes:
    • TODO

cstdlib

cstring

ctime

  • Library: Utility
  • Include: etl/ctime.hpp
  • Example: TODO
  • Implementation Progress: ctime
  • Changes:
    • TODO

cwchar

  • Library: Strings
  • Include: etl/cwchar.hpp
  • Example: TODO
  • Implementation Progress: cwchar
  • Changes:
    • TODO

exception

expected

  • Library: Utility / Error Handling
  • Include: etl/expected.hpp
  • Example: TODO
  • Implementation Progress: expected
  • Changes:
    • TODO

format

  • Library: Strings
  • Include: etl/format.hpp
  • Example: TODO
  • Implementation Progress: format
  • Changes:
    • WIP. Don't use.

functional

ios

  • Library: Input/Output
  • Include: etl/ios.hpp
  • Example: TODO
  • Implementation Progress: ios
  • Changes:
    • TODO

iterator

limits

  • Library: Utility / Numeric Limits
  • Include: etl/limits.hpp
  • Example: TODO
  • Implementation Progress: limits
  • Changes:
    • None

map

  • Library: Containers
  • Include: etl/map.hpp
  • Example: map.cpp
  • Implementation Progress: map
  • Changes:
    • Renamed map to static_map. Fixed compile-time capacity.

memory

  • Library: Utility / Dynamic Memory
  • Include: etl/memory.hpp
  • Example: memory.cpp
  • Implementation Progress: memory
  • Changes:
    • Non-standard class templates small_ptr (compressed pointer) & pointer_int_pair (pointer + integer) are provided.

mutex

  • Library: Thread
  • Include: etl/mutex.hpp
  • Example: mutex.cpp
  • Implementation Progress: mutex
  • Changes:
    • Only RAII lock types are implemented. You have to provide a mutex type that at least meets the BasicLockable requirements.

new

  • Library: Utility / Dynamic Memory
  • Include: etl/new.hpp
  • Example: TODO
  • Implementation Progress: new
  • Changes:
    • None
    • If the standard <new> is availble it is used to define the global placement new functions to avoid ODR violations when mixing std & etl headers.

numbers

numeric

optional

random

  • Library: Random Number
  • Include: etl/random.hpp
  • Example: random.cpp
  • Implementation Progress: random
  • Changes:
    • Added basic_xorshift32 and basic_xorshift64 (Non-standard)

ratio

scope

source_location

set

  • Library: Containers
  • Include: etl/set.hpp
  • Example: set.cpp
  • Implementation Progress: set
  • Changes:
    • Renamed set to static_set. Fixed compile-time capacity.
    • If is_trivial_v<T>, then is_trivially_copyable_v<static_set<T, Capacity>>
    • If is_trivial_v<T>, then is_trivially_destructible_v<static_set<T, Capacity>>

span

  • Library: Containers
  • Include: etl/span.hpp
  • Example: TODO
  • Implementation Progress: span

stack

  • Library: Containers
  • Include: etl/stack.hpp
  • Example: TODO
  • Implementation Progress: stack
  • Changes:
    • None. Works with static_vector.

stdexcept

string

  • Library: Strings
  • Include: etl/string.hpp
  • Example: string.cpp
  • Implementation Progress: string
  • Changes:
    • Only implemeted for type char at the moment.
    • Renamed basic_string to basic_static_string. Fixed compile-time capacity.

string_view

system_error

  • Library: Utility / Error Handling
  • Include: etl/system_error.hpp
  • Example: TODO
  • Implementation Progress: system_error
  • Changes:
    • Only provides errc enum and helper traits.

tuple

type_traits

utility

variant

  • Library: Utility
  • Include: etl/variant.hpp
  • Example: TODO
  • Implementation Progress: variant
  • Changes:
    • Broken at the moment.

vector

  • Library: Containers
  • Include: etl/vector.hpp
  • Example: vector.cpp
  • Implementation Progress: vector
  • Changes:
    • Renamed vector to static_vector. Fixed compile-time capacity.
    • Based on P0843r3 and the reference implementation from github.com/gnzlbg/static_vector.
    • If is_trivial_v<T>, then is_trivially_copyable_v<static_vector<T, Capacity>>
    • If is_trivial_v<T>, then is_trivially_destructible_v<static_vector<T, Capacity>>

version

Get access to all intrinsic macros & library version macro and constants. This header also include <version> from C++20 if it is available.

#include "etl/version.hpp"

#include <stdio.h>

auto main() -> int
{
  puts(TETL_VERSION_STRING);  // Print current library version

  // Detect compiler
#if defined(TETL_MSVC)
  puts("msvc");
#if defined(TETL_GCC)
  puts("gcc");
#if defined(TETL_CLANG)
  puts("clang");
#else
  puts("other compiler");
#endif

  // Detect C++ standard
  if (etl::current_standard == language_standard::cpp_20) { puts("using C++20"); }
  if (etl::current_standard == language_standard::cpp_23) { puts("using C++23"); }

  return 0;
}

warning

#include "etl/warning.hpp"

auto main(int argc, char** argv) -> int
{
  // Explicitly ignore unused arguments or variables.
  etl::ignore_unused(argc, argv);
  return 0;
}

About

Embedded template library.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C++ 97.6%
  • Python 1.2%
  • Other 1.2%