Signed-off-by: myperworld <myperworld@126.com>

This commit is contained in:
myperworld committed 2025-10-06 12:34:26 +08:00
1 parent 0986832fd1
commit aacd052c06
3403 files changed
+597376 -12

No files matched your search

@@ -0,0 +1,252 @@
#pragma once
#include "fl/stdint.h"
#include "fl/clamp.h"
#include "fl/geometry.h"
#include "fl/allocator.h"
namespace fl {
template <typename T, fl::size INLINED_SIZE> class FixedVector;
template <typename T, typename Allocator> class HeapVector;
template <typename T, fl::size INLINED_SIZE> class InlinedVector;
template <typename T, fl::size N> class array;
// Slice<int> is equivalent to int* with a length. It is used to pass around
// arrays of integers with a length, without needing to pass around a separate
// length parameter.
// It works just like an array of objects, but it also knows its length.
template <typename T> class Slice {
public:
Slice() : mData(nullptr), mSize(0) {}
Slice(T *data, fl::size size) : mData(data), mSize(size) {}
// ======= CONTAINER CONSTRUCTORS =======
// Simple constructors that work for all cases
template<typename Alloc>
Slice(const HeapVector<T, Alloc> &vector)
: mData(vector.data()), mSize(vector.size()) {}
template <fl::size INLINED_SIZE>
Slice(const FixedVector<T, INLINED_SIZE> &vector)
: mData(vector.data()), mSize(vector.size()) {}
template <fl::size INLINED_SIZE>
Slice(const InlinedVector<T, INLINED_SIZE> &vector)
: mData(vector.data()), mSize(vector.size()) {}
// Additional constructors for const conversion (U -> const U)
template<typename U, typename Alloc>
Slice(const HeapVector<U, Alloc> &vector)
: mData(vector.data()), mSize(vector.size()) {}
template<typename U, fl::size INLINED_SIZE>
Slice(const FixedVector<U, INLINED_SIZE> &vector)
: mData(vector.data()), mSize(vector.size()) {}
template<typename U, fl::size INLINED_SIZE>
Slice(const InlinedVector<U, INLINED_SIZE> &vector)
: mData(vector.data()), mSize(vector.size()) {}
// ======= NON-CONST CONTAINER CONVERSIONS =======
// Non-const versions for mutable spans
template<typename Alloc>
Slice(HeapVector<T, Alloc> &vector)
: mData(vector.data()), mSize(vector.size()) {}
template <fl::size INLINED_SIZE>
Slice(FixedVector<T, INLINED_SIZE> &vector)
: mData(vector.data()), mSize(vector.size()) {}
template <fl::size INLINED_SIZE>
Slice(InlinedVector<T, INLINED_SIZE> &vector)
: mData(vector.data()), mSize(vector.size()) {}
// ======= FL::ARRAY CONVERSIONS =======
// fl::array<T> -> Slice<T>
template <fl::size N>
Slice(const array<T, N> &arr)
: mData(arr.data()), mSize(N) {}
template <fl::size N>
Slice(array<T, N> &arr)
: mData(arr.data()), mSize(N) {}
// fl::array<U> -> Slice<T> (for type conversions like U -> const U)
template <typename U, fl::size N>
Slice(const array<U, N> &arr)
: mData(arr.data()), mSize(N) {}
template <typename U, fl::size N>
Slice(array<U, N> &arr)
: mData(arr.data()), mSize(N) {}
// ======= C-STYLE ARRAY CONVERSIONS =======
// T[] -> Slice<T>
template <fl::size ARRAYSIZE>
Slice(T (&array)[ARRAYSIZE])
: mData(array), mSize(ARRAYSIZE) {}
// U[] -> Slice<T> (for type conversions like U -> const U)
template <typename U, fl::size ARRAYSIZE>
Slice(U (&array)[ARRAYSIZE])
: mData(array), mSize(ARRAYSIZE) {}
// const U[] -> Slice<T> (for const arrays)
template <typename U, fl::size ARRAYSIZE>
Slice(const U (&array)[ARRAYSIZE])
: mData(array), mSize(ARRAYSIZE) {}
// ======= ITERATOR CONVERSIONS =======
template <typename Iterator>
Slice(Iterator begin, Iterator end)
: mData(&(*begin)), mSize(end - begin) {}
Slice(const Slice &other) : mData(other.mData), mSize(other.mSize) {}
Slice &operator=(const Slice &other) {
mData = other.mData;
mSize = other.mSize;
return *this;
}
// Automatic promotion to const Slice<const T>
operator Slice<const T>() const { return Slice<const T>(mData, mSize); }
T &operator[](fl::size index) {
// No bounds checking in embedded environment
return mData[index];
}
const T &operator[](fl::size index) const {
// No bounds checking in embedded environment
return mData[index];
}
T *begin() const { return mData; }
T *end() const { return mData + mSize; }
fl::size length() const { return mSize; }
const T *data() const { return mData; }
T *data() { return mData; }
fl::size size() const { return mSize; }
Slice<T> slice(fl::size start, fl::size end) const {
// No bounds checking in embedded environment
return Slice<T>(mData + start, end - start);
}
Slice<T> slice(fl::size start) const {
// No bounds checking in embedded environment
return Slice<T>(mData + start, mSize - start);
}
// Find the first occurrence of a value in the slice
// Returns the index of the first occurrence if found, or fl::size(-1) if not
// found
fl::size find(const T &value) const {
for (fl::size i = 0; i < mSize; ++i) {
if (mData[i] == value) {
return i;
}
}
return fl::size(-1);
}
bool pop_front() {
if (mSize == 0) {
return false;
}
++mData;
--mSize;
return true;
}
bool pop_back() {
if (mSize == 0) {
return false;
}
--mSize;
return true;
}
T &front() { return *mData; }
const T &front() const { return *mData; }
T &back() { return *(mData + mSize - 1); }
const T &back() const { return *(mData + mSize - 1); }
bool empty() { return mSize == 0; }
private:
T *mData;
fl::size mSize;
};
template <typename T> class MatrixSlice {
public:
// represents a window into a matrix
// bottom-left and top-right corners are passed as plain ints
MatrixSlice() = default;
MatrixSlice(T *data, i32 dataWidth, i32 dataHeight,
i32 bottomLeftX, i32 bottomLeftY, i32 topRightX,
i32 topRightY)
: mData(data), mDataWidth(dataWidth), mDataHeight(dataHeight),
mBottomLeft{bottomLeftX, bottomLeftY},
mTopRight{topRightX, topRightY} {}
MatrixSlice(const MatrixSlice &other) = default;
MatrixSlice &operator=(const MatrixSlice &other) = default;
// outputs a vec2 but takes x,y as inputs
vec2<i32> getParentCoord(i32 x_local, i32 y_local) const {
return {x_local + mBottomLeft.x, y_local + mBottomLeft.y};
}
vec2<i32> getLocalCoord(i32 x_world, i32 y_world) const {
// clamp to [mBottomLeft, mTopRight]
i32 x_clamped = fl::clamp(x_world, mBottomLeft.x, mTopRight.x);
i32 y_clamped = fl::clamp(y_world, mBottomLeft.y, mTopRight.y);
// convert to local
return {x_clamped - mBottomLeft.x, y_clamped - mBottomLeft.y};
}
// element access via (x,y)
T &operator()(i32 x, i32 y) { return at(x, y); }
// Add access like slice[y][x]
T *operator[](i32 row) {
i32 parentRow = row + mBottomLeft.y;
return mData + parentRow * mDataWidth + mBottomLeft.x;
}
T &at(i32 x, i32 y) {
auto parent = getParentCoord(x, y);
return mData[parent.x + parent.y * mDataWidth];
}
const T &at(i32 x, i32 y) const {
auto parent = getParentCoord(x, y);
return mData[parent.x + parent.y * mDataWidth];
}
private:
T *mData = nullptr;
i32 mDataWidth = 0;
i32 mDataHeight = 0;
vec2<i32> mBottomLeft;
vec2<i32> mTopRight;
};
} // namespace fl