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 +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
|
[](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
|
}
|