-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_string.c
More file actions
166 lines (128 loc) · 3.83 KB
/
Copy pathexample_string.c
File metadata and controls
166 lines (128 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* Example usage left-leaning red-black tree. */
#define _GNU_SOURCE /* for getline() */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include "llrb.h"
/*
Now-ubiquitous container_of macro, reconstructing containing
structure pointer by member pointer. Can be defined in a safer way
than here when typeof extension is available.
*/
#define container_of(ptr, type, member) \
((type*)(((char*)ptr)-offsetof(type,member)))
void fail(const char*str)
{
fputs(str,stderr);
abort();
}
void* nooom(void* ptr)
{
if (!ptr) {
fail("out of memory");
}
return ptr;
}
/* fail fast on out-of-memory condition */
void* xmalloc(size_t size)
{
return nooom(malloc(size));
}
char *xstrdup(const char *s)
{
return nooom(strdup(s));
}
/* struct StringNode is our data item, containing string as user data
* and participation in TWO trees independently. */
struct StringNode {
struct LLRBNode n;
struct LLRBNode aux;
char* str;
};
/* Getting original StringNode from LLRBNode member "n" is possible
* with type cast, because "n" is the first member in StringNode.
* Otherwise we'd have to use container_of (which we have for auxilary
* tree and aux member, anyway).
*
* There's an advantage of having LLRBNode as a first member, namely,
* that pointer to LLRBNode is null iff pointer to StringNode is
* null. */
#define TO_SN(node) ((struct StringNode*)node)
/* trivial wrapper for strcmp */
int rbcmp_string(struct LLRBNode *a, struct LLRBNode *b, struct LLRBTree*t)
{
(void)t;
return strcmp(TO_SN(a)->str,TO_SN(b)->str);
}
int main(void)
{
/* getline stuff */
char *line = NULL;
size_t sz = 0;
/* sorted by string value */
struct LLRBTree tree;
/* sorted by pointer location */
struct LLRBTree auxtree;
struct StringNode *sn;
int ndups = 0;
struct LLRBNode *rn;
llrb_init(&tree, rbcmp_string);
llrb_init(&auxtree, llrb_ptrcmp);
for(;;) { /* for each line of <stdin> */
ssize_t r = getline(&line,&sz,stdin);
if (r<0) /* EOF/error? */
break;
if (r>0 && line[r-1]=='\n')
line[r-1] = 0; /* chop final newline */
sn = xmalloc(sizeof *sn);
sn->str = xstrdup(line);
/* add node to auxtree first */
if (NULL != llrb_insert_or_replace(&auxtree, &sn->aux))
fail("should not happen: replaced node in pointer-sorted tree!");
sn = TO_SN(llrb_insert_or_replace(&tree,&sn->n));
if (sn) {
/* old node, not in &tree anymore */
/* delete from &auxtree as well */
llrb_delete(&auxtree,&sn->aux);
++ndups;
free(sn->str);
free(sn);
}
}
free(line);
printf("\nDuplicate string: %d\n",ndups);
puts("\nTraversal by strcmp order:");
/* TO_SN cast preserves NULLness, so we need no separate node
* pointer during traversal of &tree */
for(sn = TO_SN(llrb_min(&tree)); sn; sn = TO_SN(llrb_next(&tree,&sn->n))) {
puts(sn->str);
}
puts("\nTraversal by memory order:");
/* That's how it's done with container_of: LLRBNode member might be
* anywhere in our structure */
for(rn = llrb_min(&auxtree); rn; rn = llrb_next(&auxtree,rn)) {
sn = container_of(rn,struct StringNode,aux);
puts(sn->str);
}
{
struct StringNode key = { .str = "password" };
rn = llrb_find(&tree,&key.n);
if (rn) {
printf("Seen in the tree: %s\n", container_of(rn,struct StringNode,n)->str);
}
}
/* Free allocated memory using linked-list traversal. Both trees
become invalid as StringNodes containing both kind of LLRBNodes
are freed. */
for(rn = llrb_min(&tree); rn;) {
/* NB we MUST get next pointer before freeing current node. */
struct LLRBNode *newrn = llrb_next(&tree,rn);
/* TO_SN cast would do. container_of used for demonstration */
sn = container_of(rn,struct StringNode,n);
free(sn->str);
free(sn);
rn = newrn;
}
return 0;
}