Skip to content

Instantly share code, notes, and snippets.

@imaami
Last active July 9, 2023 00:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imaami/a6f1a7bd61a8d5dc61c7e759a4f5a1e7 to your computer and use it in GitHub Desktop.
Save imaami/a6f1a7bd61a8d5dc61c7e759a4f5a1e7 to your computer and use it in GitHub Desktop.
An SSO thing in C, WIP
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define stringify_(x) #x
#define stringify(x) stringify_(x)
#if defined __GNUC__ && !defined __clang__
# define ligma_gcc(...) _Pragma(stringify_(GCC __VA_ARGS__))
#else
# define ligma_gcc(...)
#endif
#define force_inline __attribute__((always_inline)) static inline
static void
hexdump (unsigned char const *data,
size_t size,
char *buf,
size_t off);
#define hexdump_(data, size) hexdump((data), (size), (char[72u]){""}, 0)
/**
* @brief dstr stands for dumb string.
*/
typedef struct dstr
{
_Alignas(char *) union
{
struct __attribute__((packed))
{
union {
char *ptr; //!< String pointer.
char const *view; //!< String view.
};
unsigned int size; //!< Total heap allocation size.
};
char arr[sizeof(char *) + sizeof(unsigned int)]; //!< Array.
};
unsigned int len; //!< String length excluding the null terminator.
} dstr;
#define dstr_get(s_) (__typeof__((s_)->arr[0]) *) \
{ !dstr_is_pointer(s_) ? (s_)->arr : (s_)->ptr }
#define is_char_array(x) \
_Generic((__typeof__(x) *){0}, \
char (*)[sizeof(x)]: 1, \
char const (*)[sizeof(x)]: 1, \
default: 0)
#define is_string_literal(x) \
__builtin_choose_expr(is_char_array(x), __builtin_constant_p(x), 0)
#define safe_string_literal(lit, what) \
__builtin_choose_expr( \
is_string_literal(lit) && sizeof(lit) <= sizeof(what), \
lit, "")
#define make_dstr_view_from_literal(src) \
__builtin_choose_expr( \
sizeof(src) <= sizeof(((dstr *)0)->arr), \
(dstr){.arr = {safe_string_literal(src, ((dstr*)0)->arr)}, \
.len = sizeof(src) - 1u}, \
(dstr){.view = src, .size = 0u, .len = sizeof(src) - 1u})
#define make_dstr_view_from_array(src) \
__builtin_choose_expr( \
sizeof(src) <= sizeof(((dstr *)0)->arr), \
make_dstr_from_small_string(src, sizeof(src) - 1u), \
(dstr){.view = src, .size = 0u, .len = sizeof(src) - 1u})
#define make_dstr_view(src) \
__builtin_choose_expr( \
is_string_literal(src), \
make_dstr_view_from_literal(src), \
__builtin_choose_expr( \
is_char_array(src), \
make_dstr_view_from_array(src), \
make_dstr_view_from_decay(src, strlen(src))))
force_inline dstr
make_dstr_from_small_string (char const *const src,
size_t len)
{
dstr d = {.arr = {0}, .len = (unsigned)len};
__builtin_memcpy(&d.arr[0], src, len);
return d;
}
force_inline dstr
make_dstr_view_from_decay (char const *const src,
size_t len)
{
ligma_gcc(diagnostic push)
ligma_gcc(diagnostic ignored "-Wstringop-overflow")
return !len || len > UINT_MAX - 1u
? (dstr){0}
: len < sizeof(((dstr *)0)->arr)
? make_dstr_from_small_string(src, len)
: (dstr){.view = src, .size = 0u, .len = (unsigned)len};
ligma_gcc(diagnostic pop)
}
force_inline bool
dstr_is_empty (dstr const *s)
{
return !s->len;
}
force_inline bool
dstr_is_array (dstr const *s)
{
return s->len && s->len < sizeof s->arr;
}
force_inline bool
dstr_is_pointer (dstr const *s)
{
return s->len >= sizeof s->arr;
}
force_inline bool
dstr_owns_memory (dstr const *s)
{
return dstr_is_pointer(s) && s->size;
}
force_inline void
dstr_init (dstr *s)
{
s->ptr = NULL;
s->size = 0u;
s->len = 0u;
}
force_inline void
dstr_fini (dstr *s)
{
if (dstr_owns_memory(s))
free(s->ptr);
dstr_init(s);
}
#define Y(b) &"-\0yes"[b<<1]
#define TEST_DSTR_VIEW(x) \
do { \
dstr s = make_dstr_view(x); \
printf(" %-15s\t %-15s\t%-11s %-11s %-11s \t", \
stringify(x), dstr_get(&s), Y(dstr_is_array(&s)), \
Y(dstr_is_pointer(&s)), Y(dstr_owns_memory(&s))); \
hexdump_((unsigned char const *)&s, sizeof s); \
dstr_fini(&s); \
} while (0)
int
main (void)
{
#define SMALL_STRING "Sup world"
#define LARGE_STRING "How do you do"
const char small_array[] = SMALL_STRING;
const char large_array[] = LARGE_STRING;
printf(" %-15s\t %-15s\t%-11s %-11s %-11s \t %s\n"
" %-15s\t %-15s\t%-11s %-11s %-11s \t %s\n",
"Initializer", "String value", "Is array",
"Is ptr", "Owns mem", "Hexdump",
"-----------", "------------", "--------",
"------", "--------", "-------");
TEST_DSTR_VIEW(SMALL_STRING);
TEST_DSTR_VIEW(&SMALL_STRING[0]);
TEST_DSTR_VIEW(small_array);
TEST_DSTR_VIEW(&small_array[0]);
TEST_DSTR_VIEW(LARGE_STRING);
TEST_DSTR_VIEW(&LARGE_STRING[0]);
TEST_DSTR_VIEW(large_array);
TEST_DSTR_VIEW(&large_array[0]);
return 0;
}
#undef TEST_DSTR_VIEW
#undef SMALL_STRING
#undef LARGE_STRING
#undef Y
force_inline void
ascdump (unsigned char **pp,
unsigned char const *bs,
size_t sz)
{
*(*pp)++ = ' ';
*(*pp)++ = '|';
for (size_t i = 0; i < sz; ++i)
*(*pp)++ = bs[i] > 0x1fu && bs[i] < 0x7fu
? bs[i] : (unsigned char)'.';
*(*pp)++ = '|';
}
force_inline void
hexchar (unsigned char **pp,
unsigned char ch)
{
static const unsigned char hex[16] = "0123456789abcdef";
*(*pp)++ = ' ';
*(*pp)++ = hex[ch >> 4u];
*(*pp)++ = hex[ch & 15u];
}
static void
hexdump (unsigned char const *data,
size_t size,
char *buf,
size_t off)
{
unsigned char *s = (unsigned char *)&buf[off];
unsigned char *p = s;
size_t i = 0u, n = size >> 4u;
for (size_t r = 0; r < n; ++r, i = 0u, p = s, data += 16) {
for (; i < 8u; ++i)
hexchar(&p, data[i]);
*p++ = (unsigned char)' ';
for (; i < 16u; ++i)
hexchar(&p, data[i]);
*p++ = (unsigned char)' ';
ascdump(&p, data, 16u);
*p++ = (unsigned char)'\n';
*p = (unsigned char)'\0';
fputs(buf, stdout);
}
if ((n = size & 15u)) {
for (; i < n; ++i) {
hexchar(&p, data[i]);
if ((i & 7u) == 7u)
*p++ = (unsigned char)' ';
}
for (; i < 16u; ++i) {
*p++ = (unsigned char)' ';
*p++ = (unsigned char)' ';
*p++ = (unsigned char)' ';
if ((i & 7u) == 7u)
*p++ = (unsigned char)' ';
}
ascdump(&p, data, n);
*p++ = (unsigned char)'\n';
*p = (unsigned char)'\0';
fputs(buf, stdout);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment