mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Added more documentation
Updated the documentation CSS
This commit is contained in:
parent
692360d0ed
commit
2d193ab309
220
docs/callbacks/delegate-vs-inplace_function.md
Normal file
220
docs/callbacks/delegate-vs-inplace_function.md
Normal file
@ -0,0 +1,220 @@
|
||||
---
|
||||
title: "delegate vs inplace_function"
|
||||
weight: 1
|
||||
---
|
||||
|
||||
## Efficiency and performance
|
||||
### Invocation cost
|
||||
|
||||
**delegate**
|
||||
One indirect call via stub function pointer; no allocation; forwards args directly; minimal overhead.
|
||||
|
||||
**inplace_function**
|
||||
One indirect call via vtable invoke pointer; no allocation; overhead effectively the same as `delegate`.
|
||||
|
||||
### Copy / move cost
|
||||
|
||||
**delegate**
|
||||
Trivial copy/move (object pointer + stub pointer).
|
||||
|
||||
**inplace_function**
|
||||
Copies/moves the stored callable in an inline buffer; cost depends on callable traits; may run destructor on clear/reset.
|
||||
|
||||
### Size / footprint
|
||||
|
||||
**delegate**
|
||||
Typically two pointers; very small, stable footprint.
|
||||
|
||||
**inplace_function**
|
||||
Buffer + vtable pointer + object pointer; size depends on `Object_Size`/`Object_Alignment`.
|
||||
|
||||
### Ownership / lifetime
|
||||
|
||||
**delegate**
|
||||
Non-owning for functors/lambdas; stores pointer to external callable; caller must ensure lifetime.
|
||||
|
||||
**inplace_function**
|
||||
Owning; stores a copy/move of the callable inline (RAII).
|
||||
|
||||
### When to prefer
|
||||
|
||||
**delegate**
|
||||
Minimal footprint, cheapest copies, free/member function binding, controlled lifetimes.
|
||||
|
||||
**inplace_function**
|
||||
Value semantics, safe storage of lambdas with captures, uniform SBO wrapper.
|
||||
|
||||
## External API differences
|
||||
|
||||
### Template shape and size
|
||||
|
||||
`delegate<TSignature>`
|
||||
`inplace_function<TSignature, Object_Size = 32, Object_Alignment = alignof(void*)>`
|
||||
|
||||
### Construction / binding
|
||||
|
||||
**delegate**
|
||||
`create<FreeFn>()`
|
||||
`create(T& obj, Method)` and `create(const T& obj, ConstMethod)` at run time
|
||||
`create<T, Method, Instance>()`
|
||||
Construct from functor/lambda by reference (non-owning); rvalues deleted to avoid dangling
|
||||
`set()` mirrors `create()` for re-binding
|
||||
|
||||
**inplace_function**
|
||||
Constructor from function pointer
|
||||
Constructor from object + (const/non-const) member function (run time)
|
||||
Constructor from functor/lambda by (const) reference; callable stored inline (owning)
|
||||
`set()` mirrors constructors; also `set<FreeFn>()` and `set<T, Method, Instance>()` (compile time)
|
||||
`create<FreeFn>()`, `create<T, Method, Instance>()` (compile time)
|
||||
`make_inplace_function` helpers: `make_inplace_function(free_fn)`, `make_inplace_function(obj, &T::Method)` , `make_inplace_function<TSignature>(lambda)`.
|
||||
|
||||
### Equality and swap
|
||||
|
||||
**delegate**
|
||||
`operator==`/`!=` compare stub and object; structural equality.
|
||||
|
||||
**inplace_function**
|
||||
`operator==`/`!=` with `nullptr`; `swap()` provided; no general equality between two functions.
|
||||
|
||||
### Introspection helpers
|
||||
**delegate**
|
||||
`delegate_tag`
|
||||
`is_delegate<T>`.
|
||||
|
||||
**inplace_function**
|
||||
`is_inplace_function<T>`.
|
||||
|
||||
### Call helpers
|
||||
`is_valid()`
|
||||
`explicit bool`
|
||||
`call_if(...)`
|
||||
`call_or(alternative, ...)`
|
||||
`call_or<FreeFn>(...)`.
|
||||
|
||||
### Functor storage semantics
|
||||
**delegate**
|
||||
Non-owning pointer to external functor/lambda.
|
||||
|
||||
**inplace_function**
|
||||
Owns a copy/move in fixed buffer.
|
||||
|
||||
### Size control
|
||||
**delegate**
|
||||
Fixed small size (two pointers).
|
||||
|
||||
**inplace_function**
|
||||
User-controlled via `Object_Size`/`Object_Alignment`; aliases `inplace_function_for` and `inplace_function_for_any` to compute required size/alignment.
|
||||
|
||||
### C++ language features
|
||||
Classic non-type template parameter APIs; C++17 "auto" `make_*` helpers exist when enabled.
|
||||
|
||||
## Performance differences:
|
||||
|
||||
### Call overhead
|
||||
**delegate**
|
||||
One indirect call through a stub function pointer; minimal overhead.
|
||||
|
||||
**inplace_function**
|
||||
One indirect call via `vtable->invoke(object, ...);` typically one extra pointer load; practically similar.
|
||||
|
||||
### Copy / move and lifetime
|
||||
**delegate**
|
||||
Trivial POD-like copy/move (object pointer + stub); no construction/destruction of target.
|
||||
|
||||
**inplace_function**
|
||||
Copies/moves/destroys the stored callable in the inline buffer; cost depends on callable traits.
|
||||
|
||||
### Construction / binding cost
|
||||
**delegate**
|
||||
Binding free/member functions sets two pointers; binding a functor stores its address (non-owning).
|
||||
|
||||
**inplace_function**
|
||||
Constructs a copy/move of the callable into the SBO buffer; more work up front.
|
||||
|
||||
### Memory footprint and cache locality
|
||||
**delegate**
|
||||
~2 pointers regardless of target; high container density and good cache locality.
|
||||
|
||||
**inplace_function**
|
||||
Buffer + vtable pointer + object pointer; larger, size depends on Object_Size/Object_Alignment.
|
||||
|
||||
### Clear / reset cost
|
||||
**delegate**
|
||||
Clears pointers; no destructor invocation.
|
||||
|
||||
**inplace_function**
|
||||
May run callable’s destructor; potentially non-trivial.
|
||||
|
||||
### Determinism / Real-time suitability
|
||||
**delegate**
|
||||
Very predictable and minimal costs at call/copy/reset; good for ISR/RT paths.
|
||||
|
||||
**inplace_function**
|
||||
Deterministic at call; copy/move/reset depend on callable’s traits (still allocation-free).
|
||||
|
||||
## Rule of thumb
|
||||
- Use `delegate` when:
|
||||
You only bind free/member functions or non-owning functors and want the smallest handle with the cheapest copies.
|
||||
|
||||
- Use `inplace_function` when:
|
||||
You must own captured state safely (value semantics) and still avoid the heap; accept slightly larger handle/copy costs for safety.
|
||||
|
||||
## Choose etl::delegate when
|
||||
- You need the smallest possible callable handle (two pointers) for large arrays/vectors of callbacks.
|
||||
- You must avoid any allocation, construction, destruction, or SBO buffer management in the callable wrapper.
|
||||
- You bind free functions or member functions and the target object’s lifetime is externally guaranteed.
|
||||
- You want trivial copy/move/equality semantics (copy two pointers; compare stub+object) for fast shuffling/lookup.
|
||||
- You need deterministic, RT/ISR-safe behavior with no hidden destructors or move/destruct paths on clear/reset.
|
||||
- You build static/ROM lookup tables of callbacks (compile-time create<Fn>(), create<T,Method,Instance>()).
|
||||
- You store callbacks in fixed-capacity containers (etl::array/vector) and must minimize memory per element.
|
||||
- You need ABI-stable, non-owning callback tokens passed across modules without copying callables.
|
||||
- You already use etl::delegate_service or similar indexed dispatch; its API expects etl::delegate.
|
||||
- You don't want to size/tune an inline buffer (Object_Size/Object_Alignment) per signature or platform.
|
||||
|
||||
### Typical scenarios
|
||||
- Interrupt vectors, GPIO/event ISR callbacks, hard real-time control loops.
|
||||
- Command/ID -> handler tables, message routing switchboards, state-machine transition actions.
|
||||
- Global registries/singletons where handler objects are static or live for program lifetime.
|
||||
- Shared tables of callbacks across DLLs/modules where owning captured state is undesirable.
|
||||
|
||||
### Why etl::delegate over etl::inplace_function in these cases
|
||||
- Lower footprint: always two pointers versus user-sized SBO buffer + vtable pointer + object pointer.
|
||||
- Lower copy/move cost: trivial POD-like copies; no callable copy/move/dtor required.
|
||||
- Non-owning by design: avoids accidental copies of heavy callables; no lifetime surprises at clear/reset.
|
||||
- Compile-time binding support: completely payload-free delegates for fixed targets (no storage touched).
|
||||
- Equality: pointer-based equality lets you deduplicate/lookup handlers efficiently.
|
||||
|
||||
### Notes
|
||||
- `etl::delegate` is non-owning; only choose it when the bound object outlives the delegate (rvalue lambdas are rejected by API).
|
||||
- Prefer `etl::inplace_function`0 when you must own captured state (value semantics) or need to accept arbitrary lambdas safely.
|
||||
|
||||
## Choose etl::inplace_function when
|
||||
- You need value semantics (own the callable) so lifetimes are safe without tracking external objects.
|
||||
- You want to accept arbitrary lambdas with captures and store them inline using small-buffer optimization (no heap).
|
||||
- You need a single uniform callable wrapper that erases the concrete type across modules/APIs.
|
||||
- You plan to copy/move callbacks between threads/queues safely (callable is self-contained in the buffer).
|
||||
- You must avoid dynamic allocation but still need to store captured state (tune Object_Size/Object_Alignment).
|
||||
- You want compile-time or run-time binding to free functions, member functions, and functors in one type.
|
||||
- You need reset/clear semantics that correctly destroy the stored callable (RAII).
|
||||
- You prefer exceptions on misuse (invoking uninitialized) to surface bugs early.
|
||||
|
||||
### Typical scenarios
|
||||
- Job systems, task queues, and executors that capture small state per task without heap churn.
|
||||
- Pipelines and event buses that accept user-provided lambdas with captures.
|
||||
- Configurable command tables where handlers carry lightweight configuration/state.
|
||||
- Deferred work items, timeouts, and continuations stored in fixed-capacity containers.
|
||||
- API boundaries returning/storing callbacks where the provider shouldn't manage the callee's lifetime.
|
||||
|
||||
### Why etl::inplace_function over etl::delegate in these cases
|
||||
- Ownership: inplace_function owns the callable; no external lifetime management needed.
|
||||
- Safety with captures: stores copies/moves of lambdas/functors; no dangling pointers to external objects.
|
||||
- Uniform wrapper: a single type covers free/member/functor targets with the same call site and storage.
|
||||
- No heap: SBO avoids allocations while still allowing captured state; predictable embedded-friendly footprint.
|
||||
- Destruction: clear()/reset() run the callable's destructor when needed; no leaks or latent state.
|
||||
|
||||
### Notes
|
||||
- Tune the buffer size/alignment to the largest expected callable; too-small buffers will `static_assert`.
|
||||
- Copy/move cost depends on the callable; prefer lightweight captures for best performance.
|
||||
- Invocation overhead is one indirect call through a vtable stub (similar to delegate).
|
||||
- Use make_inplace_function helpers or create<> to bind targets; is_valid(), call_if(), and call_or() are available.
|
||||
- If you only bind free/member functions and can guarantee lifetimes, etl::delegate is smaller and cheaper to copy.
|
||||
4
docs/chrono/_index.md
Normal file
4
docs/chrono/_index.md
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
title: "Chrono"
|
||||
weight: 100
|
||||
---
|
||||
32
docs/chrono/chrono-literals.md
Normal file
32
docs/chrono/chrono-literals.md
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
title: "Chrono literals"
|
||||
---
|
||||
|
||||
The ETL Chrono literals are define slightly differently from the STL in that they are user defined, as opposed to language defined.
|
||||
|
||||
**Example**
|
||||
For STL, the literal to define year `2025` would be `2025y`.
|
||||
For ETL, the literal is `2025_y`.
|
||||
|
||||
By default, the ETL uses the designations of the STL.
|
||||
As this may clash with other user defined literals, the ETL allows more verbose forms to be used, by defining the macro `ETL_USE_VERBOSE_CHRONO_LITERALS`.
|
||||
If enabled, the example of `2025_y` would be written as `2025_year`.
|
||||
|
||||
| Duration type | STL like | Verbose |
|
||||
| --------------------------- | ---------- | ------------------- |
|
||||
| `etl::chrono::year` | `2025_y` | `2025_year` |
|
||||
| `etl::chrono::day` | `10_d` | `10_day` |
|
||||
| `etl::chrono::hours` | `14_h` | `14_hours` |
|
||||
| `etl::chrono::minutes` | `30_min` | `30_minutes` |
|
||||
| `etl::chrono::seconds` | `45_s` | `45_seconds` |
|
||||
| `etl::chrono::milliseconds` | `500_ms` | `500_milliseconds` |
|
||||
| `etl::chrono::microseconds` | `500_us` | `500_microseconds` |
|
||||
| `etl::chrono::nanoseconds` | `500_ns` | `500_nanoseconds` |
|
||||
|
||||
Chrono literals may by accessed by using one of the following:-
|
||||
|
||||
```cpp
|
||||
using namespace etl::chrono;
|
||||
using namespace etl::literals;
|
||||
using namespace etl::chrono_literals;
|
||||
```
|
||||
13
docs/getting-started/ETL-logos-icons-and-graphics.md
Normal file
13
docs/getting-started/ETL-logos-icons-and-graphics.md
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
title: "ETL logos, icons and graphics"
|
||||
weight: 10
|
||||
---
|
||||
|
||||
You are given permission to ETL logos, icons and graphics in your blogs and publications.
|
||||
|
||||
**Conditions of use**
|
||||
- Do not add a drop shadow.
|
||||
- Do not adjust any part of the graphic.
|
||||
- Do not change the colours.
|
||||
- Do not change the aspect ratio.
|
||||
- Do not use the graphic to promote anything other than the ETL, unless you are informing the reader that the ETL is a major component of the work.
|
||||
15
docs/getting-started/View the docs locally/hugo commands.md
Normal file
15
docs/getting-started/View the docs locally/hugo commands.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "Hugo commands"
|
||||
---
|
||||
|
||||
## Generate hugo for localhost
|
||||
```bash
|
||||
hugo --cleanDestinationDir
|
||||
hugo server --disableFastRender
|
||||
```
|
||||
|
||||
## Generate hugo for remote host
|
||||
```bash
|
||||
hugo --cleanDestinationDir
|
||||
hugo --baseURL "https://www.your-web-site.com"`
|
||||
```
|
||||
@ -105,7 +105,3 @@ You should see `+extended` in the output, e.g.:
|
||||
```
|
||||
hugo v0.147.0+extended linux/amd64 BuildDate=...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Why extended?** The extended version includes support for **Sass/SCSS** compilation and **WebP** image processing — required by many Hugo themes.
|
||||
95
docs/getting-started/interfacing-with-c.md
Normal file
95
docs/getting-started/interfacing-with-c.md
Normal file
@ -0,0 +1,95 @@
|
||||
---
|
||||
title: "Interfacing with C"
|
||||
weight: 3
|
||||
---
|
||||
|
||||
Interfacing ETL containers with contiguous storage to a C API is fairly easy to do.
|
||||
|
||||
This is a C function that copies `count` characters , starting from `a`, to a buffer pointed to by `start`.
|
||||
|
||||
```cpp
|
||||
size_t CFunctionCopyToBuffer(char* start, size_t count)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (i < count)
|
||||
{
|
||||
*p++ = 'a' + i;
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Array**
|
||||
The ETL array is simply a C array wrapped in a C++ interface.
|
||||
|
||||
```cpp
|
||||
size_t length;
|
||||
|
||||
etl::array<char, 26> buffer;
|
||||
|
||||
length = CFunctionCopyToBuffer(buffer.data(), buffer.max_size() / 2);
|
||||
```
|
||||
|
||||
Array contains `[ a, b, c, d, e, f, g, h, i, j, k, l, m ]`
|
||||
|
||||
---
|
||||
|
||||
**Vector**
|
||||
To use a `vector` with C, you must make room for the expected new data, and then adjust to the new size after copying.
|
||||
|
||||
```cpp
|
||||
etl::vector<char, 26> buffer;
|
||||
|
||||
// Make the vector as big as it can be.
|
||||
buffer.uninitialized_resize(buffer.max_size());
|
||||
|
||||
size_t newLength = CFunctionCopyToBuffer(buffer.data(), buffer.max_size() / 2);
|
||||
|
||||
// Now adjust it back to the actual new size.
|
||||
buffer.resize(newLength);
|
||||
```
|
||||
|
||||
Vector contains `[ a, b, c, d, e, f, g, h, i, j, k, l, m ]`
|
||||
|
||||
---
|
||||
|
||||
**String**
|
||||
Strings are terminated with null characters. We can use this to easily adjust the length after copying.
|
||||
|
||||
```cpp
|
||||
etl::string<26> buffer;
|
||||
|
||||
// Ensure that the string's free space are terminator characters.
|
||||
buffer.initialize_free_space();
|
||||
|
||||
CFunctionCopyToBuffer(buffer.data(), buffer.max_size() / 2);
|
||||
|
||||
// Trim the string length at the first null terminator.
|
||||
buffer.trim_to_terminator();
|
||||
```
|
||||
|
||||
String contains `"abcdefghijklm"`
|
||||
|
||||
```cpp
|
||||
// Lets add some more characters.
|
||||
// Start at data_end() so we append to what's already there.
|
||||
// We'll use the alternative method to adjust the string length.
|
||||
// We could still use trim_to_terminator() if we wanted to.
|
||||
|
||||
// Remember the current size.
|
||||
size_t oldSize = buffer.size();
|
||||
|
||||
// Make the string as big as it can be.
|
||||
buffer.uninitialized_resize(buffer.max_size());
|
||||
|
||||
// Append the characters.
|
||||
size_t appendedSize = CFunctionCopyToBuffer(buffer.data_end(), buffer.max_size() / 2);
|
||||
|
||||
// Now adjust it back to the actual new size.
|
||||
buffer.uninitialized_resize(oldSize + appendedSize);
|
||||
```
|
||||
|
||||
String contains `"abcdefghijklmabcdefghijklm"`
|
||||
148
docs/getting-started/macros.md
Normal file
148
docs/getting-started/macros.md
Normal file
@ -0,0 +1,148 @@
|
||||
---
|
||||
title: "Macros"
|
||||
---
|
||||
|
||||
Many of the features or options in the ETL can be selected by defining the appropriate macros.
|
||||
Some macros are defined by the ETL.
|
||||
|
||||
Some of the following macros are presented as C++ constants.
|
||||
See ETL Traits
|
||||
|
||||
## User defined
|
||||
|
||||
These may be defined in the project settings or the user created `etl_profile.h`.
|
||||
|
||||
| Macro |Description |
|
||||
| --------------------------------------------- | -------------------------------------------------------------- |
|
||||
| `ETL_NO_CHECKS` | `ETL_ASSERT` has no effect. |
|
||||
| `ETL_THROW_EXCEPTIONS` | `ETL_ASSERT` throws the specified exception. |
|
||||
| `ETL_THROW_EXCEPTIONS` + `ETL_LOG_ERRORS` | `ETL_ASSERT` calls the error handler then throws an exception. |
|
||||
| `ETL_LOG_ERRORS` | `ETL_ASSERT` calls the error handler then asserts. |
|
||||
| `ETL_LOG_ERRORS` + `NDEBUG` | `ETL_ASSERT` calls the error handler. |
|
||||
| `ETL_CHECK_PUSH_POP` | Pushes and pops to containers are checked for bounds.
|
||||
| `ETL_VERBOSE_ERRORS` | If this is defined then error messages are output in their long form. |
|
||||
| `ETL_BITSET_ELEMENT_TYPE` | If this is defined, then it will become the type used for elements in the `bitset` class.<br/>Default is `uint_least8_t` |
|
||||
| `ETL_FSM_STATE_ID_TYPE` | If this is defined, then it will become the type used for FSM state id numbers.<br/>`Default is uint_least8_t`.
|
||||
| `ETL_MESSAGE_ID_TYPE` | If this is defined, then it will become the type used for message id numbers.<br/>`Default is uint_least8_t`.
|
||||
| `ETL_TIMER_SEMAPHORE_TYPE` | If this is defined, then it will become the type used for the type for the timer guard variable.<br/>This must be a type that cannot be interrupted during a read/modify/write cycle.<br/>Default is `etl::atomic_uint32_t`. |
|
||||
| `ETL_ISTRING_REPAIR_ENABLE` | Define this if you wish to `memcpy` ETL strings and repair them via an `istring` pointer or reference.<br/>Warning: This will make the container a virtual class.|
|
||||
| `ETL_IVECTOR_REPAIR_ENABLE` | Define this if you wish to memcpy ETL vectors and repair them via an `ivector` pointer or reference.<br/>Warning: This will make the container a virtual class.|
|
||||
| `ETL_IDEQUE_REPAIR_ENABLE` | Define this if you wish to memcpy ETL deques and repair them via an `ideque` pointer or reference.<br/>Warning: This will make the container a virtual class.|
|
||||
| `ETL_STLPORT` | This must be defined in the user library profile when using STLPort as the standard library implementation.|
|
||||
| `ETL_NO_STL` | If defined, the ETL will not use definitions from the STL.<br/>Instead it will use its own reverse engineered versions.|
|
||||
| `ETL_FORCE_EXPLICIT_STRING_CONVERSION_FROM_CHAR` | If defined, the ETL will force `string`, `wstring`, `u8string`, `u16string`, `u32string`, and `string_view` to have explicit construction from a character pointer.|
|
||||
| `ETL_STRING_TRUNCATION_IS_ERROR` | If defined, then a string truncation will result in an `etl::string_truncation` error being emitted.|
|
||||
| `ETL_ENABLE_ERROR_ON_STRING_TRUNCATION` | See above. |
|
||||
| `ETL_ARRAY_VIEW_IS_MUTABLE` | If defined, then `etl::array_view` is mutable. |
|
||||
| `ETL_POLYMORPHIC_BITSET` | Defining any one of these will make the corresponding container polymorphic, turning the protected non-virtual destructor to public virtual.|
|
||||
| `ETL_POLYMORPHIC_DEQUE` | |
|
||||
| `ETL_POLYMORPHIC_FLAT_MAP` | |
|
||||
| `ETL_POLYMORPHIC_FLAT_MULTIMAP` | |
|
||||
| `ETL_POLYMORPHIC_FLAT_SET` | |
|
||||
| `ETL_POLYMORPHIC_FLAT_MULTISET` | |
|
||||
| `ETL_POLYMORPHIC_FORWARD_LIST` | |
|
||||
| `ETL_POLYMORPHIC_LIST` | |
|
||||
| `ETL_POLYMORPHIC_MAP` | |
|
||||
| `ETL_POLYMORPHIC_MULTIMAP` | |
|
||||
| `ETL_POLYMORPHIC_SET` | |
|
||||
| `ETL_POLYMORPHIC_MULTISET` | |
|
||||
| `ETL_POLYMORPHIC_QUEUE` | |
|
||||
| `ETL_POLYMORPHIC_STACK` | |
|
||||
| `ETL_POLYMORPHIC_REFERENCE_FLAT_MAP` | |
|
||||
| `ETL_POLYMORPHIC_REFERENCE_FLAT_MULTIMAP` | |
|
||||
| `ETL_POLYMORPHIC_REFERENCE_FLAT_SET` | |
|
||||
| `ETL_POLYMORPHIC_REFERENCE_FLAT_MULTISET` | |
|
||||
| `ETL_POLYMORPHIC_UNORDERED_MAP` | |
|
||||
| `ETL_POLYMORPHIC_UNORDERED_MULTIMAP` | |
|
||||
| `ETL_POLYMORPHIC_UNORDERED_SET` | |
|
||||
| `ETL_POLYMORPHIC_UNORDERED_MULTISET` | |
|
||||
| `ETL_POLYMORPHIC_STRINGS` | |
|
||||
| `ETL_POLYMORPHIC_POOL` | |
|
||||
| `ETL_POLYMORPHIC_VECTOR` | |
|
||||
| `ETL_POLYMORPHIC_CONTAINERS` | If defined then all containers are polymorphic.|
|
||||
| `ETL_POLYMORPHIC_MESSAGES` | If defined then `etl::imessage` is virtual. |
|
||||
| `ETL_MESSAGES_ARE_VIRTUAL` | `ETL_MESSAGES_ARE_VIRTUAL` is deprecated and may be removed.<br/>Only valid before 19.4.1<br/>Messages are virtual, by default, from 19.4.1|
|
||||
| `ETL_USE_TYPE_TRAITS_BUILTINS` | Forces the ETL to use calls compiler built-ins.<br/>Sets all of them to be 1 if not already defined.<br/>If not defined `ETL_USE_BUILTIN_IS_ASSIGNABLE` then<br/>`ETL_USE_BUILTIN_IS_ASSIGNABLE = 1`<br/><br/>If not defined ETL_USE_BUILTIN_IS_CONSTRUCTIBLE then<br/>`ETL_USE_BUILTIN_IS_CONSTRUCTIBLE = 1`<br/><br/>If not `ETL_USE_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE` then<br/>`ETL_USE_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE = 1`<br/><br/>If not defined `ETL_USE_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE` then<br/>`ETL_USE_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE = 1`<br/><br/>If not defined `ETL_USE_BUILTIN_IS_TRIVIALLY_COPYABLE` then<br/>`ETL_USE_BUILTIN_IS_TRIVIALLY_COPYABLE = 1`<br/><br/>`ETL_TARGET_DEVICE_GENERIC`<br/>Only `ETL_TARGET_DEVICE_ARM_CORTEX_M0` and `ETL_TARGET_DEVICE_ARM` and `ETL_TARGET_DEVICE_ARM_CORTEX_M0_PLUS` are currently used in the ETL code to disable `etl::atomic`.|
|
||||
| `ETL_NO_LIBC_WCHAR_H` | Define if the libc++ used has not been compiled for `wchar_t` support.|
|
||||
|
||||
## ETL defined
|
||||
**Defined in platform.h**
|
||||
|
||||
| Macro |Description |
|
||||
| ------------------------------------ | -------------------------------------------------------------- |
|
||||
| `ETL_DEBUG` | This is defined as `1` if `DEBUG` or `_DEBUG` is defined. Otherwise `0`.|
|
||||
| `ETL_8BIT_SUPPORT` | This is defined as `1` if the platform supports 8 bit char types, otherwise 0.<br/>Deprecated.|
|
||||
| `ETL_CONSTEXPR` | If `ETL_CPP11_SUPPORTED` is defined as `1` then this macro is defined as `constexpr`, otherwise defined as blank.|
|
||||
| `ETL_CONSTEXPR11` | If `ETL_CPP11_SUPPORTED` is defined as `1` then this macro is defined as `constexpr`, otherwise defined as blank.|
|
||||
| `ETL_CONSTEXPR14` | If `ETL_CPP14_SUPPORTED` is defined as `1` then this macro is defined as `constexpr`, otherwise defined as blank.|
|
||||
| `ETL_CONSTEXPR17` | If `ETL_CPP17_SUPPORTED` is defined as `1` then this macro is defined as `constexpr`, otherwise defined as blank.|
|
||||
| `ETL_IF_CONSTEXPR` | If `ETL_CPP17_SUPPORTED` is defined as `1` then this macro is defined as `constexpr`, otherwise defined as blank.|
|
||||
| `ETL_CONSTANT` | If `ETL_CPP11_SUPPORTED` is defined as `1` then this macro is defined as `constexpr`, otherwise defined as `const`.|
|
||||
| `ETL_NOEXCEPT` | If `ETL_CPP11_SUPPORTED` is defined as `1` then this macro is defined as `noexcept`, otherwise defined as blank.|
|
||||
| `ETL_NOEXCEPT_EXPR(expression)` | If `ETL_CPP11_SUPPORTED` is defined as `1` then this macro is defined as `noexcept(expression)`, otherwise defined as blank.|
|
||||
| `ETL_NODISCARD` | If `ETL_CPP11_SUPPORTED` is defined as `1` then this macro is defined as `[[nodiscard]]`, otherwise defined as blank.|
|
||||
| `ETL_DEPRECATED` | If `ETL_CPP14_SUPPORTED` is defined as `1` then this macro is defined as `[[deprecated]]`, otherwise defined as blank.|
|
||||
| `ETL_DEPRECATED_REASON(reason)` | If `ETL_CPP14_SUPPORTED` is defined as `1` then this macro is defined as `[[deprecated(reason)]]`, otherwise defined as blank.|
|
||||
| `ETL_FALLTHROUGH` | If `ETL_CPP17_SUPPORTED` is defined as `1` then this macro is defined as `[[falltrough]]`, otherwise defined as blank.|
|
||||
| `ETL_NORETURN` | If `ETL_CPP11_SUPPORTED` is defined as `1` then this macro is defined as `[[noreturn]]`, otherwise defined as blank.|
|
||||
| `ETL_OR_STD` | If ETL_NO_STL is defined and ETL_IN_UNIT_TEST is not then `ETL_OR_STD` is defined as `etl`, otherwise it is defined as `std`.|
|
||||
| `ETL_IN_UNIT_TEST` | If defined, then the code is being compiled in the unit tests.<br/>For internal ETL use only.|
|
||||
| `ETL_HAS_ATOMIC` | This is defined as `1` if the compiler supplies an atomic class, otherwise `0`.|
|
||||
| `ETL_INLINE_VAR` | If `ETL_CPP17_SUPPORTED` is defined as `1` then this macro is defined as `inline`, otherwise defined as blank.|
|
||||
| `ETL_USING_STL` | This macro will be defined as `0` & `1` dependant of whether `ETL_NO_STL` is defined or not.|
|
||||
| `ETL_NOT_USING_STL` | Inversion of `ETL_USING_STL`.|
|
||||
| `ETL_USING_STLPORT` | This macro will be defined as `0` & `1` dependant of whether `ETL_STLPORT` is defined or not.|
|
||||
| `ETL_NOT_USING_STLPORT` | Inversion of `ETL_USING_STLPORT`.|
|
||||
| `ETL_USING_8BIT_TYPES` | This macro will be defined as `0` & `1` dependant of whether `CHAR_BIT == 8` or not.|
|
||||
| `ETL_NOT_USING_8BIT_TYPES` | Inversion of `ETL_USING_8BIT_TYPES`.|
|
||||
| `ETL_USING_64BIT_TYPES` | This macro will be defined as `0` & `1` dependant of whether `ETL_NO_64BIT_TYPES` is defined or not.|
|
||||
| `ETL_NOT_USING_64BIT_TYPES` | Inversion of `ETL_USING_64BIT_TYPES`.|
|
||||
| `ETL_HAS_ISTRING_REPAIR` | Set to `1` if the repair functionality for `etl::istring` is enabled, otherwise `0`.|
|
||||
| `ETL_HAS_IVECTOR_REPAIR` | Set to `1` if the repair functionality for `etl::ivector` is enabled, otherwise `0`.|
|
||||
| `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_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` dependant of whether `ETL_NO_LIBC_WCHAR_H` is defined or not.|
|
||||
| `ETL_NOT_USING_LIBC_WCHAR_H` | Inversion of `ETL_USING_LIBC_WCHAR_H`.|
|
||||
| `ETL_USING_CPP11` | This is defined as `1` if the compiler supports C++11, otherwise `0`.|
|
||||
| `ETL_USING_CPP14` | This is defined as `1` if the compiler supports C++14, otherwise `0`.|
|
||||
| `ETL_USING_CPP17` | This is defined as `1` if the compiler supports C++17, otherwise `0`.|
|
||||
| `ETL_USING_CPP20` | This is defined as `1` if the compiler supports C++20, otherwise `0`.|
|
||||
| `ETL_USING_CPP23` | This is defined as `1` if the compiler supports C++23, otherwise `0`.|
|
||||
|
||||
These may be user defined in `etl_profile.h`, or automatically determined in `platform.h`.
|
||||
|
||||
| Macro |Description |
|
||||
| ------------------------------------ | -------------------------------------------------------------- |
|
||||
| `ETL_CPP11_SUPPORTED` | This is defined as `1` if the compiler supports C++11, otherwise `0`.|
|
||||
| `ETL_CPP14_SUPPORTED` | This is defined as `1` if the compiler supports C++14, otherwise `0`.|
|
||||
| `ETL_CPP17_SUPPORTED` | This is defined as `1` if the compiler supports C++17, otherwise `0`.|
|
||||
| `ETL_CPP20_SUPPORTED` | This is defined as `1` if the compiler supports C++20, otherwise `0`.|
|
||||
| `ETL_CPP23_SUPPORTED` | This is defined as `1` if the compiler supports C++23, otherwise `0`.|
|
||||
| `ETL_NO_NULLPTR_SUPPORT` | This is defined as `1` if compiler does not support `nullptr`, otherwise `0`.|
|
||||
| `ETL_NO_LARGE_CHAR_SUPPORT` | This is defined as `1` if the compiler does not support `char16_t` or `char32_t` types, otherwise `0`.|
|
||||
| `ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED` | This is defined as `1` if compiler supports the `std::is_trivially_xxx` set of traits, otherwise `0`.|
|
||||
| | |
|
||||
| `ETL_COMPILER_IAR` | One of these will be defined.|
|
||||
| `ETL_COMPILER_GREEN_HILLS` | |
|
||||
| `ETL_COMPILER_INTEL` | |
|
||||
| `ETL_COMPILER_MICROSOFT` | |
|
||||
| `ETL_COMPILER_GCC` | |
|
||||
| `ETL_COMPILER_CLANG` | |
|
||||
| `ETL_COMPILER_ARM` | |
|
||||
| `ETL_COMPILER_TEXAS_INSTRUMENTS` | |
|
||||
| `ETL_COMPILER_GENERIC` | |
|
||||
| | |
|
||||
| `ETL_COMPILER_VERSION | These will be defined as the compiler version numbers, if available.|
|
||||
| `ETL_COMPILER_FULL_VERSION` | |
|
||||
| | |
|
||||
| `ETL_DEVELOPMENT_OS_WINDOWS` | One of these will be defined.|
|
||||
| `ETL_DEVELOPMENT_OS_LINUX` | |
|
||||
| `ETL_DEVELOPMENT_OS_UNIX` | |
|
||||
| `ETL_DEVELOPMENT_OS_APPLE` | |
|
||||
| `ETL_DEVELOPMENT_OS_BSD` | |
|
||||
| `ETL_DEVELOPMENT_OS_GENERIC` | |
|
||||
| | |
|
||||
| `ETL_NO_CPP_NAN_SUPPORT` | If defined, indicates that the compiler does not support nan(), nanf() or nanl().<br/>Automatically defined if using CodeWorks for ARM.|
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
ETL logos, icons and graphics
|
||||
|
||||
You are given permission to ETL logos, icons and graphics in your blogs and publications.
|
||||
|
||||
Conditions of use
|
||||
Do not add a drop shadow.
|
||||
Do not adjust any part of the graphic.
|
||||
Do not change the colours.
|
||||
Do not change the aspect ratio.
|
||||
Do not use the graphic to promote anything other than the ETL, unless you are informing the reader that the ETL is a major component of the work.
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
Interfacing with C
|
||||
|
||||
Interfacing ETL containers with contiguous storage to a C API is fairly easy to do.
|
||||
____________________________________________________________________________________________________
|
||||
This is a C function that copies count characters , starting from 'a', to a buffer pointed to by start.
|
||||
|
||||
size_t CFunctionCopyToBuffer(char* start, size_t count)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (i < count)
|
||||
{
|
||||
*p++ = 'a' + i;
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
____________________________________________________________________________________________________
|
||||
Array
|
||||
The ETL array is simply a C array wrapped in a C++ interface.
|
||||
|
||||
size_t length;
|
||||
etl::array<char, 26> buffer;
|
||||
length = CFunctionCopyToBuffer(buffer.data(), buffer.max_size() / 2);
|
||||
|
||||
Array contains [ a, b, c, d, e, f, g, h, i, j, k, l, m ]
|
||||
____________________________________________________________________________________________________
|
||||
Vector
|
||||
To use a vector with C, you must make room for the expected new data, and then adjust to the new size after copying.
|
||||
|
||||
etl::vector<char, 26> buffer;
|
||||
buffer.uninitialized_resize(buffer.max_size()); // Make the vector as big as it can be.
|
||||
size_t newLength = CFunctionCopyToBuffer(buffer.data(), buffer.max_size() / 2);
|
||||
buffer.resize(newLength); // Now adjust it back to the actual new size.
|
||||
|
||||
Vector contains [ a, b, c, d, e, f, g, h, i, j, k, l, m ]
|
||||
____________________________________________________________________________________________________
|
||||
String
|
||||
Strings are terminated with null characters. We can use this to easily adjust the length after copying.
|
||||
|
||||
etl::string<26> buffer;
|
||||
buffer.initialize_free_space(); // Ensure that the string's free space are terminators characters.
|
||||
CFunctionCopyToBuffer(buffer.data(), buffer.max_size() / 2);
|
||||
buffer.trim_to_terminator(); // Trim the string length at the first null terminator.
|
||||
|
||||
String contains "abcdefghijklm"
|
||||
|
||||
// Lets add some more characters. Start at data_end() so we append to what's already there.
|
||||
// We'll use the alternative method to adjust the string length.
|
||||
// We could still use trim_to_terminator() if we wanted to.
|
||||
size_t oldSize = buffer.size(); // Remember the current size.
|
||||
buffer.uninitialized_resize(buffer.max_size()); // Make the string as big as it can be.
|
||||
size_t appendedSize = CFunctionCopyToBuffer(buffer.data_end(), buffer.max_size() / 2);
|
||||
buffer.uninitialized_resize(oldSize + appendedSize); // Now adjust it back to the actual new size.
|
||||
|
||||
String contains "abcdefghijklmabcdefghijklm"
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
Chrono literals
|
||||
Back to chrono
|
||||
|
||||
The ETL Chrono literals are define slightly differently from the STL in that they are user defined, as opposed to language defined.
|
||||
|
||||
Example:-
|
||||
For STL, the literal to define year 2025 would be 2025y.
|
||||
For ETL, the literal is 2025_y.
|
||||
|
||||
By default, the ETL uses the designations of the STL.
|
||||
As this may clash with other user defined literals, the ETL allows more verbose forms to be used, by defining the macro ETL_USE_VERBOSE_CHRONO_LITERALS.
|
||||
If enabled, the example of 2025_y would be written as 2025_year.
|
||||
|
||||
Duration type STL like Verbose
|
||||
etl::chrono::year 2025_y 2025_year
|
||||
etl::chrono::day 10_d 10_day
|
||||
etl::chrono::hours 14_h 14_hours
|
||||
etl::chrono::minutes 30_min 30_minutes
|
||||
etl::chrono::seconds 45_s 45_seconds
|
||||
etl::chrono::milliseconds 500_ms 500_milliseconds
|
||||
etl::chrono::microseconds 500_us 500_microseconds
|
||||
etl::chrono::nanoseconds 500_ns 500_nanoseconds
|
||||
|
||||
Chrono literals may by accessed by using one of the following:-
|
||||
|
||||
using namespace etl::chrono;
|
||||
using namespace etl::literals;
|
||||
using namespace etl::chrono_literals;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,148 +0,0 @@
|
||||
etl::delegate vs etl::inplace_function
|
||||
|
||||
Efficiency and performance
|
||||
Invocation cost
|
||||
delegate: One indirect call via stub function pointer; no allocation; forwards args directly; minimal overhead.
|
||||
inplace_function: One indirect call via vtable invoke pointer; no allocation; overhead effectively the same as delegate.
|
||||
Copy/move cost
|
||||
delegate: Trivial copy/move (object pointer + stub pointer).
|
||||
inplace_function: Copies/moves the stored callable in an inline buffer; cost depends on callable traits; may run destructor on clear/reset.
|
||||
Size/footprint
|
||||
delegate: Typically two pointers; very small, stable footprint.
|
||||
inplace_function: Buffer + vtable pointer + object pointer; size depends on Object_Size/Object_Alignment.
|
||||
Ownership/lifetime
|
||||
delegate: Non-owning for functors/lambdas; stores pointer to external callable; caller must ensure lifetime.
|
||||
inplace_function: Owning; stores a copy/move of the callable inline (RAII).
|
||||
When to prefer
|
||||
delegate: Minimal footprint, cheapest copies, free/member function binding, controlled lifetimes.
|
||||
inplace_function: Value semantics, safe storage of lambdas with captures, uniform SBO wrapper.
|
||||
|
||||
External API differences
|
||||
Template shape and size
|
||||
delegate<TSignature>
|
||||
inplace_function<TSignature, Object_Size = 32, Object_Alignment = alignof(void*)>
|
||||
Construction/binding
|
||||
delegate
|
||||
create<FreeFn>()
|
||||
create(T& obj, Method) and create(const T& obj, ConstMethod) at run time
|
||||
create<T, Method, Instance>() (compile time; instance as NTTP)
|
||||
construct from functor/lambda by reference (non-owning); rvalues deleted to avoid dangling
|
||||
set() mirrors create() for re-binding
|
||||
inplace_function
|
||||
constructor from function pointer
|
||||
constructor from object + (const/non-const) member function (run time)
|
||||
constructor from functor/lambda by (const) reference; callable stored inline (owning)
|
||||
set() mirrors constructors; also set<FreeFn>() and set<T, Method, Instance>() (compile time)
|
||||
create<FreeFn>(), create<T, Method, Instance>() (compile time)
|
||||
make_inplace_function helpers: make_inplace_function(free_fn), make_inplace_function(obj, &T::Method), make_inplace_function<TSignature>(lambda)
|
||||
Equality and swap
|
||||
delegate: operator==/!= compare stub and object; structural equality.
|
||||
inplace_function: operator==/!= with nullptr; swap() provided; no general equality between two functions.
|
||||
Introspection helpers
|
||||
delegate: delegate_tag, is_delegate<T>.
|
||||
inplace_function: is_inplace_function<T>.
|
||||
Call helpers
|
||||
Both: is_valid(), explicit bool, call_if(...), call_or(alternative, ...), call_or<FreeFn>(...).
|
||||
Functor storage semantics
|
||||
delegate: Non-owning pointer to external functor/lambda.
|
||||
inplace_function: Owns a copy/move in fixed buffer.
|
||||
Size control
|
||||
delegate: Fixed small size (two pointers).
|
||||
inplace_function: User-controlled via Object_Size/Object_Alignment; aliases inplace_function_for and inplace_function_for_any to compute required size/alignment.
|
||||
C++ language features
|
||||
Both: classic non-type template parameter APIs; C++17 "auto" make_* helpers exist when enabled.
|
||||
|
||||
---------------------------------------------------------------------------------------------------
|
||||
Performance differences: etl::delegate vs etl::inplace_function
|
||||
Call overhead
|
||||
delegate: One indirect call through a stub function pointer; minimal overhead.
|
||||
inplace_function: One indirect call via vtable->invoke(object, ...); typically one extra pointer load; practically similar.
|
||||
|
||||
Copy/move and lifetime
|
||||
delegate: Trivial POD-like copy/move (object pointer + stub); no construction/destruction of target.
|
||||
inplace_function: Copies/moves/destroys the stored callable in the inline buffer; cost depends on callable traits.
|
||||
|
||||
Construction/binding cost
|
||||
delegate: Binding free/member functions sets two pointers; binding a functor stores its address (non-owning).
|
||||
inplace_function: Constructs a copy/move of the callable into the SBO buffer; more work up front.
|
||||
|
||||
Memory footprint and cache locality
|
||||
delegate: ~2 pointers regardless of target; high container density and good cache locality.
|
||||
inplace_function: Buffer + vtable pointer + object pointer; larger, size depends on Object_Size/Object_Alignment.
|
||||
|
||||
Clear/reset cost
|
||||
delegate: Clears pointers; no destructor invocation.
|
||||
inplace_function: May run callable’s destructor; potentially non-trivial.
|
||||
|
||||
Determinism/Real-time suitability
|
||||
delegate: Very predictable and minimal costs at call/copy/reset; good for ISR/RT paths.
|
||||
inplace_function: Deterministic at call; copy/move/reset depend on callable’s traits (still allocation-free).
|
||||
|
||||
Rule of thumb
|
||||
Use delegate when:
|
||||
You only bind free/member functions or non-owning functors and want the smallest handle with the cheapest copies.
|
||||
|
||||
Use inplace_function when:
|
||||
You must own captured state safely (value semantics) and still avoid the heap; accept slightly larger handle/copy costs for safety.
|
||||
|
||||
---------------------------------------------------------------------------------------------------
|
||||
Choose etl::delegate when
|
||||
You need the smallest possible callable handle (two pointers) for large arrays/vectors of callbacks.
|
||||
You must avoid any allocation, construction, destruction, or SBO buffer management in the callable wrapper.
|
||||
You bind free functions or member functions and the target object’s lifetime is externally guaranteed.
|
||||
You want trivial copy/move/equality semantics (copy two pointers; compare stub+object) for fast shuffling/lookup.
|
||||
You need deterministic, RT/ISR-safe behavior with no hidden destructors or move/destruct paths on clear/reset.
|
||||
You build static/ROM lookup tables of callbacks (compile-time create<Fn>(), create<T,Method,Instance>()).
|
||||
You store callbacks in fixed-capacity containers (etl::array/vector) and must minimize memory per element.
|
||||
You need ABI-stable, non-owning callback tokens passed across modules without copying callables.
|
||||
You already use etl::delegate_service or similar indexed dispatch; its API expects etl::delegate.
|
||||
You don't want to size/tune an inline buffer (Object_Size/Object_Alignment) per signature or platform.
|
||||
|
||||
Typical scenarios
|
||||
Interrupt vectors, GPIO/event ISR callbacks, hard real-time control loops.
|
||||
Command/ID -> handler tables, message routing switchboards, state-machine transition actions.
|
||||
Global registries/singletons where handler objects are static or live for program lifetime.
|
||||
Shared tables of callbacks across DLLs/modules where owning captured state is undesirable.
|
||||
|
||||
Why etl::delegate over etl::inplace_function in these cases
|
||||
Lower footprint: always two pointers versus user-sized SBO buffer + vtable pointer + object pointer.
|
||||
Lower copy/move cost: trivial POD-like copies; no callable copy/move/dtor required.
|
||||
Non-owning by design: avoids accidental copies of heavy callables; no lifetime surprises at clear/reset.
|
||||
Compile-time binding support: completely payload-free delegates for fixed targets (no storage touched).
|
||||
Equality: pointer-based equality lets you deduplicate/lookup handlers efficiently.
|
||||
|
||||
Notes
|
||||
etl::delegate is non-owning; only choose it when the bound object outlives the delegate (rvalue lambdas are rejected by API).
|
||||
Prefer etl::inplace_function when you must own captured state (value semantics) or need to accept arbitrary lambdas safely.
|
||||
|
||||
---------------------------------------------------------------------------------------------------
|
||||
Choose etl::inplace_function when
|
||||
You need value semantics (own the callable) so lifetimes are safe without tracking external objects.
|
||||
You want to accept arbitrary lambdas with captures and store them inline using small-buffer optimization (no heap).
|
||||
You need a single uniform callable wrapper that erases the concrete type across modules/APIs.
|
||||
You plan to copy/move callbacks between threads/queues safely (callable is self-contained in the buffer).
|
||||
You must avoid dynamic allocation but still need to store captured state (tune Object_Size/Object_Alignment).
|
||||
You want compile-time or run-time binding to free functions, member functions, and functors in one type.
|
||||
You need reset/clear semantics that correctly destroy the stored callable (RAII).
|
||||
You prefer exceptions on misuse (invoking uninitialized) to surface bugs early.
|
||||
|
||||
Typical scenarios
|
||||
Job systems, task queues, and executors that capture small state per task without heap churn.
|
||||
Pipelines and event buses that accept user-provided lambdas with captures.
|
||||
Configurable command tables where handlers carry lightweight configuration/state.
|
||||
Deferred work items, timeouts, and continuations stored in fixed-capacity containers.
|
||||
API boundaries returning/storing callbacks where the provider shouldn't manage the callee's lifetime.
|
||||
|
||||
Why etl::inplace_function over etl::delegate in these cases
|
||||
Ownership: inplace_function owns the callable; no external lifetime management needed.
|
||||
Safety with captures: stores copies/moves of lambdas/functors; no dangling pointers to external objects.
|
||||
Uniform wrapper: a single type covers free/member/functor targets with the same call site and storage.
|
||||
No heap: SBO avoids allocations while still allowing captured state; predictable embedded-friendly footprint.
|
||||
Destruction: clear()/reset() run the callable's destructor when needed; no leaks or latent state.
|
||||
|
||||
Notes
|
||||
Tune the buffer size/alignment to the largest expected callable; too-small buffers will static_assert.
|
||||
Copy/move cost depends on the callable; prefer lightweight captures for best performance.
|
||||
Invocation overhead is one indirect call through a vtable stub (similar to delegate).
|
||||
Use make_inplace_function helpers or create<> to bind targets; is_valid(), call_if(), and call_or() are available.
|
||||
If you only bind free/member functions and can guarantee lifetimes, etl::delegate is smaller and cheaper to copy.
|
||||
@ -1,6 +0,0 @@
|
||||
|
||||
Generate hugo for local
|
||||
hugo --cleanDestinationDir
|
||||
|
||||
Generate hugo for remote test
|
||||
hugo --cleanDestinationDir --baseURL "https://www.etlcpp.com/hugo/"
|
||||
@ -19,11 +19,11 @@ const_iterator Constant forward iterator
|
||||
____________________________________________________________________________________________________
|
||||
Constructor
|
||||
|
||||
etl::bresenham_line<T>;
|
||||
etl::bresenham_line<T>();
|
||||
etl::bresenham_line<T>(T first_x, T first_y, T last_x, T last_y);
|
||||
etl::bresenham_line<T>(const etl::coordinate_2d<T>& first, const etl::coordinate_2d<T>& last);
|
||||
____________________________________________________________________________________________________
|
||||
Initialization
|
||||
Initialisation
|
||||
|
||||
void reset(T first_x, T first_y, T last_x, T last_y);
|
||||
void reset(const etl::coordinate_2d<T>& first, const etl::coordinate_2d<T>& last);
|
||||
|
||||
@ -1,406 +0,0 @@
|
||||
String Utilities
|
||||
|
||||
A set of utilities to make string manipulation a little easier.
|
||||
|
||||
The documentation below is for handling etl::string.
|
||||
The other strings have a similar API, though using w, u16 or u32 types from the ETL and STL.
|
||||
The string utilities are compatible with any string-like container that exposes a compatible API.
|
||||
|
||||
Example
|
||||
void trim_whitespace_left(etl::istring& s)
|
||||
void trim_whitespace_left(etl::iwstring& s)
|
||||
void trim_whitespace_left(std::string& s)
|
||||
void trim_whitespace_left(std::u32string& s)
|
||||
|
||||
Whitespace
|
||||
Whitespace characters are deemed as ' ', '\t', '\n', '\r', '\f', '\v'
|
||||
____________________________________________________________________________________________________
|
||||
Modifying functions
|
||||
|
||||
void trim_whitespace_left(etl::istring& s)
|
||||
|
||||
Trims the whitespace characters from the left of s.
|
||||
____________________________________________________________________________________________________
|
||||
void trim_from_left(etl::istring& s,
|
||||
etl::istring::const_pointer trim_characters)
|
||||
|
||||
Trims any of the characters in trim_characters from the left of s.
|
||||
Stops at the first character not in trim_characters.
|
||||
____________________________________________________________________________________________________
|
||||
void trim_left(etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Trims all of the characters in up to the first character in delimiters from the left of s.
|
||||
____________________________________________________________________________________________________
|
||||
void trim_whitespace_right(etl::istring& s)
|
||||
|
||||
Trims the whitespace characters from the right of s.
|
||||
___________________________________________________________________________________________________
|
||||
void trim_from_right(etl::istring& s,
|
||||
etl::istring::const_pointer trim_characters)
|
||||
|
||||
Trims any of the characters in trim_characters from the right of s.
|
||||
Stops at the first character not in trim_characters.
|
||||
____________________________________________________________________________________________________
|
||||
void trim_right(etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Trims all of the characters in up to the first character in delimiters from the right of s.
|
||||
____________________________________________________________________________________________________
|
||||
void trim_whitespace(etl::istring& s)
|
||||
|
||||
Trims the whitespace characters from both ends of s.
|
||||
____________________________________________________________________________________________________
|
||||
void trim_from(etl::istring& s,
|
||||
etl::istring::const_pointer trim_characters)
|
||||
|
||||
Trims any of the characters in trim_characters from the right of s.
|
||||
Stops at the first character not in trim_characters.
|
||||
____________________________________________________________________________________________________
|
||||
void trim(etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
Trims all of the characters in up to the first character in delimiters from both ends of s.
|
||||
____________________________________________________________________________________________________
|
||||
void reverse(etl::istring& s)
|
||||
|
||||
Reverses s.
|
||||
____________________________________________________________________________________________________
|
||||
void left_n(etl::istring& s,
|
||||
size_t n)
|
||||
|
||||
Trims s to the left n most characters.
|
||||
If the string is less than n characters long then it is left unchanged.
|
||||
____________________________________________________________________________________________________
|
||||
void right_n(etl::istring& s,
|
||||
size_t n)
|
||||
|
||||
Trims s to the right n most characters.
|
||||
If the string is less than n characters long then it is left unchanged.
|
||||
____________________________________________________________________________________________________
|
||||
void pad_left(etl::istring& s,
|
||||
size_t required_size,
|
||||
etl::istring::value_type pad_char)
|
||||
|
||||
Pads s to length required_size by adding pad_char to the left.
|
||||
If the string length is greater than or equal to required_size then it is left unchanged.
|
||||
____________________________________________________________________________________________________
|
||||
void pad_right(etl::istring& s,
|
||||
size_t required_size,
|
||||
etl::istring::value_type pad_char)
|
||||
|
||||
Pads s to length required_size by adding pad_char to the right.
|
||||
If the string length is greater than or equal to required_size then it is left unchanged.
|
||||
____________________________________________________________________________________________________
|
||||
void pad(etl::istring& s,
|
||||
size_t required_size,
|
||||
string_pad_direction pad_direction,
|
||||
etl::istring::value_type pad_char)
|
||||
|
||||
Pads s to length required_size by adding pad_char to the end specified by pad_direction.
|
||||
If the string length is greater than or equal to required_size then it is left unchanged.
|
||||
____________________________________________________________________________________________________
|
||||
void to_upper_case(etl::istring& s)
|
||||
|
||||
Change s to upper case.
|
||||
"hElLo WoRLd" => "HELLO WORLD"
|
||||
|
||||
Valid for etl::istring only.
|
||||
____________________________________________________________________________________________________
|
||||
void to_lower_case(etl::istring& s)
|
||||
|
||||
Change s to lower case.
|
||||
"hElLo WoRLd" => "hello world"
|
||||
|
||||
Valid for etl::istring only.
|
||||
____________________________________________________________________________________________________
|
||||
void to_sentence_case(etl::istring& s)
|
||||
|
||||
Change s to sentence case.
|
||||
"hElLo WoRLd" => "Hello world"
|
||||
|
||||
Valid for etl::istring only.
|
||||
____________________________________________________________________________________________________
|
||||
void replace(etl::istring& s,
|
||||
const etl::pair<etl::istring::value_type,
|
||||
etl::istring::value_type>* pairsbegin,
|
||||
const etl::pair<etl::istring::value_type,
|
||||
etl::istring::value_type>* pairsend)
|
||||
|
||||
pairsbegin Pointer to the first pair in the list.
|
||||
pairsend Pointer to one past the last pair in the list.
|
||||
|
||||
Replaces characters according the supplied lookup table of etl::pair.
|
||||
Each pair specifies an old/new character replacement.
|
||||
____________________________________________________________________________________________________
|
||||
void replace(etl::istring& s,
|
||||
const etl::pair<const etl::istring::value_type*,
|
||||
const etl::istring::value_type*>* pairsbegin,
|
||||
const etl::pair<const etl::istring::value_type*,
|
||||
const etl::istring::value_type*>* pairsend)
|
||||
|
||||
pairsbegin Pointer to the first pair in the list.
|
||||
pairsend Pointer to one past the last pair in the list.
|
||||
|
||||
Replaces strings according the supplied lookup table of etl::pair.
|
||||
Each pair specifies an old/new string replacement.
|
||||
____________________________________________________________________________________________________
|
||||
Non-modifying functions
|
||||
|
||||
etl::string_view trim_view_whitespace_left(const etl::string_view& view)
|
||||
|
||||
Returns a string_view of the whitespace characters trimmed from the left of view.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view trim_from_view_left(const etl::string_view& view,
|
||||
etl::istring::const_pointer trim_characters)
|
||||
|
||||
Returns a string_view of the characters in trim_characters trimmed from the left of view.
|
||||
Stops at the first character not in trim_characters.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view trim_view_left(etl::string_view& view,
|
||||
etl::string_view::const_pointer delimiters)
|
||||
|
||||
Returns a string_view of the characters in up to the first character in delimiters from the left of view.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view trim_view_whitespace_right(const etl::string_view& view)
|
||||
|
||||
Returns a string_view of the whitespace characters trimmed from the right of view.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view trim_from_view_right(const etl::string_view& view,
|
||||
etl::istring::const_pointer trim_characters)
|
||||
|
||||
Returns a string_view of the characters in trim_characters trimmed from the right of view.
|
||||
Stops at the first character not in trim_characters.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view trim_view_right(const etl::string_view& view,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a string_view of the characters in up to the first character in delimiters from the right of view.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view trim_whitespace(const etl::string_view& view)
|
||||
|
||||
Returns a string_view of the whitespace characters trimmed from both ends of view.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view trim_view_from(const etl::string_view& view,
|
||||
etl::istring::const_pointer trim_characters)
|
||||
|
||||
Returns a string_view of the characters in trim_characters trimmed from both ends of view.
|
||||
Stops at the first character not in trim_characters.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view trim(const etl::string_view& view,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a string_view of the characters in up to the first character in delimiters from both ends of view.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view left_n_view(etl::string_view view,
|
||||
size_t n)
|
||||
|
||||
Returns a string_view to the left n most characters of view.
|
||||
If the string is less than n characters long then the returned view equal the supplied view.
|
||||
____________________________________________________________________________________________________
|
||||
etl::string_view right_n_view(etl::string_view view,
|
||||
size_t n)
|
||||
|
||||
Returns a string_view to the right n most characters of view.
|
||||
If the string is less than n characters long then the returned view equal the supplied view.
|
||||
____________________________________________________________________________________________________
|
||||
etl::optional<etl::string_view> get_token(const INPUT_TYPE& s,
|
||||
const char* delimiters,
|
||||
const etl::optional<etl::string_view>& last_view,
|
||||
bool ignore_empty_tokens)
|
||||
|
||||
Where INPUT_TYPE is any container type that supports data() and size() member functions.
|
||||
Tokenizes the string.
|
||||
The returned token will be invalid for the call after the last token has been extracted.
|
||||
|
||||
s The string to tokenize.
|
||||
delimiters The delimiters between tokens.
|
||||
last_view The last returned token view or default constructed view.
|
||||
ignore_empty_tokens If true, empty tokens will be ignored, otherwise empty tokens will return an empty view.
|
||||
|
||||
Example
|
||||
using String = etl::string<32>;
|
||||
using StringView = etl::string_view;
|
||||
using Vector = etl::vector<String, 10>;
|
||||
using Token = etl::optional<StringView>;
|
||||
|
||||
String text(" The cat.sat, on;the:mat .,;:");
|
||||
Vector tokens;
|
||||
|
||||
Token token; // Default constructed token.
|
||||
|
||||
while ((token = etl::get_token(text, " .,;:", token, true))) // Exit once we get an invalid token.
|
||||
{
|
||||
// Place it in the token list.
|
||||
tokens.emplace_back(token.value());
|
||||
}
|
||||
tokens will contain "The", "cat", "sat", "on", "the", "mat"
|
||||
____________________________________________________________________________________________________
|
||||
template <typename TInput, typename TOutput>
|
||||
bool get_token_list(const TInput& input,
|
||||
TOutput& output,
|
||||
typename TInput::const_pointer delimiters,
|
||||
bool ignore_empty_tokens,
|
||||
size_t max_n_tokens = etl::integral_limits<size_t>::max)
|
||||
|
||||
20.41.0
|
||||
Splits a string of tokens to a set of views, according to a set of delimiters.
|
||||
|
||||
input The input string.
|
||||
output A reference to an output container of string views.
|
||||
delimiters A pointer to a string of valid delimiters.
|
||||
ignore_empty_tokens If true then empty tokens are ignored.
|
||||
max_n_tokens The maximum number of tokens to collect. Default: tokenise everything.
|
||||
|
||||
Returns true if all tokens were added to the list, otherwise false.
|
||||
|
||||
The tokenisation stops if:
|
||||
1. The end of the input text is reached.
|
||||
2. The max_size() of the output container is reached.
|
||||
3. The number of tokens found reaches max_n_tokens.
|
||||
|
||||
The input container must define the type const_pointer.
|
||||
The output container must define the type value_type.
|
||||
The output container must define the member function max_size() that returns the maximum size of the container.
|
||||
The output container must define the member function push_back() that pushes the view on to the back of the container.
|
||||
|
||||
Example
|
||||
std::string text(",,,The,cat,sat,,on,the,mat");
|
||||
std::vector<std::string_view> views;
|
||||
|
||||
bool all_views_found = etl::get_token_list(text, views, ",", true, 3);
|
||||
|
||||
all_views_found == false
|
||||
views.size() == 3
|
||||
views[0] == "The"
|
||||
views[1] == "cat"
|
||||
views[2] == "sat"
|
||||
____________________________________________________________________________________________________
|
||||
Find functions
|
||||
|
||||
etl::istring::iterator find_first_of(etl::istring::iterator first,
|
||||
etl::istring::iterator last,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns an iterator to the first instance of a character in delimiters.
|
||||
Returns last if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_first_of(etl::istring::const_iterator first,
|
||||
etl::istring::const_iterator last,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the first instance of a character in delimiters.
|
||||
Returns last if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::iterator find_first_of(etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns an iterator to the first instance of a character in delimiters.
|
||||
Returns s.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_first_of(const etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the first instance of a character in delimiters.
|
||||
Returns s.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_first_of(const etl::string_view& view,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the first instance of a character in delimiters.
|
||||
Returns view.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::iterator find_first_not_of(etl::istring::iterator first,
|
||||
etl::istring::iterator last,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns an iterator to the first instance of a character not in delimiters.
|
||||
Returns last if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_first_not_of(etl::istring::const_iterator first,
|
||||
etl::istring::const_iterator last,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the first instance of a character not in delimiters.
|
||||
Returns last if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::iterator find_first_not_of(etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns an iterator to the first instance of a character not in delimiters.
|
||||
Returns s.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_first_not_of(const etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the first instance of a character not in delimiters.
|
||||
Returns s.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_first_not_of(const etl::string_view& view,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the first instance of a character not in delimiters.
|
||||
Returns view.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::iterator find_last_of(etl::istring::iterator first,
|
||||
etl::istring::iterator last,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns an iterator to the last instance of a character in delimiters.
|
||||
Returns last if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_last_of(etl::istring::const_iterator first,
|
||||
etl::istring::const_iterator last,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the last instance of a character in delimiters.
|
||||
Returns last if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::iterator find_last_of(etl::istring& s, etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns an iterator to the last instance of a character in delimiters.
|
||||
Returns s.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_last_of(const etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the last instance of a character in delimiters.
|
||||
Returns s.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_last_of(const etl::string_view& view,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the last instance of a character in delimiters.
|
||||
Returns view.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::iterator find_last_not_of(etl::istring::iterator first,
|
||||
etl::istring::iterator last,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns an iterator to the last instance of a character not in delimiters.
|
||||
Returns last if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_last_not_of(etl::istring::const_iterator first,
|
||||
etl::istring::const_iterator last,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the last instance of a character not in delimiters.
|
||||
Returns last if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::iterator find_last_not_of(etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns an iterator to the last instance of a character not in delimiters.
|
||||
Returns last if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_last_not_of(const etl::istring& s,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the last instance of a character not in delimiters.
|
||||
Returns s.end() if not found.
|
||||
____________________________________________________________________________________________________
|
||||
etl::istring::const_iterator find_last_not_of(const etl::string_view& view,
|
||||
etl::istring::const_pointer delimiters)
|
||||
|
||||
Returns a const iterator to the last instance of a character not in delimiters.
|
||||
Returns view.end() if not found.
|
||||
|
||||
@ -13,7 +13,7 @@ html:not(.dark) h1 {
|
||||
color: coral !important;
|
||||
width: 100%;
|
||||
background-color: rgb(246, 246, 246) !important;
|
||||
border: rgb(194, 97, 62) solid 3px !important;
|
||||
border: black solid 3px !important;
|
||||
padding: 0.5rem 0.5rem !important;
|
||||
}
|
||||
|
||||
@ -25,7 +25,8 @@ html:not(.dark) h2 {
|
||||
html:not(.dark) h3,
|
||||
html:not(.dark) h4
|
||||
{
|
||||
color: darkgoldenrod !important;
|
||||
color: darkgoldenrod !important;
|
||||
border-bottom: 2px solid darkgrey !important;
|
||||
}
|
||||
|
||||
html:not(.dark) p {
|
||||
@ -120,7 +121,7 @@ html.dark h1
|
||||
color: coral !important;
|
||||
width: 100%;
|
||||
background-color: rgb(50, 50, 50) !important;
|
||||
border: rgb(148, 75, 48) solid 2px !important;
|
||||
border: lightgrey solid 2px !important;
|
||||
padding: 0.5rem 0.5rem !important;
|
||||
}
|
||||
|
||||
@ -132,6 +133,7 @@ html.dark h2 {
|
||||
html.dark h3,
|
||||
html.dark h4 {
|
||||
color: lightgreen !important;
|
||||
border-bottom: 2px solid #505050 !important;
|
||||
}
|
||||
|
||||
html.dark p {
|
||||
@ -312,10 +314,11 @@ h3 {
|
||||
font-family: Roboto, sans-serif !important;
|
||||
font-style: normal !important;
|
||||
font-weight: normal !important;
|
||||
font-size: 130% !important;
|
||||
margin-top: 0.5em !important;
|
||||
font-size: 120% !important;
|
||||
margin-top: 0.7em !important;
|
||||
margin-bottom: 0em !important;
|
||||
padding: 0 !important;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@ -325,6 +328,7 @@ h4 {
|
||||
font-size: 110% !important;
|
||||
margin-top: 0.5em !important;
|
||||
margin-bottom: 0.5em !important;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
dl {
|
||||
@ -408,7 +412,12 @@ p {
|
||||
font-style: normal !important;
|
||||
font-weight: normal !important;
|
||||
font-size: 110% !important;
|
||||
margin-top: 1em !important;
|
||||
margin-top: 0.5em !important;
|
||||
}
|
||||
|
||||
tr td code{
|
||||
font-family: 'Roboto Mono', monospace !important;
|
||||
font-size: 0.8rem !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user