emlabcpp
modern opinionated embedded C++ library
|
An opinionated C++20 library focusing on embedded development. It provides a wide set of tools, from complex mechanisms (protocol library) to simple utilites (view).
Want help? Find veverak
on Amulius Embedded Discord
Repository is at https://github.com/koniarik/emlabcpp The prefered of getting the library for now is via fetchcontent:
The library can be view as a set of components. These are organized based on the root header file for the said component.
Contains a set of algorithms similar to <algorithm> standard library, with a major change. Functions take as an argument a container itself, rather than iterators. Most of the functions are also able to work with std::tuple
. This is expanded with other short functions representing simple algorithms.
The two core functions are find_if
and for_each
, both are implemented with variant over containers and tuples.
See examples for an overview of algorithms.
Provides EMLABCPP_ASSERT(c)
macro that has three states:
assert(c)
if EMLABCPP_ASSERT_NATIVE
is defined.EMLABCPP_ASSERT_FUNC(c)
if EMLABCPP_ASSERT_FUNC
is defined.By default, none of the macros are defined.
Provides bounded<T,Min,Max>
class that envelops type T
and provides interface that enforces T
to remain within bounds Min
and Max
. Can be used to relay value constrains in type information.
For example:
A set of C++ concepts designed for implementing a checks inside the library.
Simple utility class to setup code segments executed after the end of scope:
This enforces that "finished" message is send after the exec_job
call finishes.
Provides a function that converts enum value into string representative, this either does simple int->string
conversion or uses magic_enum
library if it is enabled with EMLABCPP_USE_MAGIC_ENUM
define.
For example:
Outputs FOO
if magic_enum
is enabled and 0
otherwise.
Contains generic_iterator<Derived>
CRTP baseclass. This simplifies implementation of custom iterators, as most of the methods/operators we expect of iterators can be implemented based on a small set of functions. (operator+, operator++(int), operator++ can be implemetned with operator+=)
For implementing iterator, you only provide the basic subset for this class and it takes care of the rest. Keep in mind that this is for "general" use case, and for optimallity you may be better served with fully custom iterator.
Iterator that mimics real data container of sequence of numbers. The number is stored inside the iterator and when iterator is advanced, so is the internal value changed. Use functions like range(from,to)
to creates a range from this iterators.
Match is mechanism similar to std::visit(Callable,Variant)
, but one that changes the order of arguments and allows mutliple callables. The signature is along the lines of: match(Variant,Callable...)
. The implementation composes callables together and let's method resolution pick the appropaite callable for alternative present in the variant.
This makes it possible to write constructs such as these:
Here, the function executions a lambda for the state that is present in the variant, you can think about it like a switch
but for variant.
System of physical quantities based on quantity.h
. These represent physical quantity that stores it's unit in it's own type (templated).
This makes it possible to have velocity/length/time represented as distinct types. Also, the result type of operations like length divided by time is of type velocity.
This increases safety of physical computations, as it enforces correct units in the math. The operator<<
is overloaded to output units for the type, such as: 0.25m
Basic PID regulator implementation using floats, templated based on the time type.
The protocol library serializes and deserialize C++ data structures into binary messages. The principle is that the protocol is defined with library types. Based on the definition, protocol_handler<Def>
provides routines for serialization and deserialization of data structures corresponding to said definition.
In case of work with simple robot, we can create simple protocol:
See examples for more detailed explanation.
Simple thin overlay over numeric types, that gives abillity to implement strongly typed numeric types. This is handy in case you want to enforce correctness on type level. See implementation of physical_quantity
as an example.
Basic implementation of circular buffer with static maximal size, that can store non-default constructible elements. No dynamic allocation is used.
Basic implementation of vector with static maximal size, that can store non-default constructible elements. No dynamic allocation is used.
A library of helpers for type inspection, this contains types similar to type_traits
of standard library. This follows the pattern of std::
library - type check is structure with ::value
/::type
attributes and using for _v
/_t
suffixed aliases exists.
Simple container storing a pair of iterators - non-owning container of data. This make it possible to pass a subset of container to API expecting a container itself. It is also more sensible for functions that would return std::pair
of iterators.
visit
is reimplementation of std::visit
that has worse time complexity in exchange of less code being generate for the mechanism. It also drop support for multiple variants.
zip iterator over multiple data containers, which dereference value is tuple of references to provided containers.
This is especially handy in combination with numeric iterator. Example is enumerate(cont)
which returns zip of range over cont size and cont itself, which behaves same as enumerate on python.