ninjudd-tuple 0.0.7 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|