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