iceoryx2
C++ Language Bindings
Loading...
Searching...
No Matches
static_string.hpp
Go to the documentation of this file.
1// Copyright (c) 2025 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13#ifndef IOX2_INCLUDE_GUARD_BB_STATIC_STRING_HPP
14#define IOX2_INCLUDE_GUARD_BB_STATIC_STRING_HPP
15
18#include "iox2/bb/optional.hpp"
20
21#include <algorithm>
22#include <cstddef>
23#include <cstdint>
24#include <cstring>
25#include <functional>
26#include <ostream>
27#include <type_traits>
28
29namespace iox2 {
30namespace bb {
31template <uint64_t Capacity>
33
34template <uint64_t Capacity>
36
37template <typename, uint64_t Capacity, DoesContainInvalidContent<Capacity>, DoesContainInvalidCharacter<Capacity>>
38class SemanticString;
39
40namespace detail {
44template <uint64_t StringCapacity>
45auto is_valid_path_to_file(const StaticString<StringCapacity>& name) noexcept -> bool;
46
49template <uint64_t StringCapacity>
50auto is_valid_path_to_directory(const StaticString<StringCapacity>& name) noexcept -> bool;
51
52} // namespace detail
53
54template <uint64_t>
55class StaticString;
56
57template <typename>
58struct IsStaticString : std::false_type { };
59
60template <uint64_t N>
61struct IsStaticString<StaticString<N>> : std::true_type { };
62
63template <typename T, typename ReturnType>
65 typename std::enable_if_t<IsStaticString<T>::value || legacy::is_char_array<T>::value, ReturnType>;
66
79template <uint64_t N>
81 public:
82 using ValueType = char;
83 using CodeUnitValueType = char;
84 using CodePointValueType = char32_t;
85 using SizeType = size_t;
86 using DifferenceType = ptrdiff_t;
87 using Reference = char&;
88 using ConstReference = char const&;
89 using Pointer = char*;
90 using ConstPointer = char const*;
97
101 friend class StaticString;
102
103 private:
104 StaticString const* m_parent;
105
106 constexpr explicit UncheckedConstAccessor(StaticString const& parent)
107 : m_parent(&parent) {
108 }
109
110 public:
113 // NOTE: can be changed to '= delete' when C++17 becomes mandatory and we can rely on RVO
117
118 constexpr auto operator[](SizeType index) const -> ConstReference {
119 return m_parent->m_string[index];
120 }
121
122 constexpr auto begin() const noexcept -> ConstIterator {
123 return &(m_parent->m_string[0]);
124 }
125
126 constexpr auto end() const noexcept -> ConstIterator {
127 return &(m_parent->m_string[m_parent->m_size]);
128 }
129
130 constexpr auto data() const noexcept -> ConstPointer {
131 return &(m_parent->m_string[0]);
132 }
133
134 constexpr auto c_str() const noexcept -> char const* {
135 return data();
136 }
137 };
138
144 friend class StaticString;
145
146 private:
147 StaticString* m_parent;
148
149 constexpr explicit UncheckedAccessor(StaticString& parent)
150 : m_parent(&parent) {
151 }
152
153 public:
156 // NOTE: can be changed to '= delete' when C++17 becomes mandatory and we can rely on RVO
160
161 constexpr auto operator[](SizeType index) -> Reference {
162 return m_parent->m_string[index];
163 }
164
165 constexpr auto begin() noexcept -> Iterator {
166 return &(m_parent->m_string[0]);
167 }
168
169 constexpr auto end() noexcept -> Iterator {
170 return &(m_parent->m_string[m_parent->m_size]);
171 }
172
173 constexpr auto data() noexcept -> Pointer {
174 return &(m_parent->m_string[0]);
175 }
176
177 constexpr auto c_str() noexcept -> char const* {
178 return data();
179 }
180 };
181
186 friend class StaticString;
187 template <typename,
188 uint64_t Capacity,
191 friend class bb::SemanticString;
192
193 private:
194 StaticString* m_parent;
195
196 constexpr explicit UncheckedAccessorCodeUnits(StaticString& parent)
197 : m_parent(&parent) {
198 }
199
205 template <typename T>
206 auto insert(SizeType index, T const& str, SizeType s_index, SizeType count = T::capacity()) ->
207 typename std::enable_if_t<IsStaticString<T>::value, bool> {
208 auto sub_str = str.code_unit_based_substr(s_index, count);
209 if (!sub_str.has_value()) {
210 return false;
211 }
212
213 auto const sub_str_size = sub_str->size();
214 auto const new_size = m_parent->m_size + sub_str_size;
215 // check if the new size would exceed capacity or a size overflow occured
216 if (new_size > N || new_size < m_parent->m_size) {
217 return false;
218 }
219
220 if (index > m_parent->m_size) {
221 return false;
222 }
223 std::copy_backward(
224 &m_parent->m_string[index], &m_parent->m_string[m_parent->m_size], &m_parent->m_string[new_size]);
225 std::copy(&sub_str->m_string[0], &sub_str->m_string[sub_str_size], &m_parent->m_string[index]);
226
227 m_parent->m_string[new_size] = '\0';
228 m_parent->m_size = new_size;
229
230 return true;
231 }
232
233 public:
236 // NOTE: can be changed to '= delete' when C++17 becomes mandatory and we can rely on RVO
240
244 if (index < m_parent->m_size) {
245 return m_parent->m_string[index];
246 } else {
247 return bb::NULLOPT;
248 }
249 }
250
254 if (!m_parent->empty()) {
255 return m_parent->m_string[0];
256 } else {
257 return bb::NULLOPT;
258 }
259 }
260
264 if (!m_parent->empty()) {
265 return m_parent->m_string[m_parent->size() - 1];
266 } else {
267 return bb::NULLOPT;
268 }
269 }
270
272 auto try_erase_at(SizeType index) noexcept -> bool {
273 return try_erase_at(index, index + 1);
274 }
275
277 auto try_erase_at(SizeType begin_index, SizeType end_index) noexcept -> bool {
278 if ((begin_index <= end_index) && (end_index <= m_parent->m_size)) {
279 auto const range_size = end_index - begin_index;
280 char* const string_end = std::end(m_parent->m_string);
281 std::move(&m_parent->m_string[end_index], string_end, &m_parent->m_string[begin_index]);
282 std::fill(&m_parent->m_string[m_parent->m_size - range_size], string_end, '\0');
283 m_parent->m_size -= range_size;
284 return true;
285 } else {
286 return false;
287 }
288 }
289 };
290
293 friend class StaticString;
294 friend auto bb::detail::is_valid_path_to_file<N>(const bb::StaticString<N>& name) noexcept -> bool;
295 friend auto bb::detail::is_valid_path_to_directory<N>(const bb::StaticString<N>& name) noexcept -> bool;
296
297 private:
298 StaticString const* m_parent;
299
300 constexpr explicit ConstAccessorCodeUnits(StaticString const& parent)
301 : m_parent(&parent) {
302 }
303
309 auto substr(SizeType pos, SizeType count) const -> bb::Optional<StaticString> {
310 return m_parent->code_unit_based_substr(pos, count);
311 }
312
319 template <typename T>
320 auto find_first_of(T const& str, SizeType pos = 0U) const
322 if (pos > m_parent->m_size) {
323 return bb::NULLOPT;
324 }
325
326 auto str_data = detail::get_data(str);
327 auto str_size = detail::get_size(str);
328 for (auto position = pos; position < m_parent->m_size; ++position) {
329 auto found = memchr(str_data, m_parent->m_string[position], static_cast<size_t>(str_size));
330 if (found != nullptr) {
331 return position;
332 }
333 }
334 return bb::NULLOPT;
335 }
336
343 template <typename T>
344 auto find_last_of(T const& str, SizeType pos = N) const
345 -> RequireStaticStringOrCharArray<T, bb::Optional<SizeType>> {
346 if (m_parent->m_size == 0) {
347 return bb::NULLOPT;
348 }
349
350 auto position = std::min(static_cast<uint64_t>(pos), m_parent->m_size - 1);
351 auto str_data = detail::get_data(str);
352 auto str_size = detail::get_size(str);
353 for (; position > 0; --position) {
354 auto found = memchr(str_data, m_parent->m_string[position], str_size);
355 if (found != nullptr) {
356 return position;
357 }
358 }
359 auto found = memchr(str_data, m_parent->m_string[0], static_cast<size_t>(str_size));
360 if (found != nullptr) {
361 return 0U;
362 }
363 return bb::NULLOPT;
364 }
365
366 public:
369 // NOTE: can be changed to '= delete' when C++17 becomes mandatory and we can rely on RVO
373
376 auto element_at(SizeType index) const noexcept -> OptionalConstCodeUnitReference {
377 if (index < m_parent->m_size) {
378 return m_parent->m_string[index];
379 } else {
380 return bb::NULLOPT;
381 }
382 }
383
387 if (!m_parent->empty()) {
388 return m_parent->m_string[0];
389 } else {
390 return bb::NULLOPT;
391 }
392 }
393
397 if (!m_parent->empty()) {
398 return m_parent->m_string[m_parent->size() - 1];
399 } else {
400 return bb::NULLOPT;
401 }
402 }
403 };
404
405 private:
406 template <uint64_t>
407 friend class StaticString;
408
409 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) encapsulated storage
410 char m_string[N + 1] = {};
411 uint64_t m_size = 0;
412
413 public:
414 // constructors
415 constexpr StaticString() noexcept = default;
416 constexpr StaticString(StaticString const&) noexcept = default;
417 constexpr StaticString(StaticString&&) noexcept = default;
418
419 template <uint64_t M, std::enable_if_t<(N > M), bool> = true>
420 // NOLINTNEXTLINE(hicpp-explicit-conversions), conceptually a copy constructor
421 constexpr StaticString(StaticString<M> const& rhs)
422 : m_size(rhs.m_size) {
423 for (size_t i = 0; i < m_size; ++i) {
424 m_string[i] = rhs.m_string[i];
425 }
426 }
427
428 // destructor
430
431 // assignment
432 constexpr auto operator=(StaticString const&) noexcept -> StaticString& = default;
433 constexpr auto operator=(StaticString&&) noexcept -> StaticString& = default;
434
435 template <uint64_t M, std::enable_if_t<(N > M), bool> = true>
436 constexpr auto operator=(StaticString<M> const& rhs) noexcept -> StaticString& {
437 m_size = rhs.m_size;
438 for (size_t i = 0; i < m_size; ++i) {
439 m_string[i] = rhs.m_string[i];
440 }
441 for (size_t i = m_size; i < N; ++i) {
442 m_string[i] = '\0';
443 }
444 return *this;
445 }
446
450 template <uint64_t M, std::enable_if_t<(N >= (M - 1)), bool> = true>
451 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) statically bounds checked
452 static auto from_utf8(char const (&utf8_str)[M]) noexcept -> bb::Optional<StaticString> {
453 if (utf8_str[M - 1] != '\0') {
454 return bb::NULLOPT;
455 }
456 StaticString ret;
457 for (uint64_t i = 0; i < M - 1; ++i) {
458 char const character = utf8_str[i];
459 if (!ret.try_push_back(character)) {
460 return bb::NULLOPT;
461 }
462 }
463 return ret;
464 }
465
472 StaticString ret;
473 while (*utf8_str != '\0') {
474 if (!ret.try_push_back(*utf8_str)) {
475 return bb::NULLOPT;
476 }
477 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic), unchecked access into c-style string
478 ++utf8_str;
479 }
480 return ret;
481 }
482
485 template <uint64_t M, std::enable_if_t<(N >= (M - 1)), bool> = true>
486 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) statically bounds checked
487 static auto from_utf8_unchecked(char const (&utf8_str)[M]) noexcept -> StaticString {
488 StaticString ret;
489 for (uint64_t i = 0; i < M - 1; ++i) {
490 char const character = utf8_str[i];
491 if (character == '\0') {
492 break;
493 }
494 ret.push_back(character);
495 }
496 return ret;
497 }
498
504 static auto from_utf8_null_terminated_unchecked_truncated(char const* utf8_str, SizeType count) -> StaticString {
505 StaticString ret;
506 auto index = std::min(static_cast<uint64_t>(count), N);
507 while (*utf8_str != '\0' && index > 0) {
508 ret.push_back(*utf8_str);
509 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic), unchecked access into c-style string
510 ++utf8_str;
511 --index;
512 }
513 return ret;
514 }
515
520 constexpr auto try_push_back(CodeUnitValueType character) noexcept -> bool {
521 if ((m_size < N) && (is_valid_next(character))) {
522 m_string[m_size] = character;
523 ++m_size;
524 // we explicitly write the terminator here, as the rust string
525 // may contain non-null characters after the end
526 m_string[m_size] = '\0';
527 return true;
528 } else {
529 return false;
530 }
531 }
532
537 constexpr auto try_pop_back() noexcept -> bool {
538 if (m_size > 0) {
539 m_string[m_size - 1] = '\0';
540 --m_size;
541 return true;
542 } else {
543 return false;
544 }
545 }
546
551 constexpr auto try_append(SizeType count, CodeUnitValueType character) noexcept -> bool {
552 if ((m_size + count <= N) && (is_valid_next(character))) {
553 std::fill(&(m_string[m_size]), &(m_string[m_size + count]), character);
554 m_size += count;
555 // we explicitly write the terminator here, as the rust string
556 // may contain non-null characters after the end
557 m_string[m_size] = '\0';
558 return true;
559 } else {
560 return false;
561 }
562 }
563
569 constexpr auto try_append_utf8_null_terminated_unchecked(char const* utf8_str) -> bool {
570 auto const old_size = size();
571 while (*utf8_str != '\0') {
572 if (!try_push_back(*utf8_str)) {
573 std::fill(&m_string[old_size], &m_string[m_size], '\0');
574 m_size = old_size;
575 return false;
576 }
577 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic), unchecked access into c-style string
578 ++utf8_str;
579 }
580 return true;
581 }
582
583 static constexpr auto capacity() noexcept -> SizeType {
584 return N;
585 }
586
587 constexpr auto size() const noexcept -> SizeType {
588 return m_size;
589 }
590
591 constexpr auto empty() const -> bool {
592 return size() == 0;
593 }
594
599
602 return ConstAccessorCodeUnits { *this };
603 }
604
607 return UncheckedAccessor { *this };
608 }
609
612 return UncheckedConstAccessor { *this };
613 }
614
615 // comparison operators
616 friend auto operator==(StaticString const& lhs, StaticString const& rhs) -> bool {
617 return std::equal(lhs.unchecked_access().begin(),
618 lhs.unchecked_access().end(),
619 rhs.unchecked_access().begin(),
620 rhs.unchecked_access().end());
621 }
622
623 friend auto operator!=(StaticString const& lhs, StaticString const& rhs) -> bool {
624 return !(lhs == rhs);
625 }
626
627 friend auto operator<(StaticString const& lhs, StaticString const& rhs) -> bool {
628 return lhs.compare(rhs) < 0;
629 }
630
631 friend auto operator<=(StaticString const& lhs, StaticString const& rhs) -> bool {
632 return lhs.compare(rhs) <= 0;
633 }
634
635 friend auto operator>(StaticString const& lhs, StaticString const& rhs) -> bool {
636 return lhs.compare(rhs) > 0;
637 }
638
639 friend auto operator>=(StaticString const& lhs, StaticString const& rhs) -> bool {
640 return lhs.compare(rhs) >= 0;
641 }
642
645 constexpr auto static_memory_layout_metrics() noexcept {
646 struct StringMemoryLayoutMetrics {
647 size_t string_alignment;
648 size_t string_size;
649 size_t sizeof_data;
650 size_t offset_data;
651 size_t sizeof_size;
652 size_t offset_size;
653 bool size_is_unsigned;
654 } ret;
655 using Self = std::remove_reference_t<decltype(*this)>;
656 ret.string_size = sizeof(Self);
657 ret.string_alignment = alignof(Self);
658 ret.sizeof_data = sizeof(m_string);
659 ret.offset_data = offsetof(Self, m_string);
660 ret.sizeof_size = sizeof(m_size);
661 ret.offset_size = offsetof(Self, m_size);
662 ret.size_is_unsigned = std::is_unsigned<decltype(m_size)>::value;
663 return ret;
664 }
665
666 private:
667 auto is_valid_next(char character) const noexcept -> bool {
668 constexpr char const CODE_UNIT_UPPER_BOUND = 127;
669 return (character > 0) && (character <= CODE_UNIT_UPPER_BOUND);
670 }
671
672 auto compare(StaticString const& other) const -> int64_t {
673 auto const other_size = other.size();
674 auto const res = memcmp(&m_string[0], &other.m_string[0], std::min(m_size, static_cast<uint64_t>(other_size)));
675 if (res == 0) {
676 if (m_size < other_size) {
677 return -1;
678 }
679 return ((m_size > other_size) ? 1 : 0);
680 }
681 return res;
682 }
683
684 constexpr void push_back(CodeUnitValueType character) noexcept {
685 m_string[m_size] = character;
686 ++m_size;
687 m_string[m_size] = '\0';
688 }
689
690 auto code_unit_based_substr(SizeType pos, SizeType count) const -> bb::Optional<StaticString> {
691 if (pos > m_size) {
692 return bb::NULLOPT;
693 }
694
695 auto const length = std::min(static_cast<uint64_t>(count), m_size - pos);
696 StaticString sub_str;
697 std::copy(&m_string[pos], &m_string[pos + length], &sub_str.m_string[0]);
698 sub_str.m_string[length] = '\0';
699 sub_str.m_size = length;
700 return sub_str;
701 }
702};
703
704} // namespace bb
705} // namespace iox2
706
707template <uint64_t N>
708auto operator<<(std::ostream& stream, const iox2::bb::StaticString<N>& value) -> std::ostream& {
709 stream << "StaticString::<" << N << "> { m_size: " << value.size() << ", m_string: \""
710 << value.unchecked_access().c_str() << "\" }";
711 return stream;
712}
713
714#endif // IOX2_INCLUDE_GUARD_BB_STATIC_STRING_HPP
#define IOX2_CONSTEXPR_DTOR
The SemanticString is a string which has an inner syntax and restrictions to valid content....
This class provides the interface for accessing individual code units of the string.
ConstAccessorCodeUnits(ConstAccessorCodeUnits &&)=default
auto front_element() const noexcept -> OptionalConstCodeUnitReference
auto operator=(ConstAccessorCodeUnits const &) -> ConstAccessorCodeUnits &=delete
auto operator=(ConstAccessorCodeUnits &&) -> ConstAccessorCodeUnits &=delete
auto back_element() const noexcept -> OptionalConstCodeUnitReference
ConstAccessorCodeUnits(ConstAccessorCodeUnits const &)=delete
auto element_at(SizeType index) const noexcept -> OptionalConstCodeUnitReference
auto operator=(UncheckedAccessorCodeUnits &&) -> UncheckedAccessorCodeUnits &=delete
auto element_at(SizeType index) noexcept -> OptionalCodeUnitReference
UncheckedAccessorCodeUnits(UncheckedAccessorCodeUnits &&)=default
auto try_erase_at(SizeType index) noexcept -> bool
Removes a single code unit at index.
auto front_element() noexcept -> OptionalCodeUnitReference
auto operator=(UncheckedAccessorCodeUnits const &) -> UncheckedAccessorCodeUnits &=delete
UncheckedAccessorCodeUnits(UncheckedAccessorCodeUnits const &)=delete
auto try_erase_at(SizeType begin_index, SizeType end_index) noexcept -> bool
Removes the range of code units at [begin_index, end_index).
auto back_element() noexcept -> OptionalCodeUnitReference
constexpr auto c_str() noexcept -> char const *
auto operator=(UncheckedAccessor const &) -> UncheckedAccessor &=delete
constexpr auto begin() noexcept -> Iterator
constexpr auto end() noexcept -> Iterator
UncheckedAccessor(UncheckedAccessor &&)=default
constexpr auto operator[](SizeType index) -> Reference
auto operator=(UncheckedAccessor &&) -> UncheckedAccessor &=delete
constexpr auto data() noexcept -> Pointer
UncheckedAccessor(UncheckedAccessor const &)=delete
constexpr auto operator[](SizeType index) const -> ConstReference
constexpr auto begin() const noexcept -> ConstIterator
auto operator=(UncheckedConstAccessor &&) -> UncheckedConstAccessor &=delete
UncheckedConstAccessor(UncheckedConstAccessor const &)=delete
constexpr auto c_str() const noexcept -> char const *
auto operator=(UncheckedConstAccessor const &) -> UncheckedConstAccessor &=delete
constexpr auto data() const noexcept -> ConstPointer
UncheckedConstAccessor(UncheckedConstAccessor &&)=default
constexpr auto end() const noexcept -> ConstIterator
IOX2_CONSTEXPR_DTOR ~StaticString()=default
constexpr auto operator=(StaticString &&) noexcept -> StaticString &=default
static auto from_utf8(char const (&utf8_str)[M]) noexcept -> bb::Optional< StaticString >
static constexpr auto capacity() noexcept -> SizeType
constexpr auto operator=(StaticString const &) noexcept -> StaticString &=default
static auto from_utf8_unchecked(char const (&utf8_str)[M]) noexcept -> StaticString
constexpr auto try_append_utf8_null_terminated_unchecked(char const *utf8_str) -> bool
bb::Optional< std::reference_wrapper< CodeUnitValueType const > > OptionalConstCodeUnitReference
friend auto operator<=(StaticString const &lhs, StaticString const &rhs) -> bool
static auto from_utf8_null_terminated_unchecked_truncated(char const *utf8_str, SizeType count) -> StaticString
bb::Optional< std::reference_wrapper< CodeUnitValueType > > OptionalCodeUnitReference
constexpr auto try_append(SizeType count, CodeUnitValueType character) noexcept -> bool
friend auto operator!=(StaticString const &lhs, StaticString const &rhs) -> bool
friend auto operator>=(StaticString const &lhs, StaticString const &rhs) -> bool
constexpr auto try_pop_back() noexcept -> bool
auto code_units() const -> ConstAccessorCodeUnits
Immutable access to the string contents on a per-code-unit basis.
friend auto operator<(StaticString const &lhs, StaticString const &rhs) -> bool
static auto from_utf8_null_terminated_unchecked(char const *utf8_str) -> bb::Optional< StaticString >
auto unchecked_access() const -> UncheckedConstAccessor
Unchecked immutable access to the string contents.
constexpr auto try_push_back(CodeUnitValueType character) noexcept -> bool
constexpr auto size() const noexcept -> SizeType
friend auto operator>(StaticString const &lhs, StaticString const &rhs) -> bool
auto unchecked_access() -> UncheckedAccessor
Unchecked mutable access to the string contents.
friend auto operator==(StaticString const &lhs, StaticString const &rhs) -> bool
bb::Optional< std::reference_wrapper< char const > > OptionalConstReference
constexpr auto empty() const -> bool
auto unchecked_code_units() -> UncheckedAccessorCodeUnits
Unchecked mutable access to the string contents on a per-code-unit basis.
bb::Optional< std::reference_wrapper< char > > OptionalReference
constexpr StaticString() noexcept=default
constexpr auto static_memory_layout_metrics() noexcept
auto is_valid_path_to_directory(const bb::StaticString< StringCapacity > &name) noexcept -> bool
returns true if the provided name is a valid path, otherwise false
auto is_valid_path_to_file(const bb::StaticString< StringCapacity > &name) noexcept -> bool
verifies if the given string is a valid path to a file
auto get_size(const StaticString< N > &data) -> uint64_t
auto get_data(const StaticString< N > &data) -> const char *
constexpr NulloptT NULLOPT
Definition optional.hpp:28
bool(*)(const StaticString< Capacity > &value) DoesContainInvalidCharacter
iox2::bb::variation::Optional< T > Optional
Definition optional.hpp:25
bool(*)(const StaticString< Capacity > &value) DoesContainInvalidContent
typename std::enable_if_t< IsStaticString< T >::value||legacy::is_char_array< T >::value, ReturnType > RequireStaticStringOrCharArray
auto operator<<(std::ostream &stream, const iox2::bb::StaticString< N > &value) -> std::ostream &
struct to check whether an argument is a char array