summaryrefslogtreecommitdiff
path: root/src/string.h
blob: ea4fd9b102d5a49fc1970922fd00f2c34925fb63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pragma once

#include "common.h"
#include "smrt_arena.h"

#define STRNG_BASE_POS (sizeof(strng_t))

typedef struct {
    u64 alloc_size;
    u64 len;
} strng_t;

typedef struct {
       u64   start;
       u64     end;
       u64     max;
char const *string;
} strng_view_t;

strng_t * strng_new(smrt_arena_t *arena, u64 size);
strng_t *strng_from(smrt_arena_t *arena, char const *c);
strng_t * strng_dup(smrt_arena_t *arena, strng_t const *src);
   char * strng_str(smrt_arena_t *arena, strng_t const *string);
    i32   strng_set(strng_t *string, char const *c);
// Append to strng, returns -1 if no space, new len otherwise
    i32   strng_app(strng_t *dest, strng_t const *source);
// Append char* to strng, returns -1 if no space, new len otherwise
    i32 strng_app_c(strng_t *dest, char const *source);
// Append sv to strng, returns -1 if no space, new len otherwise
    i32 strng_app_v(strng_t *dest, strng_view_t const *source);
   void strng_clear(strng_t *string);

#define STRNG_TO(s) (char *)((u8*)(s)+STRNG_BASE_POS)
#define STRNG_FMT(s) (i32)s->len, (char *)((u8*)(s)+STRNG_BASE_POS)

#define SV_TO(sv) (char *)((u8*)((sv).string) + (sv).start)
#define SV_FMT(sv) (i32)(sv_len(&(sv))), SV_TO((sv))

static inline strng_view_t sv_from(strng_t const *string) {
    return (strng_view_t){
        .string=(char*)((u8*)string+STRNG_BASE_POS),
        .start=0,
        .end=string->len-1,
        .max=string->len-1,
    };
}

static inline u64 sv_len(strng_view_t const *sv) {
    return (sv->start <= sv->end) ? (sv->end - sv->start + 1) : 0;
}

static inline strng_view_t  sv_dup(strng_view_t const *src) { return *src; }
static inline strng_view_t sv_orig(strng_view_t const *src) { return (strng_view_t){
                                                                .string=src->string,
                                                                .start=0,
                                                                .end=src->max,
                                                                .max=src->max }; }
static inline strng_view_t sv_subv(strng_view_t const *src,
                                u64 start_off, u64 max_len) {
    u64 src_len = sv_len(src);
    u64 new_start = src->start + MIN(start_off, src_len);
    u64 available_len = (src->start + src_len) - new_start;
    u64 actual_len = MIN(available_len, max_len);

    return (strng_view_t){
        .string = src->string,
        .start = new_start,
        .end = actual_len == 0 ? new_start - 1 : new_start + actual_len - 1,
        .max = src->max
    };
}
static inline strng_view_t  sv_drop_left(strng_view_t const *src, u64 n) {
    u64 src_len = sv_len(src);
    u64 m = MIN(src_len, n);
    return sv_subv(src, m, src_len - m);
}
static inline strng_view_t sv_drop_right(strng_view_t const *src, u64 n) {
    u64 src_len = sv_len(src);
    u64 m = MIN(src_len, n);
    return sv_subv(src, 0, src_len - m);
}

strng_view_t sv_from_chars(char const* c);

void sv_trimws_left (strng_view_t *sv);
void sv_trimws_right(strng_view_t *sv);
void sv_trimws      (strng_view_t *sv);

void sv_trim_pastc_left (strng_view_t *sv, char n);
void sv_trim_pastc_right(strng_view_t *sv, char n);

// Starts from start and sets end to the next char n.
// Does nothing if there is no next char n
void sv_trim_end_nextc(strng_view_t *sv, char n);
// Starts from end and sets start to the prev char n.
// Does nothing if there is no prev char n
void sv_trim_strt_prvc(strng_view_t *sv, char n);

// Sets length keeping start
void sv_set_len_left (strng_view_t *sv, u64 n);
// Sets length keeping end
void sv_set_len_right(strng_view_t *sv, u64 n);


static inline void  sv_pop_left (strng_view_t *sv) { if (sv->start <= sv->end) sv->start++; }
static inline void  sv_pop_right(strng_view_t *sv) { if (sv->end >= sv->start)   sv->end--; }
static inline void sv_popn_left (strng_view_t *sv, u64 n) { for (u64 i = 0; i < n; i++)  sv_pop_left(sv); }
static inline void sv_popn_right(strng_view_t *sv, u64 n) { for (u64 i = 0; i < n; i++) sv_pop_right(sv); }

static inline void sv_reset(strng_view_t *sv) {
    sv->start=0;
    sv->end = sv->max;
}
static inline void sv_reset_right(strng_view_t *sv) {   sv->end = sv->max; }
static inline void  sv_reset_left(strng_view_t *sv) { sv->start =       0; }

// Returns -1 if not found, otherwise distance from sv->start to beginning of needle
i32 sv_find_substr(strng_view_t const *sv, char const *needle);
// Returns -1 if not found, otherwise distance from sv->start
i32   sv_find_char(strng_view_t const *sv, char n);

b32   sv_starts_with(strng_view_t const *sv, char const *prefix);
b32     sv_ends_with(strng_view_t const *sv, char const *suffix);
static inline b32 sv_starts_with_c(strng_view_t const *sv, char c) { return
                                                            (sv_len(sv) > 0) && (*SV_TO(*sv) == c); }
static inline b32   sv_ends_with_c(strng_view_t const *sv, char c) { return
                                                            (sv_len(sv) > 0) && (*(sv->string + sv->end) == c); }

b32 sv_eq_case_insensitive(strng_view_t const *sv1, strng_view_t const *sv2);

strng_view_t   sv_split_once(strng_view_t *sv, char const *needle);
strng_view_t sv_split_once_c(strng_view_t *sv, char n);

// Returns chars read on succes, -1 if couldn't read
// Creates its own SV and skips whitespace.
// Fails if first char after trim isnt +/- or 0-9
i32 sv_to_i64(strng_view_t const *sv, i64 *value_o);