#pragma once #include #include #include #define SVIEW_LIT(S) ((void)(S "LITERAL_CHECK"), (str_view_t) { S, sizeof(S) - 1 }) #define SVIEW_NULL ((str_view_t) { NULL, 0 }) #define SBUF_NULL ((str_buf_t) { NULL, 0 }) #define SBUF_SCOPED(NAME) str_buf_t NAME __attribute__((cleanup(sb_free))) = SB_NULL #define SVIEW_PRI "%.*s" #define SVIEW_PRI_ARGS(S) (int)((S).len), (S).ptr // String which is: // - Not owned // - Not necessarily heap-allocated // - Not necessarily nul-terminated typedef struct { const char *ptr; size_t len; } str_view_t; // String which is: // - Owned // - Heap-allocated // - Nul-terminated // The length does not include the nul terminator. typedef struct { char *ptr; size_t len; } str_buf_t; static inline bool sview_is_null(str_view_t s) { return !s.ptr; } static inline bool sview_is_empty(str_view_t s) { return !s.len; } static inline bool sbuf_is_null(str_buf_t buf) { return !buf.ptr; } static inline bool sbuf_is_empty(str_buf_t buf) { return !buf.len; } static inline str_view_t sview_from_parts(const char *ptr, size_t len) { return (str_view_t) { ptr, len }; } static inline str_view_t sview_from_cstr(const char *ptr, size_t maxlen) { size_t len; len = strnlen(ptr, maxlen); return sview_from_parts(ptr, len); } static inline str_view_t sview_from_cstr_unbounded(const char *ptr) { size_t len = strlen(ptr); return sview_from_parts(ptr, len); } static inline bool sview_eq(str_view_t s1, str_view_t s2) { return (s1.len == s2.len) && ((!s1.ptr || !s2.ptr) ? (s1.ptr == s2.ptr) : !memcmp(s1.ptr, s2.ptr, s1.len)); } static inline str_view_t sview_substr(str_view_t s, size_t start, size_t end) { if ((start > end) || (start > s.len) || (end > s.len)) return SVIEW_NULL; return sview_from_parts(s.ptr + start, end - start); } static inline str_view_t sbuf_view(str_buf_t buf) { return sview_from_parts(buf.ptr, buf.len); } str_buf_t sbuf_from_sview(str_view_t s); static inline void sbuf_free(str_buf_t *buf) { free(buf->ptr); buf->ptr = NULL; buf->len = 0; }