2018-10-03 21:14:51 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
|
2018-09-29 22:37:15 +00:00
|
|
|
#pragma once
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
static inline const char *
|
|
|
|
skip_space_const(const char *src) {
|
|
|
|
if (!src)
|
|
|
|
return NULL;
|
|
|
|
while (*src && isspace(*src))
|
|
|
|
src++;
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline char *
|
|
|
|
skip_space_mut(char *src) {
|
|
|
|
if (!src)
|
|
|
|
return NULL;
|
|
|
|
while (*src && isspace(*src))
|
|
|
|
src++;
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define skip_space(x) _Generic((x), \
|
|
|
|
char *: skip_space_mut, \
|
|
|
|
const char *: skip_space_const \
|
|
|
|
)(x)
|
|
|
|
|
|
|
|
/// RC_TYPE generates a reference counted type from `type`
|
|
|
|
///
|
|
|
|
/// parameters:
|
|
|
|
/// name = the generated type will be called `name`_t.
|
|
|
|
/// ctor = the constructor of `type`, will be called when
|
|
|
|
/// a value of `type` is created. should take one
|
|
|
|
/// argument of `type *`.
|
|
|
|
/// dtor = the destructor. will be called when all reference
|
|
|
|
/// is gone. has same signature as ctor
|
|
|
|
/// Q = function qualifier. this is the qualifier that
|
|
|
|
/// will be put before generated functions
|
|
|
|
//
|
|
|
|
/// functions generated:
|
|
|
|
/// `name`_new: create a new reference counted object of `type`
|
|
|
|
/// `name`_ref: increment the reference counter, return a
|
|
|
|
/// reference to the object
|
|
|
|
/// `name`_unref: decrement the reference counter. take a `type **`
|
|
|
|
/// because it needs to nullify the reference.
|
|
|
|
#define RC_TYPE(type, name, ctor, dtor, Q) \
|
|
|
|
typedef struct { \
|
|
|
|
type inner; \
|
|
|
|
int ref_count; \
|
|
|
|
} name##_internal_t; \
|
|
|
|
typedef type name##_t; \
|
|
|
|
Q type *name##_new(void) { \
|
|
|
|
name##_internal_t *ret = malloc(sizeof(name##_internal_t)); \
|
|
|
|
ctor((type *)ret); \
|
|
|
|
ret->ref_count = 1; \
|
|
|
|
return (type *)ret; \
|
|
|
|
} \
|
|
|
|
Q type *name##_ref(type *a) { \
|
|
|
|
__auto_type b = (name##_internal_t *)a; \
|
|
|
|
b->ref_count++; \
|
|
|
|
return a; \
|
|
|
|
} \
|
|
|
|
Q void name##_unref(type **a) { \
|
|
|
|
__auto_type b = (name##_internal_t *)*a; \
|
|
|
|
if (!b) \
|
|
|
|
return; \
|
|
|
|
b->ref_count--; \
|
|
|
|
if (!b->ref_count) {\
|
|
|
|
dtor((type *)b); \
|
|
|
|
free(b); \
|
|
|
|
} \
|
|
|
|
*a = NULL; \
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generate prototypes for functions generated by RC_TYPE
|
|
|
|
#define RC_TYPE_PROTO(type, name) \
|
|
|
|
typedef type name##_t; \
|
|
|
|
type *name##_new(void); \
|
|
|
|
void name##_ref(type *a); \
|
|
|
|
void name##_unref(type **a);
|