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 +4 -4
- data/README.md +31 -1
- data/ext/list/list.c +733 -29
- data/list.gemspec +1 -1
- data/spec/bench.rb +5 -4
- data/spec/list_spec.rb +806 -259
- data/spec/mem_spec.rb +2 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19c155867c4ea51522fcf35eed15b5a2c0ea1ec5
|
4
|
+
data.tar.gz: 896b93da2032c345bc80783aaef475e0079d469d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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(
|
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
|
-
|
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
|
-
|
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,
|
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 =
|
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
|
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,
|
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
|
-
|
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,
|
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
|
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
|
-
|
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
|
}
|