birch 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ext/birch/birch.c +354 -0
- data/ext/birch/extconf.rb +3 -0
- data/lib/birch.rb +1 -0
- data/lib/birch/version.rb +3 -0
- metadata +50 -0
data/ext/birch/birch.c
ADDED
@@ -0,0 +1,354 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
|
3
|
+
/*
|
4
|
+
* Initialize the node with its value and id.
|
5
|
+
* Setup containers for the children, features
|
6
|
+
* and dependencies of this node.
|
7
|
+
*/
|
8
|
+
static VALUE birch_initialize(VALUE self, VALUE value, VALUE id)
|
9
|
+
{
|
10
|
+
VALUE parent;
|
11
|
+
VALUE children;
|
12
|
+
VALUE children_hash;
|
13
|
+
VALUE features;
|
14
|
+
VALUE edges;
|
15
|
+
|
16
|
+
parent = Qnil;
|
17
|
+
children = rb_ary_new();
|
18
|
+
children_hash = rb_hash_new();
|
19
|
+
features = rb_hash_new();
|
20
|
+
edges = rb_ary_new();
|
21
|
+
|
22
|
+
rb_iv_set(self, "@value", value);
|
23
|
+
rb_iv_set(self, "@id", id);
|
24
|
+
|
25
|
+
rb_iv_set(self, "@parent", parent);
|
26
|
+
rb_iv_set(self, "@children", children);
|
27
|
+
rb_iv_set(self, "@children_hash", children_hash);
|
28
|
+
rb_iv_set(self, "@features", features);
|
29
|
+
rb_iv_set(self, "@edges", edges);
|
30
|
+
|
31
|
+
return self;
|
32
|
+
}
|
33
|
+
|
34
|
+
/* Return the root of the tree. */
|
35
|
+
static VALUE birch_root(VALUE self) {
|
36
|
+
|
37
|
+
VALUE ancestor;
|
38
|
+
VALUE parent;
|
39
|
+
VALUE tmp;
|
40
|
+
|
41
|
+
parent = rb_iv_get(ancestor, "@parent");
|
42
|
+
|
43
|
+
if (parent == Qnil) {
|
44
|
+
return self;
|
45
|
+
} else {
|
46
|
+
ancestor = parent;
|
47
|
+
while (ancestor != Qnil) {
|
48
|
+
tmp = rb_iv_get(ancestor, "@parent");
|
49
|
+
if (tmp == Qnil) {
|
50
|
+
return ancestor;
|
51
|
+
} else {
|
52
|
+
ancestor = tmp;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
return Qnil;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
/* Add a child to this node. */
|
60
|
+
static VALUE birch_add(VALUE self, VALUE child) {
|
61
|
+
|
62
|
+
VALUE children;
|
63
|
+
VALUE children_hash;
|
64
|
+
|
65
|
+
VALUE child_id;
|
66
|
+
|
67
|
+
children = rb_iv_get(self, "@children");
|
68
|
+
child_id = rb_funcall(child, rb_intern("id"), 0);
|
69
|
+
children_hash = rb_iv_get(self, "@children_hash");
|
70
|
+
|
71
|
+
rb_funcall(children, rb_intern("push"), 1, child);
|
72
|
+
|
73
|
+
rb_funcall(
|
74
|
+
children_hash,
|
75
|
+
rb_intern("store"),
|
76
|
+
2, child_id, child
|
77
|
+
);
|
78
|
+
|
79
|
+
rb_iv_set(child, "@parent", self);
|
80
|
+
|
81
|
+
return child;
|
82
|
+
|
83
|
+
}
|
84
|
+
|
85
|
+
/* Return the feature with the supplied name. */
|
86
|
+
static VALUE birch_get(VALUE self, VALUE feature) {
|
87
|
+
if (feature == rb_intern("id")) {
|
88
|
+
return rb_iv_get(self, "@id");
|
89
|
+
} else if (feature == rb_intern("value")) {
|
90
|
+
return rb_iv_get(self, "@value");
|
91
|
+
} else {
|
92
|
+
return rb_hash_aref(rb_iv_get(self, "@features"), feature);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
/* Set the feature to the supplied value. */
|
97
|
+
static VALUE birch_set(VALUE self, VALUE feature, VALUE value) {
|
98
|
+
return rb_hash_aset(rb_iv_get(self, "@features"), feature, value);
|
99
|
+
}
|
100
|
+
|
101
|
+
/* Unset a feature. */
|
102
|
+
static VALUE birch_unset(VALUE self, VALUE feature) {
|
103
|
+
return rb_hash_delete(
|
104
|
+
rb_iv_get(self, "@features"),
|
105
|
+
feature
|
106
|
+
);
|
107
|
+
}
|
108
|
+
|
109
|
+
/* Return the total number of nodes in the subtree */
|
110
|
+
static VALUE birch_size(VALUE self) {
|
111
|
+
|
112
|
+
|
113
|
+
VALUE children;
|
114
|
+
int sum;
|
115
|
+
long len;
|
116
|
+
long i;
|
117
|
+
|
118
|
+
children = rb_iv_get(self, "@children");
|
119
|
+
len = RARRAY_LEN(children);
|
120
|
+
sum = 0;
|
121
|
+
|
122
|
+
for (i=0; i<len; i++) {
|
123
|
+
sum += rb_funcall(
|
124
|
+
RARRAY_PTR(children)[i],
|
125
|
+
rb_intern("size"), 0
|
126
|
+
);
|
127
|
+
}
|
128
|
+
|
129
|
+
return INT2NUM(sum);
|
130
|
+
|
131
|
+
}
|
132
|
+
|
133
|
+
/* Iterate over each children of the node. */
|
134
|
+
static VALUE birch_each(VALUE self) {
|
135
|
+
|
136
|
+
long i;
|
137
|
+
VALUE children;
|
138
|
+
children = rb_iv_get(self, "@children");
|
139
|
+
|
140
|
+
RETURN_ENUMERATOR(children, 0, 0);
|
141
|
+
|
142
|
+
for (i=0; i<RARRAY_LEN(children); i++) {
|
143
|
+
rb_yield(RARRAY_PTR(children)[i]);
|
144
|
+
}
|
145
|
+
|
146
|
+
return children;
|
147
|
+
|
148
|
+
}
|
149
|
+
|
150
|
+
static VALUE birch_find(VALUE self, VALUE id) {
|
151
|
+
|
152
|
+
VALUE children_hash;
|
153
|
+
VALUE children;
|
154
|
+
VALUE result;
|
155
|
+
long i;
|
156
|
+
|
157
|
+
children_hash = rb_iv_get(self, "@children_hash");
|
158
|
+
result = rb_hash_aref(children_hash, id);
|
159
|
+
|
160
|
+
if (result == Qnil) {
|
161
|
+
children = rb_iv_get(self, "@children");
|
162
|
+
for (i=0; i < RARRAY_LEN(children); i++) {
|
163
|
+
result = rb_funcall(
|
164
|
+
RARRAY_PTR(children)[i],
|
165
|
+
rb_intern("find"), 1, id
|
166
|
+
);
|
167
|
+
if (result != Qnil) { return result; }
|
168
|
+
}
|
169
|
+
return Qnil;
|
170
|
+
} else { return result; }
|
171
|
+
|
172
|
+
}
|
173
|
+
|
174
|
+
/* Boolean - is this node's subtree empty? */
|
175
|
+
static VALUE birch_is_leaf(VALUE self) {
|
176
|
+
if (RARRAY_LEN(rb_iv_get(self, "@children")) == 0) {
|
177
|
+
return Qtrue;
|
178
|
+
} else {
|
179
|
+
return Qfalse;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
/* Boolean - is this node parent-less? */
|
184
|
+
static VALUE birch_is_root(VALUE self) {
|
185
|
+
if (rb_iv_get(self, "@parent") == Qnil) {
|
186
|
+
return Qtrue;
|
187
|
+
} else {
|
188
|
+
return Qfalse;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
/* Boolean - does this node have children */
|
193
|
+
static VALUE birch_has_children(VALUE self) {
|
194
|
+
if (RARRAY_LEN(rb_iv_get(self, "@children")) == 0) {
|
195
|
+
return Qfalse;
|
196
|
+
} else {
|
197
|
+
return Qtrue;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
/* Boolean - does the node have a parent? */
|
202
|
+
static VALUE birch_has_parent(VALUE self) {
|
203
|
+
if (rb_iv_get(self, "@parent") == Qnil) {
|
204
|
+
return Qfalse;
|
205
|
+
} else {
|
206
|
+
return Qtrue;
|
207
|
+
}
|
208
|
+
}
|
209
|
+
|
210
|
+
/* Boolean - does the node have edges? */
|
211
|
+
static VALUE birch_has_edges(VALUE self) {
|
212
|
+
if (RARRAY_LEN(rb_iv_get(self, "@edges")) == 0) {
|
213
|
+
return Qfalse;
|
214
|
+
} else {
|
215
|
+
return Qtrue;
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
/* Boolean - does the node have feature? */
|
220
|
+
static VALUE birch_has_feature(VALUE self, VALUE feature) {
|
221
|
+
VALUE features;
|
222
|
+
features = rb_iv_get(self, "@features");
|
223
|
+
if (rb_hash_aref(features, feature) == Qnil) {
|
224
|
+
return Qfalse;
|
225
|
+
} else {
|
226
|
+
return Qtrue;
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
230
|
+
static VALUE birch_link(VALUE self, VALUE edge) {
|
231
|
+
|
232
|
+
VALUE edges;
|
233
|
+
edges = rb_iv_get(self, "@edges");
|
234
|
+
|
235
|
+
rb_funcall(
|
236
|
+
edges, rb_intern("push"), 1, edge
|
237
|
+
);
|
238
|
+
|
239
|
+
}
|
240
|
+
|
241
|
+
/* Remove from parent and set as root */
|
242
|
+
static VALUE birch_set_as_root(VALUE self) {
|
243
|
+
|
244
|
+
// Set the parent to be nil.
|
245
|
+
rb_iv_set(self, "@parent", Qnil);
|
246
|
+
|
247
|
+
// Return self.
|
248
|
+
return self;
|
249
|
+
|
250
|
+
}
|
251
|
+
|
252
|
+
/* Removes a node by ID and returns it */
|
253
|
+
static VALUE birch_remove(VALUE self, VALUE id) {
|
254
|
+
|
255
|
+
VALUE val;
|
256
|
+
|
257
|
+
// Delete the node from the hash and retrieve it.
|
258
|
+
val = rb_hash_delete(
|
259
|
+
rb_iv_get(self, "@children_hash"), id
|
260
|
+
);
|
261
|
+
|
262
|
+
// Raise an exception if the value can't be found.
|
263
|
+
if (val == Qundef) {
|
264
|
+
rb_raise(rb_eArgError,
|
265
|
+
"Given ID is not a children of this node.");
|
266
|
+
return Qnil;
|
267
|
+
}
|
268
|
+
|
269
|
+
// Delete the node from the children array.
|
270
|
+
rb_funcall(
|
271
|
+
rb_iv_get(self, "@children"),
|
272
|
+
rb_intern("delete"), 1, val
|
273
|
+
);
|
274
|
+
|
275
|
+
// Set the node as a root (set its parent to nil).
|
276
|
+
rb_funcall(
|
277
|
+
val, rb_intern("set_as_root!"), 0
|
278
|
+
);
|
279
|
+
|
280
|
+
return val;
|
281
|
+
|
282
|
+
}
|
283
|
+
|
284
|
+
/* Remove all children and set them as root. */
|
285
|
+
static VALUE birch_remove_all(VALUE self) {
|
286
|
+
|
287
|
+
VALUE children;
|
288
|
+
long i;
|
289
|
+
long children_len;
|
290
|
+
|
291
|
+
children = rb_iv_get(self, "@children");
|
292
|
+
|
293
|
+
for (i = 0; i < children_len; i++) {
|
294
|
+
rb_funcall(
|
295
|
+
RARRAY_PTR(children)[i],
|
296
|
+
rb_intern("set_as_root!"), 0
|
297
|
+
);
|
298
|
+
}
|
299
|
+
|
300
|
+
rb_iv_set(self, "@children", rb_ary_new());
|
301
|
+
rb_iv_set(self, "@children_hash", rb_hash_new());
|
302
|
+
|
303
|
+
return self;
|
304
|
+
}
|
305
|
+
|
306
|
+
/* This class is a node for an N-ary tree data structure
|
307
|
+
* with a unique identifier, text value, children, features
|
308
|
+
* (annotations) and dependencies.
|
309
|
+
*
|
310
|
+
* This class was partly based on the 'rubytree' gem.
|
311
|
+
* RubyTree is licensed under the BSD license and can
|
312
|
+
* be found at http://rubytree.rubyforge.org/rdoc/.
|
313
|
+
*/
|
314
|
+
void Init_birch(void) {
|
315
|
+
|
316
|
+
VALUE module = rb_define_module("Birch");
|
317
|
+
VALUE klass = rb_define_class_under(module, "Tree", rb_cObject);
|
318
|
+
|
319
|
+
// Attribute accessors
|
320
|
+
rb_attr(klass, rb_intern("id"), 1, 1, 1);
|
321
|
+
rb_attr(klass, rb_intern("value"), 1, 1, 1);
|
322
|
+
|
323
|
+
// Attribute readers
|
324
|
+
rb_attr(klass, rb_intern("parent"), 1, 0, 0);
|
325
|
+
rb_attr(klass, rb_intern("children"), 1, 0, 0);
|
326
|
+
rb_attr(klass, rb_intern("features"), 1, 0, 0);
|
327
|
+
rb_attr(klass, rb_intern("edges"), 1, 0, 0);
|
328
|
+
|
329
|
+
// Methods
|
330
|
+
rb_define_method(klass, "initialize", birch_initialize, 2);
|
331
|
+
rb_define_method(klass, "root", birch_root, 0);
|
332
|
+
rb_define_method(klass, "<<", birch_add, 1);
|
333
|
+
rb_define_method(klass, "add", birch_add, 1);
|
334
|
+
rb_define_method(klass, "[]", birch_get, 1);
|
335
|
+
rb_define_method(klass, "get", birch_get, 1);
|
336
|
+
rb_define_method(klass, "[]=", birch_set, 2);
|
337
|
+
rb_define_method(klass, "set", birch_set, 2);
|
338
|
+
rb_define_method(klass, "unset", birch_unset, 1);
|
339
|
+
rb_define_method(klass, "size", birch_size, 0);
|
340
|
+
rb_define_method(klass, "each", birch_each, 0);
|
341
|
+
rb_define_method(klass, "find", birch_find, 1);
|
342
|
+
rb_define_method(klass, "is_leaf?", birch_is_leaf, 0);
|
343
|
+
rb_define_method(klass, "is_root?", birch_is_root, 0);
|
344
|
+
rb_define_method(klass, "has_parent?", birch_has_parent, 0);
|
345
|
+
rb_define_method(klass, "has_children?", birch_has_children, 0);
|
346
|
+
rb_define_method(klass, "has_edges?", birch_has_edges, 0);
|
347
|
+
rb_define_method(klass, "has_feature?", birch_has_feature, 1);
|
348
|
+
rb_define_method(klass, "has?", birch_has_feature, 1);
|
349
|
+
rb_define_method(klass, "link", birch_link, 1);
|
350
|
+
rb_define_method(klass, "set_as_root!", birch_set_as_root, 0);
|
351
|
+
rb_define_method(klass, "remove", birch_remove, 1);
|
352
|
+
rb_define_method(klass, "remove_all!", birch_remove_all, 0);
|
353
|
+
|
354
|
+
}
|
data/lib/birch.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'birch/birch'
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: birch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Louis Mullie
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-04 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! ' '
|
15
|
+
email:
|
16
|
+
- louis.mullie@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions:
|
19
|
+
- ext/birch/extconf.rb
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- lib/birch/version.rb
|
23
|
+
- lib/birch.rb
|
24
|
+
- ext/birch/birch.c
|
25
|
+
- ext/birch/extconf.rb
|
26
|
+
homepage: https://github.com/louismullie/birch
|
27
|
+
licenses: []
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 1.8.24
|
47
|
+
signing_key:
|
48
|
+
specification_version: 3
|
49
|
+
summary: Birch is a generic tree implementation for Ruby, in C.
|
50
|
+
test_files: []
|