Skip to content

Latest commit

 

History

90 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

val — A NaN-Boxed Dynamic Value Library for C

Version License: MIT

val is a zero-dependency library that implements a dynamic val_t type for C programs via NaN-boxing. It can store:

  • IEEE-754 double-precision floats
  • Signed and unsigned 52-bit integers (as double)
  • Typed pointers (void, char, custom pointers)
  • Booleans, nil (and the nil-family constants valnone, valundefined, valtombstone, valdeleted), and user-defined constants
  • Pairs (a 16-bit and a 32-bit value in one word)
  • Stored strings (library-owned strings, via vallib)

All in one 64-bit word, with efficient runtime checks, comparisons, and hashing.

Tested on:

OS compiler notes
Linux gcc 11.4.0 64-bits and 32-bits targets
Linux clang 14.0.0 64-bits and 32-bits targets
MS Windows 11 Mingw64 15.1.0 64-bits and 32-bits targets
MS Windows 11 MS cl 19.44 /std:C11

Features

  • Compact representation: 64-bit val_t uses NaN payload bits.

  • Fast type checks: Macro utilities like valisnumber(), valisinteger(), valisptr(), valisbool(), valisnil().

  • Generic constructors:

    val_t v1 = val(3.14);     // A double
    val_t v2 = val(-42);      // A signed integer
    val_t v3 = val("hello");  // A string
  • Generic extractor:

    double d  = valtodouble(v1);
    int64_t i = valtoint(v2);
    char *s   = valtoptr(v3);
  • Comparison & hashing:

    • valcmp(a,b) returns –1, 0, or 1.
    • valhash(a) produces a 32-bit FNV1a or Murmur-style hash.
  • Pairs: valpair(l,r) packs a 16-bit and a 32-bit value in one word.

  • Data structures (in vallib): a vec used as a dynamic array, stack, queue, or map with val_t keys — plus sorting, searching, and library-owned stored strings.

  • Zero dependencies: just include val.h in any C11/C17 project (data structures need vallib.h + vallib.c).

  • Extensible: define additional pointer-tags or constants via macros.


Installation

The project ships as two layers — pick the one that matches your needs:

Core only — val.h (header-only). If you only need the val_t type and its value operations (boxing, type checks, comparison, hashing, string conversion, pointers, constants, pairs), copy val.h into your project's include directory and include it. No build steps, no linking, no heap allocation — val.h is a pure single-file header.

#include "val.h"

Full library — vallib.h + vallib.c. For the data structures (valvec, stacks, queues, maps), sorting and searching, library-owned stored strings, and library-managed buffers, also copy vallib.h and vallib.c, include vallib.h, and compile and link vallib.c with your sources:

#include "vallib.h"
cc myprog.c vallib.c -o myprog

vallib.h includes the whole core, so a program that links vallib.c gets both layers. As a rule of thumb: if you don't use any allocating function, val.h alone is enough; if you need vectors, maps, stored strings, or growable buffers, use vallib.


Quick Start

#include <stdio.h>
#include "val.h"

int main(void) {
    // Create various values
    val_t d = val(2.71828);
    val_t i = val(-12345);
    val_t u = val((unsigned int)12345);
    val_t b = val((_Bool)true);
    val_t s = val("NaN-boxing");

    // Type checks
    assert(valisnumber(d));
    assert(valisint(i));
    assert(valisint(u));
    assert(valisbool(b));
    assert(valischarptr(s));

    // Conversions
    printf("double: %f\n", valtodouble(d));
    printf("signed: %lld\n", (long long)valtoint(i));
    printf("unsigned: %llu\n", (unsigned long long)valtounsignedint(u));
    printf("bool: %s\n", valtobool(b) ? "true" : "false");
    printf("string: %s\n", (char *)valtoptr(s));

    // Comparison
    val_t x = val(10);
    val_t y = val(20);
    printf("cmp(x,y)  = %d\n", valcmp(x,y));   // –1
    
    // Note that in `valcomp()`, `10` is automatically converted to `val_t`
    printf("cmp(x,10) = %d\n", valcmp(x,10));  // 0

    // Hashing
    printf("hash(\"NaN-boxing\") = 0x%x\n", valhash(s));
    return 0;
}

Documentation

See the docs directory for full documentation.

The test directory is also a source of valuable information.


References


License

© 2025 Remo Dentato ‹rdentato@gmail.com› Released under the MIT License.

About

A small library to bring NaNboxing to C

Topics

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages