Skip to content

Commit aa7b89c

Browse files
committed
Upload source to Git from archive.
0 parents  commit aa7b89c

File tree

8 files changed

+3249
-0
lines changed

8 files changed

+3249
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.out
2+
*vscode
3+
*.dSYM

README.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# array_alg.h
2+
3+
Unintrusive algorithms for C arrays OR a C implementation of \<algorithm> from C++
4+
5+
## Pitch
6+
7+
The C++ STL is one of the most complete and reusable algorithm libraries available.
8+
This single header file brings 80% of that functionality to C99 in a non-intrusive way.
9+
There are no new data structures. Just include the library and call functions on C arrays.
10+
11+
Features:
12+
13+
- Sets (intersection, union, subset, etc)
14+
- Heaps (priority queues)
15+
- Binary search (lower bound, upper bound, etc)
16+
- Sorts (insertion sort, quick sort, merge/stable sort, heap sort, partial sort, etc)
17+
- Partitioning (partition, unique, etc)
18+
- Predicates (all of, any of, none of, etc)
19+
- Uniform random sampling and shuffling
20+
21+
## Usage
22+
23+
This library uses the preprocessor to implement generic functions.
24+
Each time you include the library, you will need to define the array element type and a function prefix:
25+
26+
#define ARRAY_ALG_TYPE int
27+
#define ARRAY_ALG_PREFIX intv_
28+
#include "array_alg.h"
29+
30+
The above will only generate the declarations.
31+
In at least one C file, you will also need to generate implementations.
32+
To generate implementations, define `ARRAY_ALG_IMPLEMENTATION` in a C file and include the library:
33+
34+
#define ARRAY_ALG_TYPE int
35+
#define ARRAY_ALG_PREFIX intv_
36+
#define ARRAY_ALG_IMPLEMENTATION
37+
#include "array_alg.h"
38+
39+
Alternatively, you can include the algorithms as static functions to avoid the need for separate implementations:
40+
41+
#define ARRAY_ALG_STATIC
42+
#define ARRAY_ALG_TYPE int
43+
#define ARRAY_ALG_PREFIX intv_
44+
#define ARRAY_ALG_IMPLEMENTATION
45+
#include "array_alg.h"
46+
47+
Repeat this process for each array type you want to use.
48+
49+
## Examples
50+
51+
Remove duplicate entries:
52+
53+
#define ARRAY_ALG_TYPE int
54+
#define ARRAY_ALG_PREFIX intv_
55+
#include "array_alg.h"
56+
57+
int compare_int(const int *a, const int *b, void *ctx) {
58+
return *a - *b;
59+
}
60+
61+
...
62+
63+
int nums[100] = ...;
64+
intv_sort(nums, nums + 100, compare_int, NULL);
65+
int* end = intv_unique(nums, nums + 100, compare_int, NULL);
66+
67+
68+
## Design
69+
70+
1. Iterators and Arrays
71+
72+
The C++ STL is designed around the concept of iterators.
73+
With iterators, one algorithm can be reused not just for multiple types, but also for many data structures.
74+
This is an ingenious design.
75+
However, in practice, this capability is rarely needed.
76+
The vast majority of real world \<algorithm> invocations are on contiguous arrays/vectors.
77+
78+
For those cases where you do have a fancy data structure (graphs, trees, etc),
79+
copy its contents to an array, perform the algorithm, and then copy the contents back.
80+
This will often help it perform better anyway!
81+
82+
2. Bounds vs counted ranges
83+
84+
STL algorithms typically operate on half-open ranges bounded by iterators [first, last).
85+
This convention is not used as often in C, but we think it offers some benefits.
86+
Internally, the functions can maintain less state by simply incrementing pointers
87+
rather than keeping track of pointers, indices, and counts.
88+
89+
Operations also compose a little easier.
90+
When a pointer is returned to an element of interest,
91+
that same pointer can be used as an argument for another algorithm.
92+
93+
3. What's left out
94+
95+
Because it's a bit verbose to define a C closure (function pointer and context), some STL algorithms are less useful in C.
96+
If an algorithm can be written as a simple for loop with no additional state or control flow, this library doesn't implement it.
97+
98+
transform -> for (int i = 0; i < n; ++i) out[i] = f(in[i])
99+
fill -> for (int i = 0; i < n; ++i) out[i] = x;
100+
iota -> for (int i = 0; i < n; ++i) out[i] = i;
101+
generate -> for (int i = 0; i < n; ++i) out[i] = f();
102+
103+
The algorithms which rely on ordered types always require a comparison function.
104+
We do not include any variants that operate on the `==` operator, as operators cannot be overloaded in C.
105+
106+
4. Generics vs `void*`
107+
108+
Including a header multiple times with various `#define`s is a little cumbersome.
109+
However, we think it's a superior way to achieve C generics compared to the `void*` style used by `qsort` and `bsearch`.
110+
The preprocessor approach provides:
111+
112+
- Better type safety and avoids verbose casting logic.
113+
114+
- Better peformance (as `void*` functions are difficult to optimize).
115+
116+
Note: The C compiler can only create one non-inlined version of each function.
117+
For example, it could not choose to use `int` instructions, even if it knew the type at compile time.
118+
With the single header approach you get a new instance of each function optimized for each application.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy