summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md137
-rw-r--r--include/stc/cstr.h2
-rw-r--r--misc/examples/coroutines/filetask.c2
-rw-r--r--src/libstc.c2
4 files changed, 88 insertions, 55 deletions
diff --git a/README.md b/README.md
index c333f5cd..69c51417 100644
--- a/README.md
+++ b/README.md
@@ -68,7 +68,7 @@ List of contents
- **Uniform, easy-to-learn API** - Just include the headers and you are good. The API and functionality resembles c++ STL and is fully listed in the docs. Intuitive method/type names and uniform usage across the various containers.
- **No signed/unsigned mixing** - Unsigned sizes and indices mixed with signed for comparison and calculation is asking for trouble. STC only uses signed numbers in the API for this reason.
- **Small footprint** - Small source code and generated executables. The executable from the example below using *four different* container types is only ***19 Kb in size*** compiled with gcc -O3 -s on Linux.
-- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the Installation section.
+- **Dual mode compilation** - By default it is a simple header-only library with inline and static methods only, but you can easily switch to create a traditional library with shared symbols, without changing existing source files. See the [installation section](#installation).
- **No callback functions** - All passed template argument functions/macros are directly called from the implementation, no slow callbacks which requires storage.
- **Compiles with C++ and C99** - C code can be compiled with C++ (container element types must be POD).
- **Forward declaration** - Templated containers may be [forward declared](#forward-declarations) without including the full API/implementation.
@@ -333,49 +333,29 @@ After erasing the elements found:
---
## Installation
-*NEEDS REWRITE!*
-Because it is headers-only, headers can simply be included in your program. By default, functions are static
-(some inlined). You may add the *include* folder to the **CPATH** environment variable to
-let GCC, Clang, and TinyC locate the headers.
+STC is primarily a "headers-only" library, so most headers can simply be included in your program. By default,
+all "templated" functions are static (many inlined). If you add the STC *include* folder to the **CPATH**
+environment variable, GCC, Clang, and TinyC will locate the headers automatically.
-If containers are used across several translation units with common instantiated container types, it is
-recommended to build as a "library" with external linking to minimize executable size. To enable this,
-specify `-DSTC_HEADER` as compiler option in your build environment. Next, place all the instantiations
-of the containers used inside a single C-source file as in the example below, and `#define STC_IMPLEMENT` at top.
-You may also cherry-pick shared linking mode on individual containers by `#define i_header` and
-`#define i_implement`, or force static symbols by `#define i_static` before container includes.
-
-As a special case, there may be non-templated functions in templated containers that should be implemented only
-once and if needed. Currently, define `i_import` before including **cregex** or **utf8** to implement them.
-
-It is possible to generate single headers by executing the python script `src/singleheader.py header-file > single`.
-
-Conveniently, `src\libstc.c` implements non-templated functions as shared symbols for **cstr**, **csview**,
-**cbits** and **crand**. When building in shared mode (-DSTC_HEADER), you may include this file in your project,
-or define your own, e.g.:
+The templated container functions are defined with static linking by default, which is normally optimal
+for both performance and compiled binary size. However, some common container type instances, e.g. `cvec_int`
+may be used in several translation units. When they are used in more than 3-4, consider creating a separate
+header file for them [as described here](#1-include-as-a-header-file). Now it will use shared
+linking, so *one* c-file must implement the templated container, e.g.:
```c
-// stc_libs.c
-#define STC_IMPLEMENT // implement all the following as shared objects
#define i_implement
-#include <stc/cstr.h>
-#include "Point.h"
-
-#define i_key int
-#define i_val int
-#define i_tag ii
-#include <stc/cmap.h> // cmap_ii: int => int
+#include "cvec_int.h"
+```
+The non-templated string type **cstr** uses shared linking by default, but can have static linking instead by
+`#define i_static`. Same for the string-view type **csview**, but most of its functions are static inlined, so
+linking specifications and implementation are only needed for a few lesser used functions.
-#define i_key int64_t
-#define i_tag ix
-#include <stc/cset.h> // cset_ix
+Conveniently, `src\libstc.c` implements all the non-templated functions with shared linking for **cstr**,
+**csview**, **cregex**, **utf8**, and **crand**.
-#define i_key int
-#include <stc/cvec.h> // cvec_int
+As a special case, you can `#define i_import` before including **cregex** or **cstr** to implement the dependent
+**utf8** functions (proper utf8 case conversions, etc.). Or link with src\libstc.
-#define i_key Point
-#define i_tag pnt
-#include <stc/clist.h> // clist_pnt
-```
---
## Specifying template parameters
@@ -521,39 +501,90 @@ Define `i_type` instead of `i_tag`:
#define i_key int
#include <stc/cvec.h>
-myvec vec = MyVec_init();
-MyVec_push_back(&vec, 1);
+MyVec vec = {0};
+MyVec_push(&vec, 42);
...
```
---
## Forward declarations
-It is possible to forward declare containers. This is useful when a container is part of a struct,
-but still not expose or include the full implementation / API of the container.
+There are two ways to pre-declare templated containers in header files:
+
+1. Include the templated container type instance as a header file. This also exposes all container
+functions, which can be used by client code. It requires that the element type is complete.
+2. Or, pre-declare the container type only. In this case, the container can be a "private" member of a
+user struct (the container functions will not be available to the user).
+
+### 1. Include as a header file
+
+Create a dedicated header for the container type instance:
+```c
+#ifndef PointVec_H_
+#define PointVec_H_
+// Do not to include user defined headers here if they use templated containers themselves
+
+#define i_type PointVec
+#define i_val struct Point // NB! Element type must be complete at this point!
+#define i_header // Do not implement, only expose API
+#include <stc/cvec.h>
+
+#endif
+```
+Usage from e.g. other headers is trivial:
+```c
+#ifndef Dataset_H_
+#define Dataset_H_
+#include "Point.h" // include element type separately
+#include "PointVec.h"
+
+typedef struct Dataset {
+ PointVec vertices;
+ PointVec colors;
+} Dataset;
+...
+#endif
+```
+
+Implement PointVec in a c-file:
+```c
+#include "Point.h"
+#define i_implement // define immediately before PointVec.h
+#include "PointVec.h"
+...
+```
+
+### 2. Forward declare only
```c
// Dataset.h
-#include <stc/forward.h> // only include data structures
+#ifndef Dataset_H_
+#define Dataset_H_
+#include <stc/forward.h> // include various container data structure templates
-// declare cstack_pnt; struct Point may be an incomplete type.
-forward_cstack(cstack_pnt, struct Point);
+// declare PointVec. Note: struct Point may be an incomplete/undeclared type.
+forward_cvec(PointVec, struct Point);
typedef struct Dataset {
- cstack_pnt vertices;
- cstack_pnt colors;
+ PointVec vertices;
+ PointVec colors;
} Dataset;
+void Dataset_drop(Dataset* self);
...
+#endif
+```
+Define and use the "private" container in the c-file:
+```c
// Dataset.c
#include "Dataset.h"
+#include "Point.h" // Point must be defined here.
-struct Point { int x, y, z; }; // Point must be defined here.
-#define i_is_forward // flag that the container was forward declared.
-#define i_key struct Point
-#define i_tag pnt
-#include <stc/cstack.h>
+#define i_is_forward // flag that the container was forward declared.
+#define i_type PointVec
+#define i_val struct Point
+#include <stc/cvec.h> // Implements PointVec with static linking by default
+...
```
-
---
## Per container-instance customization
Sometimes it is useful to extend a container type to store extra data, e.g. a comparison
diff --git a/include/stc/cstr.h b/include/stc/cstr.h
index 2648e267..f12d29b6 100644
--- a/include/stc/cstr.h
+++ b/include/stc/cstr.h
@@ -179,7 +179,7 @@ extern void cstr_lowercase(cstr* self);
extern void cstr_uppercase(cstr* self);
extern bool cstr_valid_utf8(const cstr* self);
-// other utf8
+// utf8 functions not depending on src/utf8code.c:
STC_INLINE intptr_t cstr_u8_size(const cstr* self)
{ return utf8_size(cstr_str(self)); }
diff --git a/misc/examples/coroutines/filetask.c b/misc/examples/coroutines/filetask.c
index 28292801..0607442d 100644
--- a/misc/examples/coroutines/filetask.c
+++ b/misc/examples/coroutines/filetask.c
@@ -21,7 +21,7 @@ int file_read(struct file_read* co, cco_runtime* rt)
while (true) {
// emulate async io: await 10ms per line
- cco_await_timer(&co->tm, 0.003);
+ cco_await_timer(&co->tm, 0.010);
if (!cstr_getline(&co->line, co->fp))
break;
diff --git a/src/libstc.c b/src/libstc.c
index 7b49540a..462c97c4 100644
--- a/src/libstc.c
+++ b/src/libstc.c
@@ -2,6 +2,8 @@
#include "../include/stc/cregex.h" /* cstr. utf8, and cregex */
#define i_implement
#include "../include/stc/csview.h"
+#define i_implement
+#include "../include/stc/crand.h"
#if __STDC_VERSION__ >= 201112L
# define i_implement
# include "../include/c11/fmt.h"