Repository navigation
Expand file tree
/
Copy pathcorTreeArraySort.c
More file actions
191 lines (153 loc) · 4.88 KB
/
Copy pathcorTreeArraySort.c
File metadata and controls
191 lines (153 loc) · 4.88 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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//
// FILE corTreeArraySort.c
//
// AUTHOR Ken Zangelin
//
// Copyright 2026 Ken Zangelin
//
// SPDX-License-Identifier: Apache-2.0
//
#include <string.h> // strcmp, memset
#include <unistd.h> // NULL
#include "corTree/CorNode.h" // CorNode
#include "corTree/corTreeBuilder.h" // corTreeChildRemove, corTreeChildAdd
#include "corTree/corTreeSort.h" // corTreeSort
#include "corTree/corTreeArraySort.h" // Own interface
// -----------------------------------------------------------------------------
//
// stringCompare - strcmp that accepts NULL, treating it as the empty string
//
// The name of an Array element is "" when the tree comes from corJsonParse, but a
// hand-built node may well have a NULL name.
//
static int stringCompare(const char* a, const char* b)
{
if (a == NULL) a = "";
if (b == NULL) b = "";
return strcmp(a, b);
}
// -----------------------------------------------------------------------------
//
// corTreeNodeCompare - compare two KjNodes, recursively
//
// Nothing is rendered and nothing is allocated - the two trees are walked in
// parallel and the comparison stops at the first difference.
//
int corTreeNodeCompare(CorNode* aP, CorNode* bP)
{
int diff;
if (aP->type != bP->type)
return (int) aP->type - (int) bP->type;
if ((diff = stringCompare(aP->name, bP->name)) != 0)
return diff;
switch (aP->type)
{
case CorString:
return stringCompare(aP->value.s, bP->value.s);
case CorInt:
if (aP->value.i < bP->value.i) return -1;
if (aP->value.i > bP->value.i) return 1;
return 0;
case CorFloat:
if (aP->value.f < bP->value.f) return -1;
if (aP->value.f > bP->value.f) return 1;
return 0;
case CorBoolean:
return (int) aP->value.b - (int) bP->value.b;
case CorObject:
case CorArray:
{
CorNode* aChildP = aP->value.head;
CorNode* bChildP = bP->value.head;
while ((aChildP != NULL) && (bChildP != NULL))
{
if ((diff = corTreeNodeCompare(aChildP, bChildP)) != 0)
return diff;
aChildP = aChildP->next;
bChildP = bChildP->next;
}
// All pairs equal - the shorter container comes first
if (aChildP != NULL) return 1;
if (bChildP != NULL) return -1;
return 0;
}
case CorNone:
case CorNull:
return 0; // No value to compare - the type is all there is
}
return 0;
}
// -----------------------------------------------------------------------------
//
// elementsOrder - order the children of an Array, using corTreeNodeCompare
//
// Selection sort: pull every child out into a local container and move them
// back, smallest first. Same shape as corTreeStringArraySort.
//
static void elementsOrder(CorNode* arrayP)
{
CorNode raw;
CorNode* rawP = &raw;
memset(&raw, 0, sizeof(raw));
rawP->type = CorArray;
//
// Put all items in rawP, leaving arrayP empty
//
rawP->value.head = arrayP->value.head;
rawP->value.tail = arrayP->value.tail;
arrayP->value.head = NULL;
arrayP->value.tail = NULL;
//
// Loop over rawP, find smallest, then just move it to arrayP
//
while (rawP->value.head != NULL)
{
CorNode* minP = rawP->value.head;
for (CorNode* tmpP = minP->next; tmpP != NULL; tmpP = tmpP->next)
{
if (corTreeNodeCompare(minP, tmpP) > 0)
minP = tmpP;
}
corTreeChildRemove(rawP, minP);
corTreeChildAdd(arrayP, minP);
}
}
// -----------------------------------------------------------------------------
//
// containerOrder - order every Array in the sub-tree, deepest first
//
// The children are done before the container itself, so that when the elements
// of an Array are compared, everything below them is already canonical.
//
static void containerOrder(CorNode* nodeP)
{
for (CorNode* childP = nodeP->value.head; childP != NULL; childP = childP->next)
{
if ((childP->type == CorObject) || (childP->type == CorArray))
containerOrder(childP);
}
if (nodeP->type == CorArray)
elementsOrder(nodeP);
}
// -----------------------------------------------------------------------------
//
// corTreeArraySort - order the elements of a CorNode Array
//
void corTreeArraySort(CorNode* arrayP)
{
if (arrayP->type != CorArray)
return;
if (arrayP->value.head == NULL)
return;
//
// The elements are compared member by member, in list order, so the members must be in a
// canonical order first - otherwise two elements with identical content but built by two
// different pieces of code compare as different, and where they end up depends on which
// piece of code built them.
//
// corTreeSort does exactly that and nothing else - it orders the members of every Object in the
// sub-tree and leaves the order of every Array alone.
//
corTreeSort(arrayP);
containerOrder(arrayP);
}