list 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }