string: add static NSTR_DEFINE initializer macro

This commit is contained in:
anna 2021-07-18 21:00:07 +02:00
parent 0bafd7d9b7
commit b6659a321d
Signed by: fef
GPG key ID: EC22E476DC2D3D84
7 changed files with 120 additions and 15 deletions

View file

@ -33,20 +33,11 @@
})
/**
* Declare a length field in a structure.
* This makes it compatible with the `nlen` macro.
* Quickly get the length (as in amount of items, not bytes) of any libneo data
* structure that supports it. This includes strings, buffers, lists, and more.
*
* @param name: field name, will be of type `usize`
*/
#define NLEN_FIELD(name) \
union { \
usize name; \
const usize __neo_nlen; \
}
/**
* Quickly get the length (as a `const usize`) of any libneo data structure
* that supports it. This includes strings, buffers, lists, and more.
* @param thing: Thing to get the length of
* @returns: The length as a `const usize`
*/
#define nlen(thing) ((thing)->__neo_nlen)

View file

@ -5,6 +5,33 @@
#include "neo/_types.h"
#include "neo/_toolchain.h"
/**
* Used internally for statically initializing strings created with
* the `NSTR_DEFINE` macro. This is written to a special data section that
* is iterated over before program start; see `_neo_nstr_init_array` in
* `src/string/nstr.c` for details.
*/
struct _neo_nstr_init_info {
string **dest;
const char *data;
};
/**
* Statically define a neo string.
*
* The string will be initialized before `main` is called.
*
* @param name: Name of the `string *` variable to be declared
* @param content: A `const char *` with the contents of the string
*/
#define NSTR_DEFINE(name, content) \
string *name = nil; \
__neo_section(.data.__neo.nstr_array) \
struct _neo_nstr_init_info __neo_nstr_init_info_##name = { \
.dest = &name, \
.data = content, \
}
/**
* Copy a regular C string to a neo string.
*

View file

@ -37,6 +37,18 @@ typedef long double f128;
# endif
#endif
/**
* Declare a length field in a structure.
* This makes it compatible with the `nlen` macro.
*
* @param name: field name, will be of type `usize`
*/
#define NLEN_FIELD(name) \
union { \
usize name; \
const usize __neo_nlen; \
}
struct _neo_nref {
void (*_destroy)(void *);
/** byte offset into the struct this is embedded in */

View file

@ -2,8 +2,7 @@
add_library(neo STATIC)
add_compile_options(-nodefaultlibs)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
target_link_options(neo INTERFACE -T${CMAKE_SOURCE_DIR}/src/neo.ld)
execute_process(COMMAND uname -m OUTPUT_VARIABLE HOST_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
string(TOLOWER "${HOST_ARCH}" HOST_ARCH)
@ -26,6 +25,7 @@ target_include_directories(neo PRIVATE
target_sources(neo PRIVATE
./error.c
./list.c
./nalloc.c
./nref.c
)

40
src/neo.ld Normal file
View file

@ -0,0 +1,40 @@
/* See the end of this file for copyright and license terms. */
/*
* The INSERT command at the end makes this linker script merely augment the
* default one rather than entirely replace it. This allows us to inject
* arbitrary extra sections we can reference in init and fini code without
* having to maintain a complete linker script for each architecture.
*/
SECTIONS
{
.__neo_data :
{
/*
* global strings defined with the NSTR_DEFINE macro are
* referenced in this section because their length cannot be
* calculated at compile time (because UTF-8).
*
* See nstr_init_array() in src/string/nstr.c for the
* initialization routine.
*/
__neo_nstr_array_start = .;
KEEP(*(.data.__neo.nstr_array))
__neo_nstr_array_end = .;
}
}
INSERT AFTER .data;
/*
* This file is part of libneo.
* Copyright (c) 2021 Fefie <owo@fef.moe>.
*
* libneo is non-violent software: you may only use, redistribute,
* and/or modify it under the terms of the CNPLv6+ as found in
* the LICENSE file in the source code root directory or at
* <https://git.pixie.town/thufie/CNPL>.
*
* libneo comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPLv6+ for details.
*/

View file

@ -10,6 +10,7 @@
#include "neo/_nalloc.h"
#include "neo/_nref.h"
#include "neo/_string.h"
#include "neo/_toolchain.h"
#include "neo/_types.h"
#include "neo/utf.h"
@ -108,6 +109,20 @@ nchar nchrat(const string *s, usize index, error *err)
return ret;
}
/* see src/neo.ld */
extern struct _neo_nstr_init_info __neo_nstr_array_start;
extern struct _neo_nstr_init_info __neo_nstr_array_end;
void _neo_nstr_init_array(void)
{
struct _neo_nstr_init_info *ptr = &__neo_nstr_array_start;
while (ptr != &__neo_nstr_array_end) {
*ptr->dest = nstr(ptr->data, nil);
ptr++;
}
}
__neo_init(_neo_nstr_init_array);
/*
* This file is part of libneo.
* Copyright (c) 2021 Fefie <owo@fef.moe>.

View file

@ -60,6 +60,26 @@ TEST_CASE( "nnstr: Error if raw strig is nil", "[string/nstr,c]")
errput(&err);
}
NSTR_DEFINE(static_test_string_1, "i'm gay,,,");
TEST_CASE( "_neo_nstr_init_array: Statically initialize ASCII string", "[string/nstr.c]" )
{
string *expected_s1 = nstr("i'm gay,,,", nil);
REQUIRE( nstreq(expected_s1, static_test_string_1, nil) );
REQUIRE( nlen(static_test_string_1) == 10 );
}
NSTR_DEFINE(static_test_string_2, "i'm gay\xf0\x9f\xa5\xba,,,");
TEST_CASE( "_neo_nstr_init_array: Statically initialize UTF-8 string", "[string/nstr.c]" )
{
string *expected_s2 = nstr("i'm gay\xf0\x9f\xa5\xba,,,", nil);
REQUIRE( nstreq(expected_s2, static_test_string_2, nil) );
REQUIRE( nlen(static_test_string_2) == 11 );
}
/*
* This file is part of libneo.
* Copyright (c) 2021 Fefie <owo@fef.moe>.