Skip to content

kobolds-io/stdx

Repository files navigation

Overview

CAUTION this project is current in development and should be used at your own risk. Until there is a stable tagged release, be careful.

This is a library adding several generally useful tools that are either not included in the standard library or have slightly different behavior. As the zig programming language matures, we should get more and more awesome std library features but until then...

All data structures, algorithms and utilities included in this library are written from scratch. This minimizes the threat of malicious or unintentional supply chain attacks. It also ensures that all code is controlled in a single place and HOPEFULLY minimizes the chance that zig turns into the hellish monstrocity that is npm and the nodejs ecosystem.

Table of Contents

  1. Overview
    1. Usage
    2. Installation
    3. Organization
    4. Examples
    5. Benchmarks
    6. Contributing
    7. Code of Conduct
  2. Documentation
    1. stdx
      1. ManagedQueue
      2. MemoryPool
      3. RingBuffer
      4. UnmanagedQueue
      5. IO

Usage

Using stdx is just as simple as using any other zig dependency.

// import the library into your file
const stdx = @import("stdx");

fn main() !void {
    // your code
    // ....

    const memory_pool = stdx.MemoryPool(i32).init(allocator, 200);
    defer memory_pool.deinit();

    // your code
    // ...
}

Installation

You can install stdx just like any other zig dependency by editing your build.zig.zon file.

    .dependencies = .{
        .stdx = .{
            // the latest version of the library is v0.0.2
            .url = "https://github.com/kobolds-io/stdx/archive/refs/tags/v0.0.2.tar.gz",
            .hash = "stdx-0.0.2-nyLNAQrfAABlq4y4DXa5Y_exfKnhRiS_-YRz-0Fbv9L2",
        },
    },

run zig build --fetch to fetch the dependencies. Sometimes zig is helpful and it caches stuff for you in the zig-cache dir. Try deleting that directory if you see some issues.

Organization

This library follows the organization of the zig std library. You will see familiar hierarchies like stdx.mem for memory stuff and std.RingBuffer for other data structures. As I build this library out, I'll add more notes and documentation.

Examples

There are examples included in this library that go over a brief overview of how each feature can be used. You can build and run examples by performing the following steps. Examples are in the examples directory. Examples are always welcome.

zig build examples

./zig-out/bin/<example_name>

Examples are best used if you modify the code and add print statements to figure out what is going on. Look at the source code files for additional tips on how features work by taking a look at the tests included in the source code.

Benchmarks

There are benchmarks included in this library that you can run your local hardware or target hardware. You can run benchmarksby performing the following steps. Benchmarks are in the benchmarks directory. More benchmarks are always welcome. Benchmarks in this library are written using zbench by hendriknielander. Please check out that repo and star it and support other zig developers.

Note Benchmarks are always a point of contention between everyone. One of my goals is to provision some hardware in the cloud that is consistently used as the hardware for all comparisons. Until then, you can run the code locally to test out your performance.

# with standard optimizations (debug build)
zig build bench

# or with more optimizations
zig build bench -Doptimize=ReleaseFast

Example output

--------------------------------------------------------
  Operating System: linux x86_64
  CPU:              13th Gen Intel(R) Core(TM) i9-13900K
  CPU Cores:        24
  Total Memory:     23.298GiB
--------------------------------------------------------

|-----------------------|
| RingBuffer Benchmarks |
|-----------------------|
benchmark              runs     total time     time/run (avg ± σ)     (min ... max)                p75        p99        p995
-----------------------------------------------------------------------------------------------------------------------------
enqueue 50000 items    65535    10.338s        157.76us ± 10.327us    (154.747us ... 1.372ms)      158.139us  187.669us  197.609us
enqueueMany 50000 item 65535    10.377s        158.346us ± 15.325us   (154.766us ... 2.204ms)      158.312us  189.075us  198.855us
dequeue 50000 items    65535    5.169s         78.875us ± 5.538us     (77.23us ... 429.735us)      77.284us   98.347us   105.55us
dequeueMany 50000 item 65535    10.315s        157.407us ± 42.226us   (154.468us ... 10.324ms)     156.221us  184.985us  194.235

Contributing

Please see Contributing for more information on how to get involved.

Code of Conduct

Please see the Code of Conduct file. Simple library, simple rules.


Documentation

stdx

The stdx top level module. Directly contains data structures and is the parent module to modules like io and net.

ManagedQueue

The ManagedQueue is a generic queue implementation that uses a singly linked list. It allows for the management of a queue with operations like enqueueing, dequeueing, checking if the queue is empty, concatenating two queues, and handles the allocation/deallocation of memory used by the queue. The queue is managed by an allocator, which is used for creating and destroying nodes.

See example and source for more information on usage.

MemoryPool

A MemoryPool is a structure that uses pre-allocated blocks of memory to quickly allocoate and deallocate resources quickly. It is very useful in situations where you have statically allocated memory but you will have fluctuating usage of that memory. A good example would be handling messages flowing throughout a system.

See example and source for more information on usage.

RingBuffer

A RingBuffer is a data structure that is really useful for managing memory in a fixed memory allocation. This particular implementation is particularly useful for a fixed size queue. Kobolds uses the RingBuffer data structure for inboxes and outboxes for when messages are received/sent through TCP connections.

See example and source for more information on usage.

UnmanagedQueue

The UnmanagedQueue is a generic queue implementation that uses a singly linked list. It most closely represents the std.SinglyLinkedList in its functionality. Differing from the ManagedQueue, the UnmanagedQueue requires memory allocations to be external to the queue and provides a generic Node structure to help link everything together.

Please also see UnmanagedQueueNode which is the Node used by the UnmanagedQueue.

See example and source for more information on usage.

IO

Module containing solutions for handling input and output