This library provides array slicing facilities for pure C99.
[examples/demo.c] [ Playground >> ]
#include <slice99.h>
#include <assert.h>
int main(void) {
Slice99 str = Slice99_from_str("hello world");
// Accessors {
assert(*(char *)Slice99_first(str) == 'h');
assert(*(char *)Slice99_last(str) == 'd');
assert(*(char *)Slice99_get(str, 4) == 'o');
// }
// Subslicing {
assert(Slice99_primitive_eq(Slice99_sub(str, 3, 9), Slice99_from_str("lo wor")));
// }
// Predicates {
assert(!Slice99_is_empty(str));
assert(Slice99_primitive_starts_with(str, Slice99_from_str("hello")));
assert(Slice99_primitive_ends_with(str, Slice99_from_str("world")));
// }
// Mutators {
Slice99 data = Slice99_from_array((int[]){5, 8, 1, 9});
int backup;
Slice99_swap(data, 1, 3, &backup);
assert(*(int *)Slice99_get(data, 1) == 9);
assert(*(int *)Slice99_get(data, 3) == 8);
data = Slice99_from_array((int[]){1, 2, 3});
Slice99_reverse(data, &backup);
assert(Slice99_primitive_eq(data, Slice99_from_array((int[]){3, 2, 1})));
// }
// ... and more!
}The main type is Slice99. It represents a pointer to some array accompanied with an array item size and its length. The utilities Slice99_* are used to manipulate this type.
Normally, we pass a data pointer with its length as separate arguments:
void foo(size_t len, uint8_t buffer[static len]) { /* ... */ }However, this interface is notoriously easy to misuse by passing an invalid length or a null pointer for buffer. Moreover, programmers frequently tend to perform specific operations on buffer and len, leading to even more bugs and code clutter:
// Advance the buffer by HEADER_SIZE.
buffer += HEADER_SIZE;
len -= HEADER_SIZE;Slice99 reifies such patterns into functions (Slice99_advance below), thus assisting in code safety and clarity:
void foo(Slice99 buffer) {
// ...
buffer = Slice99_advance(buffer, HEADER_SIZE);
// ...
}Another use case of Slice99 is zero-copy parsers: you can return slices from your parser pointing to actual data, without mallocing and memcpying just to append '\0' each time.
Slice99 consists of just one header slice99.h and nothing else; therefore, the only thing you need to tell your compiler is to add slice99 to include directories.
If you use CMake, the recommended way is either FetchContent or add_subdirectory, e.g.:
include(FetchContent)
FetchContent_Declare(
slice99
URL https://github.com/hirrolot/slice99/archive/refs/tags/vx.y.z.tar.gz # vx.y.z
)
FetchContent_MakeAvailable(slice99)
target_link_libraries(MyProject slice99)Using add_subdirectory:
add_subdirectory(slice99)
target_link_libraries(MyProject slice99)In the latter case, I encourage you to download Slice99 as a Git submodule to be able to update it with git submodule update --remote when necessary.
Happy hacking!
You can define a strongly typed slice with SLICE99_DEF_TYPED:
#include <slice99.h>
typedef struct {
double x, y;
} Point;
SLICE99_DEF_TYPED(MyPoints, Point);
int main(void) {
MyPoints points = (MyPoints)Slice99_typed_from_array(
(Point[]){{1.5, 32.5}, {12.0, 314.01}, {-134.10, -9.3}});
MyPoints first_two = MyPoints_sub(points, 0, 2);
Point *first = MyPoints_first(points);
bool is_empty = MyPoints_is_empty(points);
}SLICE99_DEF_TYPED(MyPoints, Point) generates a slice named MyPoints of the following structure:
typedef struct {
Point *ptr;
size_t len;
} MyPoints;It also generates inline static functions like MyPoints_sub that type-check their arguments. These functions merely desugar to their untyped Slice99_* counterparts.
This library automatically defines typed slices of several fundamental types. I recommend using them instead of untyped Slice99, if possible. For more information, see the docs.
OpenIPC/smolrtsp-- A small, portable, extensible RTSP 1.0 implementation in C99.
- Update the
PROJECT_NUMBERfield inDoxyfile. - Update
SLICE99_MAJOR,SLICE99_MINOR, andSLICE99_PATCHinslice99.h. - Update
CHANGELOG.md. - Release the project in GitHub Releases.
A: Yes, see the docs.