| .woodpecker | ||
| allib2 | ||
| examples | ||
| .clang-format | ||
| .gitignore | ||
| config.hpp.in | ||
| config.py | ||
| LICENSE | ||
| meson.build | ||
| meson.build.in | ||
| README.md | ||
| TODO | ||
ostream
light-weight byte output stream interface
stream << "some" << "text" << 123;
implementations
fixed_buf_stream
static char buf[256] = {0};
allib2::fixed_buf_stream stream = allib2::fixed_buf_stream(allib2::slice<char>(buf));
filep_stream
FILE* f = fopen(...);
filep_stream stream = filep_stream(f);
....
fclose(f);
maybe
aka optional
maybe<int> = 1;
maybe<int> = none_t;
result
result<int, err> myRes = err_result<err>(err(...));
result<int, err> myRes = ok_result<int>(0);
but also:
struct err {
static alloc_fail_err create_default_err_result() {
return err();
}
};
result<int, err> myRes = err_result<err>();
If the error type extend allib2::error, you can do result.as_dyn_err()
vec<Ty, Allocator>
Use .as_slice() for accessing elements.
box<Ty, Allocator>
basically a std::unique_ptr
strstream<Allocator>
Wrapper arround vec<uint8_t, Allocator>
stack_sbrk_alloc<256> alloc;
strstream<stack_sbrk_alloc<256> > s(&alloc);
s << "Hello " << 1 << " test";
ostream out = filep_stream(stdout);
out << str(s) << "\n";
standard error types
class alloc_fail_err ALLIB2_FINAL : public error {
public:
static alloc_fail_err create_default_err_result() {
return alloc_fail_err();
}
protected:
ostream& write(ostream& s) const ALLIB2_NOEXCEPT ALLIB2_OVERRIDE {
return s << "Memory allocation failed";
}
};
multiple variants:
class num_parse_err ALLIB2_FINAL : public error {
public:
typedef enum {
WAS_FLOAT,
WAS_NEGATIVE,
} why_t;
why_t why;
num_parse_err(why_t w) : why(w) {}
protected:
ostream& write(ostream& s) const ALLIB2_NOEXCEPT ALLIB2_OVERRIDE {
if (why == WAS_FLOAT)
return s << "Did not expect a floating point number here";
if (why == WAS_NEGATIVE)
return s << "Did not expect a negative number here";
return s << "???";
}
};
dynamic errors
dyn_err e = dyn_err::of(myError);
slices
slice<uint8_t> and slice<const uint8_t>
string slices
str - represents a valid utf8 string, backed by a slice<const uint8_t>
str.charspas(): an iterator over the unicode codepoints in the stringstr.parsei<T>(): parse signed/unsigned int
formatter
similar to rust pretty debug formatter
allib2::fmt::simple::fmt(&myOstream)
.arr()
.entry().debug("ent1")
.entry().debug("users")
.entry().map()
.key().debug("user 1")
.value().obj("User")
.field("name").debug("User 1")
.finish()
.key().debug("user 2")
.value().put(2)
.finish_etc()
.finish();
fmt::formattable<Ty>
struct Vec2 {
int16_t x, y;
};
namespace allib2 {
namespace fmt {
template <>
struct formattable<Vec2> {
template <typename Valf>
static typename Valf::parent write(Vec2 const& self, Valf val) {
// clang-format off
return val.arr()
.entry().put(self.x)
.entry().put(self.y)
.finish();
// clang-format on
}
};
}
}
Can be used using valf.fmt(formattable)
spliterator
auto iter = spliterate(str("item1<>item2<>item3").charspans(), str("<>").charspans());
for (auto item : iter) {
...
}
endianness conversion
int16_t v = 256;
endian::convert(&v, endian::host(), endian::LITTLE);
return v;
allocators
rust-y allocators
If you need to manually access allocator functions, use alloc_traits<MyAllocator>::somefunc,
for better error messages.
allocators are stateful.
built-in allocators:
c11_aligned_alloc: depends on C11aligned_alloc()stack_sbrk_alloc<NumBytes>VA: a dynamic allocator; can be constructed withVA::of(myAlloc)
allocator references
allocators are referenced from containers using pointers;
Use alloc_ref<MyAlloc> for a more efficient allocator reference,
which will be specialized for global allocators, to use up no extra storage.
mimalloc
You can manually provide a mimalloc allocator like this:
struct mimalloc_global_alloc {
public:
static mimalloc_global_alloc* global() {
static mimalloc_global_alloc x = mimalloc_global_alloc();
return &x;
}
class alloc_fail_err ALLIB2_FINAL : public error {
public:
typedef enum {
MALLOC_FAIL,
LAYOUT_ALIGN_DIFFERENT,
} why_t;
why_t why;
alloc_fail_err(why_t w) :
why(w) {}
protected:
ostream& write(ostream& s) const ALLIB2_NOEXCEPT ALLIB2_OVERRIDE {
if (why == MALLOC_FAIL)
return s << "malloc failed: probably out of memory";
if (why == LAYOUT_ALIGN_DIFFERENT)
return s << "cannot do a realloc that changes alignment";
return s << "???";
}
};
typedef alloc_fail_err error_type;
private:
static result<void *, error_type>
Realloc(void *oldPtr, alloc_layout old_layout,
alloc_layout new_layout) ALLIB2_NOEXCEPT {
if (old_layout.min_align_bytes != new_layout.min_align_bytes)
return err_result<error_type>(
(alloc_fail_err){alloc_fail_err::LAYOUT_ALIGN_DIFFERENT});
void *newPtr = ::mi_realloc_aligned(oldPtr, new_layout.size,
new_layout.min_align_bytes);
if (!newPtr)
return err_result<error_type>(
(alloc_fail_err){alloc_fail_err::MALLOC_FAIL});
return ok_result<void *>(newPtr);
}
public:
result<void *, error_type>
allocate(alloc_layout layout) ALLIB2_NOEXCEPT {
void *ptr = ::mi_aligned_alloc(layout.min_align_bytes, layout.size);
if (!ptr)
return err_result<error_type>(
(alloc_fail_err){alloc_fail_err::MALLOC_FAIL});
return ok_result<void *>(ptr);
}
void free(void *ptr, alloc_layout old_layout) ALLIB2_NOEXCEPT {
::mi_free_aligned(ptr, old_layout.min_align_bytes);
}
result<void *, error_type>
grow(void *ptr, alloc_layout old_layout,
alloc_layout new_layout) ALLIB2_NOEXCEPT {
return Realloc(ptr, old_layout, new_layout);
}
result<void *, error_type>
shrink(void *ptr, alloc_layout old_layout,
alloc_layout new_layout) ALLIB2_NOEXCEPT {
return Realloc(ptr, old_layout, new_layout);
}
};
ALLIB2_DECLARE_GLOBAL_ALLOC(mimalloc_global_alloc);