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.
Files changed (5) hide show
  1. data/LICENSE +20 -0
  2. data/VERSION.yml +2 -2
  3. data/ext/tuple.c +92 -50
  4. data/test/tuple_test.rb +14 -6
  5. 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
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 0
3
- :patch: 7
4
2
  :major: 0
3
+ :minor: 0
4
+ :patch: 10
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
- sign = (digit >= 0);
50
- header[2] = (sign ? INTP_SORT : INTN_SORT);
51
- header[3] = 0;
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
- digit = htonl(FIX2INT(item) + (sign ? 0 : MAX_INT));
55
- rb_str_cat(data, (char*)&digit, sizeof(digit));
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] = RBIGNUM(item)->len;
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 = header[3]-1; j >= 0; j--) {
64
- digit = htonl(sign ? digits[j] : (MAX_INT - 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
- item = rb_funcall(item, rb_intern("getgm"), 0);
84
- item = rb_funcall(item, rb_intern("strftime"), 1, rb_str_new2("%Y/%m/%d %H:%M:%S +0000"));
85
- len = RSTRING_LEN(item);
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
- * call-seq:
103
- * Tuple.load(string) -> tuple
104
- *
105
- * Reads in a previously dumped tuple from a string of binary data.
106
- *
107
- */
108
- static VALUE tuple_load(VALUE self, VALUE data) {
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
- data = StringValue(data);
112
- void* ptr = RSTRING_PTR(data);
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 = (header[2] == INTP_SORT);
130
- if (header[3] == 0) {
131
- digit = ntohl(*(u_int32_t*)ptr) - (sign ? 0 : MAX_INT);
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
- while (len % 4 != 0) len++;
164
- ptr += len;
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 load fixnums and bignums" do
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 = Time.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.7
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-08-22 00:00:00 -07:00
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
- has_rdoc: true
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: 2
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