Find a file
2025-11-05 17:28:47 +01:00
.woodpecker codeberg's meson image doesn't have clang , even tough they said it does.... 2025-11-05 17:05:05 +01:00
allib2 lots of standard compliancy fixes; should be 100% compliant now 2025-11-05 17:28:47 +01:00
examples lots of standard compliancy fixes; should be 100% compliant now 2025-11-05 17:28:47 +01:00
.clang-format c 2025-08-04 18:40:11 +02:00
.gitignore also push default meson.build 2025-10-25 21:49:46 +02:00
config.hpp.in lots of standard compliancy fixes; should be 100% compliant now 2025-11-05 17:28:47 +01:00
config.py allocatorsgit add . 2025-10-26 01:11:43 +02:00
LICENSE add MIT license 2025-11-05 16:43:49 +01:00
meson.build replace binary literals with hex literal, because binary literals are not standard; and add -pedantic -Wall 2025-11-05 17:17:00 +01:00
meson.build.in replace binary literals with hex literal, because binary literals are not standard; and add -pedantic -Wall 2025-11-05 17:17:00 +01:00
README.md add strstream, and c++11 fixes 2025-11-05 09:01:21 +01:00
TODO feat: allib2::box 2025-10-26 18:11:07 +01:00

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 string
  • str.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 C11 aligned_alloc()
  • stack_sbrk_alloc<NumBytes>
  • VA: a dynamic allocator; can be constructed with VA::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);