memlnaut-nisps/nisps/core/fixed_buffer.hpp
w1n5t0n 4f60fc8405 feat: nisps/core foundation — perf, types, concepts, buffers, rng, math
Greenfield C++20 core for the unified firmware+WASM rewrite (architecture.md
streams, meml-dn7). Header-only, platform-agnostic, no heap, no virtual
dispatch.

Components:
- perf.hpp        memory section + inlining macros, RP2040/RP2350-aware,
                  inert on host/Emscripten
- types.hpp       stereosample_t (mirrors firmware AudioDriver API),
                  sample_t/param_t aliases, DriverConfig negotiation struct
- concepts.hpp    MLEngine, AudioEngine, Mode (architecture §4.1-4.3)
- fixed_buffer.hpp  std::array-backed cursor; replaces std::vector in hot paths
- ring_buffer.hpp   SPSC lock-free FIFO, power-of-two capacity, atomic
                    head/tail; replaces pico/util/queue in core
- rng.hpp         xoshiro256+ with splitmix64 seeding, uniform/signed/
                  gaussian-via-3-uniforms (matches legacy MoveWeights shape)
- math.hpp        clamp01, fast_sigmoid (tanh-Padé, ~1.2% max err on [-6,6]),
                  exact_sigmoid, fast_exp, named Curve catalog (linear/exp/
                  log/square/sqrt/sigmoid/cubic) — TypeScript twin lives in
                  playground/src/output/curves.ts (stream 5)

Performance discipline (Chris's rules):
- No heap, no std::vector, no malloc/new in core
- All float literals carry .f suffix
- Memory section attrs syntactically present, inert on non-firmware builds
2026-04-29 15:21:52 +03:00

77 lines
2.9 KiB
C++

// nisps/core/fixed_buffer.hpp — heap-free dynamic-length array with
// compile-time capacity. Replaces std::vector in hot paths.
//
// API mirrors a tiny subset of std::vector: push_back / clear / size / data /
// operator[] / iterators / front / back. NO reserve, NO resize-with-default,
// NO insert. If you need those, you're probably reaching for the wrong tool.
//
// Bounds checking: push_back returns bool (false ⇒ full, no-op). operator[]
// is unchecked — match std::vector's behavior.
#pragma once
#include <array>
#include <cstddef>
#include <type_traits>
#include <utility>
namespace nisps {
template <typename T, std::size_t N>
class FixedBuffer {
public:
using value_type = T;
using size_type = std::size_t;
using iterator = T*;
using const_iterator = const T*;
constexpr FixedBuffer() noexcept = default;
// Trivially copyable when T is. Move/copy semantics fine — backing store
// is std::array, which has correct value-semantics.
constexpr size_type size() const noexcept { return n_; }
static constexpr size_type capacity() noexcept { return N; }
constexpr bool empty() const noexcept { return n_ == 0u; }
constexpr bool full() const noexcept { return n_ == N; }
constexpr T* data() noexcept { return buf_.data(); }
constexpr const T* data() const noexcept { return buf_.data(); }
constexpr T& operator[](size_type i) noexcept { return buf_[i]; }
constexpr const T& operator[](size_type i) const noexcept { return buf_[i]; }
constexpr T& front() noexcept { return buf_[0]; }
constexpr const T& front() const noexcept { return buf_[0]; }
constexpr T& back() noexcept { return buf_[n_ - 1u]; }
constexpr const T& back() const noexcept { return buf_[n_ - 1u]; }
constexpr iterator begin() noexcept { return buf_.data(); }
constexpr const_iterator begin() const noexcept { return buf_.data(); }
constexpr iterator end() noexcept { return buf_.data() + n_; }
constexpr const_iterator end() const noexcept { return buf_.data() + n_; }
constexpr void clear() noexcept { n_ = 0u; }
// Returns true on success. Does NOT throw or assert when full — callers
// are expected to size the buffer correctly.
constexpr bool push_back(const T& v) noexcept(std::is_nothrow_copy_assignable_v<T>) {
if (n_ >= N) return false;
buf_[n_++] = v;
return true;
}
constexpr bool push_back(T&& v) noexcept(std::is_nothrow_move_assignable_v<T>) {
if (n_ >= N) return false;
buf_[n_++] = std::move(v);
return true;
}
// pop_back — trivial decrement; does not destroy (T must be cleanup-free).
constexpr void pop_back() noexcept { if (n_ > 0u) --n_; }
private:
std::array<T, N> buf_{};
size_type n_ = 0u;
};
} // namespace nisps