ox 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ox might be problematic. Click here for more details.
- data/LICENSE +27 -0
- data/README +153 -0
- data/ext/ox/base64.c +123 -0
- data/ext/ox/base64.h +44 -0
- data/ext/ox/cache.c +148 -0
- data/ext/ox/cache.h +43 -0
- data/ext/ox/cache8.c +80 -0
- data/ext/ox/cache8.h +43 -0
- data/ext/ox/cache8_test.c +69 -0
- data/ext/ox/cache_test.c +69 -0
- data/ext/ox/dump.c +901 -0
- data/ext/ox/extconf.rb +7 -0
- data/ext/ox/gen_load.c +196 -0
- data/ext/ox/obj_load.c +802 -0
- data/ext/ox/ox.c +456 -0
- data/ext/ox/ox.h +190 -0
- data/ext/ox/parse.c +629 -0
- data/lib/ox.rb +97 -0
- data/lib/ox/cdata.rb +12 -0
- data/lib/ox/comment.rb +13 -0
- data/lib/ox/doctype.rb +13 -0
- data/lib/ox/document.rb +20 -0
- data/lib/ox/element.rb +67 -0
- data/lib/ox/node.rb +24 -0
- data/test/Sample.graffle +2318 -0
- data/test/cache16_test.rb +17 -0
- data/test/cache8_test.rb +17 -0
- data/test/cache_test.rb +17 -0
- data/test/files.rb +34 -0
- data/test/func.rb +228 -0
- data/test/gen_sample.rb +22 -0
- data/test/obj_sample.rb +19 -0
- data/test/ox/change.rb +16 -0
- data/test/ox/dir.rb +21 -0
- data/test/ox/doc.rb +39 -0
- data/test/ox/file.rb +33 -0
- data/test/ox/group.rb +18 -0
- data/test/ox/hasprops.rb +18 -0
- data/test/ox/layer.rb +14 -0
- data/test/ox/line.rb +22 -0
- data/test/ox/oval.rb +12 -0
- data/test/ox/rect.rb +12 -0
- data/test/ox/shape.rb +37 -0
- data/test/ox/text.rb +23 -0
- data/test/perf_gen.rb +193 -0
- data/test/perf_mars.rb +97 -0
- data/test/perf_obj.rb +201 -0
- data/test/perf_pod.rb +88 -0
- data/test/perf_write.rb +80 -0
- data/test/sample.rb +62 -0
- data/test/test.rb +70 -0
- metadata +106 -0
data/LICENSE
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (c) 2011, Peter Ohler
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
- Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
- Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
- Neither the name of Peter Ohler nor the names of its contributors may be
|
15
|
+
used to endorse or promote products derived from this software without
|
16
|
+
specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
= Ox: A fast XML parser and Object marshaller.
|
2
|
+
|
3
|
+
*GitHub* *repo*: https://github.com/ohler55/ox
|
4
|
+
|
5
|
+
=== Description:
|
6
|
+
|
7
|
+
Optimized XML (Ox), as the name implies was written to provide speed optimized
|
8
|
+
XML handling. It was designed to be an alternative to Nokogiri in generic XML
|
9
|
+
parsing and as an alternative to Marshal for Object serialization.
|
10
|
+
|
11
|
+
Nokogiri relies on libXml while Ox is self contained. Ox uses nothing other
|
12
|
+
than standard C libraries so version issues with libXml are not an issue.
|
13
|
+
|
14
|
+
Marshal uses a binary format for serializing Objects. That binary format
|
15
|
+
changes with releases making Marshal dumped Object incompatible between some
|
16
|
+
versions. The use of a binary format make debugging message streams or file
|
17
|
+
contents next to impossible unless the same version of Ruby and only Ruby is
|
18
|
+
used for inspecting the serialize Object. Ox on the other hand uses human
|
19
|
+
readable XML.
|
20
|
+
|
21
|
+
It is possible to write an XML serialization gem with Nokogiri but writing
|
22
|
+
such a package in Ruby results in a module significantly slower than
|
23
|
+
Marshal. This is what triggered the start of Ox development.
|
24
|
+
|
25
|
+
Ox handles XML documents in two ways. It is a generic XML parser and writer as
|
26
|
+
well as a fast Object / XML marshaller. Ox was written for speed as a
|
27
|
+
replacement for Nokogiri and for Marshal.
|
28
|
+
|
29
|
+
As an XML parser it is 2 or more times faster than Nokogiri and as a generic
|
30
|
+
XML writer it is as much as 20 times faster than Nokogiri. Of course different
|
31
|
+
files may result in slightly different times.
|
32
|
+
|
33
|
+
As an Object serializer Ox is up to 6 times faster than the standard Ruby
|
34
|
+
Marshal.dump() and up to 3 times faster than Marshal.load().
|
35
|
+
|
36
|
+
|
37
|
+
=== Object Dump Sample:
|
38
|
+
|
39
|
+
require 'ox'
|
40
|
+
|
41
|
+
class Sample
|
42
|
+
attr_accessor :a, :b, :c
|
43
|
+
|
44
|
+
def initialize(a, b, c)
|
45
|
+
@a = a
|
46
|
+
@b = b
|
47
|
+
@c = c
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create Object
|
52
|
+
obj = Sample.new(1, "bee", ['x', :y, 7.0])
|
53
|
+
# Now dump the Object to an XML String.
|
54
|
+
xml = Ox.dump(obj)
|
55
|
+
# Convert the object back into a Sample Object.
|
56
|
+
obj2 = Ox.parse_obj(xml)
|
57
|
+
|
58
|
+
=== Generic XML Writing and Parsing:
|
59
|
+
|
60
|
+
require 'ox'
|
61
|
+
|
62
|
+
doc = Ox::Document.new(:version => '1.0')
|
63
|
+
|
64
|
+
top = Ox::Element.new('top')
|
65
|
+
top[:name] = 'sample'
|
66
|
+
doc << top
|
67
|
+
|
68
|
+
mid = Ox::Element.new('middle')
|
69
|
+
mid[:name] = 'second'
|
70
|
+
top << mid
|
71
|
+
|
72
|
+
bot = Ox::Element.new('bottom')
|
73
|
+
bot[:name] = 'third'
|
74
|
+
mid << bot
|
75
|
+
|
76
|
+
xml = Ox.dump(doc)
|
77
|
+
puts xml
|
78
|
+
doc2 = Ox.parse(xml)
|
79
|
+
puts "Same? #{doc == doc2}"
|
80
|
+
|
81
|
+
|
82
|
+
=== Object XML format
|
83
|
+
|
84
|
+
The XML format used for Object encoding follows the structure of the
|
85
|
+
Object. Each XML element is encoded so that the XML element name is a type
|
86
|
+
indicator. Attributes of the element provide additional information such as
|
87
|
+
the Class if relevant, the Object attribute name, and Object ID if
|
88
|
+
necessary.
|
89
|
+
|
90
|
+
The type indicator map is:
|
91
|
+
|
92
|
+
- +a+ => Array
|
93
|
+
- +b+ => Base64
|
94
|
+
- +c+ => Class
|
95
|
+
- +f+ => Float
|
96
|
+
- +g+ => Regexp
|
97
|
+
- +h+ => Hash
|
98
|
+
- +i+ => Fixnum
|
99
|
+
- +j+ => Bignum
|
100
|
+
- +l+ => Rational
|
101
|
+
- +m+ => Symbol
|
102
|
+
- +n+ => FalseClass
|
103
|
+
- +o+ => Object
|
104
|
+
- +p+ => Ref
|
105
|
+
- +r+ => Range
|
106
|
+
- +s+ => String
|
107
|
+
- +t+ => Time
|
108
|
+
- +u+ => Struct
|
109
|
+
- +v+ => Complex
|
110
|
+
- +x+ => Raw
|
111
|
+
- +y+ => TrueClass
|
112
|
+
- +z+ => NilClass
|
113
|
+
|
114
|
+
If the type is an Object, type 'o' then an attribute named 'c' should be set
|
115
|
+
with the full Class name including the Module names. If the XML element
|
116
|
+
represents an Object then a sub-elements is included for each attribute of
|
117
|
+
the Object. An XML element attribute 'a' is set with a value that is the
|
118
|
+
name of the Ruby Object attribute. In all cases, except for the Exception
|
119
|
+
attribute hack the attribute names begin with an @ character. (Exception are
|
120
|
+
strange in that the attributes of the Exception Class are not named with a @
|
121
|
+
suffix. A hack since it has to be done in C and can not be done through the
|
122
|
+
interpreter.)
|
123
|
+
|
124
|
+
Values are encoded as the text portion of an element or in the sub-elements
|
125
|
+
of the principle. For example, a Fixnum is encoded as:
|
126
|
+
|
127
|
+
<i>123</i>
|
128
|
+
|
129
|
+
An Array has sub-elements and is encoded similar to this example.
|
130
|
+
|
131
|
+
<a>
|
132
|
+
<i>1</i>
|
133
|
+
<s>abc</s>
|
134
|
+
</a>
|
135
|
+
|
136
|
+
A Hash is encoded with an even number of elements where the first element is
|
137
|
+
the key and the second is the value. This is repeated for each entry in the
|
138
|
+
Hash. An example is of { 1 => 'one', 2 => 'two' } encoding is:
|
139
|
+
|
140
|
+
<h>
|
141
|
+
<i>1</i>
|
142
|
+
<s>one</s>
|
143
|
+
<i>2</i>
|
144
|
+
<s>two</s>
|
145
|
+
</h>
|
146
|
+
|
147
|
+
Strings with characters not allowed in XML are base64 encoded amd will be
|
148
|
+
converted back into a String when loaded.
|
149
|
+
|
150
|
+
Ox supports circular references where attributes of one Object can refer to
|
151
|
+
an Object that refers back to the first Object. When this option is used an
|
152
|
+
Object ID is added to each XML Object element as the value of the 'a'
|
153
|
+
attribute.
|
data/ext/ox/base64.c
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
/* base64.c
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
7
|
+
*
|
8
|
+
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
+
* list of conditions and the following disclaimer.
|
10
|
+
*
|
11
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
*
|
15
|
+
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
+
* used to endorse or promote products derived from this software without
|
17
|
+
* specific prior written permission.
|
18
|
+
*
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#include <stdlib.h>
|
32
|
+
|
33
|
+
#include "base64.h"
|
34
|
+
|
35
|
+
static char digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
36
|
+
|
37
|
+
// invalid or terminating characters are set to 'X' or \x58
|
38
|
+
static u_char s_digits[256] = "\
|
39
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
40
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
41
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x3E\x58\x58\x58\x3F\
|
42
|
+
\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x58\x58\x58\x58\x58\x58\
|
43
|
+
\x58\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\
|
44
|
+
\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x58\x58\x58\x58\x58\
|
45
|
+
\x58\x1A\x1B\x1C\x1D\x1E\x1F\x20\x21\x22\x23\x24\x25\x26\x27\x28\
|
46
|
+
\x29\x2A\x2B\x2C\x2D\x2E\x2F\x30\x31\x32\x33\x58\x58\x58\x58\x58\
|
47
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
48
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
49
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
50
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
51
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
52
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
53
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
54
|
+
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58";
|
55
|
+
|
56
|
+
void
|
57
|
+
to_base64(const u_char *src, int len, char *b64) {
|
58
|
+
const u_char *end3;
|
59
|
+
int len3 = len % 3;
|
60
|
+
u_char b1, b2, b3;
|
61
|
+
|
62
|
+
end3 = src + (len - len3);
|
63
|
+
while (src < end3) {
|
64
|
+
b1 = *src++;
|
65
|
+
b2 = *src++;
|
66
|
+
b3 = *src++;
|
67
|
+
*b64++ = digits[b1 >> 2];
|
68
|
+
*b64++ = digits[((b1 & 0x03) << 4) | (b2 >> 4)];
|
69
|
+
*b64++ = digits[((b2 & 0x0F) << 2) | (b3 >> 6)];
|
70
|
+
*b64++ = digits[b3 & 0x3F];
|
71
|
+
}
|
72
|
+
if (1 == len3) {
|
73
|
+
b1 = *src++;
|
74
|
+
*b64++ = digits[b1 >> 2];
|
75
|
+
*b64++ = digits[(b1 & 0x03) << 4];
|
76
|
+
*b64++ = '=';
|
77
|
+
*b64++ = '=';
|
78
|
+
} else if (2 == len3) {
|
79
|
+
b1 = *src++;
|
80
|
+
b2 = *src++;
|
81
|
+
*b64++ = digits[b1 >> 2];
|
82
|
+
*b64++ = digits[((b1 & 0x03) << 4) | (b2 >> 4)];
|
83
|
+
*b64++ = digits[(b2 & 0x0F) << 2];
|
84
|
+
*b64++ = '=';
|
85
|
+
}
|
86
|
+
*b64 = '\0';
|
87
|
+
}
|
88
|
+
|
89
|
+
unsigned long
|
90
|
+
b64_orig_size(const char *text) {
|
91
|
+
const char *start = text;
|
92
|
+
unsigned long size = 0;
|
93
|
+
|
94
|
+
if ('\0' != *text) {
|
95
|
+
for (; 0 != *text; text++) { }
|
96
|
+
size = (text - start) * 3 / 4;
|
97
|
+
text--;
|
98
|
+
if ('=' == *text) {
|
99
|
+
size--;
|
100
|
+
text--;
|
101
|
+
if ('=' == *text) {
|
102
|
+
size--;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
return size;
|
107
|
+
}
|
108
|
+
|
109
|
+
void
|
110
|
+
from_base64(const char *b64, u_char *str) {
|
111
|
+
u_char b0, b1, b2, b3;
|
112
|
+
|
113
|
+
while (1) {
|
114
|
+
if ('X' == (b0 = s_digits[(u_char)*b64++])) { break; }
|
115
|
+
if ('X' == (b1 = s_digits[(u_char)*b64++])) { break; }
|
116
|
+
*str++ = (b0 << 2) | ((b1 >> 4) & 0x03);
|
117
|
+
if ('X' == (b2 = s_digits[(u_char)*b64++])) { break; }
|
118
|
+
*str++ = (b1 << 4) | ((b2 >> 2) & 0x0F);
|
119
|
+
if ('X' == (b3 = s_digits[(u_char)*b64++])) { break; }
|
120
|
+
*str++ = (b2 << 6) | b3;
|
121
|
+
}
|
122
|
+
*str = '\0';
|
123
|
+
}
|
data/ext/ox/base64.h
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
/* base64.h
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
7
|
+
*
|
8
|
+
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
+
* list of conditions and the following disclaimer.
|
10
|
+
*
|
11
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
*
|
15
|
+
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
+
* used to endorse or promote products derived from this software without
|
17
|
+
* specific prior written permission.
|
18
|
+
*
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#ifndef __BASE64_H__
|
32
|
+
#define __BASE64_H__
|
33
|
+
|
34
|
+
#include <sys/types.h>
|
35
|
+
|
36
|
+
|
37
|
+
#define b64_size(len) ((len + 2) / 3 * 4)
|
38
|
+
|
39
|
+
extern unsigned long b64_orig_size(const char *text);
|
40
|
+
|
41
|
+
extern void to_base64(const u_char *src, int len, char *b64);
|
42
|
+
extern void from_base64(const char *b64, u_char *str);
|
43
|
+
|
44
|
+
#endif /* __BASE64_H__ */
|
data/ext/ox/cache.c
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
/* cache.c
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
7
|
+
*
|
8
|
+
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
+
* list of conditions and the following disclaimer.
|
10
|
+
*
|
11
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
*
|
15
|
+
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
+
* used to endorse or promote products derived from this software without
|
17
|
+
* specific prior written permission.
|
18
|
+
*
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#include <stdlib.h>
|
32
|
+
#include <errno.h>
|
33
|
+
#include <stdio.h>
|
34
|
+
#include <string.h>
|
35
|
+
#include <stdarg.h>
|
36
|
+
|
37
|
+
#include "cache.h"
|
38
|
+
|
39
|
+
struct _Cache {
|
40
|
+
char *key; // only set if the node has a value, and it is not an exact match
|
41
|
+
VALUE value;
|
42
|
+
struct _Cache *slots[16];
|
43
|
+
};
|
44
|
+
|
45
|
+
static void slot_print(Cache cache, unsigned int depth);
|
46
|
+
|
47
|
+
void
|
48
|
+
ox_cache_new(Cache *cache) {
|
49
|
+
if (0 == (*cache = (Cache)malloc(sizeof(struct _Cache)))) {
|
50
|
+
rb_raise(rb_eNoMemError, "not enough memory\n");
|
51
|
+
}
|
52
|
+
(*cache)->key = 0;
|
53
|
+
(*cache)->value = Qundef;
|
54
|
+
bzero((*cache)->slots, sizeof((*cache)->slots));
|
55
|
+
}
|
56
|
+
|
57
|
+
VALUE
|
58
|
+
ox_cache_get(Cache cache, const char *key, VALUE **slot) {
|
59
|
+
unsigned char *k = (unsigned char*)key;
|
60
|
+
Cache *cp;
|
61
|
+
|
62
|
+
for (; '\0' != *k; k++) {
|
63
|
+
cp = cache->slots + (unsigned int)(*k >> 4); // upper 4 bits
|
64
|
+
if (0 == *cp) {
|
65
|
+
ox_cache_new(cp);
|
66
|
+
}
|
67
|
+
cache = *cp;
|
68
|
+
cp = cache->slots + (unsigned int)(*k & 0x0F); // lower 4 bits
|
69
|
+
if (0 == *cp) {
|
70
|
+
ox_cache_new(cp);
|
71
|
+
cache = *cp;
|
72
|
+
cache->key = ('\0' == *(k + 1)) ? 0 : strdup(key);
|
73
|
+
break;
|
74
|
+
} else {
|
75
|
+
cache = *cp;
|
76
|
+
if (Qundef != cache->value && 0 != cache->key) {
|
77
|
+
unsigned char *ck = (unsigned char*)(cache->key + (unsigned int)(k - (unsigned char*)key + 1));
|
78
|
+
|
79
|
+
if (0 == strcmp((char*)ck, (char*)(k + 1))) {
|
80
|
+
break;
|
81
|
+
} else {
|
82
|
+
Cache *cp2 = cp;
|
83
|
+
|
84
|
+
// if value was set along with the key then there are no slots filled yet
|
85
|
+
cp2 = (*cp2)->slots + (*ck >> 4);
|
86
|
+
ox_cache_new(cp2);
|
87
|
+
cp2 = (*cp2)->slots + (*ck & 0x0F);
|
88
|
+
ox_cache_new(cp2);
|
89
|
+
if ('\0' == *(ck + 1)) {
|
90
|
+
free(cache->key);
|
91
|
+
} else {
|
92
|
+
(*cp2)->key = cache->key;
|
93
|
+
}
|
94
|
+
(*cp2)->value = cache->value;
|
95
|
+
cache->key = 0;
|
96
|
+
cache->value = Qundef;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
*slot = &cache->value;
|
102
|
+
|
103
|
+
return cache->value;
|
104
|
+
}
|
105
|
+
|
106
|
+
void
|
107
|
+
ox_cache_print(Cache cache) {
|
108
|
+
//printf("-------------------------------------------\n");
|
109
|
+
slot_print(cache, 0);
|
110
|
+
}
|
111
|
+
|
112
|
+
static void
|
113
|
+
slot_print(Cache c, unsigned int depth) {
|
114
|
+
char indent[256];
|
115
|
+
Cache *cp;
|
116
|
+
unsigned int i;
|
117
|
+
|
118
|
+
if (sizeof(indent) - 1 < depth) {
|
119
|
+
depth = ((int)sizeof(indent) - 1);
|
120
|
+
}
|
121
|
+
memset(indent, ' ', depth);
|
122
|
+
indent[depth] = '\0';
|
123
|
+
for (i = 0, cp = c->slots; i < 16; i++, cp++) {
|
124
|
+
if (0 == *cp) {
|
125
|
+
//printf("%s%02u:\n", indent, i);
|
126
|
+
} else {
|
127
|
+
if (0 == (*cp)->key && Qundef == (*cp)->value) {
|
128
|
+
printf("%s%02u:\n", indent, i);
|
129
|
+
} else {
|
130
|
+
const char *key = (0 == (*cp)->key) ? "*" : (*cp)->key;
|
131
|
+
const char *vs;
|
132
|
+
const char *clas;
|
133
|
+
|
134
|
+
if (Qundef == (*cp)->value) {
|
135
|
+
vs = "undefined";
|
136
|
+
clas = "";
|
137
|
+
} else {
|
138
|
+
VALUE rs = rb_funcall2((*cp)->value, rb_intern("to_s"), 0, 0);
|
139
|
+
|
140
|
+
vs = StringValuePtr(rs);
|
141
|
+
clas = rb_class2name(rb_obj_class((*cp)->value));
|
142
|
+
}
|
143
|
+
printf("%s%02u: %s = %s (%s)\n", indent, i, key, vs, clas);
|
144
|
+
}
|
145
|
+
slot_print(*cp, depth + 2);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|