Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ $(COMMON_OUT_DIR)/%.o: src/common/%.c
.PHONY: clean
clean:
rm -rf $(COMMON_OUT_DIR)
@mkdir -p $(COMMON_OUT_DIR)

# generate compile commands with bear if u got it!!!
# very good highly recommended ʕ·ᴥ·ʔ
Expand Down
2 changes: 1 addition & 1 deletion include/common/arena.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ typedef struct ArenaState {

void arena_init(Arena* arena);
void arena_destroy(Arena* arena);
void* arena_alloc(Arena* arena, usize size, usize align);
ALLOC_ALIGN(2, 3) void* arena_alloc(Arena* arena, usize size, usize align);

ArenaState arena_save(Arena* arena);
void arena_restore(Arena* arena, ArenaState save);
Expand Down
3 changes: 3 additions & 0 deletions include/common/portability.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
#define FALLTHROUGH __attribute__((fallthrough))
#define UNUSED __attribute__((unused))
#define NORETURN __attribute__((noreturn))
#define ALLOC_ALIGN(sz, al) __attribute__((malloc, alloc_size(sz), alloc_align(al)))
#define ALLOC_SIZE(sz) __attribute__((malloc, alloc_size(sz)))
#define FORMAT_CHECK(fmt_pos, args_pos) __attribute__((format(printf, fmt_pos, args_pos)))
#elif defined(_MSC_VER)
#define WEAK __declspec(selectany)
#define INLINE __forceinline
Expand Down
93 changes: 84 additions & 9 deletions include/common/str.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
#include <stdlib.h>

#include "common/type.h"
#include "common/portability.h"
#include "common/util.h"

// strings and string-related utils.

typedef struct string {
char* raw;
size_t len;
usize len;
} string;

#define NULL_STR ((string){nullptr, 0})
Expand All @@ -27,18 +29,91 @@ typedef struct string {
#define string_wrap(cstring) ((string){(char*)(cstring), strlen((cstring))})
#define strlit(cstring) ((string){(char*)cstring, sizeof(cstring)-1})

char* clone_to_cstring(string str); // this allocates
void printstr(string str);
string strprintf(char* format, ...);
#define string_lt(a, b) (string_cmp((a), (b)) < 0)
#define string_gt(a, b) (string_cmp((a), (b)) > 0)
#define string_le(a, b) (string_cmp((a), (b)) <= 0)
#define string_ge(a, b) (string_cmp((a), (b)) >= 0)

string string_alloc(size_t len);
#define string_free(str) free(str.raw)
string string_clone(string str); // this allocates as well
string string_concat(string a, string b); // allocates
void string_concat_buf(string buf, string a, string b); // this does not

int string_cmp(string a, string b);
/// \brief Allocates len bytes for a new string
///
/// \param len Length of buffer
///
/// \return string A string with a buffer of at least length len. The resulting
/// buffer is zero-filled.
///
/// \note a null-terminated string can be allocated by providing len + 1.
static inline string string_alloc(usize len);

/// \brief Clones the source string to owned C string.
///
/// Allocates a null-terminated C string, and copies the source string.
///
/// \return cstring Owned null terminated C string.
///
/// \see clone_to_string
static inline char* clone_to_cstring(string str);

/// \brief Prints a string
///
/// Emits each character up to the sources length to stdout.
static inline void printstr(string str);

/// \brief Prints to a newly allocated string.
///
/// \param format printf format specifier
/// \param ... printf format arguments
///
/// \return str null-terminated string, or NULL_STR on allocation fail.
string strprintf(char* format, ...) FORMAT_CHECK(1, 2);

/// \brief Clones the source string.
///
/// Allocates and copies the source string, without inserting a null terminator.
///
/// \return string Owned string
///
/// \see clone_to_cstring
string string_clone(string str);

/// \brief Concatenates two strings.
///
/// Allocates a buffer containing the concatenation of a and b.
///
/// \return str Allocated string containing ab, without a null terminator.
string string_concat(string a, string b);

/// \brief Concatenates two strings into buf.
///
/// \param[out] buf buffer of minimum length a.len + b.len.
/// buf is filled with the concatenation ab, without a null terminator
///
/// \warning buffer must be large enough contain a and b, crashes otherwise.
void string_concat_buf(string buf, string a, string b);

/// \brief Compares two strings.
///
/// \return cond Returns 0 when equal, -1 when a < b, and 1 when a > b
/// (their byte-wise, aggregate u8 difference is used to compare).
///
/// \note for equality, string_eq is more efficient, using heuristic length
/// checks before checking character by character.
///
/// \see string_eq
isize string_cmp(string a, string b);

/// \brief Checks if two strings are equal.
///
/// \return cond true if equal, else false
///
/// \see string_cmp
bool string_eq(string a, string b);

/// \brief Checks if string ends with another.
///
/// \return cond true if yes, else false. If the ending string is larger than
/// the source, returns false.
bool string_ends_with(string source, string ending);

#endif // ORBIT_STRING_H
81 changes: 80 additions & 1 deletion include/common/vec.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <stdlib.h>
#include <string.h>

#include "common/str.h"

///
/// +--------+--------+--------+--------+--------+--------+
Expand Down Expand Up @@ -37,7 +38,7 @@ typedef struct VecHeader {
/// This vector's `VecHeader`.
#define vec_header(vec) ((VecHeader*)((char*)(vec) - sizeof(VecHeader)))
/// Get the pointer to a vec's elements from the header.
#define vec_elems_from_header(header) ((void*)((char*)(header) + sizeof(VecHeader)))
#define vec_elems_from_header(header) ((void*)((u8*)(header) + sizeof(VecHeader)))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary but /shrug

/// This vector's length.
#define vec_len(vec) vec_header(vec)->len
/// This vector's capacity.
Expand Down Expand Up @@ -89,4 +90,82 @@ void _vec_reserve1(Vec(void)* v, size_t stride);
void _vec_shrink(Vec(void)* v, size_t stride);
void _vec_destroy(Vec(void)* v);

/* string specifics */

/// \brief Copies string to newly allocated owned vector.
///
/// \param str source slice to copy
/// \return vec char vector containing str
/// (of capacity equal to the input's length).
///
/// \warning The result is not null-terminated.
///
/// It may be preferable to realloc in-place to reduce fragmentation. For
/// dynamically allocated strings,
/// \see realloc_string_to_vec
Vec(char) string_to_vec(string str);

/// \brief Copies a C string to newly allocated owned vector.
///
/// \param str source C string to copy
/// \return vec char vector containing str
/// (of capacity equal to the input's length).
///
/// \warning The result is not null-terminated.
///
/// It may be preferable to create a vector in-place to reduce fragmentation.
/// For dynamically allocated C strings,
/// \see realloc_string_to_vec
static inline Vec(char) cstring_to_vec(const char* str);

/// \brief Takes ownership of string and creates a char vector.
///
/// Allocates a new space for a header at the start of the string's raw pointer,
/// then moves the string in-place, and returning the new vec.
///
/// \param str dynamically allocated string, possibly null-terminated.
/// \return vec char vector containing str
/// (with a capacity of 1.5x the input's length).
///
/// \warning The result is not null-terminated.
///
/// \warning To allocate space, the function uses realloc, so the underlying
/// data must have been allocated by an *alloc family function (i.e malloc,
/// calloc, alligned_alloc etc).
///
/// For a copy only function,
/// \see string_to_vec
Vec(char) realloc_string_to_vec(string str);

/// \brief Takes ownership of string and creates a char vector.
///
/// Allocates a new space for a header at the start of the str,
/// then moves the string in-place, and returning the new vec.
///
/// \param str dynamically allocated null-terminated string.
/// \return vec char vector containing str
/// (with a capacity of 1.5x the input's length).
///
/// \warning The result is not null-terminated.
///
/// \warning To allocate space, the function uses realloc, so the source str
/// must have been allocated by an *alloc family function (i.e malloc,
/// calloc, alligned_alloc etc).
///
/// For a copy only function,
/// \see cstring_to_vec
static inline Vec(char) realloc_cstring_to_vec(char* str);

/// \brief Format print to the end of a char vec
///
/// Appends formatted string to a Vec(char), reallocating to make space.
///
/// \param str string vector, possibly null-terminated
/// \param format printf format specifier
/// \param ... printf format arguments
///
/// \warning The result is not null-terminated, nor does the function write
/// over any old null terminators.
FORMAT_CHECK(2, 3) void vec_appendf(Vec(char) str, const char* format, ...);

#endif // VEC_H
45 changes: 20 additions & 25 deletions src/common/str.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <stdio.h>
#include <string.h>

#include "common/portability.h"
#include "common/str.h"

string strprintf(char* format, ...) {
Expand All @@ -12,7 +11,7 @@ string strprintf(char* format, ...) {
va_start(a, format);
va_list b;
va_copy(b, a);
size_t bufferlen = 1 + vsnprintf("", 0, format, a);
usize bufferlen = 1 + vsnprintf("", 0, format, a);
c = string_alloc(bufferlen);
vsnprintf(c.raw, c.len, format, b);
c.len--;
Expand All @@ -28,11 +27,15 @@ string string_concat(string a, string b) {
}

void string_concat_buf(string buf, string a, string b) {
for (size_t i = 0; i < a.len; ++i) {
if (buf.len < a.len + b.len)
CRASH("Buffer is too small. %zu < %zu + %zu", buf.len, a.len, b.len);

usize i;
for_n(i, 0, a.len) {
buf.raw[i] = a.raw[i];
}
for (size_t i = 0; i < b.len; ++i) {
buf.raw[i + a.len] = b.raw[i];
for_n(i, 0, b.len) {
buf.raw[a.len + i] = b.raw[i];
}
}

Expand All @@ -42,16 +45,11 @@ bool string_ends_with(string source, string ending) {
return string_eq(substring_len(source, source.len-ending.len, ending.len), ending);
}

string string_alloc(size_t len) {
char* raw = malloc(len);

memset(raw, '\0', len);

return (string){raw, len};
static inline string string_alloc(usize len) {
return (string){calloc(len, sizeof(char*)), len};
};

}

int string_cmp(string a, string b) {
isize string_cmp(string a, string b) {
// copied from odin's implementation lmfao
int res = memcmp(a.raw, b.raw, a.len < b.len ? a.len : b.len);
if (res == 0 && a.len != b.len) return a.len <= b.len ? -1 : 1;
Expand All @@ -67,14 +65,11 @@ bool string_eq(string a, string b) {
return true;
}

char* clone_to_cstring(string str) {
if (is_null_str(str)) return "";

char* cstr = malloc(str.len + 1);
if (cstr == nullptr) return nullptr;
memcpy(cstr, str.raw, str.len);
cstr[str.len] = '\0';
return cstr;
static inline char* clone_to_cstring(string str) {
// NOTE: the returned char* is always allocated, so no null literal
// (otherwise subsequent realloc results in undefined behaviour).
// The last null character is always allocated internally.
return strndup(str.raw, str.len);
}

string string_clone(string str) {
Expand All @@ -83,12 +78,12 @@ string string_clone(string str) {
return new_str;
}

void printn(char* text, size_t len) {
size_t c = 0;
void printn(char* text, usize len) {
usize c = 0;
while (c < len && text[c] != '\0')
putchar(text[c++]);
}

void printstr(string str) {
static inline void printstr(string str) {
printn(str.raw, str.len);
}
53 changes: 53 additions & 0 deletions src/common/vec.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <string.h>
#include <stdio.h>
#include <stdarg.h>

#include "common/portability.h"
#include "common/vec.h"
Expand Down Expand Up @@ -40,3 +41,55 @@ WEAK void _vec_destroy(Vec(void)* v) {
free(vec_header(*v));
*v = nullptr;
}

/* string specifics */

Vec(char) string_to_vec(string str) {
Vec(char) v = vec_new(char, str.len);

memcpy(v, str.raw, str.len);
return v;
}

static inline Vec(char) cstring_to_vec(const char* str) {
return string_to_vec(string_wrap(str));
}

Vec(char) realloc_string_to_vec(string str) {
// The assumption is that you make a vec to append to it, so we reserve
// more up-front.
str.raw = realloc(str.raw, str.len * 1.5 + sizeof(VecHeader));

// memmove so that strings can overlap.
memmove(str.raw, (u8*)str.raw + sizeof(VecHeader), str.len);

Vec(char) v = vec_elems_from_header(str.raw);

if (v == nullptr)
return nullptr;

vec_cap(v) += str.len / 2;
vec_len(v) = str.len;

return v;
}

static inline Vec(char) realloc_cstring_to_vec(char* str) {
return realloc_string_to_vec(string_wrap(str));
}

void vec_appendf(Vec(char) str, const char* format, ...) {
va_list a;
va_start(a, format);
va_list b;
va_copy(b, a);

usize printlen = 1 + vsnprintf("", 0, format, a);

vec_reserve(&str, printlen);

vsnprintf(&str[vec_len(str)], printlen, format, b);

va_end(a);
va_end(b);
}