list 0.0.1 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 264292b03be68afb56aa90769cddbe53f77973a9
4
- data.tar.gz: 64157b4b9936f988264f238c7e77db0cc47bbdae
3
+ metadata.gz: 19c155867c4ea51522fcf35eed15b5a2c0ea1ec5
4
+ data.tar.gz: 896b93da2032c345bc80783aaef475e0079d469d
5
5
  SHA512:
6
- metadata.gz: aae8d581f0359c840d9370d75cacdd31d0a10481353b303371790c94254958acb0ee136cbace00903037df94240cd69fab1c5b2d5f5ac65d93e0c73e0ac9b187
7
- data.tar.gz: 5752f7964479242e99c30d9b474100b70e344e81552eaa3df72820047ba9bc45cc115931aead439e654b0cb2805f982af0834707797da5cee4348676109eb32f
6
+ metadata.gz: 32552315f59851548203a9f24cd11ebf26a69f77e1680060079e117294c35b7a03f901ece9badf8bb3ec2d0a4d45ef542bf910c0eaccfc2e9d1ed4fabc92b4e0
7
+ data.tar.gz: 33bd08bb57fcae3952b2793489cff8ef29c1c9ca594f429fc02d95023d6edd7fc0e826747edbb53d1ecdb5549787cd0276b702de1d8b499ad64d42e78562f59e
data/README.md CHANGED
@@ -4,17 +4,25 @@ List in Ruby.
4
4
 
