mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
312 lines
6.9 KiB
C
312 lines
6.9 KiB
C
#pragma once
|
|
|
|
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
|
// Use of this source code is governed by the GNU LGPLv3.0 license
|
|
// a copy of which can be found in the LICENSE file.
|
|
|
|
#include "common.h"
|
|
|
|
const char* expand_path(const char* path);
|
|
char *read_file(const char *path, size_t *return_size);
|
|
int filename_to_module(const char *path, char buffer[MAX_IDENTIFIER_LENGTH + 1]);
|
|
void path_get_dir_and_filename_from_full(const char *full_path, char **filename, char **dir_path);
|
|
void file_find_top_dir();
|
|
void file_add_wildcard_files(const char ***files, const char *path, bool recursive);
|
|
|
|
void memory_init(void);
|
|
void *malloc_arena(unsigned long mem);
|
|
void free_arena(void);
|
|
|
|
void run_arena_allocator_tests(void);
|
|
|
|
#define MALLOC(mem) malloc_arena(mem)
|
|
#define MALLOCS(type) malloc_arena(sizeof(type))
|
|
#define CALLOCS(type) ({ void *__x = malloc_arena(sizeof(type)); memset(__x, 0, sizeof(type)); __x; })
|
|
|
|
static inline bool is_power_of_two(uint64_t x)
|
|
{
|
|
return x != 0 && (x & (x - 1)) == 0;
|
|
}
|
|
|
|
static inline uint32_t nextHighestPowerOf2(uint32_t v)
|
|
{
|
|
v--;
|
|
v |= v >> 1U;
|
|
v |= v >> 2U;
|
|
v |= v >> 4U;
|
|
v |= v >> 8U;
|
|
v |= v >> 16U;
|
|
v++;
|
|
return v;
|
|
}
|
|
|
|
|
|
|
|
static inline bool is_lower(char c)
|
|
{
|
|
return c >= 'a' && c <= 'z';
|
|
}
|
|
|
|
static inline bool is_upper(char c)
|
|
{
|
|
return c >= 'A' && c <= 'Z';
|
|
}
|
|
|
|
static inline bool is_oct(char c)
|
|
{
|
|
return c >= '0' && c <= '7';
|
|
}
|
|
|
|
static inline bool is_oct_or_(char c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
case '5': case '6': case '7': case '_':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline bool is_binary(char c)
|
|
{
|
|
return c == '0' || c == '1';
|
|
}
|
|
|
|
|
|
static inline bool is_binary_or_(char c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '0': case '1': case '_':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline bool is_digit_or_(char c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
case '_':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline bool is_digit(char c)
|
|
{
|
|
return c >= '0' && c <= '9';
|
|
}
|
|
|
|
/**
|
|
* Convert hex character to nibble
|
|
* @param c
|
|
* @return value or -1 if invalid.
|
|
*/
|
|
static inline int char_to_nibble(char c)
|
|
{
|
|
if (c >= '0' && c <= '9') return c - '0';
|
|
if (c <= 'F') return c - 'A';
|
|
if (c <= 'f') return c - 'f';
|
|
return -1;
|
|
}
|
|
|
|
static inline bool is_hex_or_(char c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'a': case 'b': case 'c': case 'd': case 'e':
|
|
case 'f':
|
|
case 'A': case 'B': case 'C': case 'D': case 'E':
|
|
case 'F':
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
case '_':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline bool is_hex(char c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'a': case 'b': case 'c': case 'd': case 'e':
|
|
case 'f':
|
|
case 'A': case 'B': case 'C': case 'D': case 'E':
|
|
case 'F':
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline bool is_alphanum_(char c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'a': case 'b': case 'c': case 'd': case 'e':
|
|
case 'f': case 'g': case 'h': case 'i': case 'j':
|
|
case 'k': case 'l': case 'm': case 'n': case 'o':
|
|
case 'p': case 'q': case 'r': case 's': case 't':
|
|
case 'u': case 'v': case 'w': case 'x': case 'y':
|
|
case 'z':
|
|
case 'A': case 'B': case 'C': case 'D': case 'E':
|
|
case 'F': case 'G': case 'H': case 'I': case 'J':
|
|
case 'K': case 'L': case 'M': case 'N': case 'O':
|
|
case 'P': case 'Q': case 'R': case 'S': case 'T':
|
|
case 'U': case 'V': case 'W': case 'X': case 'Y':
|
|
case 'Z':
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
case '_':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline bool is_letter(char c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'a': case 'b': case 'c': case 'd': case 'e':
|
|
case 'f': case 'g': case 'h': case 'i': case 'j':
|
|
case 'k': case 'l': case 'm': case 'n': case 'o':
|
|
case 'p': case 'q': case 'r': case 's': case 't':
|
|
case 'u': case 'v': case 'w': case 'x': case 'y':
|
|
case 'z':
|
|
case 'A': case 'B': case 'C': case 'D': case 'E':
|
|
case 'F': case 'G': case 'H': case 'I': case 'J':
|
|
case 'K': case 'L': case 'M': case 'N': case 'O':
|
|
case 'P': case 'Q': case 'R': case 'S': case 'T':
|
|
case 'U': case 'V': case 'W': case 'X': case 'Y':
|
|
case 'Z':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
#define FNV1_PRIME 0x01000193u
|
|
#define FNV1_SEED 0x811C9DC5u
|
|
#define FNV1a(c, seed) ((uint32_t)((((unsigned)(c)) ^ (seed)) * FNV1_PRIME))
|
|
|
|
static inline uint32_t fnv1a(const char *key, uint32_t len)
|
|
{
|
|
uint32_t hash = FNV1_SEED;
|
|
for (uint32_t i = 0; i < len; i++)
|
|
{
|
|
hash = FNV1a(key[i], hash);
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
unsigned size;
|
|
unsigned capacity;
|
|
} _VHeader;
|
|
|
|
static inline _VHeader* _vec_new(size_t element_size, size_t capacity)
|
|
{
|
|
_VHeader *header = malloc_arena(element_size * capacity + sizeof(_VHeader));
|
|
header->size = 0;
|
|
header->capacity = capacity;
|
|
return header;
|
|
}
|
|
|
|
static inline unsigned vec_size(const void*vec)
|
|
{
|
|
return vec ? (((_VHeader *)vec) - 1)->size : 0;
|
|
}
|
|
|
|
static inline void vec_resize(const void *vec, unsigned new_size)
|
|
{
|
|
if (vec)
|
|
{
|
|
(((_VHeader *)vec) - 1)->size = new_size;
|
|
}
|
|
}
|
|
|
|
static inline void vec_pop(const void *vec)
|
|
{
|
|
assert(vec);
|
|
assert(vec_size(vec) > 0);
|
|
(((_VHeader *)vec) - 1)->size--;
|
|
}
|
|
static inline void* _expand(void *vec, size_t element_size)
|
|
{
|
|
if (vec == NULL)
|
|
{
|
|
vec = _vec_new(element_size, 16) + 1;
|
|
}
|
|
_VHeader *header = ((_VHeader *)vec) - 1;
|
|
header->size++;
|
|
if (header->size == header->capacity)
|
|
{
|
|
_VHeader *new_array = _vec_new(element_size, header->capacity << 1U);
|
|
memcpy(new_array, header, element_size * header->capacity + sizeof(_VHeader));
|
|
header = new_array;
|
|
new_array->capacity = header->capacity << 1U;
|
|
vec = header + 1;
|
|
}
|
|
return vec;
|
|
}
|
|
|
|
#define VECEACH(_vec, _index) \
|
|
for (unsigned _index = 0, __vecsize = vec_size(_vec); _index < __vecsize; _index++)
|
|
|
|
|
|
#define VECNEW(_type, _capacity) ((_type *)(_vec_new(sizeof(_type), _capacity) + 1))
|
|
#define VECADD(_vec, _value) \
|
|
({ \
|
|
typeof(_vec) __temp = (typeof(_vec))_expand((_vec), sizeof(typeof(*(_vec)))); \
|
|
__temp[vec_size(__temp) - 1] = _value; \
|
|
_vec = __temp; })
|
|
#define vec_add(_vec, _value) do { (_vec) = VECADD((_vec), _value); } while (0)
|
|
|
|
#define VECLAST(_vec) ({ unsigned _size = vec_size(_vec); _size ? (_vec)[_size - 1] : NULL; })
|
|
|
|
|
|
static inline bool is_all_upper(const char* string)
|
|
{
|
|
char c;
|
|
while ((c = *(string++)) != '\0')
|
|
{
|
|
if (is_lower(c)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static inline bool is_all_lower(const char* string)
|
|
{
|
|
char c;
|
|
while ((c = *(string++)) != '\0')
|
|
{
|
|
if (is_upper(c)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#ifndef __printflike
|
|
#define __printflike(x, y)
|
|
#endif
|
|
|
|
char *strcat_arena(const char *a, const char *b);
|
|
char *strformat(const char *var, ...) __printflike(1, 2);
|
|
|
|
#define MAX(_a, _b) ({ \
|
|
typeof(_a) __a__ = (_a); \
|
|
typeof(_b) __b__ = (_b); \
|
|
__a__ > __b__ ? __a__ : __b__; }) |