Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

alcover/stricks

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

logo

Stricks

Augmented strings for C

CI

📙 API

Stricks make C strings easy and fast.
Managing bounds, storage and reallocations is automated,
without forcing a structured type on the user.

Principle

typedef const char* stx_t;

A strick looks like a normal char* and can be passed to <string.h> functions.
Metadata are hidden in a prefix header :

schema

Header and string occupy a continuous memory block,
avoiding the further indirection of {len,*str} schemes.
This technique is notably used in SDS, now part of Redis.

Usage

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

int main() {
    stx_t s = stx_from("Treats or...");
    stx_append(&s, "Stricks!");        
    printf(s);
    return 0;
}
$ gcc app.c stx -o app && ./app
Treats or...Stricks!

Sample

src/example.c implements a mock forum with fixed size pages.
When the next post would truncate, the buffer is flushed.

make && ./bin/example

Build & unit-test

make && make check

Speed

make && make bench (may use 1GB+ RAM)

Stricks is (much) faster than SDS.

On Intel Core i3 :

init and free
---------------
8 bytes strings :
      SDS  568 ms
  Stricks  445 ms
256 bytes strings :
      SDS  667 ms
  Stricks  654 ms

append
---------------
8 bytes strings :
      SDS  643 ms
  Stricks  372 ms
256 bytes strings :
      SDS  449 ms
  Stricks  171 ms

append format
---------------
      SDS  832 ms
  Stricks  795 ms

split and join
---------------
8 bytes strings :
      SDS  580 ms
  Stricks  224 ms
256 bytes strings :
      SDS  714 ms
  Stricks  75 ms

C++ benchmark :
(depends on libbenchmark-dev)
make && make benchcpp

On Thinkpad T420 with cpupower frequency-set --governor performance :

------------------------------------------------------------
Benchmark                     Time           CPU Iterations
------------------------------------------------------------
SDS_from/8                   33 ns         33 ns   21363820
SDS_from/64                  29 ns         29 ns   23942248
SDS_from/512                 29 ns         29 ns   23982314
SDS_from/4096               271 ns        271 ns    2585840
SDS_from/32768             2738 ns       2738 ns     255377
STX_from/8                   21 ns         21 ns   33747602
STX_from/64                  20 ns         20 ns   35346041
STX_from/512                 20 ns         20 ns   35170533
STX_from/4096               170 ns        170 ns    4104671
STX_from/32768             1462 ns       1462 ns     467821
SDS_append/8                 14 ns         14 ns   48313704
SDS_append/64                12 ns         12 ns   57793801
SDS_append/512               12 ns         12 ns   57707384
SDS_append/4096            1617 ns       1617 ns     426224
SDS_append/32768          13175 ns      13174 ns      50770
STX_append/8                  9 ns          9 ns   72565984
STX_append/64                 9 ns          9 ns   74644788
STX_append/512               10 ns         10 ns   75197471
STX_append/4096             886 ns        886 ns     776564
STX_append/32768           7035 ns       7033 ns      86241
SDS_split_join/8             13 us         13 us      52485
SDS_split_join/64            42 us         42 us      16515
SDS_split_join/512          263 us        263 us       2647
SDS_split_join/4096        2050 us       2050 us        339
SDS_split_join/32768      17462 us      17461 us         40
STX_split_join/8              5 us          5 us     152980
STX_split_join/64             6 us          6 us     112486
STX_split_join/512           16 us         16 us      43388
STX_split_join/4096         108 us        108 us       6412
STX_split_join/32768       1707 us       1707 us        404

API

create

stx_new
stx_from
stx_from_len
stx_dup
stx_split
stx_join
stx_join_len

append

stx_append
stx_append_strict
stx_append_fmt
stx_append_fmt_strict

adjust / reset

stx_resize
stx_adjust
stx_trim
stx_reset

assess

stx_cap
stx_len
stx_spc
stx_equal
stx_dbg

free

stx_free
stx_list_free

Custom allocators can be defined with

#define STX_MALLOC  my_malloc
#define STX_REALLOC my_realloc
#define STX_FREE    my_free

stx_new

Create a strick of capacity cap.

stx_t stx_new (size_t cap)
stx_t s = stx_new(10);
stx_dbg(s); 
//cap:10 len:0 data:""

stx_from

Create a strick by copying string src.

stx_t stx_from (const char* src)
stx_t s = stx_from("Bonjour");
stx_dbg(s); 
// cap:7 len:7 data:'Bonjour'

stx_from_len

Create a strick by copying srclen bytes from src.

stx_t stx_from_len (const void* src, size_t srclen)

This function is binary : exactly srclen bytes will be copied, NULs included.
If you need the stx.len property to reflect its C-string length, use stx_adjust on the result.

stx_t s = stx_from_len("Hello!", 4);
printf(s); // 'Hell'

stx_dup

Create a duplicate strick of src.

stx_t stx_dup (stx_t src)

Capacity is adjusted to length.

stx_t s = stx_new(16);
stx_append(&s, "foo");
stx_t dup = stx_dup(s);
stx_dbg(dup); 
// cap:3 len:3 data:'foo'

stx_split

Split src on separator sep into an array of stricks of resulting length *outcnt.

stx_t*  
stx_split (const char* src, const char* sep, int* outcnt);
int cnt = 0;
stx_t* list = stx_split("foo|bar", "|", &cnt);

for (int i = 0; i < cnt; ++i) {
    stx_dbg(list[i]);
}

// cap:3 len:3 data:'foo'
// cap:3 len:3 data:'bar'

Or using the list sentinel :

while (part = *list++) {
    stx_dbg(part);
}

stx_split_len

Core split method with arbitrary lengths.

stx_t*  
stx_split_len (const char* src, size_t srclen, const char* sep, size_t seplen, int* outcnt)

stx_join

Join the stricks list of length count using separator sep into a new strick.

stx_t stx_join (stx_t *list, int count, const char* sep);
int count = 0;
stx_t* parts = stx_split ("foo|bar", "|", &count);
stx_t joined = stx_join (parts, count, "|");
printf(joined); // "foo|bar"

stx_join_len

Same with known separator length.

stx_t stx_join_len (stx_t *list, int count, const char* sep, size_t seplen);

stx_append

stx_cat

size_t stx_append (stx_t* dst, const void* src, size_t srclen)

Appends len bytes from src to *dst.

  • If over capacity, *dst gets reallocated.
  • reallocation reserves 2x the needed memory.

Return code :

  • rc = 0 on error.
  • rc >= 0 on success, as new length.
stx_t s = stx_from("abc"); 
stx_append(&s, "def"); //-> 6 
stx_dbg(s); 
// cap:12 len:6 data:'abcdef'

stx_append_strict

stx_cats

long long stx_append_strict (stx_t dst, const char* src, size_t srclen)

Appends len bytes from src to dst, in place.

  • No reallocation.
  • Nothing done if input exceeds remaining space.

Return code :

  • rc >= 0 on success, as new length.
  • rc < 0 on potential truncation, as needed capacity.
  • rc = 0 on error.
stx_t s = stx_new(5);  
stx_append_strict(s, "abc"); //-> 3
printf(s); // "abc"  
stx_append_strict(s, "def"); //-> -6  (would need capacity = 6)
printf(s); // "abc"

stx_append_fmt

stx_catf

size_t stx_append_fmt (stx_t* dst, const char* fmt, ...)

Appends a formatted string to *dst.

  • If over capacity, *dst gets reallocated.
  • reallocation reserves 2x the needed memory.

Return code :

  • rc = 0 on error.
  • rc >= 0 on success, as new length.
stx_t foo = stx_new(32);
stx_append_fmt (&foo, "%s has %d apples", "Mary", 10);
stx_dbg(foo);
// cap:32 len:18 data:'Mary has 10 apples'

stx_append_fmt_strict

stx_catfs

long long stx_append_fmt_strict (stx_t dst, const char* fmt, ...)

Appends a formatted string to dst, in place.

  • No reallocation.
  • Nothing done if input exceeds remaining space.

Return code :

  • rc >= 0 on success, as new length.
  • rc < 0 on potential truncation, as needed capacity.
  • rc = 0 on error.
stx_t foo = stx_new(32);
stx_append_fmt (foo, "%s has %d apples", "Mary", 10);
stx_dbg(foo);
// cap:32 len:18 data:'Mary has 10 apples'

stx_free

Releases the enclosing memory block.

void stx_free (stx_t s)
stx_t s = stx_from("foo");
stx_free(s);

stx_list_free

Releases a list of parts generated by stx_split.

void stx_list_free (const stx_t* list)
int cnt = 0;
stx_t* list = stx_split("foo|bar", "|", &cnt);
// (..use list..)
stx_list_free(list);

stx_reset

Sets length to zero.

void stx_reset (stx_t s)
stx_t s = stx_new(16);
stx_append_strict(s, "foo");
stx_reset(s);
stx_dbg(s); 
// cap:16 len:0 data:''

stx_resize

Change capacity.

int stx_resize (stx_t *pstx, size_t newcap)
  • If increased, the passed reference may get updated.
  • If lowered below length, data gets truncated.

Returns: true/false on success/failure.

stx_t s = stx_new(3);
int rc = stx_append_strict(s, "foobar"); // -> -6
if (rc<0) stx_resize(&s, -rc);
stx_append_strict(s, "foobar");
stx_dbg(s); 
// cap:6 len:6 data:'foobar'

stx_adjust

Sets len straight in case data was modified from outside.

void stx_adjust (stx_t s)
stx_t s = stx_from("foobar");

// out-of-API modification
((char*)s)[3] = '\0';
stx_dbg(s);
// cap:6 len:6 data:'foo'  WRONG LEN!

stx_adjust(s);
stx_dbg(s);
// cap:6 len:3 data:'foo'  FAITHFUL

stx_trim

Removes white space, left and right, preserving capacity.

void stx_trim (stx_t s)
stx_t s = stx_from(" foo ");
stx_trim(s);
stx_dbg(s);
// cap:5 len:3 data:'foo'

stx_cap

Current capacity accessor.
size_t stx_cap (stx_t s)

stx_len

Current length accessor.
size_t stx_len (stx_t s)

stx_spc

Remaining space.
size_t stx_spc (stx_t s)

stx_equal

Compares a and b's data string.

int stx_equal (stx_t a, stx_t b)
  • Capacities are not compared.
  • Faster than memcmp since stored lengths are compared first.

stx_dbg

Printing the state of a strick.

stx_t s = stx_from("foo");
stx_dbg(foo);
// cap:3 len:3 data:'foo'

About

Managed C strings library

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Contributors 2

  •  
  •  
Morty Proxy This is a proxified and sanitized view of the page, visit original site.