ninjudd-tuple 0.0.7 → 0.0.10
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/LICENSE +20 -0
- data/VERSION.yml +2 -2
- data/ext/tuple.c +92 -50
- data/test/tuple_test.rb +14 -6
- metadata +12 -10
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Justin Balthrop
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/VERSION.yml
CHANGED
data/ext/tuple.c
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
#include "ruby.h"
|
2
2
|
|
3
3
|
VALUE mTuple;
|
4
|
+
VALUE rb_cDate;
|
4
5
|
|
5
6
|
#define TRUE_SORT 255 // TrueClass
|
7
|
+
#define TUPLE_SORT 192 // Array
|
8
|
+
#define TUPLE_END 191 // For nested tuples
|
6
9
|
#define TIME_SORT 128 // Time
|
7
10
|
#define SYM_SORT 64 // Symbol
|
8
11
|
#define STR_SORT 32 // String
|
@@ -11,8 +14,6 @@ VALUE mTuple;
|
|
11
14
|
#define FALSE_SORT 1 // FalseClass
|
12
15
|
#define NIL_SORT 0 // NilClass
|
13
16
|
|
14
|
-
#define MAX_INT 0xffffffff
|
15
|
-
|
16
17
|
#define BDIGITS(x) ((BDIGIT*)RBIGNUM(x)->digits)
|
17
18
|
|
18
19
|
static void null_pad(VALUE data, int len) {
|
@@ -38,6 +39,7 @@ static VALUE tuple_dump(VALUE self, VALUE tuple) {
|
|
38
39
|
int i, j, len, sign;
|
39
40
|
u_int8_t header[4];
|
40
41
|
u_int32_t digit;
|
42
|
+
int64_t fixnum;
|
41
43
|
BDIGIT *digits;
|
42
44
|
|
43
45
|
if (TYPE(tuple) != T_ARRAY) tuple = rb_ary_new4(1, &tuple);
|
@@ -46,22 +48,32 @@ static VALUE tuple_dump(VALUE self, VALUE tuple) {
|
|
46
48
|
item = RARRAY(tuple)->ptr[i];
|
47
49
|
header[0] = header[1] = header[2] = header[3] = 0;
|
48
50
|
if (FIXNUM_P(item)) {
|
49
|
-
|
50
|
-
|
51
|
-
|
51
|
+
fixnum = FIX2LONG(item);
|
52
|
+
sign = (fixnum >= 0);
|
53
|
+
if (!sign) fixnum = -fixnum;
|
54
|
+
len = fixnum > UINT_MAX ? 2 : 1;
|
55
|
+
header[2] = sign ? INTP_SORT : INTN_SORT;
|
56
|
+
header[3] = sign ? len : UCHAR_MAX - len;
|
52
57
|
rb_str_cat(data, (char*)&header, sizeof(header));
|
53
58
|
|
54
|
-
|
55
|
-
|
59
|
+
if (len == 2) {
|
60
|
+
digit = ((u_int32_t *)(&fixnum))[_QUAD_HIGHWORD];
|
61
|
+
digit = htonl(sign ? digit : UINT_MAX - digit);
|
62
|
+
rb_str_cat(data, (char*)&digit, sizeof(digit));
|
63
|
+
}
|
64
|
+
digit = ((u_int32_t *)(&fixnum))[_QUAD_LOWWORD];
|
65
|
+
digit = htonl(sign ? digit : UINT_MAX - digit);
|
66
|
+
rb_str_cat(data, (char*)&digit, sizeof(digit));
|
56
67
|
} else if (TYPE(item) == T_BIGNUM) {
|
57
68
|
sign = RBIGNUM(item)->sign;
|
69
|
+
len = RBIGNUM(item)->len;
|
58
70
|
header[2] = sign ? INTP_SORT : INTN_SORT;
|
59
|
-
header[3] =
|
71
|
+
header[3] = sign ? len : UCHAR_MAX - len;
|
60
72
|
rb_str_cat(data, (char*)&header, sizeof(header));
|
61
73
|
|
62
74
|
digits = BDIGITS(item);
|
63
|
-
for (j =
|
64
|
-
digit = htonl(sign ? digits[j] : (
|
75
|
+
for (j = len-1; j >= 0; j--) {
|
76
|
+
digit = htonl(sign ? digits[j] : (UINT_MAX - digits[j]));
|
65
77
|
rb_str_cat(data, (char*)&digit, sizeof(digit));
|
66
78
|
}
|
67
79
|
} else if (SYMBOL_P(item) || TYPE(item) == T_STRING) {
|
@@ -76,16 +88,28 @@ static VALUE tuple_dump(VALUE self, VALUE tuple) {
|
|
76
88
|
rb_str_cat(data, RSTRING_PTR(item), len);
|
77
89
|
|
78
90
|
null_pad(data, len);
|
79
|
-
} else if (rb_obj_class(item) == rb_cTime) {
|
91
|
+
} else if (rb_obj_class(item) == rb_cTime || rb_obj_class(item) == rb_cDate) {
|
80
92
|
header[2] = TIME_SORT;
|
81
93
|
rb_str_cat(data, (char*)&header, sizeof(header));
|
82
94
|
|
83
|
-
|
84
|
-
|
85
|
-
|
95
|
+
if (rb_obj_class(item) == rb_cTime) {
|
96
|
+
item = rb_funcall(item, rb_intern("getgm"), 0);
|
97
|
+
item = rb_funcall(item, rb_intern("strftime"), 1, rb_str_new2("%Y/%m/%d %H:%M:%S +0000"));
|
98
|
+
} else {
|
99
|
+
item = rb_funcall(item, rb_intern("strftime"), 1, rb_str_new2("%Y/%m/%d"));
|
100
|
+
}
|
101
|
+
len = RSTRING_LEN(item);
|
86
102
|
rb_str_cat(data, RSTRING_PTR(item), len);
|
87
103
|
|
88
104
|
null_pad(data, len);
|
105
|
+
} else if (TYPE(item) == T_ARRAY) {
|
106
|
+
header[2] = TUPLE_SORT;
|
107
|
+
rb_str_cat(data, (char*)&header, sizeof(header));
|
108
|
+
|
109
|
+
rb_str_concat(data, tuple_dump(mTuple, item));
|
110
|
+
|
111
|
+
header[2] = TUPLE_END;
|
112
|
+
rb_str_cat(data, (char*)&header, sizeof(header));
|
89
113
|
} else {
|
90
114
|
if (item == Qnil) header[2] = NIL_SORT;
|
91
115
|
else if (item == Qtrue) header[2] = TRUE_SORT;
|
@@ -98,19 +122,22 @@ static VALUE tuple_dump(VALUE self, VALUE tuple) {
|
|
98
122
|
return data;
|
99
123
|
}
|
100
124
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
125
|
+
static VALUE empty_bignum(int sign, int len) {
|
126
|
+
/* Create an empty bignum with the right number of digits. */
|
127
|
+
NEWOBJ(num, struct RBignum);
|
128
|
+
OBJSETUP(num, rb_cBignum, T_BIGNUM);
|
129
|
+
num->sign = sign ? 1 : 0;
|
130
|
+
num->len = len;
|
131
|
+
num->digits = ALLOC_N(BDIGIT, len);
|
132
|
+
|
133
|
+
return (VALUE)num;
|
134
|
+
}
|
135
|
+
|
136
|
+
static VALUE tuple_parse(void **data, int data_len) {
|
109
137
|
VALUE tuple = rb_ary_new();
|
110
138
|
VALUE item;
|
111
|
-
|
112
|
-
void*
|
113
|
-
void* end = ptr + RSTRING_LEN(data);
|
139
|
+
void* ptr = *data; *data = &ptr;
|
140
|
+
void* end = ptr + data_len;
|
114
141
|
int i, len, sign;
|
115
142
|
u_int8_t header[4];
|
116
143
|
u_int32_t digit;
|
@@ -126,58 +153,73 @@ static VALUE tuple_load(VALUE self, VALUE data) {
|
|
126
153
|
case NIL_SORT: rb_ary_push(tuple, Qnil); break;
|
127
154
|
case INTP_SORT:
|
128
155
|
case INTN_SORT:
|
129
|
-
sign
|
130
|
-
|
131
|
-
|
156
|
+
sign = (header[2] == INTP_SORT);
|
157
|
+
len = sign ? header[3] : (UCHAR_MAX - header[3]);
|
158
|
+
|
159
|
+
item = empty_bignum(sign, len);
|
160
|
+
digits = BDIGITS(item);
|
161
|
+
for (i = len-1; i >= 0; i--) {
|
162
|
+
digit = ntohl(*(u_int32_t*)ptr);
|
163
|
+
digits[i] = sign ? digit : UINT_MAX - digit;
|
132
164
|
ptr += 4;
|
133
|
-
rb_ary_push(tuple, INT2NUM(digit));
|
134
|
-
} else {
|
135
|
-
// Create an empty bignum with the right number of digits.
|
136
|
-
NEWOBJ(item, struct RBignum);
|
137
|
-
OBJSETUP(item, rb_cBignum, T_BIGNUM);
|
138
|
-
item->sign = sign ? 1 : 0;
|
139
|
-
item->len = header[3];
|
140
|
-
item->digits = ALLOC_N(BDIGIT, header[3]);
|
141
|
-
|
142
|
-
digits = BDIGITS(item);
|
143
|
-
for (i = header[3]-1; i >= 0; i--) {
|
144
|
-
digit = ntohl(*(u_int32_t*)ptr);
|
145
|
-
digits[i] = sign ? digit : MAX_INT - digit;
|
146
|
-
ptr += 4;
|
147
|
-
}
|
148
|
-
rb_ary_push(tuple, (VALUE)item);
|
149
165
|
}
|
166
|
+
rb_ary_push(tuple, item);
|
150
167
|
break;
|
151
168
|
case STR_SORT:
|
152
169
|
case SYM_SORT:
|
153
170
|
item = rb_str_new2(ptr);
|
154
171
|
len = RSTRING_LEN(item);
|
155
|
-
while (len % 4 != 0) len++;
|
156
|
-
ptr += len;
|
157
172
|
if (header[2] == SYM_SORT) item = rb_funcall(item, rb_intern("to_sym"), 0);
|
158
173
|
rb_ary_push(tuple, item);
|
174
|
+
while (len % 4 != 0) len++; ptr += len;
|
159
175
|
break;
|
160
176
|
case TIME_SORT:
|
161
177
|
item = rb_str_new2(ptr);
|
162
178
|
len = RSTRING_LEN(item);
|
163
|
-
|
164
|
-
|
165
|
-
item = rb_funcall(rb_cTime, rb_intern("parse"), 1, item);
|
179
|
+
if (len == 10) item = rb_funcall(rb_cDate, rb_intern("parse"), 1, item);
|
180
|
+
else item = rb_funcall(rb_cTime, rb_intern("parse"), 1, item);
|
166
181
|
rb_ary_push(tuple, item);
|
182
|
+
while (len % 4 != 0) len++; ptr += len;
|
167
183
|
break;
|
184
|
+
case TUPLE_SORT:
|
185
|
+
item = tuple_parse(&ptr, end - ptr);
|
186
|
+
rb_ary_push(tuple, item);
|
187
|
+
break;
|
188
|
+
case TUPLE_END:
|
189
|
+
return tuple;
|
168
190
|
default:
|
169
191
|
rb_raise(rb_eTypeError, "invalid type code %d in tuple", header[2]);
|
170
192
|
break;
|
171
193
|
}
|
172
|
-
}
|
194
|
+
}
|
173
195
|
return tuple;
|
174
196
|
}
|
175
197
|
|
198
|
+
/*
|
199
|
+
* call-seq:
|
200
|
+
* Tuple.load(string) -> tuple
|
201
|
+
*
|
202
|
+
* Reads in a previously dumped tuple from a string of binary data.
|
203
|
+
*
|
204
|
+
*/
|
205
|
+
static VALUE tuple_load(VALUE self, VALUE data) {
|
206
|
+
data = StringValue(data);
|
207
|
+
void* ptr = RSTRING_PTR(data);
|
208
|
+
return tuple_parse(&ptr, RSTRING_LEN(data));
|
209
|
+
}
|
210
|
+
|
211
|
+
static VALUE array_compare(VALUE self, VALUE other) {
|
212
|
+
rb_funcall(tuple_dump(mTuple, self), rb_intern("<=>"), 1, tuple_dump(mTuple, other));
|
213
|
+
}
|
214
|
+
|
176
215
|
VALUE mTuple;
|
177
216
|
void Init_tuple() {
|
178
217
|
rb_require("time");
|
218
|
+
rb_require("date");
|
219
|
+
rb_cDate = rb_const_get(rb_cObject, rb_intern("Date"));
|
179
220
|
|
180
221
|
mTuple = rb_define_module("Tuple");
|
181
222
|
rb_define_module_function(mTuple, "dump", tuple_dump, 1);
|
182
223
|
rb_define_module_function(mTuple, "load", tuple_load, 1);
|
224
|
+
rb_define_method(rb_cArray, "<=>", array_compare, 1);
|
183
225
|
}
|
data/test/tuple_test.rb
CHANGED
@@ -9,14 +9,15 @@ end
|
|
9
9
|
|
10
10
|
class TupleTest < Test::Unit::TestCase
|
11
11
|
should "dump and load arrays of simple types" do
|
12
|
-
t = [1, true, :foo, "foo", -1001, false, nil, Time.now]
|
12
|
+
t = [1, true, :foo, "foo", -1001, false, nil, Time.now, Date.today - 7, [:foo, 1, 4, nil]]
|
13
13
|
assert_equal t, Tuple.load(Tuple.dump(t))
|
14
14
|
end
|
15
15
|
|
16
|
-
should "dump and
|
17
|
-
t = [2**64, 2**32, 2**32 - 1, 2**31, 2**31 - 1, 1, 0]
|
18
|
-
t = t + t.collect {|n| -n}
|
16
|
+
should "dump, load, and sort fixnums and bignums" do
|
17
|
+
t = [2**64, 2**38, 2**32, 2**32 - 1, 2**31, 2**31 - 1, 1, 0]
|
18
|
+
t = t + t.reverse.collect {|n| -n}
|
19
19
|
assert_equal t, Tuple.load(Tuple.dump(t))
|
20
|
+
assert_equal t.reverse, t.sort_by {|i| Tuple.dump(i)}
|
20
21
|
end
|
21
22
|
|
22
23
|
should "convert single value into array" do
|
@@ -24,7 +25,8 @@ class TupleTest < Test::Unit::TestCase
|
|
24
25
|
end
|
25
26
|
|
26
27
|
should "sort tuples using binary" do
|
27
|
-
now
|
28
|
+
now = Time.now.getgm
|
29
|
+
today = Date.parse(now.to_s)
|
28
30
|
|
29
31
|
tuples = [
|
30
32
|
[1, "foo"],
|
@@ -47,6 +49,9 @@ class TupleTest < Test::Unit::TestCase
|
|
47
49
|
[now, "foo"],
|
48
50
|
[now, "bar"],
|
49
51
|
[now - 24 * 60 * 60],
|
52
|
+
[today + 1],
|
53
|
+
[today - 1],
|
54
|
+
[today],
|
50
55
|
]
|
51
56
|
|
52
57
|
expected = [
|
@@ -66,11 +71,14 @@ class TupleTest < Test::Unit::TestCase
|
|
66
71
|
[:foo, -18446744073709551616],
|
67
72
|
[:foo, -1],
|
68
73
|
[:foo, 18446744073709551616],
|
74
|
+
[today - 1],
|
69
75
|
[now - 24 * 60 * 60],
|
76
|
+
[today],
|
70
77
|
[now, "bar"],
|
71
78
|
[now, "foo"],
|
79
|
+
[today + 1],
|
72
80
|
[true]
|
73
|
-
]
|
81
|
+
]
|
74
82
|
assert_equal expected, tuples.sort_by {|t| Tuple.dump(t)}
|
75
83
|
|
76
84
|
100.times do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ninjudd-tuple
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Balthrop
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-21 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -19,21 +19,22 @@ executables: []
|
|
19
19
|
|
20
20
|
extensions:
|
21
21
|
- ext/extconf.rb
|
22
|
-
extra_rdoc_files:
|
23
|
-
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
24
25
|
files:
|
25
26
|
- README.rdoc
|
26
27
|
- VERSION.yml
|
27
|
-
- ext/tuple.c
|
28
28
|
- ext/extconf.rb
|
29
|
+
- ext/tuple.c
|
29
30
|
- test/test_helper.rb
|
30
31
|
- test/tuple_test.rb
|
31
|
-
|
32
|
+
- LICENSE
|
33
|
+
has_rdoc: false
|
32
34
|
homepage: http://github.com/ninjudd/tuple
|
33
35
|
licenses:
|
34
36
|
post_install_message:
|
35
37
|
rdoc_options:
|
36
|
-
- --inline-source
|
37
38
|
- --charset=UTF-8
|
38
39
|
require_paths:
|
39
40
|
- ext
|
@@ -54,7 +55,8 @@ requirements: []
|
|
54
55
|
rubyforge_project:
|
55
56
|
rubygems_version: 1.3.5
|
56
57
|
signing_key:
|
57
|
-
specification_version:
|
58
|
+
specification_version: 3
|
58
59
|
summary: Tuple serialization functions.
|
59
|
-
test_files:
|
60
|
-
|
60
|
+
test_files:
|
61
|
+
- test/test_helper.rb
|
62
|
+
- test/tuple_test.rb
|