feat: add dyn-arr
This commit is contained in:
17
.envrc
Normal file
17
.envrc
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ^ make editor happy
|
||||||
|
|
||||||
|
#
|
||||||
|
# Use https://direnv.net/ to automatically load the dev shell.
|
||||||
|
#
|
||||||
|
|
||||||
|
if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then
|
||||||
|
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4="
|
||||||
|
fi
|
||||||
|
|
||||||
|
watch_file nix/**
|
||||||
|
watch_file -- **/*.nix
|
||||||
|
# Adding files to git includes them in a flake
|
||||||
|
# But it is also a bit much reloading.
|
||||||
|
# watch_file .git/index .git/HEAD
|
||||||
|
use flake . --show-trace
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
build
|
||||||
|
.direnv
|
||||||
22
CMakeLists.txt
Normal file
22
CMakeLists.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
project(
|
||||||
|
c-lib
|
||||||
|
DESCRIPTION "C Libraries for recreational Programming."
|
||||||
|
LANGUAGES C)
|
||||||
|
|
||||||
|
add_library(c-libs ${PROJECT_SOURCE_DIR}/src/dyn-arr.c)
|
||||||
|
target_include_directories(c-libs PUBLIC "${PROJECT_SOURCE_DIR}/include")
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(CRITERION REQUIRED IMPORTED_TARGET GLOBAL criterion)
|
||||||
|
|
||||||
|
add_executable(tests test/main.c)
|
||||||
|
target_link_libraries(tests c-libs PkgConfig::CRITERION)
|
||||||
|
|
||||||
|
add_test(NAME all_tests COMMAND tests)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS c-libs)
|
||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1772408722,
|
||||||
|
"narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1773821835,
|
||||||
|
"narHash": "sha256-TJ3lSQtW0E2JrznGVm8hOQGVpXjJyXY2guAxku2O9A4=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "b40629efe5d6ec48dd1efba650c797ddbd39ace0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1772328832,
|
||||||
|
"narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
57
flake.nix
Normal file
57
flake.nix
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
description = "Some C Libs for recreational programming.";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = inputs @ {
|
||||||
|
self,
|
||||||
|
flake-parts,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
flake-parts.lib.mkFlake {inherit inputs;} (
|
||||||
|
top: {
|
||||||
|
imports = [];
|
||||||
|
|
||||||
|
flake = {
|
||||||
|
overlays.default = final: prev: {
|
||||||
|
c-libs = final.callPackage ./nix/c-libs.nix {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systems = [
|
||||||
|
"x86_64-linux"
|
||||||
|
];
|
||||||
|
|
||||||
|
perSystem = {
|
||||||
|
self',
|
||||||
|
pkgs,
|
||||||
|
system,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
_module.args.pkgs = import inputs.nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [self.overlays.default];
|
||||||
|
};
|
||||||
|
|
||||||
|
packages.default = pkgs.c-libs;
|
||||||
|
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
packages = [
|
||||||
|
pkgs.cmake-language-server
|
||||||
|
pkgs.cmake-format
|
||||||
|
pkgs.clang-tools
|
||||||
|
pkgs.gdb
|
||||||
|
];
|
||||||
|
inputsFrom = [self'.packages.default];
|
||||||
|
shellHook = ''
|
||||||
|
export CMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||||
|
export BUILD_TESTING=ON
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
106
include/c-libs/dyn-arr.h
Normal file
106
include/c-libs/dyn-arr.h
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#ifndef CLIBS_DYN_ARR_H
|
||||||
|
#define CLIBS_DYN_ARR_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t cap;
|
||||||
|
size_t size;
|
||||||
|
} DArrHeader;
|
||||||
|
|
||||||
|
/// Initialize a dynamic array
|
||||||
|
/// @param darr a pointer, which will be overwritten to point to the dynamic
|
||||||
|
/// array's data part
|
||||||
|
/// @param capacity the initial capacity allocated
|
||||||
|
#define darr_init(darr, capacity) \
|
||||||
|
do { \
|
||||||
|
size_t c = (capacity); \
|
||||||
|
DArrHeader *header = malloc(sizeof(DArrHeader) + c * sizeof(*(darr))); \
|
||||||
|
header->cap = c; \
|
||||||
|
header->size = 0; \
|
||||||
|
(darr) = (typeof(darr))(header + 1); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/// Grow an danamic array by an amount
|
||||||
|
/// @param darr a pointer initialized with darr_init, will be changed to point
|
||||||
|
/// to the new data location
|
||||||
|
/// @param extra_cap the extra capacity to add
|
||||||
|
#define darr_grow(darr, extra_cap) \
|
||||||
|
do { \
|
||||||
|
DArrHeader *header = ((DArrHeader *)(darr)) - 1; \
|
||||||
|
header->cap += (extra_cap); \
|
||||||
|
\
|
||||||
|
header = \
|
||||||
|
realloc(header, header->cap * sizeof(*(darr)) + sizeof(DArrHeader)); \
|
||||||
|
(darr) = (typeof((darr)))(header + 1); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/// Append an element to a dynamic array.
|
||||||
|
/// @param darr a pointer initialized with darr_init, may be overwritten if
|
||||||
|
/// memory changes
|
||||||
|
/// @param x the element to insert at darr[darr_size(darr)]
|
||||||
|
#define darr_push(darr, x) \
|
||||||
|
do { \
|
||||||
|
DArrHeader *header = ((DArrHeader *)(darr)) - 1; \
|
||||||
|
\
|
||||||
|
if (header->size == header->cap) { \
|
||||||
|
size_t inc = header->cap / 2; \
|
||||||
|
darr_grow(darr, inc ? inc : 1); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
header = ((DArrHeader *)(darr)) - 1; \
|
||||||
|
darr[header->size++] = (x); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/// Clone an dynamic array
|
||||||
|
/// @param darr a pointer initialized with darr_init
|
||||||
|
/// Returns a fresh pointer to the cloned data
|
||||||
|
#define darr_clone(darr) (typeof(darr))darr_clone_impl((darr), sizeof(*(darr)))
|
||||||
|
|
||||||
|
/// Clone an untyped dynamic array
|
||||||
|
/// @param arr any pointer initialized with darr_init
|
||||||
|
/// @param elem_size the byte-size of the contained elements
|
||||||
|
/// Returns a fresh pointer to the cloned data, must be freed with darr_free
|
||||||
|
void *darr_clone_impl(void *arr, size_t elem_size);
|
||||||
|
|
||||||
|
/// Get the number of elements in the dynamic array
|
||||||
|
/// @param arr a pointer initialized with darr_init
|
||||||
|
size_t darr_size(void *arr);
|
||||||
|
|
||||||
|
/// Get the capacity of the dynamic array
|
||||||
|
/// @param arr a pointer initialized with darr_init
|
||||||
|
size_t darr_cap(void *arr);
|
||||||
|
|
||||||
|
/// Free a dynamic array
|
||||||
|
/// @param arr a pointer initialized with darr_init or returned from darr_clone
|
||||||
|
void darr_free(void *arr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CLIBS_DYN_ARR_IMPL
|
||||||
|
|
||||||
|
size_t darr_size(void *arr) {
|
||||||
|
DArrHeader *header = ((DArrHeader *)arr) - 1;
|
||||||
|
return header->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t darr_cap(void *arr) {
|
||||||
|
DArrHeader *header = ((DArrHeader *)arr) - 1;
|
||||||
|
return header->cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *darr_clone_impl(void *arr, size_t elem_size) {
|
||||||
|
DArrHeader *header = ((DArrHeader *)arr) - 1;
|
||||||
|
size_t size = sizeof(DArrHeader) + elem_size * header->cap;
|
||||||
|
DArrHeader *tgt = malloc(size);
|
||||||
|
memcpy(tgt, header, size);
|
||||||
|
|
||||||
|
return (void *)(tgt + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void darr_free(void *arr) {
|
||||||
|
DArrHeader *header = ((DArrHeader *)arr) - 1;
|
||||||
|
free(header);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
25
nix/c-libs.nix
Normal file
25
nix/c-libs.nix
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
cmake,
|
||||||
|
criterion,
|
||||||
|
lib,
|
||||||
|
pkg-config,
|
||||||
|
stdenv,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
stdenv.mkDerivation (finalAttrs: {
|
||||||
|
pname = "c-libs";
|
||||||
|
version = "0.1.0";
|
||||||
|
src = ../.;
|
||||||
|
nativeBuildInputs = [cmake] ++ lib.optional finalAttrs.doCheck pkg-config;
|
||||||
|
buildInputs = [] ++ lib.optional finalAttrs.doCheck criterion;
|
||||||
|
|
||||||
|
cmakeFlags = [
|
||||||
|
(lib.cmakeBool "BUILD_TESTING" finalAttrs.doCheck)
|
||||||
|
];
|
||||||
|
|
||||||
|
doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Some C libs for recreational programming.";
|
||||||
|
};
|
||||||
|
})
|
||||||
2
src/dyn-arr.c
Normal file
2
src/dyn-arr.c
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define CLIBS_DYN_ARR_IMPL
|
||||||
|
#include "c-libs/dyn-arr.h"
|
||||||
46
test/main.c
Normal file
46
test/main.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include "c-libs/dyn-arr.h"
|
||||||
|
#include <criterion/criterion.h>
|
||||||
|
|
||||||
|
Test(darr, basic_usage) {
|
||||||
|
int *darr = NULL;
|
||||||
|
darr_init(darr, 2);
|
||||||
|
cr_assert(darr_size(darr) == 0, "Dynamic array size is 0 after init");
|
||||||
|
cr_assert(darr_cap(darr) == 2, "Dynamic array capacity is 2 after init");
|
||||||
|
|
||||||
|
darr_push(darr, 10);
|
||||||
|
darr_push(darr, 20);
|
||||||
|
|
||||||
|
cr_assert(darr[0] == 10);
|
||||||
|
cr_assert(darr[1] == 20);
|
||||||
|
cr_assert(darr_size(darr) == 2, "Dynamic array size is 2 after push");
|
||||||
|
cr_assert(darr_cap(darr) == 2, "Dynamic array capacity is 2 after push");
|
||||||
|
|
||||||
|
darr_push(darr, 30);
|
||||||
|
darr_push(darr, 40);
|
||||||
|
darr_push(darr, 50);
|
||||||
|
cr_assert(darr_size(darr) == 5, "Dynamic array size is 5 after grow push");
|
||||||
|
cr_assert(darr_cap(darr) == 6, "Dynamic array capacity is 6 after grow push");
|
||||||
|
|
||||||
|
darr_free(darr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(darr, clone_array) {
|
||||||
|
int *darr = NULL;
|
||||||
|
darr_init(darr, 5);
|
||||||
|
darr[0] = 1;
|
||||||
|
darr[1] = 10;
|
||||||
|
darr[2] = 100;
|
||||||
|
darr[3] = 1000;
|
||||||
|
darr[4] = 10000;
|
||||||
|
|
||||||
|
int *darr2 = darr_clone(darr);
|
||||||
|
|
||||||
|
cr_assert(darr_size(darr) == darr_size(darr2));
|
||||||
|
cr_assert(darr_cap(darr) == darr_cap(darr2));
|
||||||
|
for (int i = 0; i < darr_size(darr); i++) {
|
||||||
|
cr_assert(darr[i] == darr2[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
darr_free(darr);
|
||||||
|
darr_free(darr2);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user