/* See copyright information at the end of the file */ /*! @file std.h * @brief Mario Forzanini's "standard" library */ #ifndef __STD_H__ #define __STD_H__ #include #include #ifndef STD_MALLOC #include /*! malloc(3) compatible function to use to allocate memory. */ #define STD_MALLOC(size) (malloc(size)) #define STD_FREE(size) (free(size)) #endif /* STD_MALLOC */ #ifndef STD_FREE #error "You should define STD_FREE if you provide a custom definition of STD_MALLOC" #endif /* STD_FREE */ #ifndef STD_ERROR #include #include /*! Function to use to report errors, by default will call exit(3). */ #define STD_ERROR(...) \ do { \ fprintf(stderr, __VA_ARGS__); \ exit(EXIT_FAILURE); \ } while (0) #endif /* STD_ERROR */ #ifndef STD_ASSERT #include /*! assert(3) compatible function. */ #define STD_ASSERT(...) assert(__VA_ARGS__) #endif /* STD_ASSERT */ #define STD_UNREACHABLE() STD_ASSERT(0 && "Unreachable") #define KB (1024) #define MB (1024 * 1024) #define LEN(x) (sizeof(x) / sizeof(x[0])) #define UNUSED(x) ((void)x) #define STRLEN(str) (LEN(str) - 1) #if defined(__SSE__) || defined(__SSE2__) || defined(__SSE3__) \ || defined(STD_THREAD) #include #endif /* __SSE__ */ #define STD_TODO(str) STD_ASSERT(0 && "TODO: " str) #define global_var static #define internal static #define local_persist static typedef struct MemPool MemPool; typedef struct Region Region; typedef struct String String; typedef struct StrView StrView; /*! Pool allocator */ struct MemPool { Region *r; size_t len; /*!< Number of allocated elements */ size_t capacity; /*!< Total number of elements in the pool */ size_t chunk_size; /*!< Size of a single element */ void *buf; /*!< The buffer in which allocations are stored */ }; /*! Arena allocator */ struct Region { void *buf; /*!< The buffer in which allocations are stored */ size_t bcap, bsize; /*!< capacity and occupied size, in bytes */ Region *next; /*!< Singly-linked list of regions */ }; /*! Owned string */ struct String { char *buf; /*!< Data buffer containing the string */ size_t len; /*!< Length of string */ size_t cap; /*!< Capacity of the buffer */ }; /*! Immutable slice into a string */ struct StrView { const char *str; /*!< Pointer to the beginning of the string */ size_t len; /*!< Length of the slice */ }; #define String_Fmt "%.*s" #define String_Arg(s) (int)s.len, (s).buf /*! Use this in format strings to print StrViews */ #define StrView_Fmt "%.*s" /*! Use this in format arguments to print StrView_Fmt. * e.g. * @code * StrView to_print = STRVIEW_STATIC("blabla"); * printf(StrView_Fmt, StrView_Arg(to_print)); * @endcode */ #define StrView_Arg(s) (int)(s).len, (s).str #define STRVIEW_STATIC(str) \ { \ str, sizeof(str) / sizeof(char) - 1 \ } #define STRVIEW_LITERAL(s) \ (StrView) { .len = sizeof(s) / sizeof(char) - 1, .str = (s) } #define STRVIEW_FROM_STRING(string) *(StrView *)&(string) /*! Copy a file. * * @param src Name of the file to copy. * @param dst File to copy to. * @return errno(3) */ int cp(const char src[static restrict 1], const char dst[static restrict 1]); void *ecalloc(size_t nmemb, size_t size); void *emalloc(size_t size); /*! Allocate a string. * * @param r Region to use * @param len Length of the backing buffer * @return a zero-initialized, owned string. */ String string_alloc(Region *r, size_t len); String string_concat(Region *r, String a, String b); /*! Copy a string. * * @param r Region to use * @param src String to be copied * @return An exact copy of src into a newly allocated string. */ String string_copy(Region *r, String src); /*! Copy NULL-terminated string into an owned String. * * @param r Region to use * @param str NULL-terminated string to copy * @param len strlen(str) * @return An exact copy of str into a newly allocated string. */ String string_from_cstr(Region *r, const char *str, size_t len); /*! Copy StrView into an owned String. * * @param r Region to use * @param str StrView that has to be copied * @return An exact copy of str into a newly allocated String. */ String string_from_strview(Region *r, const StrView str); void string_downcase(String str); /*! Read the whole contents of a stream into a String. * * @param r Region on which to allocate the string. * @param stream File stream to read from. * @param contents pointer to the string to fill. * @return false on error, setting errno(3). * * @warning This does not work for non seekable files. */ bool string_read( Region *r, FILE stream[static 1], String contents[static 1]); /* StrView functions */ StrView strview_from_string(const String str); StrView strview_from_cstr(char *cstr); bool strview_is_null(StrView); StrView make_strview(size_t, const char *); /*! Acts like strcmp(3) on s1 and s2. */ int strview_cmp(StrView s1, StrView s2); bool strview_contains(const StrView s, const char *charbag, const size_t len); /*! Checks whether str ends with end. */ bool strview_ends_with(StrView end, StrView str); /*! Return next line in StrView. * * Cannot be used to count the number of lines in a file as it will * skip empty lines. * * @see strview_next_tok * @param str StrView to tokenize. * @todo handle CRLF */ StrView strview_next_line(StrView str[static 1]); /*! Return next word in StrView. * * @see strview_next_tok * @param str StrView to tokenize. */ StrView strview_next_word(StrView str[static 1]); /*! Tokenize str based on delim, and return the next token. * * Multiple delimiters are skipped and produce only two tokens, e.g.: * * @code * StrView str = STRVIEW_STATIC("a b c"); * StrView tok1 = strview_next_tok(&str, ' '); * StrView tok2 = strview_next_tok(&str, ' '); * StrView tok3 = strview_next_tok(&str, ' '); * @endcode * * tok1 == (StrView){.count = 1, .str = "a"}; * tok2 == (StrView){.count = 1, .str = "b"}; * tok3 == (StrView){.count = 1, .str = "c"}; * * @param str The string to modify. * @param delim The delimiter to look for when tokenizing. * @return The next token found until delim, or a StrView where .str = NULL. * Note that after the execution str will point to the character after the * delimiter. */ StrView strview_next_tok(StrView str[static 1], char delim); /*! Read the whole contents of a stream into a StrView. * * @param r Region on which to allocate the string. * @param stream File stream to read from. * @param contents pointer to the string to fill. * @return false on error, setting errno(3). * * @warning This does not work for non seekable files. */ bool strview_read( Region *r, FILE stream[static 1], StrView contents[static 1]); /*! Read the whole file into a StrView. * * @see strview_read */ bool strview_read_file( Region *r, const char filename[static 1], StrView contents[static 1]); /*! Check whether str starts with start. */ bool strview_starts_with(StrView start, StrView str); /*! Strip the first n characters off of a StrView. * * @param str pointer to StrView to modify. * @param n Number of characters to consume. * @return The first n characters of str, or less if str is not long * enough. */ StrView strview_take(StrView str[static 1], size_t n); /*! Remove whitespace from StrView. * * @param str Input StrView to be modified. */ void strview_trim(StrView str[static 1]); /*! Remove leading or trailing characters from StrView. * * @param str Input StrView to be modified. * @param charbag String of characters to be removed * @param len Length of charbag */ void strview_trim_chars( StrView s[static 1], const char *charbag, const size_t len); /*! Behaves like strcat(3) for StrViews. * * @param r Region in which to allocate the result * @param x First string to concatenate. * @param y Second string to concatenate. * @return Concatenation of x and y, allocated on r. */ StrView strview_strcat(Region *r, StrView x, StrView y); /*! Convert StrView to int. * * @warning First converts to long, it may truncate the result. * @param[in] str StrView to convert. * @param[out] i Pointer to the result. * @return true if no error occurred, false otherwise (check errno(3)). */ bool strview_strtoi(StrView str, int i[static 1]); /*! Convert StrView to unsigned long. * * @param[in] str StrView to convert. * @param[out] ul Pointer to the result. * @return true if no error occurred, false otherwise (check errno(3)). */ bool strview_strtoul(StrView str, unsigned long ul[static 1]); /*! Convert StrView to long. * * @param[in] str StrView to convert. * @param[out] l Pointer to the result. * @return true if no error occurred, false otherwise (check errno(3)). */ bool strview_strtol(StrView str, long l[static 1]); /*! Convert StrView to double. * * @param[in] str StrView to convert. * @param[out] d Pointer to the result. * @return true if no error occurred, false otherwise (check errno(3)). */ bool strview_strtod(StrView str, double d[static 1]); /* Region functions */ /*! Allocate linear allocator in a heap buffer. * @param bcap Capacity in bytes. * @return Heap allocated, zero-initialized, empty Region. */ Region *region_alloc(size_t bcap); /*! Allocate memory in region r. * * Note that if the requested size is bigger that the region's * capacity, a new node in the linked list of regions is allocated * using region_alloc. * @see region_alloc * @see Region * * @warning Allocates memory aligned to sizeof(void *). * @param r Region to allocate on. * @param bsize Size of needed space in bytes. * @return Pointer to the allocated buffer. */ void *region_malloc(void *r, size_t bsize); /*! Reset a region to it's initial state. * * @warning Does not zero the memory, in this sense the region will * not be exactly in its initial state. * @param r Region to reset. */ void region_reset(Region *r); /*! Free heap allocated region. * @see region_alloc */ void region_free(Region *r); /* Pool functions */ /*! Allocate pool allocator in a heap buffer. * @param count Number of elements in the pool. * @param chunk_size Size of each element in the pool; * @return Heap allocated, zero-initialized, empty Region. */ MemPool pool_alloc(Region *r, size_t count, size_t chunk_size); /*! Free all of the elements in the pool allocator. */ void pool_free_all(MemPool *pool); /*! Allocate an element from the pool allocator. */ void *pool_malloc(MemPool *pool); /*! Free heap allocated memory pool. * @see pool_alloc */ void pool_free(MemPool *pool); void pool_reset(MemPool *pool); #endif /* __STD_H__ */ /* * Copyright ©️ 2023 Mario Forzanini * * This file is part of my bachelor thesis. * * This file is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this file. If not, see . * */