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.
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