5
5
  [![Build Status](https://travis-ci.org/ksss/list.png?branch=master)](https://travis-ci.org/ksss/list)
6
6
 
7
+ **List** is a class of wrapped singly-linked list.
8
+
9
+ It's can use same as **Array**. But processing speed is different.
10
+
7
11
  ## Usage
8
12
 
9
13
  All interface is same with Array class.
10
14
 
11
15
  ```ruby
16
+ require 'list'
17
+
12
18
  list = List.new
13
19
  list.push 1,2,3
14
20
  list.pop
15
- list[0,1]
21
+ list[0,1] = 1
16
22
  list.each do |i|
23
+ puts i #=> 1,2
17
24
  end
25
+ puts List[1,2,3].map {|i| i * i}.inject(:+) #=> 14
18
26
  ```
19
27
 
20
28
  +---------+ +->+---------+ +->+---------+
@@ -37,6 +45,20 @@ end
37
45
  | +---------+ +---------+ +---------+ |
38
46
  +-----------------------------------------------+
39
47
 
48
+ ## Feature
49
+
50
+ - List have all same method with Array.
51
+ - **insert** and **delete** is more faster than Array.
52
+ - Can use MRI at version 1.9.3, 2.0.0 and 2.1.0.
53
+
54
+ ## Other API
55
+
56
+ `List#ring`: experimental method for expressing the ring buffer.
57
+
58
+ `Enumeratable#to_list`: all class of included Enumeratable, can convert to List instance
59
+
60
+ `List#to_list`: is for duck typing this.
61
+
40
62
  ## Installation
41
63
 
42
64
  Add this line to your application's Gemfile:
@@ -58,3 +80,11 @@ Or install it yourself as:
58
80
  3. Commit your changes (`git commit -am 'Add some feature'`)
59
81
  4. Push to the branch (`git push origin my-new-feature`)
60
82
  5. Create new Pull Request
83
+
84
+ ## Other
85
+
86
+ [RDoc for Array](http://ruby-doc.org/core-2.1.0/Array.html)
87
+
88
+ [benchmark script result](https://gist.github.com/ksss/8760144)
89
+
90
+ [wikipedia](http://en.wikipedia.org/wiki/Linked_list)
data/ext/list/list.c CHANGED
@@ -1,11 +1,11 @@
1
1
  #include "ruby.h"
2
2
  #include "ruby/encoding.h"
3
3
 
4
- #define LIST_VERSION "0.0.1"
4
+ #define LIST_VERSION "0.1.0"
5
5
 
6
6
  VALUE cList;
7
7
 
8
- ID id_cmp, id_each;
8
+ ID id_cmp, id_each, id_to_list;
9
9
 
10
10
  typedef struct item_t {
11
11
  VALUE value;
@@ -18,6 +18,12 @@ typedef struct {
18
18
  long len;
19
19
  } list_t;
20
20
 
21
+ static VALUE list_push_ary(VALUE, VALUE);
22
+ static VALUE list_push(VALUE, VALUE);
23
+ static VALUE list_unshift(VALUE, VALUE);
24
+ static VALUE list_replace(VALUE, VALUE);
25
+ static VALUE list_length(VALUE);
26
+
21
27
  #define DEBUG 0
22
28
 
23
29
  #define LIST_MAX_SIZE ULONG_MAX
@@ -55,9 +61,35 @@ list_enum_length(VALUE self, VALUE args, VALUE eobj)
55
61
  Data_Get_Struct(self, list_t, ptr);
56
62
  return LONG2NUM(ptr->len);
57
63
  }
64
+ static VALUE
65
+ list_cycle_size(VALUE self, VALUE args, VALUE eobj)
66
+ {
67
+ VALUE n = Qnil;
68
+ list_t *ptr;
69
+ long mul;
70
+
71
+ Data_Get_Struct(self, list_t, ptr);
72
+ if (args && (0 < RARRAY_LEN(args))) {
73
+ n = rb_ary_entry(args, 0);
74
+ }
75
+ if (ptr->len == 0) return INT2FIX(0);
76
+ if (n == Qnil) return DBL2NUM(INFINITY);
77
+ mul = NUM2LONG(n);
78
+ if (mul <= 0) return INT2FIX(0);
79
+ return rb_funcall(list_length(self), '*', 1, LONG2FIX(mul));
80
+ }
81
+ #endif
82
+
83
+ /* from intern.h */
84
+ #ifndef RBASIC_CLEAR_CLASS
85
+ # define RBASIC_CLEAR_CLASS(obj) (((struct RBasicRaw *)((VALUE)(obj)))->klass = 0)
86
+ struct RBasicRaw {
87
+ VALUE flags;
88
+ VALUE klass;
89
+ };
58
90
  #endif
59
91
 
60
- #define LIST_FOR(ptr, c) for (c = ptr->first; c; c = c->next)
92
+ #define LIST_FOR(p, c) for (c = (p)->first; c; c = (c)->next)
61
93
 
62
94
  #define LIST_FOR_DOUBLE(ptr1, c1, ptr2, c2, code) do { \
63
95
  c1 = (ptr1)->first; \
@@ -74,11 +106,6 @@ enum list_take_pos_flags {
74
106
  LIST_TAKE_LAST
75
107
  };
76
108
 
77
- static VALUE list_push_ary(VALUE, VALUE);
78
- static VALUE list_push(VALUE, VALUE);
79
- static VALUE list_unshift(VALUE, VALUE);
80
- static VALUE list_replace(VALUE, VALUE);
81
-
82
109
  #if DEBUG
83
110
  static void
84
111
  p(const char *str)
@@ -156,14 +183,21 @@ ary_to_list(int argc, VALUE *argv, VALUE obj)
156
183
  static VALUE
157
184
  to_list(VALUE obj)
158
185
  {
186
+ VALUE list;
187
+
159
188
  switch (rb_type(obj)) {
160
189
  case T_DATA:
161
190
  return obj;
162
191
  case T_ARRAY:
163
192
  return ary_to_list(0, NULL, obj);
164
193
  default:
165
- return Qnil;
194
+ if (rb_respond_to(obj, id_to_list)) {
195
+ return rb_funcall(obj, id_to_list, 0);
196
+ }
166
197
  }
198
+
199
+ list = list_new();
200
+ return list_push(list, obj);
167
201
  }
168
202
 
169
203
  static inline void
@@ -359,7 +393,8 @@ list_s_create(int argc, VALUE *argv, VALUE klass)
359
393
  static VALUE
360
394
  check_list_type(VALUE obj)
361
395
  {
362
- return to_list(obj);
396
+ if (TYPE(obj) == T_DATA) return obj;
397
+ return rb_check_convert_type(obj, T_DATA, "List", "to_list");
363
398
  }
364
399
 
365
400
  static VALUE
@@ -611,6 +646,15 @@ recursive_equal(VALUE list1, VALUE list2, int recur)
611
646
  return Qtrue;
612
647
  }
613
648
 
649
+ static VALUE
650
+ list_delegate_rb(int argc, VALUE *argv, VALUE list, ID id)
651
+ {
652
+ VALUE ary;
653
+ ary = rb_funcall2(list_to_a(list), id, argc, argv);
654
+ return to_list(ary);
655
+ }
656
+
657
+
614
658
  static VALUE
615
659
  list_equal(VALUE self, VALUE obj)
616
660
  {
@@ -621,7 +665,7 @@ list_equal(VALUE self, VALUE obj)
621
665
  if (rb_type(obj) == T_ARRAY) {
622
666
  return Qfalse;
623
667
  }
624
- if (!rb_respond_to(obj, rb_intern("to_list"))) {
668
+ if (!rb_respond_to(obj, id_to_list)) {
625
669
  return Qfalse;
626
670
  }
627
671
  return rb_equal(obj, self);
@@ -903,15 +947,16 @@ list_aset(int argc, VALUE *argv, VALUE self)
903
947
  long offset, beg, len;
904
948
  list_t *ptr;
905
949
 
906
- list_modify_check(self);
907
950
  Data_Get_Struct(self, list_t, ptr);
908
951
  if (argc == 3) {
952
+ list_modify_check(self);
909
953
  beg = NUM2LONG(argv[0]);
910
954
  len = NUM2LONG(argv[1]);
911
955
  list_splice(self, beg, len, argv[2]);
912
956
  return argv[2];
913
957
  }
914
958
  rb_check_arity(argc, 2, 2);
959
+ list_modify_check(self);
915
960
  if (FIXNUM_P(argv[0])) {
916
961
  offset = FIX2LONG(argv[0]);
917
962
  goto fixnum;
@@ -1137,7 +1182,7 @@ list_unshift_m(int argc, VALUE *argv, VALUE self)
1137
1182
 
1138
1183
  list_modify_check(self);
1139
1184
  if (argc == 0) return self;
1140
- for (i = 0; i < argc; i++) {
1185
+ for (i = argc - 1; 0 <= i; i--) {
1141
1186
  list_unshift(self, argv[i]);
1142
1187
  }
1143
1188
  return self;
@@ -1230,7 +1275,7 @@ static VALUE
1230
1275
  recursive_join(VALUE obj, VALUE argp, int recur)
1231
1276
  {
1232
1277
  VALUE *arg = (VALUE *)argp;
1233
- VALUE ary = arg[0];
1278
+ VALUE list = arg[0];
1234
1279
  VALUE sep = arg[1];
1235
1280
  VALUE result = arg[2];
1236
1281
  int *first = (int *)arg[3];
@@ -1238,7 +1283,7 @@ recursive_join(VALUE obj, VALUE argp, int recur)
1238
1283
  if (recur) {
1239
1284
  rb_raise(rb_eArgError, "recursive list join");
1240
1285
  } else {
1241
- list_join_1(obj, ary, sep, 0, result, first);
1286
+ list_join_1(obj, list, sep, 0, result, first);
1242
1287
  }
1243
1288
  return Qnil;
1244
1289
  }
@@ -1287,9 +1332,10 @@ list_join_1(VALUE obj, VALUE list, VALUE sep, long i, VALUE result, int *first)
1287
1332
  *first = FALSE;
1288
1333
  break;
1289
1334
  case T_ARRAY:
1335
+ val = to_list(val);
1290
1336
  case T_DATA:
1291
1337
  obj = val;
1292
- ary_join:
1338
+ list_join:
1293
1339
  if (val == list) {
1294
1340
  rb_raise(rb_eArgError, "recursive list join");
1295
1341
  }
@@ -1306,11 +1352,11 @@ list_join_1(VALUE obj, VALUE list, VALUE sep, long i, VALUE result, int *first)
1306
1352
  val = tmp;
1307
1353
  goto str_join;
1308
1354
  }
1309
- tmp = rb_check_convert_type(val, T_ARRAY, "Array", "to_ary");
1355
+ tmp = rb_check_convert_type(val, T_DATA, "List", "to_list");
1310
1356
  if (!NIL_P(tmp)) {
1311
1357
  obj = val;
1312
1358
  val = tmp;
1313
- goto ary_join;
1359
+ goto list_join;
1314
1360
  }
1315
1361
  val = rb_obj_as_string(val);
1316
1362
  if (*first) {
@@ -1762,9 +1808,6 @@ list_zip(int argc, VALUE *argv, VALUE self)
1762
1808
  long i;
1763
1809
 
1764
1810
  ary = rb_funcall2(list_to_a(self), rb_intern("zip"), argc, argv);
1765
- for (i = 0; i < RARRAY_LEN(ary); i++) {
1766
- rb_ary_store(ary, i, to_list(rb_ary_entry(ary, i)));
1767
- }
1768
1811
  if (rb_block_given_p()) {
1769
1812
  for (i = 0; i < RARRAY_LEN(ary); i++) {
1770
1813
  rb_yield(rb_ary_entry(ary, i));
@@ -1778,14 +1821,7 @@ list_zip(int argc, VALUE *argv, VALUE self)
1778
1821
  static VALUE
1779
1822
  list_transpose(VALUE self)
1780
1823
  {
1781
- VALUE ary;
1782
- long i;
1783
-
1784
- ary = rb_funcall(list_to_a(self), rb_intern("transpose"), 0);
1785
- for (i = 0; i < RARRAY_LEN(ary); i++) {
1786
- rb_ary_store(ary, i, to_list(rb_ary_entry(ary, i)));
1787
- }
1788
- return to_list(ary);
1824
+ return list_delegate_rb(0, NULL, self, rb_intern("transpose"));
1789
1825
  }
1790
1826
 
1791
1827
  static VALUE
@@ -1955,6 +1991,641 @@ list_slice_bang(int argc, VALUE *argv, VALUE self)
1955
1991
  return list2;
1956
1992
  }
1957
1993
 
1994
+ static VALUE
1995
+ list_assoc(VALUE self, VALUE key)
1996
+ {
1997
+ VALUE v;
1998
+ list_t *ptr;
1999
+ list_t *p;
2000
+ item_t *c;
2001
+
2002
+ if (list_empty_p(self)) return Qnil;
2003
+ Data_Get_Struct(self, list_t, ptr);
2004
+ LIST_FOR(ptr, c) {
2005
+ v = check_list_type(c->value);
2006
+ if (!NIL_P(v)) {
2007
+ Data_Get_Struct(v, list_t, p);
2008
+ if (0 < p->len && rb_equal(list_first(0,NULL,v), key)) {
2009
+ return v;
2010
+ }
2011
+ }
2012
+ }
2013
+ return Qnil;
2014
+ }
2015
+
2016
+ static VALUE
2017
+ list_rassoc(VALUE self, VALUE value)
2018
+ {
2019
+ VALUE v;
2020
+ list_t *ptr;
2021
+ list_t *p;
2022
+ item_t *c;
2023
+
2024
+ if (list_empty_p(self)) return Qnil;
2025
+ Data_Get_Struct(self, list_t, ptr);
2026
+ LIST_FOR(ptr, c) {
2027
+ v = check_list_type(c->value);
2028
+ if (!NIL_P(v)) {
2029
+ Data_Get_Struct(v, list_t, p);
2030
+ if (1 < p->len && rb_equal(list_elt(v,1), value)) {
2031
+ return v;
2032
+ }
2033
+ }
2034
+ }
2035
+ return Qnil;
2036
+ }
2037
+
2038
+ static VALUE
2039
+ list_plus(VALUE x, VALUE y)
2040
+ {
2041
+ list_t *px, *py;
2042
+ item_t *cx, *cy;
2043
+ long len;
2044
+ VALUE result;
2045
+
2046
+ Data_Get_Struct(x, list_t, px);
2047
+ Data_Get_Struct(y, list_t, py);
2048
+ len = px->len + py->len;
2049
+
2050
+ result = list_new();
2051
+ LIST_FOR(px,cx) {
2052
+ list_push(result, cx->value);
2053
+ }
2054
+ LIST_FOR(py,cy) {
2055
+ list_push(result, cy->value);
2056
+ }
2057
+ return result;
2058
+ }
2059
+
2060
+ static VALUE
2061
+ list_times(VALUE self, VALUE times)
2062
+ {
2063
+ VALUE result;
2064
+ VALUE tmp;
2065
+ long i, len;
2066
+ list_t *ptr;
2067
+ item_t *c;
2068
+
2069
+ tmp = rb_check_string_type(times);
2070
+ if (!NIL_P(tmp)) {
2071
+ return list_join(self, tmp);
2072
+ }
2073
+
2074
+ len = NUM2LONG(times);
2075
+ if (len == 0) {
2076
+ return rb_obj_alloc(rb_obj_class(self));
2077
+ }
2078
+ if (len < 0) {
2079
+ rb_raise(rb_eArgError, "negative argument");
2080
+ }
2081
+
2082
+ Data_Get_Struct(self, list_t, ptr);
2083
+ if (LIST_MAX_SIZE / len < ptr->len) {
2084
+ rb_raise(rb_eArgError, "argument too big");
2085
+ }
2086
+
2087
+ result = rb_obj_alloc(rb_obj_class(self));
2088
+ if (0 < ptr->len) {
2089
+ for (i = 0; i < len; i++) {
2090
+ LIST_FOR(ptr, c) {
2091
+ list_push(result, c->value);
2092
+ }
2093
+ }
2094
+ }
2095
+ return result;
2096
+ }
2097
+
2098
+ static inline VALUE
2099
+ list_tmp_hash_new(void)
2100
+ {
2101
+ VALUE hash = rb_hash_new();
2102
+ RBASIC_CLEAR_CLASS(hash);
2103
+ return hash;
2104
+ }
2105
+
2106
+ static VALUE
2107
+ list_add_hash(VALUE hash, VALUE list)
2108
+ {
2109
+ list_t *ptr;
2110
+ item_t *c;
2111
+
2112
+ Data_Get_Struct(list, list_t, ptr);
2113
+ LIST_FOR(ptr, c) {
2114
+ if (rb_hash_lookup2(hash, c->value, Qundef) == Qundef) {
2115
+ rb_hash_aset(hash, c->value, c->value);
2116
+ }
2117
+ }
2118
+ return hash;
2119
+ }
2120
+
2121
+ static VALUE
2122
+ list_make_hash(VALUE list)
2123
+ {
2124
+ VALUE hash = list_tmp_hash_new();
2125
+ return list_add_hash(hash, list);
2126
+ }
2127
+
2128
+ static VALUE
2129
+ list_add_hash_by(VALUE hash, VALUE list)
2130
+ {
2131
+ VALUE v, k;
2132
+ list_t *ptr;
2133
+ item_t *c;
2134
+
2135
+ Data_Get_Struct(list, list_t, ptr);
2136
+ LIST_FOR(ptr, c) {
2137
+ v = c->value;
2138
+ k = rb_yield(v);
2139
+ if (rb_hash_lookup2(hash, k, Qundef) == Qundef) {
2140
+ rb_hash_aset(hash, k, v);
2141
+ }
2142
+ }
2143
+ return hash;
2144
+ }
2145
+
2146
+ static VALUE
2147
+ list_make_hash_by(VALUE list)
2148
+ {
2149
+ VALUE hash = list_tmp_hash_new();
2150
+ return list_add_hash_by(hash, list);
2151
+ }
2152
+
2153
+ static inline void
2154
+ list_recycle_hash(VALUE hash)
2155
+ {
2156
+ if (RHASH(hash)->ntbl) {
2157
+ st_table *tbl = RHASH(hash)->ntbl;
2158
+ RHASH(hash)->ntbl = 0;
2159
+ st_free_table(tbl);
2160
+ }
2161
+ }
2162
+
2163
+ static VALUE
2164
+ list_diff(VALUE list1, VALUE list2)
2165
+ {
2166
+ VALUE list3;
2167
+ volatile VALUE hash;
2168
+ list_t *ptr;
2169
+ item_t *c;
2170
+
2171
+ hash = list_make_hash(to_list(list2));
2172
+ list3 = list_new();
2173
+
2174
+ Data_Get_Struct(list1, list_t, ptr);
2175
+ LIST_FOR(ptr, c) {
2176
+ if (st_lookup(RHASH_TBL(hash), c->value, 0)) continue;
2177
+ list_push(list3, c->value);
2178
+ }
2179
+ list_recycle_hash(hash);
2180
+ return list3;
2181
+ }
2182
+
2183
+ static VALUE
2184
+ list_and(VALUE list1, VALUE list2)
2185
+ {
2186
+ VALUE list3, hash;
2187
+ st_table *table;
2188
+ st_data_t vv;
2189
+ list_t *p1, *p2;
2190
+ item_t *c1;
2191
+
2192
+ list2 = to_list(list2);
2193
+ list3 = list_new();
2194
+ Data_Get_Struct(list2, list_t, p2);
2195
+ if (p2->len == 0) return list3;
2196
+ hash = list_make_hash(list2);
2197
+ table = RHASH_TBL(hash);
2198
+
2199
+ Data_Get_Struct(list1, list_t, p1);
2200
+ LIST_FOR(p1, c1) {
2201
+ vv = (st_data_t) c1->value;
2202
+ if (st_delete(table, &vv, 0)) {
2203
+ list_push(list3, c1->value);
2204
+ }
2205
+ }
2206
+ list_recycle_hash(hash);
2207
+
2208
+ return list3;
2209
+ }
2210
+
2211
+ static int
2212
+ values_i(VALUE key, VALUE value, VALUE list)
2213
+ {
2214
+ list_push(list, value);
2215
+ return ST_CONTINUE;
2216
+ }
2217
+
2218
+ static VALUE
2219
+ list_hash_values(VALUE hash)
2220
+ {
2221
+ VALUE list;
2222
+
2223
+ list = list_new();
2224
+ rb_hash_foreach(hash, values_i, list);
2225
+
2226
+ return list;
2227
+ }
2228
+
2229
+ static VALUE
2230
+ list_or(VALUE list1, VALUE list2)
2231
+ {
2232
+ VALUE hash, list3;
2233
+ st_data_t vv;
2234
+ list_t *p1, *p2;
2235
+ item_t *c1, *c2;
2236
+
2237
+ list2 = to_list(list2);
2238
+ list3 = list_new();
2239
+ hash = list_add_hash(list_make_hash(list1), list2);
2240
+
2241
+ Data_Get_Struct(list1, list_t, p1);
2242
+ Data_Get_Struct(list2, list_t, p2);
2243
+ LIST_FOR(p1,c1) {
2244
+ vv = (st_data_t)c1->value;
2245
+ if (st_delete(RHASH_TBL(hash), &vv, 0)) {
2246
+ list_push(list3, c1->value);
2247
+ }
2248
+ }
2249
+ LIST_FOR(p2,c2) {
2250
+ vv = (st_data_t)c2->value;
2251
+ if (st_delete(RHASH_TBL(hash), &vv, 0)) {
2252
+ list_push(list3, c2->value);
2253
+ }
2254
+ }
2255
+ list_recycle_hash(hash);
2256
+ return list3;
2257
+ }
2258
+
2259
+ static VALUE
2260
+ list_dup(VALUE self)
2261
+ {
2262
+ return list_replace(list_new(), self);
2263
+ }
2264
+
2265
+ static VALUE
2266
+ list_uniq(VALUE self)
2267
+ {
2268
+ VALUE hash, uniq;
2269
+ list_t *ptr;
2270
+
2271
+ Data_Get_Struct(self, list_t, ptr);
2272
+ if (ptr->len <= 1)
2273
+ return list_dup(self);
2274
+
2275
+ if (rb_block_given_p()) {
2276
+ hash = list_make_hash_by(self);
2277
+ } else {
2278
+ hash = list_make_hash(self);
2279
+ }
2280
+ uniq = list_hash_values(hash);
2281
+ list_recycle_hash(hash);
2282
+ return uniq;
2283
+ }
2284
+
2285
+ static VALUE
2286
+ list_uniq_bang(VALUE self)
2287
+ {
2288
+ long len;
2289
+ list_t *ptr;
2290
+
2291
+ list_modify_check(self);
2292
+ Data_Get_Struct(self, list_t, ptr);
2293
+ len = ptr->len;
2294
+ if (len <= 1)
2295
+ return Qnil;
2296
+
2297
+ list_replace(self, list_uniq(self));
2298
+ Data_Get_Struct(self, list_t, ptr);
2299
+ if (len == ptr->len) {
2300
+ return Qnil;
2301
+ }
2302
+
2303
+ return self;
2304
+ }
2305
+
2306
+ static VALUE
2307
+ list_compact_bang(VALUE self)
2308
+ {
2309
+ long len;
2310
+ list_t *ptr;
2311
+
2312
+ list_modify_check(self);
2313
+ Data_Get_Struct(self, list_t, ptr);
2314
+ len = ptr->len;
2315
+ list_delete(self, Qnil);
2316
+ Data_Get_Struct(self, list_t, ptr);
2317
+ if (len == ptr->len) {
2318
+ return Qnil;
2319
+ }
2320
+ return self;
2321
+ }
2322
+
2323
+ static VALUE
2324
+ list_compact(VALUE self)
2325
+ {
2326
+ self = list_dup(self);
2327
+ list_compact_bang(self);
2328
+ return self;
2329
+ }
2330
+
2331
+ static VALUE
2332
+ list_make_shared_copy(VALUE list)
2333
+ {
2334
+ list_t *ptr;
2335
+ Data_Get_Struct(list, list_t, ptr);
2336
+ return list_make_partial(list, rb_obj_class(list), 0, ptr->len);
2337
+ }
2338
+
2339
+ static VALUE
2340
+ flatten(VALUE list, int level, int *modified)
2341
+ {
2342
+ VALUE stack, result;
2343
+ VALUE val;
2344
+ list_t *ptr, *pv;
2345
+ item_t *c;
2346
+
2347
+ *modified = 0;
2348
+ stack = rb_ary_new();
2349
+ result = list_new();
2350
+ Data_Get_Struct(list, list_t, ptr);
2351
+ c = ptr->first;
2352
+ while (1) {
2353
+ while (c) {
2354
+ val = check_list_type(c->value);
2355
+ if (NIL_P(val) || (0 <= level && level <= RARRAY_LEN(stack))) {
2356
+ list_push(result, c->value);
2357
+ c = c->next;
2358
+ } else {
2359
+ *modified = 1;
2360
+ rb_ary_push(stack, (VALUE)c); /* stack address */
2361
+ Data_Get_Struct(val, list_t, pv);
2362
+ c = pv->first;
2363
+ }
2364
+ }
2365
+ if (RARRAY_LEN(stack) == 0) {
2366
+ break;
2367
+ }
2368
+ c = (item_t *)rb_ary_pop(stack); /* pop address */
2369
+ c = c->next;
2370
+ }
2371
+
2372
+ return result;
2373
+ }
2374
+
2375
+ static VALUE
2376
+ list_flatten(int argc, VALUE *argv, VALUE self)
2377
+ {
2378
+ int mod = 0, level = -1;
2379
+ VALUE result, lv;
2380
+
2381
+ rb_scan_args(argc, argv, "01", &lv);
2382
+ if (!NIL_P(lv)) level = NUM2INT(lv);
2383
+ if (level == 0) return list_make_shared_copy(self);
2384
+
2385
+ result = flatten(self, level, &mod);
2386
+ OBJ_INFECT(result, self);
2387
+
2388
+ return result;
2389
+ }
2390
+
2391
+ static VALUE
2392
+ list_flatten_bang(int argc, VALUE *argv, VALUE self)
2393
+ {
2394
+ int mod = 0, level = -1;
2395
+ VALUE result, lv;
2396
+
2397
+ rb_scan_args(argc, argv, "01", &lv);
2398
+ list_modify_check(self);
2399
+ if (!NIL_P(lv)) level = NUM2INT(lv);
2400
+ if (level == 0) return Qnil;
2401
+
2402
+ result = flatten(self, level, &mod);
2403
+ if (mod == 0) {
2404
+ return Qnil;
2405
+ }
2406
+ list_replace(self, result);
2407
+ return self;
2408
+ }
2409
+
2410
+ static VALUE
2411
+ list_count(int argc, VALUE *argv, VALUE self)
2412
+ {
2413
+ VALUE obj;
2414
+ list_t *ptr;
2415
+ item_t *c;
2416
+ long n = 0;
2417
+
2418
+ Data_Get_Struct(self, list_t, ptr);
2419
+ if (argc == 0) {
2420
+ if (!rb_block_given_p()) {
2421
+ return list_length(self);
2422
+ }
2423
+ LIST_FOR(ptr,c) {
2424
+ if (RTEST(rb_yield(c->value))) n++;
2425
+ }
2426
+ } else {
2427
+ rb_scan_args(argc, argv, "1", &obj);
2428
+ if (rb_block_given_p()) {
2429
+ rb_warn("given block not used");
2430
+ }
2431
+ LIST_FOR(ptr,c) {
2432
+ if (rb_equal(c->value, obj)) n++;
2433
+ }
2434
+ }
2435
+ return LONG2NUM(n);
2436
+ }
2437
+
2438
+ static VALUE
2439
+ list_shuffle(int argc, VALUE *argv, VALUE self)
2440
+ {
2441
+ return list_delegate_rb(argc, argv, self, rb_intern("shuffle"));
2442
+ }
2443
+
2444
+ static VALUE
2445
+ list_shuffle_bang(int argc, VALUE *argv, VALUE self)
2446
+ {
2447
+ return list_replace(self, list_shuffle(argc, argv, self));
2448
+ }
2449
+
2450
+ static VALUE
2451
+ list_sample(int argc, VALUE *argv, VALUE self)
2452
+ {
2453
+ return list_delegate_rb(argc, argv, self, rb_intern("sample"));
2454
+ }
2455
+
2456
+ static VALUE
2457
+ list_cycle(int argc, VALUE *argv, VALUE self)
2458
+ {
2459
+ VALUE nv = Qnil;
2460
+ list_t *ptr;
2461
+ item_t *c;
2462
+ long n;
2463
+
2464
+ RETURN_SIZED_ENUMERATOR(self, argc, argv, list_cycle_size);
2465
+ rb_scan_args(argc, argv, "01", &nv);
2466
+
2467
+ if (NIL_P(nv)) {
2468
+ n = -1;
2469
+ } else {
2470
+ n = NUM2LONG(nv);
2471
+ if (n <= 0) return Qnil;
2472
+ }
2473
+
2474
+ Data_Get_Struct(self, list_t, ptr);
2475
+ while (0 < ptr->len && (n < 0 || 0 < n--)) {
2476
+ Data_Get_Struct(self, list_t, ptr);
2477
+ LIST_FOR(ptr, c) {
2478
+ rb_yield(c->value);
2479
+ if (list_empty_p(self)) break;
2480
+ }
2481
+ }
2482
+ return Qnil;
2483
+ }
2484
+
2485
+ static VALUE
2486
+ list_permutation(int argc, VALUE *argv, VALUE self)
2487
+ {
2488
+ return list_delegate_rb(argc, argv, self, rb_intern("permutation"));
2489
+ }
2490
+
2491
+ static VALUE
2492
+ list_combination(VALUE self, VALUE num)
2493
+ {
2494
+ return list_delegate_rb(1, &num, self, rb_intern("combination"));
2495
+ }
2496
+
2497
+ static VALUE
2498
+ list_repeated_permutation(VALUE self, VALUE num)
2499
+ {
2500
+ return list_delegate_rb(1, &num, self, rb_intern("repeated_permutation"));
2501
+ }
2502
+
2503
+ static VALUE
2504
+ list_repeated_combination(VALUE self, VALUE num)
2505
+ {
2506
+ return list_delegate_rb(1, &num, self, rb_intern("repeated_combination"));
2507
+ }
2508
+
2509
+ static VALUE
2510
+ list_product(int argc, VALUE *argv, VALUE self)
2511
+ {
2512
+ return list_delegate_rb(argc, argv, self, rb_intern("product"));
2513
+ }
2514
+
2515
+ static VALUE
2516
+ list_take(VALUE self, VALUE n)
2517
+ {
2518
+ int len = NUM2LONG(n);
2519
+
2520
+ if (len < 0) {
2521
+ rb_raise(rb_eArgError, "attempt to take negative size");
2522
+ }
2523
+ return list_subseq(self, 0, len);
2524
+ }
2525
+
2526
+ static VALUE
2527
+ list_take_while(VALUE self)
2528
+ {
2529
+ list_t *ptr;
2530
+ item_t *c;
2531
+ long i = 0;
2532
+
2533
+ RETURN_ENUMERATOR(self, 0, 0);
2534
+ Data_Get_Struct(self, list_t, ptr);
2535
+ LIST_FOR(ptr, c) {
2536
+ if (!RTEST(rb_yield(c->value))) break;
2537
+ i++;
2538
+ }
2539
+ return list_take(self, LONG2FIX(i));
2540
+ }
2541
+
2542
+ static VALUE
2543
+ list_drop(VALUE self, VALUE n)
2544
+ {
2545
+ list_t *ptr;
2546
+ VALUE result;
2547
+ long pos = NUM2LONG(n);
2548
+
2549
+ if (pos < 0) {
2550
+ rb_raise(rb_eArgError, "attempt to drop negative size");
2551
+ }
2552
+ Data_Get_Struct(self, list_t, ptr);
2553
+ result = list_subseq(self, pos, ptr->len);
2554
+ if (result == Qnil) result = list_new();
2555
+ return result;
2556
+ }
2557
+
2558
+ static VALUE
2559
+ list_drop_while(VALUE self)
2560
+ {
2561
+ long i = 0;
2562
+ list_t *ptr;
2563
+ item_t *c;
2564
+
2565
+ RETURN_ENUMERATOR(self, 0, 0);
2566
+ Data_Get_Struct(self, list_t, ptr);
2567
+ LIST_FOR(ptr, c) {
2568
+ if (!RTEST(rb_yield(c->value))) break;
2569
+ i++;
2570
+ }
2571
+ return list_drop(self, LONG2FIX(i));
2572
+ }
2573
+
2574
+ /**
2575
+ * from CRuby rb_ary_bsearch
2576
+ */
2577
+ static VALUE
2578
+ list_bsearch(VALUE self)
2579
+ {
2580
+ long low, high, mid;
2581
+ int smaller = 0, satisfied = 0;
2582
+ VALUE v, val, ary;
2583
+
2584
+ ary = list_to_a(self);
2585
+ low = 0;
2586
+ high = RARRAY_LEN(ary);
2587
+
2588
+ RETURN_ENUMERATOR(self, 0, 0);
2589
+ while (low < high) {
2590
+ mid = low + ((high - low) / 2);
2591
+ val = rb_ary_entry(ary, mid);
2592
+ v = rb_yield(val);
2593
+ if (FIXNUM_P(v)) {
2594
+ if (FIX2INT(v) == 0) return val;
2595
+ smaller = FIX2INT(v) < 0;
2596
+ }
2597
+ else if (v == Qtrue) {
2598
+ satisfied = 1;
2599
+ smaller = 1;
2600
+ }
2601
+ else if (v == Qfalse || v == Qnil) {
2602
+ smaller = 0;
2603
+ }
2604
+ else if (rb_obj_is_kind_of(v, rb_cNumeric)) {
2605
+ const VALUE zero = INT2FIX(0);
2606
+ switch (rb_cmpint(rb_funcall(v, id_cmp, 1, zero), v, INT2FIX(0))) {
2607
+ case 0: return val;
2608
+ case 1: smaller = 1; break;
2609
+ case -1: smaller = 0;
2610
+ }
2611
+ }
2612
+ else {
2613
+ rb_raise(rb_eTypeError, "wrong argument type %s"
2614
+ " (must be numeric, true, false or nil)",
2615
+ rb_obj_classname(v));
2616
+ }
2617
+ if (smaller) {
2618
+ high = mid;
2619
+ }
2620
+ else {
2621
+ low = mid + 1;
2622
+ }
2623
+ }
2624
+ if (low == RARRAY_LEN(ary)) return Qnil;
2625
+ if (!satisfied) return Qnil;
2626
+ return rb_ary_entry(ary, low);
2627
+ }
2628
+
1958
2629
  static VALUE
1959
2630
  list_ring_bang(VALUE self)
1960
2631
  {
@@ -2070,6 +2741,38 @@ Init_list(void)
2070
2741
  rb_define_method(cList, "slice", list_aref, -1);
2071
2742
  rb_define_method(cList, "slice!", list_slice_bang, -1);
2072
2743
 
2744
+ rb_define_method(cList, "assoc", list_assoc, 1);
2745
+ rb_define_method(cList, "rassoc", list_rassoc, 1);
2746
+
2747
+ rb_define_method(cList, "+", list_plus, 1);
2748
+ rb_define_method(cList, "*", list_times, 1);
2749
+ rb_define_method(cList, "-", list_diff, 1);
2750
+ rb_define_method(cList, "&", list_and, 1);
2751
+ rb_define_method(cList, "|", list_or, 1);
2752
+
2753
+ rb_define_method(cList, "uniq", list_uniq, 0);
2754
+ rb_define_method(cList, "uniq!", list_uniq_bang, 0);
2755
+ rb_define_method(cList, "compact", list_compact, 0);
2756
+ rb_define_method(cList, "compact!", list_compact_bang, 0);
2757
+ rb_define_method(cList, "flatten", list_flatten, -1);
2758
+ rb_define_method(cList, "flatten!", list_flatten_bang, -1);
2759
+ rb_define_method(cList, "count", list_count, -1);
2760
+ rb_define_method(cList, "shuffle", list_shuffle, -1);
2761
+ rb_define_method(cList, "shuffle!", list_shuffle_bang, -1);
2762
+ rb_define_method(cList, "sample", list_sample, -1);
2763
+ rb_define_method(cList, "cycle", list_cycle, -1);
2764
+ rb_define_method(cList, "permutation", list_permutation, -1);
2765
+ rb_define_method(cList, "combination", list_combination, 1);
2766
+ rb_define_method(cList, "repeated_permutation", list_repeated_permutation, 1);
2767
+ rb_define_method(cList, "repeated_combination", list_repeated_combination, 1);
2768
+ rb_define_method(cList, "product", list_product, -1);
2769
+
2770
+ rb_define_method(cList, "take", list_take, 1);
2771
+ rb_define_method(cList, "take_while", list_take_while, 0);
2772
+ rb_define_method(cList, "drop", list_drop, 1);
2773
+ rb_define_method(cList, "drop_while", list_drop_while, 0);
2774
+ rb_define_method(cList, "bsearch", list_bsearch, 0);
2775
+
2073
2776
  rb_define_method(cList, "ring", list_ring, 0);
2074
2777
  rb_define_method(cList, "ring!", list_ring_bang, 0);
2075
2778
  rb_define_method(cList, "ring?", list_ring_p, 0);
@@ -2081,4 +2784,5 @@ Init_list(void)
2081
2784
 
2082
2785
  id_cmp = rb_intern("<=>");
2083
2786
  id_each = rb_intern("each");
2787
+ id_to_list = rb_intern("to_list");
2084
2788
  }