yard 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of yard might be problematic. Click here for more details.
- data/ChangeLog +585 -1
- data/README.md +10 -2
- data/benchmarks/yri_cache.rb +19 -0
- data/bin/yri +1 -26
- data/docs/WhatsNew.md +99 -0
- data/lib/rubygems_plugin.rb +2 -0
- data/lib/yard.rb +2 -2
- data/lib/yard/autoload.rb +9 -4
- data/lib/yard/cli/base.rb +26 -0
- data/lib/yard/cli/yard_graph.rb +2 -9
- data/lib/yard/cli/yardoc.rb +93 -33
- data/lib/yard/cli/yri.rb +128 -0
- data/lib/yard/code_objects/base.rb +16 -5
- data/lib/yard/code_objects/class_object.rb +11 -4
- data/lib/yard/code_objects/method_object.rb +11 -1
- data/lib/yard/code_objects/proxy.rb +5 -2
- data/lib/yard/code_objects/root_object.rb +1 -0
- data/lib/yard/core_ext/file.rb +1 -1
- data/lib/yard/core_ext/hash.rb +15 -0
- data/lib/yard/core_ext/module.rb +2 -2
- data/lib/yard/core_ext/string.rb +66 -0
- data/lib/yard/core_ext/symbol_hash.rb +1 -1
- data/lib/yard/docstring.rb +5 -5
- data/lib/yard/handlers/base.rb +10 -4
- data/lib/yard/handlers/processor.rb +3 -4
- data/lib/yard/handlers/ruby/attribute_handler.rb +3 -2
- data/lib/yard/handlers/ruby/legacy/attribute_handler.rb +2 -2
- data/lib/yard/handlers/ruby/legacy/method_handler.rb +7 -1
- data/lib/yard/handlers/ruby/method_handler.rb +7 -1
- data/lib/yard/logging.rb +11 -1
- data/lib/yard/parser/c_parser.rb +407 -0
- data/lib/yard/parser/ruby/ast_node.rb +2 -2
- data/lib/yard/parser/ruby/legacy/ruby_lex.rb +3 -4
- data/lib/yard/parser/source_parser.rb +18 -7
- data/lib/yard/rake/yardoc_task.rb +1 -1
- data/lib/yard/registry.rb +83 -29
- data/lib/yard/registry_store.rb +213 -0
- data/lib/yard/serializers/base.rb +1 -1
- data/lib/yard/serializers/yardoc_serializer.rb +113 -0
- data/lib/yard/tags/library.rb +4 -0
- data/lib/yard/tags/overload_tag.rb +16 -5
- data/lib/yard/tags/tag.rb +1 -2
- data/lib/yard/templates/engine.rb +3 -3
- data/lib/yard/templates/helpers/html_helper.rb +50 -16
- data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +1 -3
- data/lib/yard/templates/helpers/html_syntax_highlight_helper18.rb +1 -3
- data/lib/yard/templates/helpers/method_helper.rb +11 -4
- data/lib/yard/templates/helpers/text_helper.rb +24 -2
- data/lib/yard/verifier.rb +3 -3
- data/spec/cli/yardoc_spec.rb +33 -6
- data/spec/cli/yri_spec.rb +30 -0
- data/spec/code_objects/base_spec.rb +7 -0
- data/spec/code_objects/class_object_spec.rb +6 -1
- data/spec/code_objects/method_object_spec.rb +25 -0
- data/spec/core_ext/hash_spec.rb +10 -0
- data/spec/core_ext/module_spec.rb +1 -1
- data/spec/core_ext/string_spec.rb +50 -12
- data/spec/handlers/attribute_handler_spec.rb +4 -0
- data/spec/handlers/examples/method_handler_001.rb.txt +9 -0
- data/spec/handlers/method_handler_spec.rb +22 -4
- data/spec/parser/c_parser_spec.rb +22 -0
- data/spec/parser/examples/array.c.txt +3887 -0
- data/spec/parser/source_parser_spec.rb +29 -7
- data/spec/registry_spec.rb +93 -72
- data/spec/registry_store_spec.rb +184 -0
- data/spec/serializers/file_system_serializer_spec.rb +96 -75
- data/spec/spec_helper.rb +2 -2
- data/spec/tags/overload_tag_spec.rb +18 -0
- data/spec/templates/examples/class001.html +32 -30
- data/spec/templates/examples/method001.html +4 -1
- data/spec/templates/examples/method002.html +7 -2
- data/spec/templates/examples/method002.txt +1 -1
- data/spec/templates/examples/method003.html +30 -8
- data/spec/templates/examples/method003.txt +4 -4
- data/spec/templates/examples/method004.html +44 -0
- data/spec/templates/examples/method004.txt +10 -0
- data/spec/templates/examples/method005.html +99 -0
- data/spec/templates/examples/method005.txt +33 -0
- data/spec/templates/examples/module001.dot +1 -1
- data/spec/templates/examples/module001.html +391 -37
- data/spec/templates/examples/module001.txt +1 -1
- data/spec/templates/helpers/base_helper_spec.rb +2 -2
- data/spec/templates/helpers/html_helper_spec.rb +83 -0
- data/spec/templates/helpers/method_helper_spec.rb +47 -0
- data/spec/templates/helpers/shared_signature_examples.rb +102 -0
- data/spec/templates/helpers/text_helper_spec.rb +31 -0
- data/spec/templates/method_spec.rb +43 -18
- data/spec/templates/module_spec.rb +22 -1
- data/spec/templates/spec_helper.rb +10 -1
- data/spec/yard_spec.rb +4 -3
- data/templates/default/class/html/constructor_details.erb +1 -1
- data/templates/default/docstring/html/returns_void.erb +1 -0
- data/templates/default/docstring/setup.rb +9 -4
- data/templates/default/docstring/text/returns_void.erb +1 -0
- data/templates/default/fulldoc/html/css/style.css +4 -2
- data/templates/default/fulldoc/html/full_list.erb +2 -2
- data/templates/default/fulldoc/html/js/app.js +1 -1
- data/templates/default/fulldoc/html/setup.rb +14 -6
- data/templates/default/layout/dot/setup.rb +1 -1
- data/templates/default/layout/html/breadcrumb.erb +2 -2
- data/templates/default/layout/html/index.erb +2 -2
- data/templates/default/layout/html/setup.rb +5 -5
- data/templates/default/method/html/header.erb +6 -4
- data/templates/default/method_details/html/method_signature.erb +2 -1
- data/templates/default/method_details/html/source.erb +1 -1
- data/templates/default/method_details/setup.rb +2 -1
- data/templates/default/method_details/text/setup.rb +1 -1
- data/templates/default/module/html/attribute_details.erb +4 -4
- data/templates/default/module/html/attribute_summary.erb +3 -3
- data/templates/default/module/html/box_info.erb +2 -2
- data/templates/default/module/html/defines.erb +1 -1
- data/templates/default/module/html/inherited_constants.erb +1 -1
- data/templates/default/module/html/inherited_methods.erb +1 -1
- data/templates/default/module/html/item_summary.erb +13 -4
- data/templates/default/module/html/method_details_list.erb +5 -4
- data/templates/default/module/html/method_summary.erb +5 -4
- data/templates/default/module/html/methodmissing.erb +1 -1
- data/templates/default/module/setup.rb +14 -5
- data/templates/default/tags/html/overload.erb +3 -2
- data/templates/default/tags/setup.rb +4 -0
- metadata +23 -2
data/spec/cli/yardoc_spec.rb
CHANGED
@@ -6,19 +6,19 @@ describe YARD::CLI::Yardoc do
|
|
6
6
|
before do
|
7
7
|
@yardoc = YARD::CLI::Yardoc.new
|
8
8
|
@yardoc.stub!(:generate).and_return(false)
|
9
|
-
|
9
|
+
YARD.stub!(:parse)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "should accept --title" do
|
13
13
|
@yardoc.optparse('--title', 'hello world')
|
14
|
-
@yardoc.options[:title].should ==
|
14
|
+
@yardoc.options[:title].should == 'hello world'
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should alias --main to the --readme flag" do
|
18
18
|
readme = File.join(File.dirname(__FILE__),'..','..','README.md')
|
19
19
|
|
20
20
|
@yardoc.optparse('--main', readme)
|
21
|
-
@yardoc.options[:readme].should == readme
|
21
|
+
@yardoc.options[:readme].should == readme
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should select a markup provider when --markup-provider or -mp is set" do
|
@@ -36,6 +36,23 @@ describe YARD::CLI::Yardoc do
|
|
36
36
|
@yardoc.options[:serializer].options[:basepath].should == :MYPATH
|
37
37
|
@yardoc.files.should == ["FILE1", "FILE2"]
|
38
38
|
end
|
39
|
+
|
40
|
+
it "should use String#shell_split to split .yardopts tokens" do
|
41
|
+
optsdata = "foo bar"
|
42
|
+
optsdata.should_receive(:shell_split)
|
43
|
+
IO.should_receive(:read).with("test").and_return(optsdata)
|
44
|
+
@yardoc.stub!(:support_rdoc_document_file!).and_return([])
|
45
|
+
@yardoc.options_file = "test"
|
46
|
+
@yardoc.run
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should allow --title to have multiple spaces in .yardopts" do
|
50
|
+
IO.should_receive(:read).with("test").and_return("--title \"Foo Bar\"")
|
51
|
+
@yardoc.stub!(:support_rdoc_document_file!).and_return([])
|
52
|
+
@yardoc.options_file = "test"
|
53
|
+
@yardoc.run
|
54
|
+
@yardoc.options[:title].should == "Foo Bar"
|
55
|
+
end
|
39
56
|
|
40
57
|
it "should allow opts specified in command line to override yardopts file" do
|
41
58
|
IO.should_receive(:read).with(".yardopts").and_return("-o NOTMYPATH")
|
@@ -63,7 +80,7 @@ describe YARD::CLI::Yardoc do
|
|
63
80
|
|
64
81
|
it "should accept files section only containing extra files" do
|
65
82
|
@yardoc.optparse *%w( - LICENSE )
|
66
|
-
@yardoc.files.should == %w( lib/**/*.rb )
|
83
|
+
@yardoc.files.should == %w( lib/**/*.rb ext/**/*.c )
|
67
84
|
@yardoc.options[:files].should == %w( LICENSE )
|
68
85
|
end
|
69
86
|
|
@@ -77,9 +94,9 @@ describe YARD::CLI::Yardoc do
|
|
77
94
|
@yardoc.options[:files].should == %w( a.txt b.txt )
|
78
95
|
end
|
79
96
|
|
80
|
-
it "should accept no params and parse lib/**/*.rb" do
|
97
|
+
it "should accept no params and parse lib/**/*.rb ext/**/*.c" do
|
81
98
|
@yardoc.optparse
|
82
|
-
@yardoc.files.should == %w( lib/**/*.rb )
|
99
|
+
@yardoc.files.should == %w( lib/**/*.rb ext/**/*.c )
|
83
100
|
end
|
84
101
|
|
85
102
|
it "should accept a --query" do
|
@@ -102,4 +119,14 @@ describe YARD::CLI::Yardoc do
|
|
102
119
|
@yardoc.optparse *%w( --no-private )
|
103
120
|
@yardoc.options[:verifier].call(obj).should == false
|
104
121
|
end
|
122
|
+
|
123
|
+
it "should accept --default-return" do
|
124
|
+
@yardoc.optparse *%w( --default-return XYZ )
|
125
|
+
@yardoc.options[:default_return].should == "XYZ"
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should allow --hide-void-return to be set" do
|
129
|
+
@yardoc.optparse *%w( --hide-void-return )
|
130
|
+
@yardoc.options[:hide_void_return].should be_true
|
131
|
+
end
|
105
132
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
class YARD::CLI::YRI
|
4
|
+
public :optparse, :find_object, :cache_object
|
5
|
+
end
|
6
|
+
|
7
|
+
describe YARD::CLI::Yardoc do
|
8
|
+
before do
|
9
|
+
@yri = YARD::CLI::YRI.new
|
10
|
+
Registry.instance.stub!(:load)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#find_object' do
|
14
|
+
it "should use cache if available" do
|
15
|
+
@yri.stub!(:cache_object)
|
16
|
+
Registry.should_receive(:load).with('bar.yardoc')
|
17
|
+
Registry.should_receive(:at).with('Foo').and_return('OBJ')
|
18
|
+
@yri.instance_variable_set("@cache", {'Foo' => 'bar.yardoc'})
|
19
|
+
@yri.find_object('Foo').should == 'OBJ'
|
20
|
+
@yri.instance_variable_get("@search_paths")[0].should == 'bar.yardoc'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#cache_object' do
|
25
|
+
it "should skip caching for Registry.yardoc_file" do
|
26
|
+
File.should_not_receive(:open).with(CLI::YRI::CACHE_FILE, 'w')
|
27
|
+
@yri.cache_object('Foo', Registry.yardoc_file)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -212,4 +212,11 @@ describe YARD::CodeObjects::Base do
|
|
212
212
|
object.format :x => 1
|
213
213
|
end
|
214
214
|
end
|
215
|
+
|
216
|
+
describe '#source_type' do
|
217
|
+
it "should default source_type to :ruby" do
|
218
|
+
object = MethodObject.new(:root, :method)
|
219
|
+
object.source_type.should == :ruby
|
220
|
+
end
|
221
|
+
end
|
215
222
|
end
|
@@ -150,8 +150,13 @@ describe YARD::CodeObjects::ClassObject do
|
|
150
150
|
consts.should_not include(P("YARD::CONST4"))
|
151
151
|
end
|
152
152
|
|
153
|
-
it "should not set a superclass on
|
153
|
+
it "should not set a superclass on BasicObject class" do
|
154
154
|
o = ClassObject.new(:root, :Object)
|
155
|
+
o.superclass.should == P(:BasicObject)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should set superclass of Object to BasicObject" do
|
159
|
+
o = ClassObject.new(:root, :BasicObject)
|
155
160
|
o.superclass.should be_nil
|
156
161
|
end
|
157
162
|
|
@@ -55,4 +55,29 @@ describe YARD::CodeObjects::MethodObject do
|
|
55
55
|
obj.name(true).should == "something"
|
56
56
|
end
|
57
57
|
end
|
58
|
+
|
59
|
+
describe '#is_attribute?' do
|
60
|
+
it "should only return true if attribute is set in namespace for read/write" do
|
61
|
+
obj = MethodObject.new(@yard, :foo)
|
62
|
+
@yard.attributes[:instance][:foo] = {:read => obj, :write => nil}
|
63
|
+
obj.is_attribute?.should be_true
|
64
|
+
MethodObject.new(@yard, :foo=).is_attribute?.should be_false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#constructor?' do
|
69
|
+
before { @class = ClassObject.new(:root, :MyClass) }
|
70
|
+
|
71
|
+
it "should mark the #initialize method as constructor" do
|
72
|
+
MethodObject.new(@class, :initialize)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should not mark Klass.initialize as constructor" do
|
76
|
+
MethodObject.new(@class, :initialize, :class).constructor?.should be_false
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should not mark module method #initialize as constructor" do
|
80
|
+
MethodObject.new(@yard, :initialize).constructor?.should be_false
|
81
|
+
end
|
82
|
+
end
|
58
83
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Hash do
|
4
|
+
describe '.[]' do
|
5
|
+
it "should accept an Array argument (Ruby 1.8.6 and older)" do
|
6
|
+
list = [['foo', 'bar'], ['foo2', 'bar2']]
|
7
|
+
Hash[list].should == {'foo' => 'bar', 'foo2' => 'bar2'}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -9,7 +9,7 @@ describe Module do
|
|
9
9
|
|
10
10
|
describe '#namespace' do
|
11
11
|
it "should return everything before the class name" do
|
12
|
-
YARD::CodeObjects::Base.
|
12
|
+
YARD::CodeObjects::Base.namespace_name.should == "YARD::CodeObjects"
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -3,22 +3,60 @@ require File.dirname(__FILE__) + '/../spec_helper'
|
|
3
3
|
#described_in_docs String, '#camelcase'
|
4
4
|
#described_in_docs String, '#underscore'
|
5
5
|
|
6
|
-
describe String
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
describe String do
|
7
|
+
describe '#underscore' do
|
8
|
+
it 'should turn HelloWorld into hello_world' do
|
9
|
+
"HelloWorld".underscore.should == "hello_world"
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
it "should turn Hello::World into hello/world" do
|
13
|
+
"Hello::World".underscore.should == "hello/world"
|
14
|
+
end
|
13
15
|
end
|
14
|
-
end
|
15
16
|
|
16
|
-
describe
|
17
|
-
|
18
|
-
|
17
|
+
describe '#camelcase' do
|
18
|
+
it 'should turn hello_world into HelloWorld' do
|
19
|
+
"hello_world".camelcase.should == "HelloWorld"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should turn hello/world into Hello::World" do
|
23
|
+
"Hello::World".underscore.should == "hello/world"
|
24
|
+
end
|
19
25
|
end
|
26
|
+
|
27
|
+
describe '#shell_split' do
|
28
|
+
it "should split simple non-quoted text" do
|
29
|
+
"a b c".shell_split.should == %w(a b c)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should split double quoted text into single token" do
|
33
|
+
'a "b c d" e'.shell_split.should == ["a", "b c d", "e"]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should split single quoted text into single token" do
|
37
|
+
"a 'b c d' e".shell_split.should == ["a", "b c d", "e"]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should handle escaped quotations in quotes" do
|
41
|
+
"'a \\' b'".shell_split.should == ["a ' b"]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should handle escaped quotations outside quotes" do
|
45
|
+
"\\'a 'b'".shell_split.should == %w('a b)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should handle escaped backslash" do
|
49
|
+
"\\\\'a b c'".shell_split.should == ['\a b c']
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should handle any whitespace as space" do
|
53
|
+
text = "foo\tbar\nbaz\r\nfoo2 bar2"
|
54
|
+
text.shell_split.should == %w(foo bar baz foo2 bar2)
|
55
|
+
end
|
20
56
|
|
21
|
-
|
22
|
-
|
57
|
+
it "should handle complex input" do
|
58
|
+
text = "hello \\\"world \"1 2\\\" 3\" a 'b \"\\\\\\'' c"
|
59
|
+
text.shell_split.should == ["hello", "\"world", "1 2\" 3", "a", "b \"\\'", "c"]
|
60
|
+
end
|
23
61
|
end
|
24
62
|
end
|
@@ -75,4 +75,8 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}AttributeHandler" do
|
|
75
75
|
meth.is_explicit?.should == false
|
76
76
|
end
|
77
77
|
end
|
78
|
+
|
79
|
+
it "should handle attr call with no arguments" do
|
80
|
+
lambda { StubbedSourceParser.parse_string "attr" }.should_not raise_error
|
81
|
+
end
|
78
82
|
end
|
@@ -54,17 +54,17 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}MethodHandler" do
|
|
54
54
|
meth = P('Foo#foo')
|
55
55
|
|
56
56
|
o1 = meth.tags(:overload).first
|
57
|
-
o1.name.should == :
|
57
|
+
o1.name.should == :bar
|
58
58
|
o1.parameters.should == [[:a, nil], [:b, "1"]]
|
59
59
|
o1.tag(:return).type.should == "String"
|
60
60
|
|
61
61
|
o2 = meth.tags(:overload)[1]
|
62
|
-
o2.name.should == :
|
62
|
+
o2.name.should == :baz
|
63
63
|
o2.parameters.should == [[:b, nil], [:c, nil]]
|
64
64
|
o2.tag(:return).type.should == "Fixnum"
|
65
65
|
|
66
66
|
o3 = meth.tags(:overload)[2]
|
67
|
-
o3.name.should == :
|
67
|
+
o3.name.should == :bang
|
68
68
|
o3.parameters.should == [[:d, nil], [:e, nil]]
|
69
69
|
o3.docstring.should be_empty
|
70
70
|
o3.docstring.should be_blank
|
@@ -75,7 +75,7 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}MethodHandler" do
|
|
75
75
|
|
76
76
|
meth.should have_tag(:return)
|
77
77
|
meth.tag(:return).types.should == ["Foo"]
|
78
|
-
meth.tag(:return).text.should == "a new instance of
|
78
|
+
meth.tag(:return).text.should == "a new instance of Foo"
|
79
79
|
end
|
80
80
|
|
81
81
|
%w(inherited included method_added method_removed method_undefined).each do |meth|
|
@@ -87,4 +87,22 @@ describe "YARD::Handlers::Ruby::#{RUBY18 ? "Legacy::" : ""}MethodHandler" do
|
|
87
87
|
it "should not set @private tag on extended callback method since docstring is set" do
|
88
88
|
P('Foo.extended').should_not have_tag(:private)
|
89
89
|
end
|
90
|
+
|
91
|
+
it "should add @return [Boolean] tag to methods ending in ? without return types" do
|
92
|
+
meth = P('Foo#boolean?')
|
93
|
+
meth.should have_tag(:return)
|
94
|
+
meth.tag(:return).types.should == ['Boolean']
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should add Boolean type to return tag without types" do
|
98
|
+
meth = P('Foo#boolean2?')
|
99
|
+
meth.should have_tag(:return)
|
100
|
+
meth.tag(:return).types.should == ['Boolean']
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should not change return type for method ending in ? with return types set" do
|
104
|
+
meth = P('Foo#boolean3?')
|
105
|
+
meth.should have_tag(:return)
|
106
|
+
meth.tag(:return).types.should == ['NotBoolean', 'nil']
|
107
|
+
end
|
90
108
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe YARD::Parser::CParser do
|
4
|
+
before(:all) do
|
5
|
+
file = File.join(File.dirname(__FILE__), 'examples', 'array.c.txt')
|
6
|
+
@parser = Parser::CParser.new(IO.read(file)).parse
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#parse' do
|
10
|
+
it "should parse Array class" do
|
11
|
+
obj = YARD::Registry.at('Array')
|
12
|
+
obj.should_not be_nil
|
13
|
+
obj.docstring.should_not be_blank
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should parse method" do
|
17
|
+
obj = YARD::Registry.at('Array#initialize')
|
18
|
+
obj.docstring.should_not be_blank
|
19
|
+
obj.tags(:overload).size.should > 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,3887 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
|
3
|
+
array.c -
|
4
|
+
|
5
|
+
$Author: yugui $
|
6
|
+
created at: Fri Aug 6 09:46:12 JST 1993
|
7
|
+
|
8
|
+
Copyright (C) 1993-2007 Yukihiro Matsumoto
|
9
|
+
Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
10
|
+
Copyright (C) 2000 Information-technology Promotion Agency, Japan
|
11
|
+
|
12
|
+
**********************************************************************/
|
13
|
+
|
14
|
+
#include "ruby/ruby.h"
|
15
|
+
#include "ruby/util.h"
|
16
|
+
#include "ruby/st.h"
|
17
|
+
|
18
|
+
#ifndef ARRAY_DEBUG
|
19
|
+
# define NDEBUG
|
20
|
+
#endif
|
21
|
+
#include <assert.h>
|
22
|
+
|
23
|
+
VALUE rb_cArray;
|
24
|
+
|
25
|
+
static ID id_cmp;
|
26
|
+
|
27
|
+
#define ARY_DEFAULT_SIZE 16
|
28
|
+
#define ARY_MAX_SIZE (LONG_MAX / sizeof(VALUE))
|
29
|
+
|
30
|
+
void
|
31
|
+
rb_mem_clear(register VALUE *mem, register long size)
|
32
|
+
{
|
33
|
+
while (size--) {
|
34
|
+
*mem++ = Qnil;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
static inline void
|
39
|
+
memfill(register VALUE *mem, register long size, register VALUE val)
|
40
|
+
{
|
41
|
+
while (size--) {
|
42
|
+
*mem++ = val;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
# define ARY_SHARED_P(ary) \
|
47
|
+
(assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \
|
48
|
+
FL_TEST(ary,ELTS_SHARED))
|
49
|
+
# define ARY_EMBED_P(ary) \
|
50
|
+
(assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \
|
51
|
+
FL_TEST(ary, RARRAY_EMBED_FLAG))
|
52
|
+
|
53
|
+
#define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr)
|
54
|
+
#define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len)
|
55
|
+
#define ARY_EMBED_PTR(a) (assert(ARY_EMBED_P(a)), RARRAY(a)->as.ary)
|
56
|
+
#define ARY_EMBED_LEN(a) \
|
57
|
+
(assert(ARY_EMBED_P(a)), \
|
58
|
+
(long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \
|
59
|
+
(RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT)))
|
60
|
+
|
61
|
+
#define ARY_OWNS_HEAP_P(a) (!FL_TEST(a, ELTS_SHARED|RARRAY_EMBED_FLAG))
|
62
|
+
#define FL_SET_EMBED(a) do { \
|
63
|
+
assert(!ARY_SHARED_P(a)); \
|
64
|
+
assert(!OBJ_FROZEN(a)); \
|
65
|
+
FL_SET(a, RARRAY_EMBED_FLAG); \
|
66
|
+
} while (0)
|
67
|
+
#define FL_UNSET_EMBED(ary) FL_UNSET(ary, RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK)
|
68
|
+
#define FL_SET_SHARED(ary) do { \
|
69
|
+
assert(!ARY_EMBED_P(ary)); \
|
70
|
+
FL_SET(ary, ELTS_SHARED); \
|
71
|
+
} while (0)
|
72
|
+
#define FL_UNSET_SHARED(ary) FL_UNSET(ary, ELTS_SHARED)
|
73
|
+
|
74
|
+
#define ARY_SET_PTR(ary, p) do { \
|
75
|
+
assert(!ARY_EMBED_P(ary)); \
|
76
|
+
assert(!OBJ_FROZEN(ary)); \
|
77
|
+
RARRAY(ary)->as.heap.ptr = (p); \
|
78
|
+
} while (0)
|
79
|
+
#define ARY_SET_EMBED_LEN(ary, n) do { \
|
80
|
+
long tmp_n = n; \
|
81
|
+
assert(ARY_EMBED_P(ary)); \
|
82
|
+
assert(!OBJ_FROZEN(ary)); \
|
83
|
+
RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \
|
84
|
+
RBASIC(ary)->flags |= (tmp_n) << RARRAY_EMBED_LEN_SHIFT; \
|
85
|
+
} while (0)
|
86
|
+
#define ARY_SET_HEAP_LEN(ary, n) do { \
|
87
|
+
assert(!ARY_EMBED_P(ary)); \
|
88
|
+
RARRAY(ary)->as.heap.len = n; \
|
89
|
+
} while (0)
|
90
|
+
#define ARY_SET_LEN(ary, n) do { \
|
91
|
+
if (ARY_EMBED_P(ary)) { \
|
92
|
+
ARY_SET_EMBED_LEN(ary, n); \
|
93
|
+
} \
|
94
|
+
else { \
|
95
|
+
ARY_SET_HEAP_LEN(ary, n); \
|
96
|
+
} \
|
97
|
+
assert(RARRAY_LEN(ary) == n); \
|
98
|
+
} while (0)
|
99
|
+
#define ARY_INCREASE_PTR(ary, n) do { \
|
100
|
+
assert(!ARY_EMBED_P(ary)); \
|
101
|
+
assert(!OBJ_FROZEN(ary)); \
|
102
|
+
RARRAY(ary)->as.heap.ptr += n; \
|
103
|
+
} while (0)
|
104
|
+
#define ARY_INCREASE_LEN(ary, n) do { \
|
105
|
+
assert(!OBJ_FROZEN(ary)); \
|
106
|
+
if (ARY_EMBED_P(ary)) { \
|
107
|
+
ARY_SET_EMBED_LEN(ary, RARRAY_LEN(ary)+n); \
|
108
|
+
} \
|
109
|
+
else { \
|
110
|
+
RARRAY(ary)->as.heap.len += n; \
|
111
|
+
} \
|
112
|
+
} while (0)
|
113
|
+
|
114
|
+
#define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? RARRAY_EMBED_LEN_MAX : \
|
115
|
+
ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : RARRAY(ary)->as.heap.aux.capa)
|
116
|
+
#define ARY_SET_CAPA(ary, n) do { \
|
117
|
+
assert(!ARY_EMBED_P(ary)); \
|
118
|
+
assert(!ARY_SHARED_P(ary)); \
|
119
|
+
assert(!OBJ_FROZEN(ary)); \
|
120
|
+
RARRAY(ary)->as.heap.aux.capa = (n); \
|
121
|
+
} while (0)
|
122
|
+
|
123
|
+
#define ARY_SHARED(ary) (assert(ARY_SHARED_P(ary)), RARRAY(ary)->as.heap.aux.shared)
|
124
|
+
#define ARY_SET_SHARED(ary, value) do { \
|
125
|
+
assert(!ARY_EMBED_P(ary)); \
|
126
|
+
assert(ARY_SHARED_P(ary)); \
|
127
|
+
assert(ARY_SHARED_ROOT_P(value)); \
|
128
|
+
RARRAY(ary)->as.heap.aux.shared = (value); \
|
129
|
+
} while (0)
|
130
|
+
#define RARRAY_SHARED_ROOT_FLAG FL_USER5
|
131
|
+
#define ARY_SHARED_ROOT_P(ary) (FL_TEST(ary, RARRAY_SHARED_ROOT_FLAG))
|
132
|
+
#define ARY_SHARED_NUM(ary) \
|
133
|
+
(assert(ARY_SHARED_ROOT_P(ary)), RARRAY(ary)->as.heap.aux.capa)
|
134
|
+
#define ARY_SET_SHARED_NUM(ary, value) do { \
|
135
|
+
assert(ARY_SHARED_ROOT_P(ary)); \
|
136
|
+
RARRAY(ary)->as.heap.aux.capa = (value); \
|
137
|
+
} while (0)
|
138
|
+
#define FL_SET_SHARED_ROOT(ary) do { \
|
139
|
+
assert(!ARY_EMBED_P(ary)); \
|
140
|
+
FL_SET(ary, RARRAY_SHARED_ROOT_FLAG); \
|
141
|
+
} while (0)
|
142
|
+
|
143
|
+
static void
|
144
|
+
ary_resize_capa(VALUE ary, long capacity)
|
145
|
+
{
|
146
|
+
assert(RARRAY_LEN(ary) <= capacity);
|
147
|
+
assert(!OBJ_FROZEN(ary));
|
148
|
+
assert(!ARY_SHARED_P(ary));
|
149
|
+
if (capacity > RARRAY_EMBED_LEN_MAX) {
|
150
|
+
if (ARY_EMBED_P(ary)) {
|
151
|
+
long len = ARY_EMBED_LEN(ary);
|
152
|
+
VALUE *ptr = ALLOC_N(VALUE, (capacity));
|
153
|
+
MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len);
|
154
|
+
FL_UNSET_EMBED(ary);
|
155
|
+
ARY_SET_PTR(ary, ptr);
|
156
|
+
ARY_SET_HEAP_LEN(ary, len);
|
157
|
+
}
|
158
|
+
else {
|
159
|
+
REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, (capacity));
|
160
|
+
}
|
161
|
+
ARY_SET_CAPA(ary, (capacity));
|
162
|
+
}
|
163
|
+
else {
|
164
|
+
if (!ARY_EMBED_P(ary)) {
|
165
|
+
long len = RARRAY_LEN(ary);
|
166
|
+
VALUE *ptr = RARRAY_PTR(ary);
|
167
|
+
MEMCPY(RARRAY(ary)->as.ary, ptr, VALUE, len);
|
168
|
+
FL_SET_EMBED(ary);
|
169
|
+
ARY_SET_LEN(ary, len);
|
170
|
+
xfree(ptr);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
static void
|
176
|
+
rb_ary_decrement_share(VALUE shared)
|
177
|
+
{
|
178
|
+
if (shared) {
|
179
|
+
int num = ARY_SHARED_NUM(shared) - 1;
|
180
|
+
if (num == 0) {
|
181
|
+
rb_ary_free(shared);
|
182
|
+
rb_gc_force_recycle(shared);
|
183
|
+
}
|
184
|
+
else if (num > 0) {
|
185
|
+
ARY_SET_SHARED_NUM(shared, num);
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
static void
|
191
|
+
rb_ary_unshare(VALUE ary)
|
192
|
+
{
|
193
|
+
VALUE shared = RARRAY(ary)->as.heap.aux.shared;
|
194
|
+
rb_ary_decrement_share(shared);
|
195
|
+
FL_UNSET_SHARED(ary);
|
196
|
+
}
|
197
|
+
|
198
|
+
static inline void
|
199
|
+
rb_ary_unshare_safe(VALUE ary) {
|
200
|
+
if (ARY_SHARED_P(ary) && !ARY_EMBED_P(ary)) {
|
201
|
+
rb_ary_unshare(ary);
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
static VALUE
|
206
|
+
rb_ary_increment_share(VALUE shared) {
|
207
|
+
int num = ARY_SHARED_NUM(shared);
|
208
|
+
if (num >= 0) {
|
209
|
+
ARY_SET_SHARED_NUM(shared, num + 1);
|
210
|
+
}
|
211
|
+
return shared;
|
212
|
+
}
|
213
|
+
|
214
|
+
static void
|
215
|
+
rb_ary_set_shared(VALUE ary, VALUE shared)
|
216
|
+
{
|
217
|
+
rb_ary_increment_share(shared);
|
218
|
+
FL_SET_SHARED(ary);
|
219
|
+
ARY_SET_SHARED(ary, shared);
|
220
|
+
}
|
221
|
+
|
222
|
+
static inline void
|
223
|
+
rb_ary_modify_check(VALUE ary)
|
224
|
+
{
|
225
|
+
if (OBJ_FROZEN(ary)) rb_error_frozen("array");
|
226
|
+
if (!OBJ_UNTRUSTED(ary) && rb_safe_level() >= 4)
|
227
|
+
rb_raise(rb_eSecurityError, "Insecure: can't modify array");
|
228
|
+
}
|
229
|
+
|
230
|
+
static void
|
231
|
+
rb_ary_modify(VALUE ary)
|
232
|
+
{
|
233
|
+
rb_ary_modify_check(ary);
|
234
|
+
if (ARY_SHARED_P(ary)) {
|
235
|
+
long len = RARRAY_LEN(ary);
|
236
|
+
if (len <= RARRAY_EMBED_LEN_MAX) {
|
237
|
+
VALUE *ptr = ARY_HEAP_PTR(ary);
|
238
|
+
VALUE shared = ARY_SHARED(ary);
|
239
|
+
FL_UNSET_SHARED(ary);
|
240
|
+
FL_SET_EMBED(ary);
|
241
|
+
MEMCPY(ARY_EMBED_PTR(ary), ptr, VALUE, len);
|
242
|
+
rb_ary_decrement_share(shared);
|
243
|
+
ARY_SET_EMBED_LEN(ary, len);
|
244
|
+
}
|
245
|
+
else {
|
246
|
+
VALUE *ptr = ALLOC_N(VALUE, len);
|
247
|
+
MEMCPY(ptr, RARRAY_PTR(ary), VALUE, len);
|
248
|
+
rb_ary_unshare(ary);
|
249
|
+
ARY_SET_CAPA(ary, len);
|
250
|
+
ARY_SET_PTR(ary, ptr);
|
251
|
+
}
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
VALUE
|
256
|
+
rb_ary_freeze(VALUE ary)
|
257
|
+
{
|
258
|
+
return rb_obj_freeze(ary);
|
259
|
+
}
|
260
|
+
|
261
|
+
/*
|
262
|
+
* call-seq:
|
263
|
+
* array.frozen? -> true or false
|
264
|
+
*
|
265
|
+
* Return <code>true</code> if this array is frozen (or temporarily frozen
|
266
|
+
* while being sorted).
|
267
|
+
*/
|
268
|
+
|
269
|
+
static VALUE
|
270
|
+
rb_ary_frozen_p(VALUE ary)
|
271
|
+
{
|
272
|
+
if (OBJ_FROZEN(ary)) return Qtrue;
|
273
|
+
return Qfalse;
|
274
|
+
}
|
275
|
+
|
276
|
+
static VALUE
|
277
|
+
ary_alloc(VALUE klass)
|
278
|
+
{
|
279
|
+
NEWOBJ(ary, struct RArray);
|
280
|
+
OBJSETUP(ary, klass, T_ARRAY);
|
281
|
+
FL_SET_EMBED((VALUE)ary);
|
282
|
+
ARY_SET_EMBED_LEN((VALUE)ary, 0);
|
283
|
+
|
284
|
+
return (VALUE)ary;
|
285
|
+
}
|
286
|
+
|
287
|
+
static VALUE
|
288
|
+
ary_new(VALUE klass, long len)
|
289
|
+
{
|
290
|
+
VALUE ary;
|
291
|
+
|
292
|
+
if (len < 0) {
|
293
|
+
rb_raise(rb_eArgError, "negative array size (or size too big)");
|
294
|
+
}
|
295
|
+
if (len > ARY_MAX_SIZE) {
|
296
|
+
rb_raise(rb_eArgError, "array size too big");
|
297
|
+
}
|
298
|
+
ary = ary_alloc(klass);
|
299
|
+
if (len > RARRAY_EMBED_LEN_MAX) {
|
300
|
+
FL_UNSET_EMBED(ary);
|
301
|
+
ARY_SET_PTR(ary, ALLOC_N(VALUE, len));
|
302
|
+
ARY_SET_CAPA(ary, len);
|
303
|
+
ARY_SET_HEAP_LEN(ary, 0);
|
304
|
+
}
|
305
|
+
|
306
|
+
return ary;
|
307
|
+
}
|
308
|
+
|
309
|
+
VALUE
|
310
|
+
rb_ary_new2(long len)
|
311
|
+
{
|
312
|
+
return ary_new(rb_cArray, len);
|
313
|
+
}
|
314
|
+
|
315
|
+
|
316
|
+
VALUE
|
317
|
+
rb_ary_new(void)
|
318
|
+
{
|
319
|
+
return rb_ary_new2(RARRAY_EMBED_LEN_MAX);
|
320
|
+
}
|
321
|
+
|
322
|
+
#include <stdarg.h>
|
323
|
+
|
324
|
+
VALUE
|
325
|
+
rb_ary_new3(long n, ...)
|
326
|
+
{
|
327
|
+
va_list ar;
|
328
|
+
VALUE ary;
|
329
|
+
long i;
|
330
|
+
|
331
|
+
ary = rb_ary_new2(n);
|
332
|
+
|
333
|
+
va_start(ar, n);
|
334
|
+
for (i=0; i<n; i++) {
|
335
|
+
RARRAY_PTR(ary)[i] = va_arg(ar, VALUE);
|
336
|
+
}
|
337
|
+
va_end(ar);
|
338
|
+
|
339
|
+
ARY_SET_LEN(ary, n);
|
340
|
+
return ary;
|
341
|
+
}
|
342
|
+
|
343
|
+
VALUE
|
344
|
+
rb_ary_new4(long n, const VALUE *elts)
|
345
|
+
{
|
346
|
+
VALUE ary;
|
347
|
+
|
348
|
+
ary = rb_ary_new2(n);
|
349
|
+
if (n > 0 && elts) {
|
350
|
+
MEMCPY(RARRAY_PTR(ary), elts, VALUE, n);
|
351
|
+
ARY_SET_LEN(ary, n);
|
352
|
+
}
|
353
|
+
|
354
|
+
return ary;
|
355
|
+
}
|
356
|
+
|
357
|
+
VALUE
|
358
|
+
rb_ary_tmp_new(long len)
|
359
|
+
{
|
360
|
+
return ary_new(0, len);
|
361
|
+
}
|
362
|
+
|
363
|
+
void
|
364
|
+
rb_ary_free(VALUE ary)
|
365
|
+
{
|
366
|
+
if (ARY_OWNS_HEAP_P(ary)) {
|
367
|
+
xfree(RARRAY_PTR(ary));
|
368
|
+
}
|
369
|
+
}
|
370
|
+
|
371
|
+
static VALUE
|
372
|
+
ary_make_shared(VALUE ary)
|
373
|
+
{
|
374
|
+
assert(!ARY_EMBED_P(ary));
|
375
|
+
if (ARY_SHARED_P(ary)) {
|
376
|
+
return ARY_SHARED(ary);
|
377
|
+
}
|
378
|
+
else {
|
379
|
+
NEWOBJ(shared, struct RArray);
|
380
|
+
OBJSETUP(shared, 0, T_ARRAY);
|
381
|
+
FL_UNSET_EMBED(shared);
|
382
|
+
|
383
|
+
ARY_SET_LEN((VALUE)shared, RARRAY_LEN(ary));
|
384
|
+
ARY_SET_PTR((VALUE)shared, RARRAY_PTR(ary));
|
385
|
+
FL_SET_SHARED_ROOT(shared);
|
386
|
+
ARY_SET_SHARED_NUM((VALUE)shared, 1);
|
387
|
+
FL_SET_SHARED(ary);
|
388
|
+
ARY_SET_SHARED(ary, (VALUE)shared);
|
389
|
+
OBJ_FREEZE(shared);
|
390
|
+
return (VALUE)shared;
|
391
|
+
}
|
392
|
+
}
|
393
|
+
|
394
|
+
|
395
|
+
static VALUE
|
396
|
+
ary_make_substitution(VALUE ary)
|
397
|
+
{
|
398
|
+
if (RARRAY_LEN(ary) <= RARRAY_EMBED_LEN_MAX) {
|
399
|
+
VALUE subst = rb_ary_new2(RARRAY_LEN(ary));
|
400
|
+
MEMCPY(ARY_EMBED_PTR(subst), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
|
401
|
+
ARY_SET_EMBED_LEN(subst, RARRAY_LEN(ary));
|
402
|
+
return subst;
|
403
|
+
}
|
404
|
+
else {
|
405
|
+
return rb_ary_increment_share(ary_make_shared(ary));
|
406
|
+
}
|
407
|
+
}
|
408
|
+
|
409
|
+
VALUE
|
410
|
+
rb_assoc_new(VALUE car, VALUE cdr)
|
411
|
+
{
|
412
|
+
return rb_ary_new3(2, car, cdr);
|
413
|
+
}
|
414
|
+
|
415
|
+
static VALUE
|
416
|
+
to_ary(VALUE ary)
|
417
|
+
{
|
418
|
+
return rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
|
419
|
+
}
|
420
|
+
|
421
|
+
VALUE
|
422
|
+
rb_check_array_type(VALUE ary)
|
423
|
+
{
|
424
|
+
return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary");
|
425
|
+
}
|
426
|
+
|
427
|
+
/*
|
428
|
+
* call-seq:
|
429
|
+
* Array.try_convert(obj) -> array or nil
|
430
|
+
*
|
431
|
+
* Try to convert <i>obj</i> into an array, using to_ary method.
|
432
|
+
* Returns converted array or nil if <i>obj</i> cannot be converted
|
433
|
+
* for any reason. This method is to check if an argument is an
|
434
|
+
* array.
|
435
|
+
*
|
436
|
+
* Array.try_convert([1]) # => [1]
|
437
|
+
* Array.try_convert("1") # => nil
|
438
|
+
*
|
439
|
+
* if tmp = Array.try_convert(arg)
|
440
|
+
* # the argument is an array
|
441
|
+
* elsif tmp = String.try_convert(arg)
|
442
|
+
* # the argument is a string
|
443
|
+
* end
|
444
|
+
*
|
445
|
+
*/
|
446
|
+
|
447
|
+
static VALUE
|
448
|
+
rb_ary_s_try_convert(VALUE dummy, VALUE ary)
|
449
|
+
{
|
450
|
+
return rb_check_array_type(ary);
|
451
|
+
}
|
452
|
+
|
453
|
+
/*
|
454
|
+
* call-seq:
|
455
|
+
* Array.new(size=0, obj=nil)
|
456
|
+
* Array.new(array)
|
457
|
+
* Array.new(size) {|index| block }
|
458
|
+
*
|
459
|
+
* Returns a new array. In the first form, the new array is
|
460
|
+
* empty. In the second it is created with _size_ copies of _obj_
|
461
|
+
* (that is, _size_ references to the same
|
462
|
+
* _obj_). The third form creates a copy of the array
|
463
|
+
* passed as a parameter (the array is generated by calling
|
464
|
+
* to_ary on the parameter). In the last form, an array
|
465
|
+
* of the given size is created. Each element in this array is
|
466
|
+
* calculated by passing the element's index to the given block and
|
467
|
+
* storing the return value.
|
468
|
+
*
|
469
|
+
* Array.new
|
470
|
+
* Array.new(2)
|
471
|
+
* Array.new(5, "A")
|
472
|
+
*
|
473
|
+
* # only one copy of the object is created
|
474
|
+
* a = Array.new(2, Hash.new)
|
475
|
+
* a[0]['cat'] = 'feline'
|
476
|
+
* a
|
477
|
+
* a[1]['cat'] = 'Felix'
|
478
|
+
* a
|
479
|
+
*
|
480
|
+
* # here multiple copies are created
|
481
|
+
* a = Array.new(2) { Hash.new }
|
482
|
+
* a[0]['cat'] = 'feline'
|
483
|
+
* a
|
484
|
+
*
|
485
|
+
* squares = Array.new(5) {|i| i*i}
|
486
|
+
* squares
|
487
|
+
*
|
488
|
+
* copy = Array.new(squares)
|
489
|
+
*/
|
490
|
+
|
491
|
+
static VALUE
|
492
|
+
rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
|
493
|
+
{
|
494
|
+
long len;
|
495
|
+
VALUE size, val;
|
496
|
+
|
497
|
+
rb_ary_modify(ary);
|
498
|
+
if (argc == 0) {
|
499
|
+
if (ARY_OWNS_HEAP_P(ary) && RARRAY_PTR(ary)) {
|
500
|
+
xfree(RARRAY_PTR(ary));
|
501
|
+
}
|
502
|
+
rb_ary_unshare_safe(ary);
|
503
|
+
FL_SET_EMBED(ary);
|
504
|
+
ARY_SET_EMBED_LEN(ary, 0);
|
505
|
+
if (rb_block_given_p()) {
|
506
|
+
rb_warning("given block not used");
|
507
|
+
}
|
508
|
+
return ary;
|
509
|
+
}
|
510
|
+
rb_scan_args(argc, argv, "02", &size, &val);
|
511
|
+
if (argc == 1 && !FIXNUM_P(size)) {
|
512
|
+
val = rb_check_array_type(size);
|
513
|
+
if (!NIL_P(val)) {
|
514
|
+
rb_ary_replace(ary, val);
|
515
|
+
return ary;
|
516
|
+
}
|
517
|
+
}
|
518
|
+
|
519
|
+
len = NUM2LONG(size);
|
520
|
+
if (len < 0) {
|
521
|
+
rb_raise(rb_eArgError, "negative array size");
|
522
|
+
}
|
523
|
+
if (len > ARY_MAX_SIZE) {
|
524
|
+
rb_raise(rb_eArgError, "array size too big");
|
525
|
+
}
|
526
|
+
rb_ary_modify(ary);
|
527
|
+
ary_resize_capa(ary, len);
|
528
|
+
if (rb_block_given_p()) {
|
529
|
+
long i;
|
530
|
+
|
531
|
+
if (argc == 2) {
|
532
|
+
rb_warn("block supersedes default value argument");
|
533
|
+
}
|
534
|
+
for (i=0; i<len; i++) {
|
535
|
+
rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
|
536
|
+
ARY_SET_LEN(ary, i + 1);
|
537
|
+
}
|
538
|
+
}
|
539
|
+
else {
|
540
|
+
memfill(RARRAY_PTR(ary), len, val);
|
541
|
+
ARY_SET_LEN(ary, len);
|
542
|
+
}
|
543
|
+
return ary;
|
544
|
+
}
|
545
|
+
|
546
|
+
|
547
|
+
/*
|
548
|
+
* Returns a new array populated with the given objects.
|
549
|
+
*
|
550
|
+
* Array.[]( 1, 'a', /^A/ )
|
551
|
+
* Array[ 1, 'a', /^A/ ]
|
552
|
+
* [ 1, 'a', /^A/ ]
|
553
|
+
*/
|
554
|
+
|
555
|
+
static VALUE
|
556
|
+
rb_ary_s_create(int argc, VALUE *argv, VALUE klass)
|
557
|
+
{
|
558
|
+
VALUE ary = ary_new(klass, argc);
|
559
|
+
if (argc > 0 && argv) {
|
560
|
+
MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
|
561
|
+
ARY_SET_LEN(ary, argc);
|
562
|
+
}
|
563
|
+
|
564
|
+
return ary;
|
565
|
+
}
|
566
|
+
|
567
|
+
void
|
568
|
+
rb_ary_store(VALUE ary, long idx, VALUE val)
|
569
|
+
{
|
570
|
+
if (idx < 0) {
|
571
|
+
idx += RARRAY_LEN(ary);
|
572
|
+
if (idx < 0) {
|
573
|
+
rb_raise(rb_eIndexError, "index %ld out of array",
|
574
|
+
idx - RARRAY_LEN(ary));
|
575
|
+
}
|
576
|
+
}
|
577
|
+
else if (idx >= ARY_MAX_SIZE) {
|
578
|
+
rb_raise(rb_eIndexError, "index %ld too big", idx);
|
579
|
+
}
|
580
|
+
|
581
|
+
rb_ary_modify(ary);
|
582
|
+
if (idx >= ARY_CAPA(ary)) {
|
583
|
+
long new_capa = ARY_CAPA(ary) / 2;
|
584
|
+
|
585
|
+
if (new_capa < ARY_DEFAULT_SIZE) {
|
586
|
+
new_capa = ARY_DEFAULT_SIZE;
|
587
|
+
}
|
588
|
+
if (new_capa >= ARY_MAX_SIZE - idx) {
|
589
|
+
new_capa = (ARY_MAX_SIZE - idx) / 2;
|
590
|
+
}
|
591
|
+
new_capa += idx;
|
592
|
+
ary_resize_capa(ary, new_capa);
|
593
|
+
}
|
594
|
+
if (idx > RARRAY_LEN(ary)) {
|
595
|
+
rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary),
|
596
|
+
idx-RARRAY_LEN(ary) + 1);
|
597
|
+
}
|
598
|
+
|
599
|
+
if (idx >= RARRAY_LEN(ary)) {
|
600
|
+
ARY_SET_LEN(ary, idx + 1);
|
601
|
+
}
|
602
|
+
RARRAY_PTR(ary)[idx] = val;
|
603
|
+
}
|
604
|
+
|
605
|
+
static VALUE
|
606
|
+
ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
|
607
|
+
{
|
608
|
+
assert(offset >= 0);
|
609
|
+
assert(len >= 0);
|
610
|
+
assert(offset+len <= RARRAY_LEN(ary));
|
611
|
+
|
612
|
+
if (len <= RARRAY_EMBED_LEN_MAX) {
|
613
|
+
VALUE result = ary_alloc(klass);
|
614
|
+
MEMCPY(ARY_EMBED_PTR(result), RARRAY_PTR(ary) + offset, VALUE, len);
|
615
|
+
ARY_SET_EMBED_LEN(result, len);
|
616
|
+
return result;
|
617
|
+
}
|
618
|
+
else {
|
619
|
+
VALUE shared, result = ary_alloc(klass);
|
620
|
+
FL_UNSET_EMBED(result);
|
621
|
+
|
622
|
+
shared = ary_make_shared(ary);
|
623
|
+
ARY_SET_PTR(result, RARRAY_PTR(ary));
|
624
|
+
ARY_SET_LEN(result, RARRAY_LEN(ary));
|
625
|
+
rb_ary_set_shared(result, shared);
|
626
|
+
|
627
|
+
ARY_INCREASE_PTR(result, offset);
|
628
|
+
ARY_SET_LEN(result, len);
|
629
|
+
return result;
|
630
|
+
}
|
631
|
+
}
|
632
|
+
|
633
|
+
static VALUE
|
634
|
+
ary_make_shared_copy(VALUE ary)
|
635
|
+
{
|
636
|
+
return ary_make_partial(ary, rb_obj_class(ary), 0, RARRAY_LEN(ary));
|
637
|
+
}
|
638
|
+
|
639
|
+
enum ary_take_pos_flags
|
640
|
+
{
|
641
|
+
ARY_TAKE_FIRST = 0,
|
642
|
+
ARY_TAKE_LAST = 1
|
643
|
+
};
|
644
|
+
|
645
|
+
static VALUE
|
646
|
+
ary_take_first_or_last(int argc, VALUE *argv, VALUE ary, enum ary_take_pos_flags last)
|
647
|
+
{
|
648
|
+
VALUE nv;
|
649
|
+
long n;
|
650
|
+
long offset = 0;
|
651
|
+
|
652
|
+
rb_scan_args(argc, argv, "1", &nv);
|
653
|
+
n = NUM2LONG(nv);
|
654
|
+
if (n > RARRAY_LEN(ary)) {
|
655
|
+
n = RARRAY_LEN(ary);
|
656
|
+
}
|
657
|
+
else if (n < 0) {
|
658
|
+
rb_raise(rb_eArgError, "negative array size");
|
659
|
+
}
|
660
|
+
if (last) {
|
661
|
+
offset = RARRAY_LEN(ary) - n;
|
662
|
+
}
|
663
|
+
return ary_make_partial(ary, rb_cArray, offset, n);
|
664
|
+
}
|
665
|
+
|
666
|
+
/*
|
667
|
+
* call-seq:
|
668
|
+
* array << obj -> array
|
669
|
+
*
|
670
|
+
* Append---Pushes the given object on to the end of this array. This
|
671
|
+
* expression returns the array itself, so several appends
|
672
|
+
* may be chained together.
|
673
|
+
*
|
674
|
+
* [ 1, 2 ] << "c" << "d" << [ 3, 4 ]
|
675
|
+
* #=> [ 1, 2, "c", "d", [ 3, 4 ] ]
|
676
|
+
*
|
677
|
+
*/
|
678
|
+
|
679
|
+
VALUE
|
680
|
+
rb_ary_push(VALUE ary, VALUE item)
|
681
|
+
{
|
682
|
+
rb_ary_store(ary, RARRAY_LEN(ary), item);
|
683
|
+
return ary;
|
684
|
+
}
|
685
|
+
|
686
|
+
/*
|
687
|
+
* call-seq:
|
688
|
+
* array.push(obj, ... ) -> array
|
689
|
+
*
|
690
|
+
* Append---Pushes the given object(s) on to the end of this array. This
|
691
|
+
* expression returns the array itself, so several appends
|
692
|
+
* may be chained together.
|
693
|
+
*
|
694
|
+
* a = [ "a", "b", "c" ]
|
695
|
+
* a.push("d", "e", "f")
|
696
|
+
* #=> ["a", "b", "c", "d", "e", "f"]
|
697
|
+
*/
|
698
|
+
|
699
|
+
static VALUE
|
700
|
+
rb_ary_push_m(int argc, VALUE *argv, VALUE ary)
|
701
|
+
{
|
702
|
+
rb_ary_modify_check(ary);
|
703
|
+
while (argc--) {
|
704
|
+
rb_ary_push(ary, *argv++);
|
705
|
+
}
|
706
|
+
return ary;
|
707
|
+
}
|
708
|
+
|
709
|
+
VALUE
|
710
|
+
rb_ary_pop(VALUE ary)
|
711
|
+
{
|
712
|
+
long n;
|
713
|
+
rb_ary_modify_check(ary);
|
714
|
+
if (RARRAY_LEN(ary) == 0) return Qnil;
|
715
|
+
if (ARY_OWNS_HEAP_P(ary) &&
|
716
|
+
RARRAY_LEN(ary) * 3 < ARY_CAPA(ary) &&
|
717
|
+
ARY_CAPA(ary) > ARY_DEFAULT_SIZE)
|
718
|
+
{
|
719
|
+
ary_resize_capa(ary, RARRAY_LEN(ary) * 2);
|
720
|
+
}
|
721
|
+
n = RARRAY_LEN(ary)-1;
|
722
|
+
ARY_SET_LEN(ary, n);
|
723
|
+
return RARRAY_PTR(ary)[n];
|
724
|
+
}
|
725
|
+
|
726
|
+
/*
|
727
|
+
* call-seq:
|
728
|
+
* array.pop -> obj or nil
|
729
|
+
* array.pop(n) -> array
|
730
|
+
*
|
731
|
+
* Removes the last element from <i>self</i> and returns it, or
|
732
|
+
* <code>nil</code> if the array is empty.
|
733
|
+
*
|
734
|
+
* If a number _n_ is given, returns an array of the last n elements
|
735
|
+
* (or less) just like <code>array.slice!(-n, n)</code> does.
|
736
|
+
*
|
737
|
+
* a = [ "a", "b", "c", "d" ]
|
738
|
+
* a.pop #=> "d"
|
739
|
+
* a.pop(2) #=> ["b", "c"]
|
740
|
+
* a #=> ["a"]
|
741
|
+
*/
|
742
|
+
|
743
|
+
static VALUE
|
744
|
+
rb_ary_pop_m(int argc, VALUE *argv, VALUE ary)
|
745
|
+
{
|
746
|
+
VALUE result;
|
747
|
+
|
748
|
+
if (argc == 0) {
|
749
|
+
return rb_ary_pop(ary);
|
750
|
+
}
|
751
|
+
|
752
|
+
rb_ary_modify_check(ary);
|
753
|
+
result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
|
754
|
+
ARY_INCREASE_LEN(ary, -RARRAY_LEN(result));
|
755
|
+
return result;
|
756
|
+
}
|
757
|
+
|
758
|
+
VALUE
|
759
|
+
rb_ary_shift(VALUE ary)
|
760
|
+
{
|
761
|
+
VALUE top;
|
762
|
+
|
763
|
+
rb_ary_modify_check(ary);
|
764
|
+
if (RARRAY_LEN(ary) == 0) return Qnil;
|
765
|
+
top = RARRAY_PTR(ary)[0];
|
766
|
+
if (!ARY_SHARED_P(ary)) {
|
767
|
+
if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
|
768
|
+
MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+1, VALUE, RARRAY_LEN(ary)-1);
|
769
|
+
ARY_INCREASE_LEN(ary, -1);
|
770
|
+
return top;
|
771
|
+
}
|
772
|
+
assert(!ARY_EMBED_P(ary)); /* ARY_EMBED_LEN_MAX < ARY_DEFAULT_SIZE */
|
773
|
+
|
774
|
+
RARRAY_PTR(ary)[0] = Qnil;
|
775
|
+
ary_make_shared(ary);
|
776
|
+
}
|
777
|
+
ARY_INCREASE_PTR(ary, 1); /* shift ptr */
|
778
|
+
ARY_INCREASE_LEN(ary, -1);
|
779
|
+
|
780
|
+
return top;
|
781
|
+
}
|
782
|
+
|
783
|
+
/*
|
784
|
+
* call-seq:
|
785
|
+
* array.shift -> obj or nil
|
786
|
+
* array.shift(n) -> array
|
787
|
+
*
|
788
|
+
* Returns the first element of <i>self</i> and removes it (shifting all
|
789
|
+
* other elements down by one). Returns <code>nil</code> if the array
|
790
|
+
* is empty.
|
791
|
+
*
|
792
|
+
* If a number _n_ is given, returns an array of the first n elements
|
793
|
+
* (or less) just like <code>array.slice!(0, n)</code> does.
|
794
|
+
*
|
795
|
+
* args = [ "-m", "-q", "filename" ]
|
796
|
+
* args.shift #=> "-m"
|
797
|
+
* args #=> ["-q", "filename"]
|
798
|
+
*
|
799
|
+
* args = [ "-m", "-q", "filename" ]
|
800
|
+
* args.shift(2) #=> ["-m", "-q"]
|
801
|
+
* args #=> ["filename"]
|
802
|
+
*/
|
803
|
+
|
804
|
+
static VALUE
|
805
|
+
rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
|
806
|
+
{
|
807
|
+
VALUE result;
|
808
|
+
long n;
|
809
|
+
|
810
|
+
if (argc == 0) {
|
811
|
+
return rb_ary_shift(ary);
|
812
|
+
}
|
813
|
+
|
814
|
+
rb_ary_modify_check(ary);
|
815
|
+
result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
|
816
|
+
n = RARRAY_LEN(result);
|
817
|
+
if (ARY_SHARED_P(ary)) {
|
818
|
+
ARY_INCREASE_PTR(ary, n);
|
819
|
+
}
|
820
|
+
else {
|
821
|
+
MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n);
|
822
|
+
}
|
823
|
+
ARY_INCREASE_LEN(ary, -n);
|
824
|
+
|
825
|
+
return result;
|
826
|
+
}
|
827
|
+
|
828
|
+
/*
|
829
|
+
* call-seq:
|
830
|
+
* array.unshift(obj, ...) -> array
|
831
|
+
*
|
832
|
+
* Prepends objects to the front of <i>array</i>.
|
833
|
+
* other elements up one.
|
834
|
+
*
|
835
|
+
* a = [ "b", "c", "d" ]
|
836
|
+
* a.unshift("a") #=> ["a", "b", "c", "d"]
|
837
|
+
* a.unshift(1, 2) #=> [ 1, 2, "a", "b", "c", "d"]
|
838
|
+
*/
|
839
|
+
|
840
|
+
static VALUE
|
841
|
+
rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
|
842
|
+
{
|
843
|
+
long len;
|
844
|
+
|
845
|
+
if (argc == 0) return ary;
|
846
|
+
rb_ary_modify(ary);
|
847
|
+
if (ARY_CAPA(ary) <= (len = RARRAY_LEN(ary)) + argc) {
|
848
|
+
ary_resize_capa(ary, len + argc + ARY_DEFAULT_SIZE);
|
849
|
+
}
|
850
|
+
|
851
|
+
/* sliding items */
|
852
|
+
MEMMOVE(RARRAY_PTR(ary) + argc, RARRAY_PTR(ary), VALUE, len);
|
853
|
+
MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
|
854
|
+
ARY_INCREASE_LEN(ary, argc);
|
855
|
+
|
856
|
+
return ary;
|
857
|
+
}
|
858
|
+
|
859
|
+
VALUE
|
860
|
+
rb_ary_unshift(VALUE ary, VALUE item)
|
861
|
+
{
|
862
|
+
return rb_ary_unshift_m(1,&item,ary);
|
863
|
+
}
|
864
|
+
|
865
|
+
/* faster version - use this if you don't need to treat negative offset */
|
866
|
+
static inline VALUE
|
867
|
+
rb_ary_elt(VALUE ary, long offset)
|
868
|
+
{
|
869
|
+
if (RARRAY_LEN(ary) == 0) return Qnil;
|
870
|
+
if (offset < 0 || RARRAY_LEN(ary) <= offset) {
|
871
|
+
return Qnil;
|
872
|
+
}
|
873
|
+
return RARRAY_PTR(ary)[offset];
|
874
|
+
}
|
875
|
+
|
876
|
+
VALUE
|
877
|
+
rb_ary_entry(VALUE ary, long offset)
|
878
|
+
{
|
879
|
+
if (offset < 0) {
|
880
|
+
offset += RARRAY_LEN(ary);
|
881
|
+
}
|
882
|
+
return rb_ary_elt(ary, offset);
|
883
|
+
}
|
884
|
+
|
885
|
+
VALUE
|
886
|
+
rb_ary_subseq(VALUE ary, long beg, long len)
|
887
|
+
{
|
888
|
+
VALUE klass;
|
889
|
+
|
890
|
+
if (beg > RARRAY_LEN(ary)) return Qnil;
|
891
|
+
if (beg < 0 || len < 0) return Qnil;
|
892
|
+
|
893
|
+
if (RARRAY_LEN(ary) < len || RARRAY_LEN(ary) < beg + len) {
|
894
|
+
len = RARRAY_LEN(ary) - beg;
|
895
|
+
}
|
896
|
+
klass = rb_obj_class(ary);
|
897
|
+
if (len == 0) return ary_new(klass, 0);
|
898
|
+
|
899
|
+
return ary_make_partial(ary, klass, beg, len);
|
900
|
+
}
|
901
|
+
|
902
|
+
/*
|
903
|
+
* call-seq:
|
904
|
+
* array[index] -> obj or nil
|
905
|
+
* array[start, length] -> an_array or nil
|
906
|
+
* array[range] -> an_array or nil
|
907
|
+
* array.slice(index) -> obj or nil
|
908
|
+
* array.slice(start, length) -> an_array or nil
|
909
|
+
* array.slice(range) -> an_array or nil
|
910
|
+
*
|
911
|
+
* Element Reference---Returns the element at _index_,
|
912
|
+
* or returns a subarray starting at _start_ and
|
913
|
+
* continuing for _length_ elements, or returns a subarray
|
914
|
+
* specified by _range_.
|
915
|
+
* Negative indices count backward from the end of the
|
916
|
+
* array (-1 is the last element). Returns nil if the index
|
917
|
+
* (or starting index) are out of range.
|
918
|
+
*
|
919
|
+
* a = [ "a", "b", "c", "d", "e" ]
|
920
|
+
* a[2] + a[0] + a[1] #=> "cab"
|
921
|
+
* a[6] #=> nil
|
922
|
+
* a[1, 2] #=> [ "b", "c" ]
|
923
|
+
* a[1..3] #=> [ "b", "c", "d" ]
|
924
|
+
* a[4..7] #=> [ "e" ]
|
925
|
+
* a[6..10] #=> nil
|
926
|
+
* a[-3, 3] #=> [ "c", "d", "e" ]
|
927
|
+
* # special cases
|
928
|
+
* a[5] #=> nil
|
929
|
+
* a[5, 1] #=> []
|
930
|
+
* a[5..10] #=> []
|
931
|
+
*
|
932
|
+
*/
|
933
|
+
|
934
|
+
VALUE
|
935
|
+
rb_ary_aref(int argc, VALUE *argv, VALUE ary)
|
936
|
+
{
|
937
|
+
VALUE arg;
|
938
|
+
long beg, len;
|
939
|
+
|
940
|
+
if (argc == 2) {
|
941
|
+
beg = NUM2LONG(argv[0]);
|
942
|
+
len = NUM2LONG(argv[1]);
|
943
|
+
if (beg < 0) {
|
944
|
+
beg += RARRAY_LEN(ary);
|
945
|
+
}
|
946
|
+
return rb_ary_subseq(ary, beg, len);
|
947
|
+
}
|
948
|
+
if (argc != 1) {
|
949
|
+
rb_scan_args(argc, argv, "11", 0, 0);
|
950
|
+
}
|
951
|
+
arg = argv[0];
|
952
|
+
/* special case - speeding up */
|
953
|
+
if (FIXNUM_P(arg)) {
|
954
|
+
return rb_ary_entry(ary, FIX2LONG(arg));
|
955
|
+
}
|
956
|
+
/* check if idx is Range */
|
957
|
+
switch (rb_range_beg_len(arg, &beg, &len, RARRAY_LEN(ary), 0)) {
|
958
|
+
case Qfalse:
|
959
|
+
break;
|
960
|
+
case Qnil:
|
961
|
+
return Qnil;
|
962
|
+
default:
|
963
|
+
return rb_ary_subseq(ary, beg, len);
|
964
|
+
}
|
965
|
+
return rb_ary_entry(ary, NUM2LONG(arg));
|
966
|
+
}
|
967
|
+
|
968
|
+
/*
|
969
|
+
* call-seq:
|
970
|
+
* array.at(index) -> obj or nil
|
971
|
+
*
|
972
|
+
* Returns the element at _index_. A
|
973
|
+
* negative index counts from the end of _self_. Returns +nil+
|
974
|
+
* if the index is out of range. See also <code>Array#[]</code>.
|
975
|
+
*
|
976
|
+
* a = [ "a", "b", "c", "d", "e" ]
|
977
|
+
* a.at(0) #=> "a"
|
978
|
+
* a.at(-1) #=> "e"
|
979
|
+
*/
|
980
|
+
|
981
|
+
static VALUE
|
982
|
+
rb_ary_at(VALUE ary, VALUE pos)
|
983
|
+
{
|
984
|
+
return rb_ary_entry(ary, NUM2LONG(pos));
|
985
|
+
}
|
986
|
+
|
987
|
+
/*
|
988
|
+
* call-seq:
|
989
|
+
* array.first -> obj or nil
|
990
|
+
* array.first(n) -> an_array
|
991
|
+
*
|
992
|
+
* Returns the first element, or the first +n+ elements, of the array.
|
993
|
+
* If the array is empty, the first form returns <code>nil</code>, and the
|
994
|
+
* second form returns an empty array.
|
995
|
+
*
|
996
|
+
* a = [ "q", "r", "s", "t" ]
|
997
|
+
* a.first #=> "q"
|
998
|
+
* a.first(2) #=> ["q", "r"]
|
999
|
+
*/
|
1000
|
+
|
1001
|
+
static VALUE
|
1002
|
+
rb_ary_first(int argc, VALUE *argv, VALUE ary)
|
1003
|
+
{
|
1004
|
+
if (argc == 0) {
|
1005
|
+
if (RARRAY_LEN(ary) == 0) return Qnil;
|
1006
|
+
return RARRAY_PTR(ary)[0];
|
1007
|
+
}
|
1008
|
+
else {
|
1009
|
+
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
|
1010
|
+
}
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
/*
|
1014
|
+
* call-seq:
|
1015
|
+
* array.last -> obj or nil
|
1016
|
+
* array.last(n) -> an_array
|
1017
|
+
*
|
1018
|
+
* Returns the last element(s) of <i>self</i>. If the array is empty,
|
1019
|
+
* the first form returns <code>nil</code>.
|
1020
|
+
*
|
1021
|
+
* a = [ "w", "x", "y", "z" ]
|
1022
|
+
* a.last #=> "z"
|
1023
|
+
* a.last(2) #=> ["y", "z"]
|
1024
|
+
*/
|
1025
|
+
|
1026
|
+
VALUE
|
1027
|
+
rb_ary_last(int argc, VALUE *argv, VALUE ary)
|
1028
|
+
{
|
1029
|
+
if (argc == 0) {
|
1030
|
+
if (RARRAY_LEN(ary) == 0) return Qnil;
|
1031
|
+
return RARRAY_PTR(ary)[RARRAY_LEN(ary)-1];
|
1032
|
+
}
|
1033
|
+
else {
|
1034
|
+
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
|
1035
|
+
}
|
1036
|
+
}
|
1037
|
+
|
1038
|
+
/*
|
1039
|
+
* call-seq:
|
1040
|
+
* array.fetch(index) -> obj
|
1041
|
+
* array.fetch(index, default ) -> obj
|
1042
|
+
* array.fetch(index) {|index| block } -> obj
|
1043
|
+
*
|
1044
|
+
* Tries to return the element at position <i>index</i>. If the index
|
1045
|
+
* lies outside the array, the first form throws an
|
1046
|
+
* <code>IndexError</code> exception, the second form returns
|
1047
|
+
* <i>default</i>, and the third form returns the value of invoking
|
1048
|
+
* the block, passing in the index. Negative values of <i>index</i>
|
1049
|
+
* count from the end of the array.
|
1050
|
+
*
|
1051
|
+
* a = [ 11, 22, 33, 44 ]
|
1052
|
+
* a.fetch(1) #=> 22
|
1053
|
+
* a.fetch(-1) #=> 44
|
1054
|
+
* a.fetch(4, 'cat') #=> "cat"
|
1055
|
+
* a.fetch(4) { |i| i*i } #=> 16
|
1056
|
+
*/
|
1057
|
+
|
1058
|
+
static VALUE
|
1059
|
+
rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
|
1060
|
+
{
|
1061
|
+
VALUE pos, ifnone;
|
1062
|
+
long block_given;
|
1063
|
+
long idx;
|
1064
|
+
|
1065
|
+
rb_scan_args(argc, argv, "11", &pos, &ifnone);
|
1066
|
+
block_given = rb_block_given_p();
|
1067
|
+
if (block_given && argc == 2) {
|
1068
|
+
rb_warn("block supersedes default value argument");
|
1069
|
+
}
|
1070
|
+
idx = NUM2LONG(pos);
|
1071
|
+
|
1072
|
+
if (idx < 0) {
|
1073
|
+
idx += RARRAY_LEN(ary);
|
1074
|
+
}
|
1075
|
+
if (idx < 0 || RARRAY_LEN(ary) <= idx) {
|
1076
|
+
if (block_given) return rb_yield(pos);
|
1077
|
+
if (argc == 1) {
|
1078
|
+
rb_raise(rb_eIndexError, "index %ld out of array", idx);
|
1079
|
+
}
|
1080
|
+
return ifnone;
|
1081
|
+
}
|
1082
|
+
return RARRAY_PTR(ary)[idx];
|
1083
|
+
}
|
1084
|
+
|
1085
|
+
/*
|
1086
|
+
* call-seq:
|
1087
|
+
* array.index(obj) -> int or nil
|
1088
|
+
* array.index {|item| block} -> int or nil
|
1089
|
+
*
|
1090
|
+
* Returns the index of the first object in <i>self</i> such that is
|
1091
|
+
* <code>==</code> to <i>obj</i>. If a block is given instead of an
|
1092
|
+
* argument, returns first object for which <em>block</em> is true.
|
1093
|
+
* Returns <code>nil</code> if no match is found.
|
1094
|
+
*
|
1095
|
+
* a = [ "a", "b", "c" ]
|
1096
|
+
* a.index("b") #=> 1
|
1097
|
+
* a.index("z") #=> nil
|
1098
|
+
* a.index{|x|x=="b"} #=> 1
|
1099
|
+
*
|
1100
|
+
* This is an alias of <code>#find_index</code>.
|
1101
|
+
*/
|
1102
|
+
|
1103
|
+
static VALUE
|
1104
|
+
rb_ary_index(int argc, VALUE *argv, VALUE ary)
|
1105
|
+
{
|
1106
|
+
VALUE val;
|
1107
|
+
long i;
|
1108
|
+
|
1109
|
+
if (argc == 0) {
|
1110
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
1111
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
1112
|
+
if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
|
1113
|
+
return LONG2NUM(i);
|
1114
|
+
}
|
1115
|
+
}
|
1116
|
+
return Qnil;
|
1117
|
+
}
|
1118
|
+
rb_scan_args(argc, argv, "01", &val);
|
1119
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
1120
|
+
if (rb_equal(RARRAY_PTR(ary)[i], val))
|
1121
|
+
return LONG2NUM(i);
|
1122
|
+
}
|
1123
|
+
return Qnil;
|
1124
|
+
}
|
1125
|
+
|
1126
|
+
/*
|
1127
|
+
* call-seq:
|
1128
|
+
* array.rindex(obj) -> int or nil
|
1129
|
+
*
|
1130
|
+
* Returns the index of the last object in <i>array</i>
|
1131
|
+
* <code>==</code> to <i>obj</i>. If a block is given instead of an
|
1132
|
+
* argument, returns first object for which <em>block</em> is
|
1133
|
+
* true. Returns <code>nil</code> if no match is found.
|
1134
|
+
*
|
1135
|
+
* a = [ "a", "b", "b", "b", "c" ]
|
1136
|
+
* a.rindex("b") #=> 3
|
1137
|
+
* a.rindex("z") #=> nil
|
1138
|
+
* a.rindex{|x|x=="b"} #=> 3
|
1139
|
+
*/
|
1140
|
+
|
1141
|
+
static VALUE
|
1142
|
+
rb_ary_rindex(int argc, VALUE *argv, VALUE ary)
|
1143
|
+
{
|
1144
|
+
VALUE val;
|
1145
|
+
long i = RARRAY_LEN(ary);
|
1146
|
+
|
1147
|
+
if (argc == 0) {
|
1148
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
1149
|
+
while (i--) {
|
1150
|
+
if (RTEST(rb_yield(RARRAY_PTR(ary)[i])))
|
1151
|
+
return LONG2NUM(i);
|
1152
|
+
if (i > RARRAY_LEN(ary)) {
|
1153
|
+
i = RARRAY_LEN(ary);
|
1154
|
+
}
|
1155
|
+
}
|
1156
|
+
return Qnil;
|
1157
|
+
}
|
1158
|
+
rb_scan_args(argc, argv, "01", &val);
|
1159
|
+
while (i--) {
|
1160
|
+
if (rb_equal(RARRAY_PTR(ary)[i], val))
|
1161
|
+
return LONG2NUM(i);
|
1162
|
+
if (i > RARRAY_LEN(ary)) {
|
1163
|
+
i = RARRAY_LEN(ary);
|
1164
|
+
}
|
1165
|
+
}
|
1166
|
+
return Qnil;
|
1167
|
+
}
|
1168
|
+
|
1169
|
+
VALUE
|
1170
|
+
rb_ary_to_ary(VALUE obj)
|
1171
|
+
{
|
1172
|
+
if (TYPE(obj) == T_ARRAY) {
|
1173
|
+
return obj;
|
1174
|
+
}
|
1175
|
+
if (rb_respond_to(obj, rb_intern("to_ary"))) {
|
1176
|
+
return to_ary(obj);
|
1177
|
+
}
|
1178
|
+
return rb_ary_new3(1, obj);
|
1179
|
+
}
|
1180
|
+
|
1181
|
+
static void
|
1182
|
+
rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl)
|
1183
|
+
{
|
1184
|
+
long rlen;
|
1185
|
+
|
1186
|
+
if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
|
1187
|
+
if (beg < 0) {
|
1188
|
+
beg += RARRAY_LEN(ary);
|
1189
|
+
if (beg < 0) {
|
1190
|
+
beg -= RARRAY_LEN(ary);
|
1191
|
+
rb_raise(rb_eIndexError, "index %ld out of array", beg);
|
1192
|
+
}
|
1193
|
+
}
|
1194
|
+
if (RARRAY_LEN(ary) < len || RARRAY_LEN(ary) < beg + len) {
|
1195
|
+
len = RARRAY_LEN(ary) - beg;
|
1196
|
+
}
|
1197
|
+
|
1198
|
+
if (rpl == Qundef) {
|
1199
|
+
rlen = 0;
|
1200
|
+
}
|
1201
|
+
else {
|
1202
|
+
rpl = rb_ary_to_ary(rpl);
|
1203
|
+
rlen = RARRAY_LEN(rpl);
|
1204
|
+
}
|
1205
|
+
rb_ary_modify(ary);
|
1206
|
+
if (beg >= RARRAY_LEN(ary)) {
|
1207
|
+
if (beg > ARY_MAX_SIZE - rlen) {
|
1208
|
+
rb_raise(rb_eIndexError, "index %ld too big", beg);
|
1209
|
+
}
|
1210
|
+
len = beg + rlen;
|
1211
|
+
if (len >= ARY_CAPA(ary)) {
|
1212
|
+
ary_resize_capa(ary, len);
|
1213
|
+
}
|
1214
|
+
rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), beg - RARRAY_LEN(ary));
|
1215
|
+
if (rlen > 0) {
|
1216
|
+
MEMCPY(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen);
|
1217
|
+
}
|
1218
|
+
ARY_SET_LEN(ary, len);
|
1219
|
+
}
|
1220
|
+
else {
|
1221
|
+
long alen;
|
1222
|
+
|
1223
|
+
alen = RARRAY_LEN(ary) + rlen - len;
|
1224
|
+
if (alen >= ARY_CAPA(ary)) {
|
1225
|
+
ary_resize_capa(ary, alen);
|
1226
|
+
}
|
1227
|
+
|
1228
|
+
if (len != rlen) {
|
1229
|
+
MEMMOVE(RARRAY_PTR(ary) + beg + rlen, RARRAY_PTR(ary) + beg + len,
|
1230
|
+
VALUE, RARRAY_LEN(ary) - (beg + len));
|
1231
|
+
ARY_SET_LEN(ary, alen);
|
1232
|
+
}
|
1233
|
+
if (rlen > 0) {
|
1234
|
+
MEMMOVE(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen);
|
1235
|
+
}
|
1236
|
+
}
|
1237
|
+
}
|
1238
|
+
|
1239
|
+
/*
|
1240
|
+
* call-seq:
|
1241
|
+
* array[index] = obj -> obj
|
1242
|
+
* array[start, length] = obj or an_array or nil -> obj or an_array or nil
|
1243
|
+
* array[range] = obj or an_array or nil -> obj or an_array or nil
|
1244
|
+
*
|
1245
|
+
* Element Assignment---Sets the element at _index_,
|
1246
|
+
* or replaces a subarray starting at _start_ and
|
1247
|
+
* continuing for _length_ elements, or replaces a subarray
|
1248
|
+
* specified by _range_. If indices are greater than
|
1249
|
+
* the current capacity of the array, the array grows
|
1250
|
+
* automatically. A negative indices will count backward
|
1251
|
+
* from the end of the array. Inserts elements if _length_ is
|
1252
|
+
* zero. An +IndexError+ is raised if a negative index points
|
1253
|
+
* past the beginning of the array. See also
|
1254
|
+
* <code>Array#push</code>, and <code>Array#unshift</code>.
|
1255
|
+
*
|
1256
|
+
* a = Array.new
|
1257
|
+
* a[4] = "4"; #=> [nil, nil, nil, nil, "4"]
|
1258
|
+
* a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"]
|
1259
|
+
* a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"]
|
1260
|
+
* a[0, 2] = "?" #=> ["?", 2, nil, "4"]
|
1261
|
+
* a[0..2] = "A" #=> ["A", "4"]
|
1262
|
+
* a[-1] = "Z" #=> ["A", "Z"]
|
1263
|
+
* a[1..-1] = nil #=> ["A", nil]
|
1264
|
+
* a[1..-1] = [] #=> ["A"]
|
1265
|
+
*/
|
1266
|
+
|
1267
|
+
static VALUE
|
1268
|
+
rb_ary_aset(int argc, VALUE *argv, VALUE ary)
|
1269
|
+
{
|
1270
|
+
long offset, beg, len;
|
1271
|
+
|
1272
|
+
if (argc == 3) {
|
1273
|
+
beg = NUM2LONG(argv[0]);
|
1274
|
+
len = NUM2LONG(argv[1]);
|
1275
|
+
rb_ary_splice(ary, beg, len, argv[2]);
|
1276
|
+
return argv[2];
|
1277
|
+
}
|
1278
|
+
if (argc != 2) {
|
1279
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc);
|
1280
|
+
}
|
1281
|
+
if (FIXNUM_P(argv[0])) {
|
1282
|
+
offset = FIX2LONG(argv[0]);
|
1283
|
+
goto fixnum;
|
1284
|
+
}
|
1285
|
+
if (rb_range_beg_len(argv[0], &beg, &len, RARRAY_LEN(ary), 1)) {
|
1286
|
+
/* check if idx is Range */
|
1287
|
+
rb_ary_splice(ary, beg, len, argv[1]);
|
1288
|
+
return argv[1];
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
offset = NUM2LONG(argv[0]);
|
1292
|
+
fixnum:
|
1293
|
+
rb_ary_store(ary, offset, argv[1]);
|
1294
|
+
return argv[1];
|
1295
|
+
}
|
1296
|
+
|
1297
|
+
/*
|
1298
|
+
* call-seq:
|
1299
|
+
* array.insert(index, obj...) -> array
|
1300
|
+
*
|
1301
|
+
* Inserts the given values before the element with the given index
|
1302
|
+
* (which may be negative).
|
1303
|
+
*
|
1304
|
+
* a = %w{ a b c d }
|
1305
|
+
* a.insert(2, 99) #=> ["a", "b", 99, "c", "d"]
|
1306
|
+
* a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"]
|
1307
|
+
*/
|
1308
|
+
|
1309
|
+
static VALUE
|
1310
|
+
rb_ary_insert(int argc, VALUE *argv, VALUE ary)
|
1311
|
+
{
|
1312
|
+
long pos;
|
1313
|
+
|
1314
|
+
if (argc == 1) return ary;
|
1315
|
+
if (argc < 1) {
|
1316
|
+
rb_raise(rb_eArgError, "wrong number of arguments (at least 1)");
|
1317
|
+
}
|
1318
|
+
pos = NUM2LONG(argv[0]);
|
1319
|
+
if (pos == -1) {
|
1320
|
+
pos = RARRAY_LEN(ary);
|
1321
|
+
}
|
1322
|
+
if (pos < 0) {
|
1323
|
+
pos++;
|
1324
|
+
}
|
1325
|
+
rb_ary_splice(ary, pos, 0, rb_ary_new4(argc - 1, argv + 1));
|
1326
|
+
return ary;
|
1327
|
+
}
|
1328
|
+
|
1329
|
+
/*
|
1330
|
+
* call-seq:
|
1331
|
+
* array.each {|item| block } -> array
|
1332
|
+
*
|
1333
|
+
* Calls <i>block</i> once for each element in <i>self</i>, passing that
|
1334
|
+
* element as a parameter.
|
1335
|
+
*
|
1336
|
+
* a = [ "a", "b", "c" ]
|
1337
|
+
* a.each {|x| print x, " -- " }
|
1338
|
+
*
|
1339
|
+
* produces:
|
1340
|
+
*
|
1341
|
+
* a -- b -- c --
|
1342
|
+
*/
|
1343
|
+
|
1344
|
+
VALUE
|
1345
|
+
rb_ary_each(VALUE ary)
|
1346
|
+
{
|
1347
|
+
long i;
|
1348
|
+
|
1349
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
1350
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
1351
|
+
rb_yield(RARRAY_PTR(ary)[i]);
|
1352
|
+
}
|
1353
|
+
return ary;
|
1354
|
+
}
|
1355
|
+
|
1356
|
+
/*
|
1357
|
+
* call-seq:
|
1358
|
+
* array.each_index {|index| block } -> array
|
1359
|
+
*
|
1360
|
+
* Same as <code>Array#each</code>, but passes the index of the element
|
1361
|
+
* instead of the element itself.
|
1362
|
+
*
|
1363
|
+
* a = [ "a", "b", "c" ]
|
1364
|
+
* a.each_index {|x| print x, " -- " }
|
1365
|
+
*
|
1366
|
+
* produces:
|
1367
|
+
*
|
1368
|
+
* 0 -- 1 -- 2 --
|
1369
|
+
*/
|
1370
|
+
|
1371
|
+
static VALUE
|
1372
|
+
rb_ary_each_index(VALUE ary)
|
1373
|
+
{
|
1374
|
+
long i;
|
1375
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
1376
|
+
|
1377
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
1378
|
+
rb_yield(LONG2NUM(i));
|
1379
|
+
}
|
1380
|
+
return ary;
|
1381
|
+
}
|
1382
|
+
|
1383
|
+
/*
|
1384
|
+
* call-seq:
|
1385
|
+
* array.reverse_each {|item| block }
|
1386
|
+
*
|
1387
|
+
* Same as <code>Array#each</code>, but traverses <i>self</i> in reverse
|
1388
|
+
* order.
|
1389
|
+
*
|
1390
|
+
* a = [ "a", "b", "c" ]
|
1391
|
+
* a.reverse_each {|x| print x, " " }
|
1392
|
+
*
|
1393
|
+
* produces:
|
1394
|
+
*
|
1395
|
+
* c b a
|
1396
|
+
*/
|
1397
|
+
|
1398
|
+
static VALUE
|
1399
|
+
rb_ary_reverse_each(VALUE ary)
|
1400
|
+
{
|
1401
|
+
long len;
|
1402
|
+
|
1403
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
1404
|
+
len = RARRAY_LEN(ary);
|
1405
|
+
while (len--) {
|
1406
|
+
rb_yield(RARRAY_PTR(ary)[len]);
|
1407
|
+
if (RARRAY_LEN(ary) < len) {
|
1408
|
+
len = RARRAY_LEN(ary);
|
1409
|
+
}
|
1410
|
+
}
|
1411
|
+
return ary;
|
1412
|
+
}
|
1413
|
+
|
1414
|
+
/*
|
1415
|
+
* call-seq:
|
1416
|
+
* array.length -> int
|
1417
|
+
*
|
1418
|
+
* Returns the number of elements in <i>self</i>. May be zero.
|
1419
|
+
*
|
1420
|
+
* [ 1, 2, 3, 4, 5 ].length #=> 5
|
1421
|
+
*/
|
1422
|
+
|
1423
|
+
static VALUE
|
1424
|
+
rb_ary_length(VALUE ary)
|
1425
|
+
{
|
1426
|
+
long len = RARRAY_LEN(ary);
|
1427
|
+
return LONG2NUM(len);
|
1428
|
+
}
|
1429
|
+
|
1430
|
+
/*
|
1431
|
+
* call-seq:
|
1432
|
+
* array.empty? -> true or false
|
1433
|
+
*
|
1434
|
+
* Returns <code>true</code> if <i>self</i> array contains no elements.
|
1435
|
+
*
|
1436
|
+
* [].empty? #=> true
|
1437
|
+
*/
|
1438
|
+
|
1439
|
+
static VALUE
|
1440
|
+
rb_ary_empty_p(VALUE ary)
|
1441
|
+
{
|
1442
|
+
if (RARRAY_LEN(ary) == 0)
|
1443
|
+
return Qtrue;
|
1444
|
+
return Qfalse;
|
1445
|
+
}
|
1446
|
+
|
1447
|
+
VALUE
|
1448
|
+
rb_ary_dup(VALUE ary)
|
1449
|
+
{
|
1450
|
+
VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
|
1451
|
+
int is_embed = ARY_EMBED_P(dup);
|
1452
|
+
DUPSETUP(dup, ary);
|
1453
|
+
if (is_embed) FL_SET_EMBED(dup);
|
1454
|
+
MEMCPY(RARRAY_PTR(dup), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
|
1455
|
+
ARY_SET_LEN(dup, RARRAY_LEN(ary));
|
1456
|
+
|
1457
|
+
return dup;
|
1458
|
+
}
|
1459
|
+
|
1460
|
+
extern VALUE rb_output_fs;
|
1461
|
+
|
1462
|
+
static VALUE
|
1463
|
+
recursive_join(VALUE ary, VALUE argp, int recur)
|
1464
|
+
{
|
1465
|
+
VALUE *arg = (VALUE *)argp;
|
1466
|
+
if (recur) {
|
1467
|
+
return rb_usascii_str_new2("[...]");
|
1468
|
+
}
|
1469
|
+
return rb_ary_join(arg[0], arg[1]);
|
1470
|
+
}
|
1471
|
+
|
1472
|
+
VALUE
|
1473
|
+
rb_ary_join(VALUE ary, VALUE sep)
|
1474
|
+
{
|
1475
|
+
long len = 1, i;
|
1476
|
+
int taint = Qfalse;
|
1477
|
+
int untrust = Qfalse;
|
1478
|
+
VALUE result, tmp;
|
1479
|
+
|
1480
|
+
if (RARRAY_LEN(ary) == 0) return rb_str_new(0, 0);
|
1481
|
+
if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue;
|
1482
|
+
if (OBJ_UNTRUSTED(ary) || OBJ_UNTRUSTED(sep)) untrust = Qtrue;
|
1483
|
+
|
1484
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
1485
|
+
tmp = rb_check_string_type(RARRAY_PTR(ary)[i]);
|
1486
|
+
len += NIL_P(tmp) ? 10 : RSTRING_LEN(tmp);
|
1487
|
+
}
|
1488
|
+
if (!NIL_P(sep)) {
|
1489
|
+
StringValue(sep);
|
1490
|
+
len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1);
|
1491
|
+
}
|
1492
|
+
result = rb_str_buf_new(len);
|
1493
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
1494
|
+
tmp = RARRAY_PTR(ary)[i];
|
1495
|
+
switch (TYPE(tmp)) {
|
1496
|
+
case T_STRING:
|
1497
|
+
break;
|
1498
|
+
case T_ARRAY:
|
1499
|
+
if (tmp == ary) {
|
1500
|
+
tmp = rb_usascii_str_new2("[...]");
|
1501
|
+
}
|
1502
|
+
else {
|
1503
|
+
VALUE args[2];
|
1504
|
+
|
1505
|
+
args[0] = tmp;
|
1506
|
+
args[1] = sep;
|
1507
|
+
tmp = rb_exec_recursive(recursive_join, ary, (VALUE)args);
|
1508
|
+
}
|
1509
|
+
break;
|
1510
|
+
default:
|
1511
|
+
tmp = rb_obj_as_string(tmp);
|
1512
|
+
}
|
1513
|
+
if (i > 0 && !NIL_P(sep))
|
1514
|
+
rb_str_buf_append(result, sep);
|
1515
|
+
rb_str_buf_append(result, tmp);
|
1516
|
+
if (OBJ_TAINTED(tmp)) taint = Qtrue;
|
1517
|
+
if (OBJ_UNTRUSTED(tmp)) untrust = Qtrue;
|
1518
|
+
}
|
1519
|
+
|
1520
|
+
if (taint) OBJ_TAINT(result);
|
1521
|
+
if (untrust) OBJ_UNTRUST(result);
|
1522
|
+
return result;
|
1523
|
+
}
|
1524
|
+
|
1525
|
+
/*
|
1526
|
+
* call-seq:
|
1527
|
+
* array.join(sep=$,) -> str
|
1528
|
+
*
|
1529
|
+
* Returns a string created by converting each element of the array to
|
1530
|
+
* a string, separated by <i>sep</i>.
|
1531
|
+
*
|
1532
|
+
* [ "a", "b", "c" ].join #=> "abc"
|
1533
|
+
* [ "a", "b", "c" ].join("-") #=> "a-b-c"
|
1534
|
+
*/
|
1535
|
+
|
1536
|
+
static VALUE
|
1537
|
+
rb_ary_join_m(int argc, VALUE *argv, VALUE ary)
|
1538
|
+
{
|
1539
|
+
VALUE sep;
|
1540
|
+
|
1541
|
+
rb_scan_args(argc, argv, "01", &sep);
|
1542
|
+
if (NIL_P(sep)) sep = rb_output_fs;
|
1543
|
+
|
1544
|
+
return rb_ary_join(ary, sep);
|
1545
|
+
}
|
1546
|
+
|
1547
|
+
static VALUE
|
1548
|
+
inspect_ary(VALUE ary, VALUE dummy, int recur)
|
1549
|
+
{
|
1550
|
+
int tainted = OBJ_TAINTED(ary);
|
1551
|
+
int untrust = OBJ_UNTRUSTED(ary);
|
1552
|
+
long i;
|
1553
|
+
VALUE s, str;
|
1554
|
+
|
1555
|
+
if (recur) return rb_tainted_str_new2("[...]");
|
1556
|
+
str = rb_str_buf_new2("[");
|
1557
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
1558
|
+
s = rb_inspect(RARRAY_PTR(ary)[i]);
|
1559
|
+
if (OBJ_TAINTED(s)) tainted = Qtrue;
|
1560
|
+
if (OBJ_UNTRUSTED(s)) untrust = Qtrue;
|
1561
|
+
if (i > 0) rb_str_buf_cat2(str, ", ");
|
1562
|
+
rb_str_buf_append(str, s);
|
1563
|
+
}
|
1564
|
+
rb_str_buf_cat2(str, "]");
|
1565
|
+
if (tainted) OBJ_TAINT(str);
|
1566
|
+
if (untrust) OBJ_UNTRUST(str);
|
1567
|
+
return str;
|
1568
|
+
}
|
1569
|
+
|
1570
|
+
/*
|
1571
|
+
* call-seq:
|
1572
|
+
* array.to_s -> string
|
1573
|
+
* array.inspect -> string
|
1574
|
+
*
|
1575
|
+
* Create a printable version of <i>array</i>.
|
1576
|
+
*/
|
1577
|
+
|
1578
|
+
static VALUE
|
1579
|
+
rb_ary_inspect(VALUE ary)
|
1580
|
+
{
|
1581
|
+
if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]");
|
1582
|
+
return rb_exec_recursive(inspect_ary, ary, 0);
|
1583
|
+
}
|
1584
|
+
|
1585
|
+
VALUE
|
1586
|
+
rb_ary_to_s(VALUE ary)
|
1587
|
+
{
|
1588
|
+
return rb_ary_inspect(ary);
|
1589
|
+
}
|
1590
|
+
|
1591
|
+
/*
|
1592
|
+
* call-seq:
|
1593
|
+
* array.to_a -> array
|
1594
|
+
*
|
1595
|
+
* Returns _self_. If called on a subclass of Array, converts
|
1596
|
+
* the receiver to an Array object.
|
1597
|
+
*/
|
1598
|
+
|
1599
|
+
static VALUE
|
1600
|
+
rb_ary_to_a(VALUE ary)
|
1601
|
+
{
|
1602
|
+
if (rb_obj_class(ary) != rb_cArray) {
|
1603
|
+
VALUE dup = rb_ary_new2(RARRAY_LEN(ary));
|
1604
|
+
rb_ary_replace(dup, ary);
|
1605
|
+
return dup;
|
1606
|
+
}
|
1607
|
+
return ary;
|
1608
|
+
}
|
1609
|
+
|
1610
|
+
/*
|
1611
|
+
* call-seq:
|
1612
|
+
* array.to_ary -> array
|
1613
|
+
*
|
1614
|
+
* Returns _self_.
|
1615
|
+
*/
|
1616
|
+
|
1617
|
+
static VALUE
|
1618
|
+
rb_ary_to_ary_m(VALUE ary)
|
1619
|
+
{
|
1620
|
+
return ary;
|
1621
|
+
}
|
1622
|
+
|
1623
|
+
VALUE
|
1624
|
+
rb_ary_reverse(VALUE ary)
|
1625
|
+
{
|
1626
|
+
VALUE *p1, *p2;
|
1627
|
+
VALUE tmp;
|
1628
|
+
|
1629
|
+
rb_ary_modify(ary);
|
1630
|
+
if (RARRAY_LEN(ary) > 1) {
|
1631
|
+
p1 = RARRAY_PTR(ary);
|
1632
|
+
p2 = p1 + RARRAY_LEN(ary) - 1; /* points last item */
|
1633
|
+
|
1634
|
+
while (p1 < p2) {
|
1635
|
+
tmp = *p1;
|
1636
|
+
*p1++ = *p2;
|
1637
|
+
*p2-- = tmp;
|
1638
|
+
}
|
1639
|
+
}
|
1640
|
+
return ary;
|
1641
|
+
}
|
1642
|
+
|
1643
|
+
/*
|
1644
|
+
* call-seq:
|
1645
|
+
* array.reverse! -> array
|
1646
|
+
*
|
1647
|
+
* Reverses _self_ in place.
|
1648
|
+
*
|
1649
|
+
* a = [ "a", "b", "c" ]
|
1650
|
+
* a.reverse! #=> ["c", "b", "a"]
|
1651
|
+
* a #=> ["c", "b", "a"]
|
1652
|
+
*/
|
1653
|
+
|
1654
|
+
static VALUE
|
1655
|
+
rb_ary_reverse_bang(VALUE ary)
|
1656
|
+
{
|
1657
|
+
return rb_ary_reverse(ary);
|
1658
|
+
}
|
1659
|
+
|
1660
|
+
/*
|
1661
|
+
* call-seq:
|
1662
|
+
* array.reverse -> an_array
|
1663
|
+
*
|
1664
|
+
* Returns a new array containing <i>self</i>'s elements in reverse order.
|
1665
|
+
*
|
1666
|
+
* [ "a", "b", "c" ].reverse #=> ["c", "b", "a"]
|
1667
|
+
* [ 1 ].reverse #=> [1]
|
1668
|
+
*/
|
1669
|
+
|
1670
|
+
static VALUE
|
1671
|
+
rb_ary_reverse_m(VALUE ary)
|
1672
|
+
{
|
1673
|
+
return rb_ary_reverse(rb_ary_dup(ary));
|
1674
|
+
}
|
1675
|
+
|
1676
|
+
struct ary_sort_data {
|
1677
|
+
VALUE ary;
|
1678
|
+
int opt_methods;
|
1679
|
+
int opt_inited;
|
1680
|
+
};
|
1681
|
+
|
1682
|
+
enum {
|
1683
|
+
sort_opt_Fixnum,
|
1684
|
+
sort_opt_String,
|
1685
|
+
sort_optimizable_count
|
1686
|
+
};
|
1687
|
+
|
1688
|
+
#define STRING_P(s) (TYPE(s) == T_STRING && CLASS_OF(s) == rb_cString)
|
1689
|
+
|
1690
|
+
#define SORT_OPTIMIZABLE_BIT(type) (1U << TOKEN_PASTE(sort_opt_,type))
|
1691
|
+
#define SORT_OPTIMIZABLE(data, type) \
|
1692
|
+
((data->opt_inited & SORT_OPTIMIZABLE_BIT(type)) ? \
|
1693
|
+
(data->opt_methods & SORT_OPTIMIZABLE_BIT(type)) : \
|
1694
|
+
((data->opt_inited |= SORT_OPTIMIZABLE_BIT(type)), \
|
1695
|
+
rb_method_basic_definition_p(TOKEN_PASTE(rb_c,type), id_cmp) && \
|
1696
|
+
(data->opt_methods |= SORT_OPTIMIZABLE_BIT(type))))
|
1697
|
+
|
1698
|
+
static VALUE
|
1699
|
+
sort_reentered(VALUE ary)
|
1700
|
+
{
|
1701
|
+
if (RBASIC(ary)->klass) {
|
1702
|
+
rb_raise(rb_eRuntimeError, "sort reentered");
|
1703
|
+
}
|
1704
|
+
return Qnil;
|
1705
|
+
}
|
1706
|
+
|
1707
|
+
static int
|
1708
|
+
sort_1(const void *ap, const void *bp, void *dummy)
|
1709
|
+
{
|
1710
|
+
struct ary_sort_data *data = dummy;
|
1711
|
+
VALUE retval = sort_reentered(data->ary);
|
1712
|
+
VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
|
1713
|
+
int n;
|
1714
|
+
|
1715
|
+
retval = rb_yield_values(2, a, b);
|
1716
|
+
n = rb_cmpint(retval, a, b);
|
1717
|
+
sort_reentered(data->ary);
|
1718
|
+
return n;
|
1719
|
+
}
|
1720
|
+
|
1721
|
+
static int
|
1722
|
+
sort_2(const void *ap, const void *bp, void *dummy)
|
1723
|
+
{
|
1724
|
+
struct ary_sort_data *data = dummy;
|
1725
|
+
VALUE retval = sort_reentered(data->ary);
|
1726
|
+
VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
|
1727
|
+
int n;
|
1728
|
+
|
1729
|
+
if (FIXNUM_P(a) && FIXNUM_P(b) && SORT_OPTIMIZABLE(data, Fixnum)) {
|
1730
|
+
if ((long)a > (long)b) return 1;
|
1731
|
+
if ((long)a < (long)b) return -1;
|
1732
|
+
return 0;
|
1733
|
+
}
|
1734
|
+
if (STRING_P(a) && STRING_P(b) && SORT_OPTIMIZABLE(data, String)) {
|
1735
|
+
return rb_str_cmp(a, b);
|
1736
|
+
}
|
1737
|
+
|
1738
|
+
retval = rb_funcall(a, id_cmp, 1, b);
|
1739
|
+
n = rb_cmpint(retval, a, b);
|
1740
|
+
sort_reentered(data->ary);
|
1741
|
+
|
1742
|
+
return n;
|
1743
|
+
}
|
1744
|
+
|
1745
|
+
/*
|
1746
|
+
* call-seq:
|
1747
|
+
* array.sort! -> array
|
1748
|
+
* array.sort! {| a,b | block } -> array
|
1749
|
+
*
|
1750
|
+
* Sorts _self_. Comparisons for
|
1751
|
+
* the sort will be done using the <code><=></code> operator or using
|
1752
|
+
* an optional code block. The block implements a comparison between
|
1753
|
+
* <i>a</i> and <i>b</i>, returning -1, 0, or +1. See also
|
1754
|
+
* <code>Enumerable#sort_by</code>.
|
1755
|
+
*
|
1756
|
+
* a = [ "d", "a", "e", "c", "b" ]
|
1757
|
+
* a.sort #=> ["a", "b", "c", "d", "e"]
|
1758
|
+
* a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
|
1759
|
+
*/
|
1760
|
+
|
1761
|
+
VALUE
|
1762
|
+
rb_ary_sort_bang(VALUE ary)
|
1763
|
+
{
|
1764
|
+
rb_ary_modify(ary);
|
1765
|
+
assert(!ARY_SHARED_P(ary));
|
1766
|
+
if (RARRAY_LEN(ary) > 1) {
|
1767
|
+
VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */
|
1768
|
+
struct ary_sort_data data;
|
1769
|
+
|
1770
|
+
RBASIC(tmp)->klass = 0;
|
1771
|
+
data.ary = tmp;
|
1772
|
+
data.opt_methods = 0;
|
1773
|
+
data.opt_inited = 0;
|
1774
|
+
ruby_qsort(RARRAY_PTR(tmp), RARRAY_LEN(tmp), sizeof(VALUE),
|
1775
|
+
rb_block_given_p()?sort_1:sort_2, &data);
|
1776
|
+
|
1777
|
+
if (ARY_EMBED_P(tmp)) {
|
1778
|
+
assert(ARY_EMBED_P(tmp));
|
1779
|
+
if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */
|
1780
|
+
rb_ary_unshare(ary);
|
1781
|
+
}
|
1782
|
+
FL_SET_EMBED(ary);
|
1783
|
+
MEMCPY(RARRAY_PTR(ary), ARY_EMBED_PTR(tmp), VALUE, ARY_EMBED_LEN(tmp));
|
1784
|
+
ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
|
1785
|
+
}
|
1786
|
+
else {
|
1787
|
+
assert(!ARY_EMBED_P(tmp));
|
1788
|
+
if (ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) {
|
1789
|
+
assert(!ARY_EMBED_P(ary));
|
1790
|
+
FL_UNSET_SHARED(ary);
|
1791
|
+
ARY_SET_CAPA(ary, ARY_CAPA(tmp));
|
1792
|
+
}
|
1793
|
+
else {
|
1794
|
+
assert(!ARY_SHARED_P(tmp));
|
1795
|
+
if (ARY_EMBED_P(ary)) {
|
1796
|
+
FL_UNSET_EMBED(ary);
|
1797
|
+
}
|
1798
|
+
else if (ARY_SHARED_P(ary)) {
|
1799
|
+
/* ary might be destructively operated in the given block */
|
1800
|
+
rb_ary_unshare(ary);
|
1801
|
+
}
|
1802
|
+
else {
|
1803
|
+
xfree(ARY_HEAP_PTR(ary));
|
1804
|
+
}
|
1805
|
+
ARY_SET_PTR(ary, RARRAY_PTR(tmp));
|
1806
|
+
ARY_SET_HEAP_LEN(ary, RARRAY_LEN(tmp));
|
1807
|
+
ARY_SET_CAPA(ary, ARY_CAPA(tmp));
|
1808
|
+
}
|
1809
|
+
/* tmp was lost ownership for the ptr */
|
1810
|
+
FL_UNSET(tmp, FL_FREEZE);
|
1811
|
+
FL_SET_EMBED(tmp);
|
1812
|
+
ARY_SET_EMBED_LEN(tmp, 0);
|
1813
|
+
FL_SET(tmp, FL_FREEZE);
|
1814
|
+
}
|
1815
|
+
/* tmp will be GC'ed. */
|
1816
|
+
RBASIC(tmp)->klass = rb_cArray;
|
1817
|
+
}
|
1818
|
+
return ary;
|
1819
|
+
}
|
1820
|
+
|
1821
|
+
/*
|
1822
|
+
* call-seq:
|
1823
|
+
* array.sort -> an_array
|
1824
|
+
* array.sort {| a,b | block } -> an_array
|
1825
|
+
*
|
1826
|
+
* Returns a new array created by sorting <i>self</i>. Comparisons for
|
1827
|
+
* the sort will be done using the <code><=></code> operator or using
|
1828
|
+
* an optional code block. The block implements a comparison between
|
1829
|
+
* <i>a</i> and <i>b</i>, returning -1, 0, or +1. See also
|
1830
|
+
* <code>Enumerable#sort_by</code>.
|
1831
|
+
*
|
1832
|
+
* a = [ "d", "a", "e", "c", "b" ]
|
1833
|
+
* a.sort #=> ["a", "b", "c", "d", "e"]
|
1834
|
+
* a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
|
1835
|
+
*/
|
1836
|
+
|
1837
|
+
VALUE
|
1838
|
+
rb_ary_sort(VALUE ary)
|
1839
|
+
{
|
1840
|
+
ary = rb_ary_dup(ary);
|
1841
|
+
rb_ary_sort_bang(ary);
|
1842
|
+
return ary;
|
1843
|
+
}
|
1844
|
+
|
1845
|
+
|
1846
|
+
/*
|
1847
|
+
* call-seq:
|
1848
|
+
* array.collect {|item| block } -> an_array
|
1849
|
+
* array.map {|item| block } -> an_array
|
1850
|
+
*
|
1851
|
+
* Invokes <i>block</i> once for each element of <i>self</i>. Creates a
|
1852
|
+
* new array containing the values returned by the block.
|
1853
|
+
* See also <code>Enumerable#collect</code>.
|
1854
|
+
*
|
1855
|
+
* a = [ "a", "b", "c", "d" ]
|
1856
|
+
* a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"]
|
1857
|
+
* a #=> ["a", "b", "c", "d"]
|
1858
|
+
*/
|
1859
|
+
|
1860
|
+
static VALUE
|
1861
|
+
rb_ary_collect(VALUE ary)
|
1862
|
+
{
|
1863
|
+
long i;
|
1864
|
+
VALUE collect;
|
1865
|
+
|
1866
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
1867
|
+
collect = rb_ary_new2(RARRAY_LEN(ary));
|
1868
|
+
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
1869
|
+
rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i]));
|
1870
|
+
}
|
1871
|
+
return collect;
|
1872
|
+
}
|
1873
|
+
|
1874
|
+
|
1875
|
+
/*
|
1876
|
+
* call-seq:
|
1877
|
+
* array.collect! {|item| block } -> array
|
1878
|
+
* array.map! {|item| block } -> array
|
1879
|
+
*
|
1880
|
+
* Invokes the block once for each element of _self_, replacing the
|
1881
|
+
* element with the value returned by _block_.
|
1882
|
+
* See also <code>Enumerable#collect</code>.
|
1883
|
+
*
|
1884
|
+
* a = [ "a", "b", "c", "d" ]
|
1885
|
+
* a.collect! {|x| x + "!" }
|
1886
|
+
* a #=> [ "a!", "b!", "c!", "d!" ]
|
1887
|
+
*/
|
1888
|
+
|
1889
|
+
static VALUE
|
1890
|
+
rb_ary_collect_bang(VALUE ary)
|
1891
|
+
{
|
1892
|
+
long i;
|
1893
|
+
|
1894
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
1895
|
+
rb_ary_modify(ary);
|
1896
|
+
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
1897
|
+
rb_ary_store(ary, i, rb_yield(RARRAY_PTR(ary)[i]));
|
1898
|
+
}
|
1899
|
+
return ary;
|
1900
|
+
}
|
1901
|
+
|
1902
|
+
VALUE
|
1903
|
+
rb_get_values_at(VALUE obj, long olen, int argc, VALUE *argv, VALUE (*func) (VALUE, long))
|
1904
|
+
{
|
1905
|
+
VALUE result = rb_ary_new2(argc);
|
1906
|
+
long beg, len, i, j;
|
1907
|
+
|
1908
|
+
for (i=0; i<argc; i++) {
|
1909
|
+
if (FIXNUM_P(argv[i])) {
|
1910
|
+
rb_ary_push(result, (*func)(obj, FIX2LONG(argv[i])));
|
1911
|
+
continue;
|
1912
|
+
}
|
1913
|
+
/* check if idx is Range */
|
1914
|
+
switch (rb_range_beg_len(argv[i], &beg, &len, olen, 0)) {
|
1915
|
+
case Qfalse:
|
1916
|
+
break;
|
1917
|
+
case Qnil:
|
1918
|
+
continue;
|
1919
|
+
default:
|
1920
|
+
for (j=0; j<len; j++) {
|
1921
|
+
rb_ary_push(result, (*func)(obj, j+beg));
|
1922
|
+
}
|
1923
|
+
continue;
|
1924
|
+
}
|
1925
|
+
rb_ary_push(result, (*func)(obj, NUM2LONG(argv[i])));
|
1926
|
+
}
|
1927
|
+
return result;
|
1928
|
+
}
|
1929
|
+
|
1930
|
+
/*
|
1931
|
+
* call-seq:
|
1932
|
+
* array.values_at(selector,... ) -> an_array
|
1933
|
+
*
|
1934
|
+
* Returns an array containing the elements in
|
1935
|
+
* _self_ corresponding to the given selector(s). The selectors
|
1936
|
+
* may be either integer indices or ranges.
|
1937
|
+
* See also <code>Array#select</code>.
|
1938
|
+
*
|
1939
|
+
* a = %w{ a b c d e f }
|
1940
|
+
* a.values_at(1, 3, 5)
|
1941
|
+
* a.values_at(1, 3, 5, 7)
|
1942
|
+
* a.values_at(-1, -3, -5, -7)
|
1943
|
+
* a.values_at(1..3, 2...5)
|
1944
|
+
*/
|
1945
|
+
|
1946
|
+
static VALUE
|
1947
|
+
rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
|
1948
|
+
{
|
1949
|
+
return rb_get_values_at(ary, RARRAY_LEN(ary), argc, argv, rb_ary_entry);
|
1950
|
+
}
|
1951
|
+
|
1952
|
+
|
1953
|
+
/*
|
1954
|
+
* call-seq:
|
1955
|
+
* array.select {|item| block } -> an_array
|
1956
|
+
*
|
1957
|
+
* Invokes the block passing in successive elements from <i>array</i>,
|
1958
|
+
* returning an array containing those elements for which the block
|
1959
|
+
* returns a true value (equivalent to <code>Enumerable#select</code>).
|
1960
|
+
*
|
1961
|
+
* a = %w{ a b c d e f }
|
1962
|
+
* a.select {|v| v =~ /[aeiou]/} #=> ["a", "e"]
|
1963
|
+
*/
|
1964
|
+
|
1965
|
+
static VALUE
|
1966
|
+
rb_ary_select(VALUE ary)
|
1967
|
+
{
|
1968
|
+
VALUE result;
|
1969
|
+
long i;
|
1970
|
+
|
1971
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
1972
|
+
result = rb_ary_new2(RARRAY_LEN(ary));
|
1973
|
+
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
1974
|
+
if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
|
1975
|
+
rb_ary_push(result, rb_ary_elt(ary, i));
|
1976
|
+
}
|
1977
|
+
}
|
1978
|
+
return result;
|
1979
|
+
}
|
1980
|
+
|
1981
|
+
/*
|
1982
|
+
* call-seq:
|
1983
|
+
* array.delete(obj) -> obj or nil
|
1984
|
+
* array.delete(obj) { block } -> obj or nil
|
1985
|
+
*
|
1986
|
+
* Deletes items from <i>self</i> that are equal to <i>obj</i>. If
|
1987
|
+
* the item is not found, returns <code>nil</code>. If the optional
|
1988
|
+
* code block is given, returns the result of <i>block</i> if the item
|
1989
|
+
* is not found.
|
1990
|
+
*
|
1991
|
+
* a = [ "a", "b", "b", "b", "c" ]
|
1992
|
+
* a.delete("b") #=> "b"
|
1993
|
+
* a #=> ["a", "c"]
|
1994
|
+
* a.delete("z") #=> nil
|
1995
|
+
* a.delete("z") { "not found" } #=> "not found"
|
1996
|
+
*/
|
1997
|
+
|
1998
|
+
VALUE
|
1999
|
+
rb_ary_delete(VALUE ary, VALUE item)
|
2000
|
+
{
|
2001
|
+
VALUE v = item;
|
2002
|
+
long i1, i2;
|
2003
|
+
|
2004
|
+
for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
|
2005
|
+
VALUE e = RARRAY_PTR(ary)[i1];
|
2006
|
+
|
2007
|
+
if (rb_equal(e, item)) {
|
2008
|
+
v = e;
|
2009
|
+
continue;
|
2010
|
+
}
|
2011
|
+
if (i1 != i2) {
|
2012
|
+
rb_ary_store(ary, i2, e);
|
2013
|
+
}
|
2014
|
+
i2++;
|
2015
|
+
}
|
2016
|
+
if (RARRAY_LEN(ary) == i2) {
|
2017
|
+
if (rb_block_given_p()) {
|
2018
|
+
return rb_yield(item);
|
2019
|
+
}
|
2020
|
+
return Qnil;
|
2021
|
+
}
|
2022
|
+
|
2023
|
+
rb_ary_modify(ary);
|
2024
|
+
if (RARRAY_LEN(ary) > i2) {
|
2025
|
+
ARY_SET_LEN(ary, i2);
|
2026
|
+
if (i2 * 2 < ARY_CAPA(ary) &&
|
2027
|
+
ARY_CAPA(ary) > ARY_DEFAULT_SIZE) {
|
2028
|
+
ary_resize_capa(ary, i2*2);
|
2029
|
+
}
|
2030
|
+
}
|
2031
|
+
|
2032
|
+
return v;
|
2033
|
+
}
|
2034
|
+
|
2035
|
+
VALUE
|
2036
|
+
rb_ary_delete_at(VALUE ary, long pos)
|
2037
|
+
{
|
2038
|
+
long len = RARRAY_LEN(ary);
|
2039
|
+
VALUE del;
|
2040
|
+
|
2041
|
+
if (pos >= len) return Qnil;
|
2042
|
+
if (pos < 0) {
|
2043
|
+
pos += len;
|
2044
|
+
if (pos < 0) return Qnil;
|
2045
|
+
}
|
2046
|
+
|
2047
|
+
rb_ary_modify(ary);
|
2048
|
+
del = RARRAY_PTR(ary)[pos];
|
2049
|
+
MEMMOVE(RARRAY_PTR(ary)+pos, RARRAY_PTR(ary)+pos+1, VALUE,
|
2050
|
+
RARRAY_LEN(ary)-pos-1);
|
2051
|
+
ARY_INCREASE_LEN(ary, -1);
|
2052
|
+
|
2053
|
+
return del;
|
2054
|
+
}
|
2055
|
+
|
2056
|
+
/*
|
2057
|
+
* call-seq:
|
2058
|
+
* array.delete_at(index) -> obj or nil
|
2059
|
+
*
|
2060
|
+
* Deletes the element at the specified index, returning that element,
|
2061
|
+
* or <code>nil</code> if the index is out of range. See also
|
2062
|
+
* <code>Array#slice!</code>.
|
2063
|
+
*
|
2064
|
+
* a = %w( ant bat cat dog )
|
2065
|
+
* a.delete_at(2) #=> "cat"
|
2066
|
+
* a #=> ["ant", "bat", "dog"]
|
2067
|
+
* a.delete_at(99) #=> nil
|
2068
|
+
*/
|
2069
|
+
|
2070
|
+
static VALUE
|
2071
|
+
rb_ary_delete_at_m(VALUE ary, VALUE pos)
|
2072
|
+
{
|
2073
|
+
return rb_ary_delete_at(ary, NUM2LONG(pos));
|
2074
|
+
}
|
2075
|
+
|
2076
|
+
/*
|
2077
|
+
* call-seq:
|
2078
|
+
* array.slice!(index) -> obj or nil
|
2079
|
+
* array.slice!(start, length) -> sub_array or nil
|
2080
|
+
* array.slice!(range) -> sub_array or nil
|
2081
|
+
*
|
2082
|
+
* Deletes the element(s) given by an index (optionally with a length)
|
2083
|
+
* or by a range. Returns the deleted object, subarray, or
|
2084
|
+
* <code>nil</code> if the index is out of range.
|
2085
|
+
*
|
2086
|
+
* a = [ "a", "b", "c" ]
|
2087
|
+
* a.slice!(1) #=> "b"
|
2088
|
+
* a #=> ["a", "c"]
|
2089
|
+
* a.slice!(-1) #=> "c"
|
2090
|
+
* a #=> ["a"]
|
2091
|
+
* a.slice!(100) #=> nil
|
2092
|
+
* a #=> ["a"]
|
2093
|
+
*/
|
2094
|
+
|
2095
|
+
static VALUE
|
2096
|
+
rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary)
|
2097
|
+
{
|
2098
|
+
VALUE arg1, arg2;
|
2099
|
+
long pos, len, orig_len;
|
2100
|
+
|
2101
|
+
rb_ary_modify_check(ary);
|
2102
|
+
if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) {
|
2103
|
+
pos = NUM2LONG(arg1);
|
2104
|
+
len = NUM2LONG(arg2);
|
2105
|
+
delete_pos_len:
|
2106
|
+
if (len < 0) return Qnil;
|
2107
|
+
orig_len = RARRAY_LEN(ary);
|
2108
|
+
if (pos < 0) {
|
2109
|
+
pos += orig_len;
|
2110
|
+
if (pos < 0) return Qnil;
|
2111
|
+
}
|
2112
|
+
else if (orig_len < pos) return Qnil;
|
2113
|
+
if (orig_len < pos + len) {
|
2114
|
+
len = orig_len - pos;
|
2115
|
+
}
|
2116
|
+
if (len == 0) return rb_ary_new2(0);
|
2117
|
+
arg2 = rb_ary_new4(len, RARRAY_PTR(ary)+pos);
|
2118
|
+
RBASIC(arg2)->klass = rb_obj_class(ary);
|
2119
|
+
rb_ary_splice(ary, pos, len, Qundef);
|
2120
|
+
return arg2;
|
2121
|
+
}
|
2122
|
+
|
2123
|
+
if (!FIXNUM_P(arg1)) {
|
2124
|
+
switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) {
|
2125
|
+
case Qtrue:
|
2126
|
+
/* valid range */
|
2127
|
+
goto delete_pos_len;
|
2128
|
+
case Qnil:
|
2129
|
+
/* invalid range */
|
2130
|
+
return Qnil;
|
2131
|
+
default:
|
2132
|
+
/* not a range */
|
2133
|
+
break;
|
2134
|
+
}
|
2135
|
+
}
|
2136
|
+
|
2137
|
+
return rb_ary_delete_at(ary, NUM2LONG(arg1));
|
2138
|
+
}
|
2139
|
+
|
2140
|
+
/*
|
2141
|
+
* call-seq:
|
2142
|
+
* array.reject! {|item| block } -> array or nil
|
2143
|
+
*
|
2144
|
+
* Equivalent to <code>Array#delete_if</code>, deleting elements from
|
2145
|
+
* _self_ for which the block evaluates to true, but returns
|
2146
|
+
* <code>nil</code> if no changes were made. Also see
|
2147
|
+
* <code>Enumerable#reject</code>.
|
2148
|
+
*/
|
2149
|
+
|
2150
|
+
static VALUE
|
2151
|
+
rb_ary_reject_bang(VALUE ary)
|
2152
|
+
{
|
2153
|
+
long i1, i2;
|
2154
|
+
|
2155
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
2156
|
+
rb_ary_modify(ary);
|
2157
|
+
for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) {
|
2158
|
+
VALUE v = RARRAY_PTR(ary)[i1];
|
2159
|
+
if (RTEST(rb_yield(v))) continue;
|
2160
|
+
if (i1 != i2) {
|
2161
|
+
rb_ary_store(ary, i2, v);
|
2162
|
+
}
|
2163
|
+
i2++;
|
2164
|
+
}
|
2165
|
+
|
2166
|
+
if (RARRAY_LEN(ary) == i2) return Qnil;
|
2167
|
+
if (i2 < RARRAY_LEN(ary))
|
2168
|
+
ARY_SET_LEN(ary, i2);
|
2169
|
+
return ary;
|
2170
|
+
}
|
2171
|
+
|
2172
|
+
/*
|
2173
|
+
* call-seq:
|
2174
|
+
* array.reject {|item| block } -> an_array
|
2175
|
+
*
|
2176
|
+
* Returns a new array containing the items in _self_
|
2177
|
+
* for which the block is not true.
|
2178
|
+
*/
|
2179
|
+
|
2180
|
+
static VALUE
|
2181
|
+
rb_ary_reject(VALUE ary)
|
2182
|
+
{
|
2183
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
2184
|
+
ary = rb_ary_dup(ary);
|
2185
|
+
rb_ary_reject_bang(ary);
|
2186
|
+
return ary;
|
2187
|
+
}
|
2188
|
+
|
2189
|
+
/*
|
2190
|
+
* call-seq:
|
2191
|
+
* array.delete_if {|item| block } -> array
|
2192
|
+
*
|
2193
|
+
* Deletes every element of <i>self</i> for which <i>block</i> evaluates
|
2194
|
+
* to <code>true</code>.
|
2195
|
+
*
|
2196
|
+
* a = [ "a", "b", "c" ]
|
2197
|
+
* a.delete_if {|x| x >= "b" } #=> ["a"]
|
2198
|
+
*/
|
2199
|
+
|
2200
|
+
static VALUE
|
2201
|
+
rb_ary_delete_if(VALUE ary)
|
2202
|
+
{
|
2203
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
2204
|
+
rb_ary_reject_bang(ary);
|
2205
|
+
return ary;
|
2206
|
+
}
|
2207
|
+
|
2208
|
+
static VALUE
|
2209
|
+
take_i(VALUE val, VALUE *args, int argc, VALUE *argv)
|
2210
|
+
{
|
2211
|
+
if (args[1]-- == 0) rb_iter_break();
|
2212
|
+
if (argc > 1) val = rb_ary_new4(argc, argv);
|
2213
|
+
rb_ary_push(args[0], val);
|
2214
|
+
return Qnil;
|
2215
|
+
}
|
2216
|
+
|
2217
|
+
static VALUE
|
2218
|
+
take_items(VALUE obj, long n)
|
2219
|
+
{
|
2220
|
+
VALUE result = rb_check_array_type(obj);
|
2221
|
+
VALUE args[2];
|
2222
|
+
|
2223
|
+
if (!NIL_P(result)) return rb_ary_subseq(result, 0, n);
|
2224
|
+
result = rb_ary_new2(n);
|
2225
|
+
args[0] = result; args[1] = (VALUE)n;
|
2226
|
+
rb_block_call(obj, rb_intern("each"), 0, 0, take_i, (VALUE)args);
|
2227
|
+
return result;
|
2228
|
+
}
|
2229
|
+
|
2230
|
+
|
2231
|
+
/*
|
2232
|
+
* call-seq:
|
2233
|
+
* array.zip(arg, ...) -> an_array
|
2234
|
+
* array.zip(arg, ...) {| arr | block } -> nil
|
2235
|
+
*
|
2236
|
+
* Converts any arguments to arrays, then merges elements of
|
2237
|
+
* <i>self</i> with corresponding elements from each argument. This
|
2238
|
+
* generates a sequence of <code>self.size</code> <em>n</em>-element
|
2239
|
+
* arrays, where <em>n</em> is one more that the count of arguments. If
|
2240
|
+
* the size of any argument is less than <code>enumObj.size</code>,
|
2241
|
+
* <code>nil</code> values are supplied. If a block given, it is
|
2242
|
+
* invoked for each output array, otherwise an array of arrays is
|
2243
|
+
* returned.
|
2244
|
+
*
|
2245
|
+
* a = [ 4, 5, 6 ]
|
2246
|
+
* b = [ 7, 8, 9 ]
|
2247
|
+
* [1,2,3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
|
2248
|
+
* [1,2].zip(a,b) #=> [[1, 4, 7], [2, 5, 8]]
|
2249
|
+
* a.zip([1,2],[8]) #=> [[4,1,8], [5,2,nil], [6,nil,nil]]
|
2250
|
+
*/
|
2251
|
+
|
2252
|
+
static VALUE
|
2253
|
+
rb_ary_zip(int argc, VALUE *argv, VALUE ary)
|
2254
|
+
{
|
2255
|
+
int i, j;
|
2256
|
+
long len;
|
2257
|
+
VALUE result = Qnil;
|
2258
|
+
|
2259
|
+
len = RARRAY_LEN(ary);
|
2260
|
+
for (i=0; i<argc; i++) {
|
2261
|
+
argv[i] = take_items(argv[i], len);
|
2262
|
+
}
|
2263
|
+
if (!rb_block_given_p()) {
|
2264
|
+
result = rb_ary_new2(len);
|
2265
|
+
}
|
2266
|
+
|
2267
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2268
|
+
VALUE tmp = rb_ary_new2(argc+1);
|
2269
|
+
|
2270
|
+
rb_ary_push(tmp, rb_ary_elt(ary, i));
|
2271
|
+
for (j=0; j<argc; j++) {
|
2272
|
+
rb_ary_push(tmp, rb_ary_elt(argv[j], i));
|
2273
|
+
}
|
2274
|
+
if (NIL_P(result)) {
|
2275
|
+
rb_yield(tmp);
|
2276
|
+
}
|
2277
|
+
else {
|
2278
|
+
rb_ary_push(result, tmp);
|
2279
|
+
}
|
2280
|
+
}
|
2281
|
+
return result;
|
2282
|
+
}
|
2283
|
+
|
2284
|
+
/*
|
2285
|
+
* call-seq:
|
2286
|
+
* array.transpose -> an_array
|
2287
|
+
*
|
2288
|
+
* Assumes that <i>self</i> is an array of arrays and transposes the
|
2289
|
+
* rows and columns.
|
2290
|
+
*
|
2291
|
+
* a = [[1,2], [3,4], [5,6]]
|
2292
|
+
* a.transpose #=> [[1, 3, 5], [2, 4, 6]]
|
2293
|
+
*/
|
2294
|
+
|
2295
|
+
static VALUE
|
2296
|
+
rb_ary_transpose(VALUE ary)
|
2297
|
+
{
|
2298
|
+
long elen = -1, alen, i, j;
|
2299
|
+
VALUE tmp, result = 0;
|
2300
|
+
|
2301
|
+
alen = RARRAY_LEN(ary);
|
2302
|
+
if (alen == 0) return rb_ary_dup(ary);
|
2303
|
+
for (i=0; i<alen; i++) {
|
2304
|
+
tmp = to_ary(rb_ary_elt(ary, i));
|
2305
|
+
if (elen < 0) { /* first element */
|
2306
|
+
elen = RARRAY_LEN(tmp);
|
2307
|
+
result = rb_ary_new2(elen);
|
2308
|
+
for (j=0; j<elen; j++) {
|
2309
|
+
rb_ary_store(result, j, rb_ary_new2(alen));
|
2310
|
+
}
|
2311
|
+
}
|
2312
|
+
else if (elen != RARRAY_LEN(tmp)) {
|
2313
|
+
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
2314
|
+
RARRAY_LEN(tmp), elen);
|
2315
|
+
}
|
2316
|
+
for (j=0; j<elen; j++) {
|
2317
|
+
rb_ary_store(rb_ary_elt(result, j), i, rb_ary_elt(tmp, j));
|
2318
|
+
}
|
2319
|
+
}
|
2320
|
+
return result;
|
2321
|
+
}
|
2322
|
+
|
2323
|
+
/*
|
2324
|
+
* call-seq:
|
2325
|
+
* array.replace(other_array) -> array
|
2326
|
+
*
|
2327
|
+
* Replaces the contents of <i>self</i> with the contents of
|
2328
|
+
* <i>other_array</i>, truncating or expanding if necessary.
|
2329
|
+
*
|
2330
|
+
* a = [ "a", "b", "c", "d", "e" ]
|
2331
|
+
* a.replace([ "x", "y", "z" ]) #=> ["x", "y", "z"]
|
2332
|
+
* a #=> ["x", "y", "z"]
|
2333
|
+
*/
|
2334
|
+
|
2335
|
+
VALUE
|
2336
|
+
rb_ary_replace(VALUE copy, VALUE orig)
|
2337
|
+
{
|
2338
|
+
orig = to_ary(orig);
|
2339
|
+
rb_ary_modify_check(copy);
|
2340
|
+
if (copy == orig) return copy;
|
2341
|
+
|
2342
|
+
if (RARRAY_LEN(orig) <= RARRAY_EMBED_LEN_MAX) {
|
2343
|
+
VALUE *ptr;
|
2344
|
+
VALUE shared = 0;
|
2345
|
+
|
2346
|
+
if (ARY_OWNS_HEAP_P(copy)) {
|
2347
|
+
xfree(RARRAY_PTR(copy));
|
2348
|
+
}
|
2349
|
+
else if (ARY_SHARED_P(copy)) {
|
2350
|
+
shared = ARY_SHARED(copy);
|
2351
|
+
FL_UNSET_SHARED(copy);
|
2352
|
+
}
|
2353
|
+
FL_SET_EMBED(copy);
|
2354
|
+
ptr = RARRAY_PTR(orig);
|
2355
|
+
MEMCPY(RARRAY_PTR(copy), ptr, VALUE, RARRAY_LEN(orig));
|
2356
|
+
if (shared) {
|
2357
|
+
rb_ary_decrement_share(shared);
|
2358
|
+
}
|
2359
|
+
ARY_SET_LEN(copy, RARRAY_LEN(orig));
|
2360
|
+
}
|
2361
|
+
else {
|
2362
|
+
VALUE shared = ary_make_shared(orig);
|
2363
|
+
if (ARY_OWNS_HEAP_P(copy)) {
|
2364
|
+
xfree(RARRAY_PTR(copy));
|
2365
|
+
} else {
|
2366
|
+
rb_ary_unshare_safe(copy);
|
2367
|
+
}
|
2368
|
+
FL_UNSET_EMBED(copy);
|
2369
|
+
ARY_SET_PTR(copy, RARRAY_PTR(orig));
|
2370
|
+
ARY_SET_LEN(copy, RARRAY_LEN(orig));
|
2371
|
+
rb_ary_set_shared(copy, shared);
|
2372
|
+
}
|
2373
|
+
return copy;
|
2374
|
+
}
|
2375
|
+
|
2376
|
+
/*
|
2377
|
+
* call-seq:
|
2378
|
+
* array.clear -> array
|
2379
|
+
*
|
2380
|
+
* Removes all elements from _self_.
|
2381
|
+
*
|
2382
|
+
* a = [ "a", "b", "c", "d", "e" ]
|
2383
|
+
* a.clear #=> [ ]
|
2384
|
+
*/
|
2385
|
+
|
2386
|
+
VALUE
|
2387
|
+
rb_ary_clear(VALUE ary)
|
2388
|
+
{
|
2389
|
+
rb_ary_modify(ary);
|
2390
|
+
ARY_SET_LEN(ary, 0);
|
2391
|
+
if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
|
2392
|
+
ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2);
|
2393
|
+
}
|
2394
|
+
return ary;
|
2395
|
+
}
|
2396
|
+
|
2397
|
+
/*
|
2398
|
+
* call-seq:
|
2399
|
+
* array.fill(obj) -> array
|
2400
|
+
* array.fill(obj, start [, length]) -> array
|
2401
|
+
* array.fill(obj, range ) -> array
|
2402
|
+
* array.fill {|index| block } -> array
|
2403
|
+
* array.fill(start [, length] ) {|index| block } -> array
|
2404
|
+
* array.fill(range) {|index| block } -> array
|
2405
|
+
*
|
2406
|
+
* The first three forms set the selected elements of <i>self</i> (which
|
2407
|
+
* may be the entire array) to <i>obj</i>. A <i>start</i> of
|
2408
|
+
* <code>nil</code> is equivalent to zero. A <i>length</i> of
|
2409
|
+
* <code>nil</code> is equivalent to <i>self.length</i>. The last three
|
2410
|
+
* forms fill the array with the value of the block. The block is
|
2411
|
+
* passed the absolute index of each element to be filled.
|
2412
|
+
*
|
2413
|
+
* a = [ "a", "b", "c", "d" ]
|
2414
|
+
* a.fill("x") #=> ["x", "x", "x", "x"]
|
2415
|
+
* a.fill("z", 2, 2) #=> ["x", "x", "z", "z"]
|
2416
|
+
* a.fill("y", 0..1) #=> ["y", "y", "z", "z"]
|
2417
|
+
* a.fill {|i| i*i} #=> [0, 1, 4, 9]
|
2418
|
+
* a.fill(-2) {|i| i*i*i} #=> [0, 1, 8, 27]
|
2419
|
+
*/
|
2420
|
+
|
2421
|
+
static VALUE
|
2422
|
+
rb_ary_fill(int argc, VALUE *argv, VALUE ary)
|
2423
|
+
{
|
2424
|
+
VALUE item, arg1, arg2;
|
2425
|
+
long beg = 0, end = 0, len = 0;
|
2426
|
+
VALUE *p, *pend;
|
2427
|
+
int block_p = Qfalse;
|
2428
|
+
|
2429
|
+
if (rb_block_given_p()) {
|
2430
|
+
block_p = Qtrue;
|
2431
|
+
rb_scan_args(argc, argv, "02", &arg1, &arg2);
|
2432
|
+
argc += 1; /* hackish */
|
2433
|
+
}
|
2434
|
+
else {
|
2435
|
+
rb_scan_args(argc, argv, "12", &item, &arg1, &arg2);
|
2436
|
+
}
|
2437
|
+
switch (argc) {
|
2438
|
+
case 1:
|
2439
|
+
beg = 0;
|
2440
|
+
len = RARRAY_LEN(ary);
|
2441
|
+
break;
|
2442
|
+
case 2:
|
2443
|
+
if (rb_range_beg_len(arg1, &beg, &len, RARRAY_LEN(ary), 1)) {
|
2444
|
+
break;
|
2445
|
+
}
|
2446
|
+
/* fall through */
|
2447
|
+
case 3:
|
2448
|
+
beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1);
|
2449
|
+
if (beg < 0) {
|
2450
|
+
beg = RARRAY_LEN(ary) + beg;
|
2451
|
+
if (beg < 0) beg = 0;
|
2452
|
+
}
|
2453
|
+
len = NIL_P(arg2) ? RARRAY_LEN(ary) - beg : NUM2LONG(arg2);
|
2454
|
+
break;
|
2455
|
+
}
|
2456
|
+
rb_ary_modify(ary);
|
2457
|
+
if (len < 0) {
|
2458
|
+
return ary;
|
2459
|
+
}
|
2460
|
+
if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) {
|
2461
|
+
rb_raise(rb_eArgError, "argument too big");
|
2462
|
+
}
|
2463
|
+
end = beg + len;
|
2464
|
+
if (RARRAY_LEN(ary) < end) {
|
2465
|
+
if (end >= ARY_CAPA(ary)) {
|
2466
|
+
ary_resize_capa(ary, end);
|
2467
|
+
}
|
2468
|
+
rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), end - RARRAY_LEN(ary));
|
2469
|
+
ARY_SET_LEN(ary, end);
|
2470
|
+
}
|
2471
|
+
|
2472
|
+
if (block_p) {
|
2473
|
+
VALUE v;
|
2474
|
+
long i;
|
2475
|
+
|
2476
|
+
for (i=beg; i<end; i++) {
|
2477
|
+
v = rb_yield(LONG2NUM(i));
|
2478
|
+
if (i>=RARRAY_LEN(ary)) break;
|
2479
|
+
RARRAY_PTR(ary)[i] = v;
|
2480
|
+
}
|
2481
|
+
}
|
2482
|
+
else {
|
2483
|
+
p = RARRAY_PTR(ary) + beg;
|
2484
|
+
pend = p + len;
|
2485
|
+
while (p < pend) {
|
2486
|
+
*p++ = item;
|
2487
|
+
}
|
2488
|
+
}
|
2489
|
+
return ary;
|
2490
|
+
}
|
2491
|
+
|
2492
|
+
/*
|
2493
|
+
* call-seq:
|
2494
|
+
* array + other_array -> an_array
|
2495
|
+
*
|
2496
|
+
* Concatenation---Returns a new array built by concatenating the
|
2497
|
+
* two arrays together to produce a third array.
|
2498
|
+
*
|
2499
|
+
* [ 1, 2, 3 ] + [ 4, 5 ] #=> [ 1, 2, 3, 4, 5 ]
|
2500
|
+
*/
|
2501
|
+
|
2502
|
+
VALUE
|
2503
|
+
rb_ary_plus(VALUE x, VALUE y)
|
2504
|
+
{
|
2505
|
+
VALUE z;
|
2506
|
+
long len;
|
2507
|
+
|
2508
|
+
y = to_ary(y);
|
2509
|
+
len = RARRAY_LEN(x) + RARRAY_LEN(y);
|
2510
|
+
z = rb_ary_new2(len);
|
2511
|
+
MEMCPY(RARRAY_PTR(z), RARRAY_PTR(x), VALUE, RARRAY_LEN(x));
|
2512
|
+
MEMCPY(RARRAY_PTR(z) + RARRAY_LEN(x), RARRAY_PTR(y), VALUE, RARRAY_LEN(y));
|
2513
|
+
ARY_SET_LEN(z, len);
|
2514
|
+
return z;
|
2515
|
+
}
|
2516
|
+
|
2517
|
+
/*
|
2518
|
+
* call-seq:
|
2519
|
+
* array.concat(other_array) -> array
|
2520
|
+
*
|
2521
|
+
* Appends the elements in other_array to _self_.
|
2522
|
+
*
|
2523
|
+
* [ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ]
|
2524
|
+
*/
|
2525
|
+
|
2526
|
+
|
2527
|
+
VALUE
|
2528
|
+
rb_ary_concat(VALUE x, VALUE y)
|
2529
|
+
{
|
2530
|
+
y = to_ary(y);
|
2531
|
+
if (RARRAY_LEN(y) > 0) {
|
2532
|
+
rb_ary_splice(x, RARRAY_LEN(x), 0, y);
|
2533
|
+
}
|
2534
|
+
return x;
|
2535
|
+
}
|
2536
|
+
|
2537
|
+
|
2538
|
+
/*
|
2539
|
+
* call-seq:
|
2540
|
+
* array * int -> an_array
|
2541
|
+
* array * str -> a_string
|
2542
|
+
*
|
2543
|
+
* Repetition---With a String argument, equivalent to
|
2544
|
+
* self.join(str). Otherwise, returns a new array
|
2545
|
+
* built by concatenating the _int_ copies of _self_.
|
2546
|
+
*
|
2547
|
+
*
|
2548
|
+
* [ 1, 2, 3 ] * 3 #=> [ 1, 2, 3, 1, 2, 3, 1, 2, 3 ]
|
2549
|
+
* [ 1, 2, 3 ] * "," #=> "1,2,3"
|
2550
|
+
*
|
2551
|
+
*/
|
2552
|
+
|
2553
|
+
static VALUE
|
2554
|
+
rb_ary_times(VALUE ary, VALUE times)
|
2555
|
+
{
|
2556
|
+
VALUE ary2, tmp;
|
2557
|
+
long i, len;
|
2558
|
+
|
2559
|
+
tmp = rb_check_string_type(times);
|
2560
|
+
if (!NIL_P(tmp)) {
|
2561
|
+
return rb_ary_join(ary, tmp);
|
2562
|
+
}
|
2563
|
+
|
2564
|
+
len = NUM2LONG(times);
|
2565
|
+
if (len == 0) {
|
2566
|
+
ary2 = ary_new(rb_obj_class(ary), 0);
|
2567
|
+
goto out;
|
2568
|
+
}
|
2569
|
+
if (len < 0) {
|
2570
|
+
rb_raise(rb_eArgError, "negative argument");
|
2571
|
+
}
|
2572
|
+
if (ARY_MAX_SIZE/len < RARRAY_LEN(ary)) {
|
2573
|
+
rb_raise(rb_eArgError, "argument too big");
|
2574
|
+
}
|
2575
|
+
len *= RARRAY_LEN(ary);
|
2576
|
+
|
2577
|
+
ary2 = ary_new(rb_obj_class(ary), len);
|
2578
|
+
ARY_SET_LEN(ary2, len);
|
2579
|
+
|
2580
|
+
for (i=0; i<len; i+=RARRAY_LEN(ary)) {
|
2581
|
+
MEMCPY(RARRAY_PTR(ary2)+i, RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
|
2582
|
+
}
|
2583
|
+
out:
|
2584
|
+
OBJ_INFECT(ary2, ary);
|
2585
|
+
|
2586
|
+
return ary2;
|
2587
|
+
}
|
2588
|
+
|
2589
|
+
/*
|
2590
|
+
* call-seq:
|
2591
|
+
* array.assoc(obj) -> an_array or nil
|
2592
|
+
*
|
2593
|
+
* Searches through an array whose elements are also arrays
|
2594
|
+
* comparing _obj_ with the first element of each contained array
|
2595
|
+
* using obj.==.
|
2596
|
+
* Returns the first contained array that matches (that
|
2597
|
+
* is, the first associated array),
|
2598
|
+
* or +nil+ if no match is found.
|
2599
|
+
* See also <code>Array#rassoc</code>.
|
2600
|
+
*
|
2601
|
+
* s1 = [ "colors", "red", "blue", "green" ]
|
2602
|
+
* s2 = [ "letters", "a", "b", "c" ]
|
2603
|
+
* s3 = "foo"
|
2604
|
+
* a = [ s1, s2, s3 ]
|
2605
|
+
* a.assoc("letters") #=> [ "letters", "a", "b", "c" ]
|
2606
|
+
* a.assoc("foo") #=> nil
|
2607
|
+
*/
|
2608
|
+
|
2609
|
+
VALUE
|
2610
|
+
rb_ary_assoc(VALUE ary, VALUE key)
|
2611
|
+
{
|
2612
|
+
long i;
|
2613
|
+
VALUE v;
|
2614
|
+
|
2615
|
+
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
2616
|
+
v = rb_check_array_type(RARRAY_PTR(ary)[i]);
|
2617
|
+
if (!NIL_P(v) && RARRAY_LEN(v) > 0 &&
|
2618
|
+
rb_equal(RARRAY_PTR(v)[0], key))
|
2619
|
+
return v;
|
2620
|
+
}
|
2621
|
+
return Qnil;
|
2622
|
+
}
|
2623
|
+
|
2624
|
+
/*
|
2625
|
+
* call-seq:
|
2626
|
+
* array.rassoc(obj) -> an_array or nil
|
2627
|
+
*
|
2628
|
+
* Searches through the array whose elements are also arrays. Compares
|
2629
|
+
* _obj_ with the second element of each contained array using
|
2630
|
+
* <code>==</code>. Returns the first contained array that matches. See
|
2631
|
+
* also <code>Array#assoc</code>.
|
2632
|
+
*
|
2633
|
+
* a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
|
2634
|
+
* a.rassoc("two") #=> [2, "two"]
|
2635
|
+
* a.rassoc("four") #=> nil
|
2636
|
+
*/
|
2637
|
+
|
2638
|
+
VALUE
|
2639
|
+
rb_ary_rassoc(VALUE ary, VALUE value)
|
2640
|
+
{
|
2641
|
+
long i;
|
2642
|
+
VALUE v;
|
2643
|
+
|
2644
|
+
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
2645
|
+
v = RARRAY_PTR(ary)[i];
|
2646
|
+
if (TYPE(v) == T_ARRAY &&
|
2647
|
+
RARRAY_LEN(v) > 1 &&
|
2648
|
+
rb_equal(RARRAY_PTR(v)[1], value))
|
2649
|
+
return v;
|
2650
|
+
}
|
2651
|
+
return Qnil;
|
2652
|
+
}
|
2653
|
+
|
2654
|
+
static VALUE
|
2655
|
+
recursive_equal(VALUE ary1, VALUE ary2, int recur)
|
2656
|
+
{
|
2657
|
+
long i;
|
2658
|
+
|
2659
|
+
if (recur) return Qtrue; /* Subtle! */
|
2660
|
+
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
2661
|
+
if (!rb_equal(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
|
2662
|
+
return Qfalse;
|
2663
|
+
}
|
2664
|
+
return Qtrue;
|
2665
|
+
}
|
2666
|
+
|
2667
|
+
/*
|
2668
|
+
* call-seq:
|
2669
|
+
* array == other_array -> bool
|
2670
|
+
*
|
2671
|
+
* Equality---Two arrays are equal if they contain the same number
|
2672
|
+
* of elements and if each element is equal to (according to
|
2673
|
+
* Object.==) the corresponding element in the other array.
|
2674
|
+
*
|
2675
|
+
* [ "a", "c" ] == [ "a", "c", 7 ] #=> false
|
2676
|
+
* [ "a", "c", 7 ] == [ "a", "c", 7 ] #=> true
|
2677
|
+
* [ "a", "c", 7 ] == [ "a", "d", "f" ] #=> false
|
2678
|
+
*
|
2679
|
+
*/
|
2680
|
+
|
2681
|
+
static VALUE
|
2682
|
+
rb_ary_equal(VALUE ary1, VALUE ary2)
|
2683
|
+
{
|
2684
|
+
if (ary1 == ary2) return Qtrue;
|
2685
|
+
if (TYPE(ary2) != T_ARRAY) {
|
2686
|
+
if (!rb_respond_to(ary2, rb_intern("to_ary"))) {
|
2687
|
+
return Qfalse;
|
2688
|
+
}
|
2689
|
+
return rb_equal(ary2, ary1);
|
2690
|
+
}
|
2691
|
+
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
|
2692
|
+
return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2);
|
2693
|
+
}
|
2694
|
+
|
2695
|
+
static VALUE
|
2696
|
+
recursive_eql(VALUE ary1, VALUE ary2, int recur)
|
2697
|
+
{
|
2698
|
+
long i;
|
2699
|
+
|
2700
|
+
if (recur) return Qtrue; /* Subtle! */
|
2701
|
+
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
2702
|
+
if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
|
2703
|
+
return Qfalse;
|
2704
|
+
}
|
2705
|
+
return Qtrue;
|
2706
|
+
}
|
2707
|
+
|
2708
|
+
/*
|
2709
|
+
* call-seq:
|
2710
|
+
* array.eql?(other) -> true or false
|
2711
|
+
*
|
2712
|
+
* Returns <code>true</code> if _array_ and _other_ are the same object,
|
2713
|
+
* or are both arrays with the same content.
|
2714
|
+
*/
|
2715
|
+
|
2716
|
+
static VALUE
|
2717
|
+
rb_ary_eql(VALUE ary1, VALUE ary2)
|
2718
|
+
{
|
2719
|
+
if (ary1 == ary2) return Qtrue;
|
2720
|
+
if (TYPE(ary2) != T_ARRAY) return Qfalse;
|
2721
|
+
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
|
2722
|
+
return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
|
2723
|
+
}
|
2724
|
+
|
2725
|
+
static VALUE
|
2726
|
+
recursive_hash(VALUE ary, VALUE dummy, int recur)
|
2727
|
+
{
|
2728
|
+
long i, h;
|
2729
|
+
VALUE n;
|
2730
|
+
|
2731
|
+
if (recur) {
|
2732
|
+
return LONG2FIX(0);
|
2733
|
+
}
|
2734
|
+
h = RARRAY_LEN(ary);
|
2735
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2736
|
+
h = (h << 1) | (h<0 ? 1 : 0);
|
2737
|
+
n = rb_hash(RARRAY_PTR(ary)[i]);
|
2738
|
+
h ^= NUM2LONG(n);
|
2739
|
+
}
|
2740
|
+
return LONG2FIX(h);
|
2741
|
+
}
|
2742
|
+
|
2743
|
+
/*
|
2744
|
+
* call-seq:
|
2745
|
+
* array.hash -> fixnum
|
2746
|
+
*
|
2747
|
+
* Compute a hash-code for this array. Two arrays with the same content
|
2748
|
+
* will have the same hash code (and will compare using <code>eql?</code>).
|
2749
|
+
*/
|
2750
|
+
|
2751
|
+
static VALUE
|
2752
|
+
rb_ary_hash(VALUE ary)
|
2753
|
+
{
|
2754
|
+
return rb_exec_recursive(recursive_hash, ary, 0);
|
2755
|
+
}
|
2756
|
+
|
2757
|
+
/*
|
2758
|
+
* call-seq:
|
2759
|
+
* array.include?(obj) -> true or false
|
2760
|
+
*
|
2761
|
+
* Returns <code>true</code> if the given object is present in
|
2762
|
+
* <i>self</i> (that is, if any object <code>==</code> <i>anObject</i>),
|
2763
|
+
* <code>false</code> otherwise.
|
2764
|
+
*
|
2765
|
+
* a = [ "a", "b", "c" ]
|
2766
|
+
* a.include?("b") #=> true
|
2767
|
+
* a.include?("z") #=> false
|
2768
|
+
*/
|
2769
|
+
|
2770
|
+
VALUE
|
2771
|
+
rb_ary_includes(VALUE ary, VALUE item)
|
2772
|
+
{
|
2773
|
+
long i;
|
2774
|
+
|
2775
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
2776
|
+
if (rb_equal(RARRAY_PTR(ary)[i], item)) {
|
2777
|
+
return Qtrue;
|
2778
|
+
}
|
2779
|
+
}
|
2780
|
+
return Qfalse;
|
2781
|
+
}
|
2782
|
+
|
2783
|
+
|
2784
|
+
static VALUE
|
2785
|
+
recursive_cmp(VALUE ary1, VALUE ary2, int recur)
|
2786
|
+
{
|
2787
|
+
long i, len;
|
2788
|
+
|
2789
|
+
if (recur) return Qundef; /* Subtle! */
|
2790
|
+
len = RARRAY_LEN(ary1);
|
2791
|
+
if (len > RARRAY_LEN(ary2)) {
|
2792
|
+
len = RARRAY_LEN(ary2);
|
2793
|
+
}
|
2794
|
+
for (i=0; i<len; i++) {
|
2795
|
+
VALUE v = rb_funcall(rb_ary_elt(ary1, i), id_cmp, 1, rb_ary_elt(ary2, i));
|
2796
|
+
if (v != INT2FIX(0)) {
|
2797
|
+
return v;
|
2798
|
+
}
|
2799
|
+
}
|
2800
|
+
return Qundef;
|
2801
|
+
}
|
2802
|
+
|
2803
|
+
/*
|
2804
|
+
* call-seq:
|
2805
|
+
* array <=> other_array -> -1, 0, +1
|
2806
|
+
*
|
2807
|
+
* Comparison---Returns an integer (-1, 0,
|
2808
|
+
* or +1) if this array is less than, equal to, or greater than
|
2809
|
+
* other_array. Each object in each array is compared
|
2810
|
+
* (using <=>). If any value isn't
|
2811
|
+
* equal, then that inequality is the return value. If all the
|
2812
|
+
* values found are equal, then the return is based on a
|
2813
|
+
* comparison of the array lengths. Thus, two arrays are
|
2814
|
+
* ``equal'' according to <code>Array#<=></code> if and only if they have
|
2815
|
+
* the same length and the value of each element is equal to the
|
2816
|
+
* value of the corresponding element in the other array.
|
2817
|
+
*
|
2818
|
+
* [ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1
|
2819
|
+
* [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1
|
2820
|
+
*
|
2821
|
+
*/
|
2822
|
+
|
2823
|
+
VALUE
|
2824
|
+
rb_ary_cmp(VALUE ary1, VALUE ary2)
|
2825
|
+
{
|
2826
|
+
long len;
|
2827
|
+
VALUE v;
|
2828
|
+
|
2829
|
+
ary2 = to_ary(ary2);
|
2830
|
+
if (ary1 == ary2) return INT2FIX(0);
|
2831
|
+
v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2);
|
2832
|
+
if (v != Qundef) return v;
|
2833
|
+
len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2);
|
2834
|
+
if (len == 0) return INT2FIX(0);
|
2835
|
+
if (len > 0) return INT2FIX(1);
|
2836
|
+
return INT2FIX(-1);
|
2837
|
+
}
|
2838
|
+
|
2839
|
+
static VALUE
|
2840
|
+
ary_make_hash(VALUE ary1, VALUE ary2)
|
2841
|
+
{
|
2842
|
+
VALUE hash = rb_hash_new();
|
2843
|
+
long i;
|
2844
|
+
|
2845
|
+
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
2846
|
+
rb_hash_aset(hash, RARRAY_PTR(ary1)[i], Qtrue);
|
2847
|
+
}
|
2848
|
+
if (ary2) {
|
2849
|
+
for (i=0; i<RARRAY_LEN(ary2); i++) {
|
2850
|
+
rb_hash_aset(hash, RARRAY_PTR(ary2)[i], Qtrue);
|
2851
|
+
}
|
2852
|
+
}
|
2853
|
+
return hash;
|
2854
|
+
}
|
2855
|
+
|
2856
|
+
/*
|
2857
|
+
* call-seq:
|
2858
|
+
* array - other_array -> an_array
|
2859
|
+
*
|
2860
|
+
* Array Difference---Returns a new array that is a copy of
|
2861
|
+
* the original array, removing any items that also appear in
|
2862
|
+
* other_array. (If you need set-like behavior, see the
|
2863
|
+
* library class Set.)
|
2864
|
+
*
|
2865
|
+
* [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ]
|
2866
|
+
*/
|
2867
|
+
|
2868
|
+
static VALUE
|
2869
|
+
rb_ary_diff(VALUE ary1, VALUE ary2)
|
2870
|
+
{
|
2871
|
+
VALUE ary3;
|
2872
|
+
volatile VALUE hash;
|
2873
|
+
long i;
|
2874
|
+
|
2875
|
+
hash = ary_make_hash(to_ary(ary2), 0);
|
2876
|
+
ary3 = rb_ary_new();
|
2877
|
+
|
2878
|
+
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
2879
|
+
if (st_lookup(RHASH_TBL(hash), RARRAY_PTR(ary1)[i], 0)) continue;
|
2880
|
+
rb_ary_push(ary3, rb_ary_elt(ary1, i));
|
2881
|
+
}
|
2882
|
+
return ary3;
|
2883
|
+
}
|
2884
|
+
|
2885
|
+
/*
|
2886
|
+
* call-seq:
|
2887
|
+
* array & other_array
|
2888
|
+
*
|
2889
|
+
* Set Intersection---Returns a new array
|
2890
|
+
* containing elements common to the two arrays, with no duplicates.
|
2891
|
+
*
|
2892
|
+
* [ 1, 1, 3, 5 ] & [ 1, 2, 3 ] #=> [ 1, 3 ]
|
2893
|
+
*/
|
2894
|
+
|
2895
|
+
|
2896
|
+
static VALUE
|
2897
|
+
rb_ary_and(VALUE ary1, VALUE ary2)
|
2898
|
+
{
|
2899
|
+
VALUE hash, ary3, v, vv;
|
2900
|
+
long i;
|
2901
|
+
|
2902
|
+
ary2 = to_ary(ary2);
|
2903
|
+
ary3 = rb_ary_new2(RARRAY_LEN(ary1) < RARRAY_LEN(ary2) ?
|
2904
|
+
RARRAY_LEN(ary1) : RARRAY_LEN(ary2));
|
2905
|
+
hash = ary_make_hash(ary2, 0);
|
2906
|
+
|
2907
|
+
if (RHASH_EMPTY_P(hash))
|
2908
|
+
return ary3;
|
2909
|
+
|
2910
|
+
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
2911
|
+
v = vv = rb_ary_elt(ary1, i);
|
2912
|
+
if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) {
|
2913
|
+
rb_ary_push(ary3, v);
|
2914
|
+
}
|
2915
|
+
}
|
2916
|
+
|
2917
|
+
return ary3;
|
2918
|
+
}
|
2919
|
+
|
2920
|
+
/*
|
2921
|
+
* call-seq:
|
2922
|
+
* array | other_array -> an_array
|
2923
|
+
*
|
2924
|
+
* Set Union---Returns a new array by joining this array with
|
2925
|
+
* other_array, removing duplicates.
|
2926
|
+
*
|
2927
|
+
* [ "a", "b", "c" ] | [ "c", "d", "a" ]
|
2928
|
+
* #=> [ "a", "b", "c", "d" ]
|
2929
|
+
*/
|
2930
|
+
|
2931
|
+
static VALUE
|
2932
|
+
rb_ary_or(VALUE ary1, VALUE ary2)
|
2933
|
+
{
|
2934
|
+
VALUE hash, ary3;
|
2935
|
+
VALUE v, vv;
|
2936
|
+
long i;
|
2937
|
+
|
2938
|
+
ary2 = to_ary(ary2);
|
2939
|
+
ary3 = rb_ary_new2(RARRAY_LEN(ary1)+RARRAY_LEN(ary2));
|
2940
|
+
hash = ary_make_hash(ary1, ary2);
|
2941
|
+
|
2942
|
+
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
2943
|
+
v = vv = rb_ary_elt(ary1, i);
|
2944
|
+
if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) {
|
2945
|
+
rb_ary_push(ary3, v);
|
2946
|
+
}
|
2947
|
+
}
|
2948
|
+
for (i=0; i<RARRAY_LEN(ary2); i++) {
|
2949
|
+
v = vv = rb_ary_elt(ary2, i);
|
2950
|
+
if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) {
|
2951
|
+
rb_ary_push(ary3, v);
|
2952
|
+
}
|
2953
|
+
}
|
2954
|
+
return ary3;
|
2955
|
+
}
|
2956
|
+
|
2957
|
+
/*
|
2958
|
+
* call-seq:
|
2959
|
+
* array.uniq! -> array or nil
|
2960
|
+
*
|
2961
|
+
* Removes duplicate elements from _self_.
|
2962
|
+
* Returns <code>nil</code> if no changes are made (that is, no
|
2963
|
+
* duplicates are found).
|
2964
|
+
*
|
2965
|
+
* a = [ "a", "a", "b", "b", "c" ]
|
2966
|
+
* a.uniq! #=> ["a", "b", "c"]
|
2967
|
+
* b = [ "a", "b", "c" ]
|
2968
|
+
* b.uniq! #=> nil
|
2969
|
+
*/
|
2970
|
+
|
2971
|
+
static VALUE
|
2972
|
+
rb_ary_uniq_bang(VALUE ary)
|
2973
|
+
{
|
2974
|
+
VALUE hash, v, vv;
|
2975
|
+
long i, j;
|
2976
|
+
|
2977
|
+
hash = ary_make_hash(ary, 0);
|
2978
|
+
|
2979
|
+
if (RARRAY_LEN(ary) == RHASH_SIZE(hash)) {
|
2980
|
+
return Qnil;
|
2981
|
+
}
|
2982
|
+
for (i=j=0; i<RARRAY_LEN(ary); i++) {
|
2983
|
+
v = vv = rb_ary_elt(ary, i);
|
2984
|
+
if (st_delete(RHASH_TBL(hash), (st_data_t*)&vv, 0)) {
|
2985
|
+
rb_ary_store(ary, j++, v);
|
2986
|
+
}
|
2987
|
+
}
|
2988
|
+
ARY_SET_LEN(ary, j);
|
2989
|
+
|
2990
|
+
return ary;
|
2991
|
+
}
|
2992
|
+
|
2993
|
+
/*
|
2994
|
+
* call-seq:
|
2995
|
+
* array.uniq -> an_array
|
2996
|
+
*
|
2997
|
+
* Returns a new array by removing duplicate values in <i>self</i>.
|
2998
|
+
*
|
2999
|
+
* a = [ "a", "a", "b", "b", "c" ]
|
3000
|
+
* a.uniq #=> ["a", "b", "c"]
|
3001
|
+
*/
|
3002
|
+
|
3003
|
+
static VALUE
|
3004
|
+
rb_ary_uniq(VALUE ary)
|
3005
|
+
{
|
3006
|
+
ary = rb_ary_dup(ary);
|
3007
|
+
rb_ary_uniq_bang(ary);
|
3008
|
+
return ary;
|
3009
|
+
}
|
3010
|
+
|
3011
|
+
/*
|
3012
|
+
* call-seq:
|
3013
|
+
* array.compact! -> array or nil
|
3014
|
+
*
|
3015
|
+
* Removes +nil+ elements from array.
|
3016
|
+
* Returns +nil+ if no changes were made.
|
3017
|
+
*
|
3018
|
+
* [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ]
|
3019
|
+
* [ "a", "b", "c" ].compact! #=> nil
|
3020
|
+
*/
|
3021
|
+
|
3022
|
+
static VALUE
|
3023
|
+
rb_ary_compact_bang(VALUE ary)
|
3024
|
+
{
|
3025
|
+
VALUE *p, *t, *end;
|
3026
|
+
long n;
|
3027
|
+
|
3028
|
+
rb_ary_modify(ary);
|
3029
|
+
p = t = RARRAY_PTR(ary);
|
3030
|
+
end = p + RARRAY_LEN(ary);
|
3031
|
+
|
3032
|
+
while (t < end) {
|
3033
|
+
if (NIL_P(*t)) t++;
|
3034
|
+
else *p++ = *t++;
|
3035
|
+
}
|
3036
|
+
n = p - RARRAY_PTR(ary);
|
3037
|
+
if (RARRAY_LEN(ary) == n) {
|
3038
|
+
return Qnil;
|
3039
|
+
}
|
3040
|
+
ARY_SET_LEN(ary, n);
|
3041
|
+
if (n * 2 < ARY_CAPA(ary) && ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) {
|
3042
|
+
ary_resize_capa(ary, n * 2);
|
3043
|
+
}
|
3044
|
+
|
3045
|
+
return ary;
|
3046
|
+
}
|
3047
|
+
|
3048
|
+
/*
|
3049
|
+
* call-seq:
|
3050
|
+
* array.compact -> an_array
|
3051
|
+
*
|
3052
|
+
* Returns a copy of _self_ with all +nil+ elements removed.
|
3053
|
+
*
|
3054
|
+
* [ "a", nil, "b", nil, "c", nil ].compact
|
3055
|
+
* #=> [ "a", "b", "c" ]
|
3056
|
+
*/
|
3057
|
+
|
3058
|
+
static VALUE
|
3059
|
+
rb_ary_compact(VALUE ary)
|
3060
|
+
{
|
3061
|
+
ary = rb_ary_dup(ary);
|
3062
|
+
rb_ary_compact_bang(ary);
|
3063
|
+
return ary;
|
3064
|
+
}
|
3065
|
+
|
3066
|
+
/*
|
3067
|
+
* call-seq:
|
3068
|
+
* array.count -> int
|
3069
|
+
* array.count(obj) -> int
|
3070
|
+
* array.count { |item| block } -> int
|
3071
|
+
*
|
3072
|
+
* Returns the number of elements. If an argument is given, counts
|
3073
|
+
* the number of elements which equals to <i>obj</i>. If a block is
|
3074
|
+
* given, counts the number of elements yielding a true value.
|
3075
|
+
*
|
3076
|
+
* ary = [1, 2, 4, 2]
|
3077
|
+
* ary.count # => 4
|
3078
|
+
* ary.count(2) # => 2
|
3079
|
+
* ary.count{|x|x%2==0} # => 3
|
3080
|
+
*
|
3081
|
+
*/
|
3082
|
+
|
3083
|
+
static VALUE
|
3084
|
+
rb_ary_count(int argc, VALUE *argv, VALUE ary)
|
3085
|
+
{
|
3086
|
+
long n = 0;
|
3087
|
+
|
3088
|
+
if (argc == 0) {
|
3089
|
+
VALUE *p, *pend;
|
3090
|
+
|
3091
|
+
if (!rb_block_given_p())
|
3092
|
+
return LONG2NUM(RARRAY_LEN(ary));
|
3093
|
+
|
3094
|
+
for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) {
|
3095
|
+
if (RTEST(rb_yield(*p))) n++;
|
3096
|
+
}
|
3097
|
+
}
|
3098
|
+
else {
|
3099
|
+
VALUE obj, *p, *pend;
|
3100
|
+
|
3101
|
+
rb_scan_args(argc, argv, "1", &obj);
|
3102
|
+
if (rb_block_given_p()) {
|
3103
|
+
rb_warn("given block not used");
|
3104
|
+
}
|
3105
|
+
for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) {
|
3106
|
+
if (rb_equal(*p, obj)) n++;
|
3107
|
+
}
|
3108
|
+
}
|
3109
|
+
|
3110
|
+
return LONG2NUM(n);
|
3111
|
+
}
|
3112
|
+
|
3113
|
+
static VALUE
|
3114
|
+
flatten(VALUE ary, int level, int *modified)
|
3115
|
+
{
|
3116
|
+
long i = 0;
|
3117
|
+
VALUE stack, result, tmp, elt;
|
3118
|
+
st_table *memo;
|
3119
|
+
st_data_t id;
|
3120
|
+
|
3121
|
+
stack = ary_new(0, ARY_DEFAULT_SIZE);
|
3122
|
+
result = ary_new(0, RARRAY_LEN(ary));
|
3123
|
+
memo = st_init_numtable();
|
3124
|
+
st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue);
|
3125
|
+
*modified = 0;
|
3126
|
+
|
3127
|
+
while (1) {
|
3128
|
+
while (i < RARRAY_LEN(ary)) {
|
3129
|
+
elt = RARRAY_PTR(ary)[i++];
|
3130
|
+
tmp = rb_check_array_type(elt);
|
3131
|
+
if (RBASIC(result)->klass) {
|
3132
|
+
rb_raise(rb_eRuntimeError, "flatten reentered");
|
3133
|
+
}
|
3134
|
+
if (NIL_P(tmp) || (level >= 0 && RARRAY_LEN(stack) / 2 >= level)) {
|
3135
|
+
rb_ary_push(result, elt);
|
3136
|
+
}
|
3137
|
+
else {
|
3138
|
+
*modified = 1;
|
3139
|
+
id = (st_data_t)tmp;
|
3140
|
+
if (st_lookup(memo, id, 0)) {
|
3141
|
+
st_free_table(memo);
|
3142
|
+
rb_raise(rb_eArgError, "tried to flatten recursive array");
|
3143
|
+
}
|
3144
|
+
st_insert(memo, id, (st_data_t)Qtrue);
|
3145
|
+
rb_ary_push(stack, ary);
|
3146
|
+
rb_ary_push(stack, LONG2NUM(i));
|
3147
|
+
ary = tmp;
|
3148
|
+
i = 0;
|
3149
|
+
}
|
3150
|
+
}
|
3151
|
+
if (RARRAY_LEN(stack) == 0) {
|
3152
|
+
break;
|
3153
|
+
}
|
3154
|
+
id = (st_data_t)ary;
|
3155
|
+
st_delete(memo, &id, 0);
|
3156
|
+
tmp = rb_ary_pop(stack);
|
3157
|
+
i = NUM2LONG(tmp);
|
3158
|
+
ary = rb_ary_pop(stack);
|
3159
|
+
}
|
3160
|
+
|
3161
|
+
st_free_table(memo);
|
3162
|
+
|
3163
|
+
RBASIC(result)->klass = rb_class_of(ary);
|
3164
|
+
return result;
|
3165
|
+
}
|
3166
|
+
|
3167
|
+
/*
|
3168
|
+
* call-seq:
|
3169
|
+
* array.flatten! -> array or nil
|
3170
|
+
* array.flatten!(level) -> array or nil
|
3171
|
+
*
|
3172
|
+
* Flattens _self_ in place.
|
3173
|
+
* Returns <code>nil</code> if no modifications were made (i.e.,
|
3174
|
+
* <i>array</i> contains no subarrays.) If the optional <i>level</i>
|
3175
|
+
* argument determines the level of recursion to flatten.
|
3176
|
+
*
|
3177
|
+
* a = [ 1, 2, [3, [4, 5] ] ]
|
3178
|
+
* a.flatten! #=> [1, 2, 3, 4, 5]
|
3179
|
+
* a.flatten! #=> nil
|
3180
|
+
* a #=> [1, 2, 3, 4, 5]
|
3181
|
+
* a = [ 1, 2, [3, [4, 5] ] ]
|
3182
|
+
* a.flatten!(1) #=> [1, 2, 3, [4, 5]]
|
3183
|
+
*/
|
3184
|
+
|
3185
|
+
static VALUE
|
3186
|
+
rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
|
3187
|
+
{
|
3188
|
+
int mod = 0, level = -1;
|
3189
|
+
VALUE result, lv;
|
3190
|
+
|
3191
|
+
rb_scan_args(argc, argv, "01", &lv);
|
3192
|
+
if (!NIL_P(lv)) level = NUM2INT(lv);
|
3193
|
+
if (level == 0) return Qnil;
|
3194
|
+
|
3195
|
+
result = flatten(ary, level, &mod);
|
3196
|
+
if (mod == 0) return Qnil;
|
3197
|
+
rb_ary_replace(ary, result);
|
3198
|
+
|
3199
|
+
return ary;
|
3200
|
+
}
|
3201
|
+
|
3202
|
+
/*
|
3203
|
+
* call-seq:
|
3204
|
+
* array.flatten -> an_array
|
3205
|
+
* array.flatten(level) -> an_array
|
3206
|
+
*
|
3207
|
+
* Returns a new array that is a one-dimensional flattening of this
|
3208
|
+
* array (recursively). That is, for every element that is an array,
|
3209
|
+
* extract its elements into the new array. If the optional
|
3210
|
+
* <i>level</i> argument determines the level of recursion to flatten.
|
3211
|
+
*
|
3212
|
+
* s = [ 1, 2, 3 ] #=> [1, 2, 3]
|
3213
|
+
* t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
|
3214
|
+
* a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
|
3215
|
+
* a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
3216
|
+
* a = [ 1, 2, [3, [4, 5] ] ]
|
3217
|
+
* a.flatten(1) #=> [1, 2, 3, [4, 5]]
|
3218
|
+
*/
|
3219
|
+
|
3220
|
+
static VALUE
|
3221
|
+
rb_ary_flatten(int argc, VALUE *argv, VALUE ary)
|
3222
|
+
{
|
3223
|
+
int mod = 0, level = -1;
|
3224
|
+
VALUE result, lv;
|
3225
|
+
|
3226
|
+
rb_scan_args(argc, argv, "01", &lv);
|
3227
|
+
if (!NIL_P(lv)) level = NUM2INT(lv);
|
3228
|
+
if (level == 0) return ary_make_shared_copy(ary);
|
3229
|
+
|
3230
|
+
result = flatten(ary, level, &mod);
|
3231
|
+
OBJ_INFECT(result, ary);
|
3232
|
+
|
3233
|
+
return result;
|
3234
|
+
}
|
3235
|
+
|
3236
|
+
/*
|
3237
|
+
* call-seq:
|
3238
|
+
* array.shuffle! -> array
|
3239
|
+
*
|
3240
|
+
* Shuffles elements in _self_ in place.
|
3241
|
+
*/
|
3242
|
+
|
3243
|
+
|
3244
|
+
static VALUE
|
3245
|
+
rb_ary_shuffle_bang(VALUE ary)
|
3246
|
+
{
|
3247
|
+
long i = RARRAY_LEN(ary);
|
3248
|
+
|
3249
|
+
rb_ary_modify(ary);
|
3250
|
+
while (i) {
|
3251
|
+
long j = rb_genrand_real()*i;
|
3252
|
+
VALUE tmp = RARRAY_PTR(ary)[--i];
|
3253
|
+
RARRAY_PTR(ary)[i] = RARRAY_PTR(ary)[j];
|
3254
|
+
RARRAY_PTR(ary)[j] = tmp;
|
3255
|
+
}
|
3256
|
+
return ary;
|
3257
|
+
}
|
3258
|
+
|
3259
|
+
|
3260
|
+
/*
|
3261
|
+
* call-seq:
|
3262
|
+
* array.shuffle -> an_array
|
3263
|
+
*
|
3264
|
+
* Returns a new array with elements of this array shuffled.
|
3265
|
+
*
|
3266
|
+
* a = [ 1, 2, 3 ] #=> [1, 2, 3]
|
3267
|
+
* a.shuffle #=> [2, 3, 1]
|
3268
|
+
*/
|
3269
|
+
|
3270
|
+
static VALUE
|
3271
|
+
rb_ary_shuffle(VALUE ary)
|
3272
|
+
{
|
3273
|
+
ary = rb_ary_dup(ary);
|
3274
|
+
rb_ary_shuffle_bang(ary);
|
3275
|
+
return ary;
|
3276
|
+
}
|
3277
|
+
|
3278
|
+
|
3279
|
+
/*
|
3280
|
+
* call-seq:
|
3281
|
+
* array.sample -> obj
|
3282
|
+
* array.sample(n) -> an_array
|
3283
|
+
*
|
3284
|
+
* Choose a random element, or the random +n+ elements, from the array.
|
3285
|
+
* If the array is empty, the first form returns <code>nil</code>, and the
|
3286
|
+
* second form returns an empty array.
|
3287
|
+
*
|
3288
|
+
*/
|
3289
|
+
|
3290
|
+
|
3291
|
+
static VALUE
|
3292
|
+
rb_ary_sample(int argc, VALUE *argv, VALUE ary)
|
3293
|
+
{
|
3294
|
+
VALUE nv, result, *ptr;
|
3295
|
+
long n, len, i, j, k, idx[10];
|
3296
|
+
|
3297
|
+
len = RARRAY_LEN(ary);
|
3298
|
+
if (argc == 0) {
|
3299
|
+
if (len == 0) return Qnil;
|
3300
|
+
i = len == 1 ? 0 : rb_genrand_real()*len;
|
3301
|
+
return RARRAY_PTR(ary)[i];
|
3302
|
+
}
|
3303
|
+
rb_scan_args(argc, argv, "1", &nv);
|
3304
|
+
n = NUM2LONG(nv);
|
3305
|
+
if (n < 0) rb_raise(rb_eArgError, "negative sample number");
|
3306
|
+
ptr = RARRAY_PTR(ary);
|
3307
|
+
len = RARRAY_LEN(ary);
|
3308
|
+
if (n > len) n = len;
|
3309
|
+
switch (n) {
|
3310
|
+
case 0: return rb_ary_new2(0);
|
3311
|
+
case 1:
|
3312
|
+
return rb_ary_new4(1, &ptr[(long)(rb_genrand_real()*len)]);
|
3313
|
+
case 2:
|
3314
|
+
i = rb_genrand_real()*len;
|
3315
|
+
j = rb_genrand_real()*(len-1);
|
3316
|
+
if (j >= i) j++;
|
3317
|
+
return rb_ary_new3(2, ptr[i], ptr[j]);
|
3318
|
+
case 3:
|
3319
|
+
i = rb_genrand_real()*len;
|
3320
|
+
j = rb_genrand_real()*(len-1);
|
3321
|
+
k = rb_genrand_real()*(len-2);
|
3322
|
+
{
|
3323
|
+
long l = j, g = i;
|
3324
|
+
if (j >= i) l = i, g = ++j;
|
3325
|
+
if (k >= l && (++k >= g)) ++k;
|
3326
|
+
}
|
3327
|
+
return rb_ary_new3(3, ptr[i], ptr[j], ptr[k]);
|
3328
|
+
}
|
3329
|
+
if (n < sizeof(idx)/sizeof(idx[0])) {
|
3330
|
+
long sorted[sizeof(idx)/sizeof(idx[0])];
|
3331
|
+
sorted[0] = idx[0] = rb_genrand_real()*len;
|
3332
|
+
for (i=1; i<n; i++) {
|
3333
|
+
k = rb_genrand_real()*--len;
|
3334
|
+
for (j = 0; j < i; ++j) {
|
3335
|
+
if (k < sorted[j]) break;
|
3336
|
+
++k;
|
3337
|
+
}
|
3338
|
+
memmove(&sorted[j+1], &sorted[j], sizeof(sorted[0])*(i-j));
|
3339
|
+
sorted[j] = idx[i] = k;
|
3340
|
+
}
|
3341
|
+
result = rb_ary_new2(n);
|
3342
|
+
for (i=0; i<n; i++) {
|
3343
|
+
RARRAY_PTR(result)[i] = RARRAY_PTR(ary)[idx[i]];
|
3344
|
+
}
|
3345
|
+
}
|
3346
|
+
else {
|
3347
|
+
result = rb_ary_new4(len, ptr);
|
3348
|
+
RB_GC_GUARD(ary);
|
3349
|
+
for (i=0; i<n; i++) {
|
3350
|
+
j = (long)(rb_genrand_real()*(len-i)) + i;
|
3351
|
+
nv = RARRAY_PTR(result)[j];
|
3352
|
+
RARRAY_PTR(result)[j] = RARRAY_PTR(result)[i];
|
3353
|
+
RARRAY_PTR(result)[i] = nv;
|
3354
|
+
}
|
3355
|
+
}
|
3356
|
+
ARY_SET_LEN(result, n);
|
3357
|
+
|
3358
|
+
return result;
|
3359
|
+
}
|
3360
|
+
|
3361
|
+
|
3362
|
+
/*
|
3363
|
+
* call-seq:
|
3364
|
+
* ary.cycle {|obj| block }
|
3365
|
+
* ary.cycle(n) {|obj| block }
|
3366
|
+
*
|
3367
|
+
* Calls <i>block</i> for each element repeatedly _n_ times or
|
3368
|
+
* forever if none or nil is given. If a non-positive number is
|
3369
|
+
* given or the array is empty, does nothing. Returns nil if the
|
3370
|
+
* loop has finished without getting interrupted.
|
3371
|
+
*
|
3372
|
+
* a = ["a", "b", "c"]
|
3373
|
+
* a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever.
|
3374
|
+
* a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c.
|
3375
|
+
*
|
3376
|
+
*/
|
3377
|
+
|
3378
|
+
static VALUE
|
3379
|
+
rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
|
3380
|
+
{
|
3381
|
+
long n, i;
|
3382
|
+
VALUE nv = Qnil;
|
3383
|
+
|
3384
|
+
rb_scan_args(argc, argv, "01", &nv);
|
3385
|
+
|
3386
|
+
RETURN_ENUMERATOR(ary, argc, argv);
|
3387
|
+
if (NIL_P(nv)) {
|
3388
|
+
n = -1;
|
3389
|
+
}
|
3390
|
+
else {
|
3391
|
+
n = NUM2LONG(nv);
|
3392
|
+
if (n <= 0) return Qnil;
|
3393
|
+
}
|
3394
|
+
|
3395
|
+
while (RARRAY_LEN(ary) > 0 && (n < 0 || 0 < n--)) {
|
3396
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
3397
|
+
rb_yield(RARRAY_PTR(ary)[i]);
|
3398
|
+
}
|
3399
|
+
}
|
3400
|
+
return Qnil;
|
3401
|
+
}
|
3402
|
+
|
3403
|
+
#define tmpbuf(n, size) rb_str_tmp_new((n)*(size))
|
3404
|
+
|
3405
|
+
/*
|
3406
|
+
* Recursively compute permutations of r elements of the set [0..n-1].
|
3407
|
+
* When we have a complete permutation of array indexes, copy the values
|
3408
|
+
* at those indexes into a new array and yield that array.
|
3409
|
+
*
|
3410
|
+
* n: the size of the set
|
3411
|
+
* r: the number of elements in each permutation
|
3412
|
+
* p: the array (of size r) that we're filling in
|
3413
|
+
* index: what index we're filling in now
|
3414
|
+
* used: an array of booleans: whether a given index is already used
|
3415
|
+
* values: the Ruby array that holds the actual values to permute
|
3416
|
+
*/
|
3417
|
+
static void
|
3418
|
+
permute0(long n, long r, long *p, long index, int *used, VALUE values)
|
3419
|
+
{
|
3420
|
+
long i,j;
|
3421
|
+
for (i = 0; i < n; i++) {
|
3422
|
+
if (used[i] == 0) {
|
3423
|
+
p[index] = i;
|
3424
|
+
if (index < r-1) { /* if not done yet */
|
3425
|
+
used[i] = 1; /* mark index used */
|
3426
|
+
permute0(n, r, p, index+1, /* recurse */
|
3427
|
+
used, values);
|
3428
|
+
used[i] = 0; /* index unused */
|
3429
|
+
}
|
3430
|
+
else {
|
3431
|
+
/* We have a complete permutation of array indexes */
|
3432
|
+
/* Build a ruby array of the corresponding values */
|
3433
|
+
/* And yield it to the associated block */
|
3434
|
+
VALUE result = rb_ary_new2(r);
|
3435
|
+
VALUE *result_array = RARRAY_PTR(result);
|
3436
|
+
const VALUE *values_array = RARRAY_PTR(values);
|
3437
|
+
|
3438
|
+
for (j = 0; j < r; j++) result_array[j] = values_array[p[j]];
|
3439
|
+
ARY_SET_LEN(result, r);
|
3440
|
+
rb_yield(result);
|
3441
|
+
}
|
3442
|
+
}
|
3443
|
+
}
|
3444
|
+
}
|
3445
|
+
|
3446
|
+
/*
|
3447
|
+
* call-seq:
|
3448
|
+
* ary.permutation { |p| block } -> array
|
3449
|
+
* ary.permutation -> enumerator
|
3450
|
+
* ary.permutation(n) { |p| block } -> array
|
3451
|
+
* ary.permutation(n) -> enumerator
|
3452
|
+
*
|
3453
|
+
* When invoked with a block, yield all permutations of length <i>n</i>
|
3454
|
+
* of the elements of <i>ary</i>, then return the array itself.
|
3455
|
+
* If <i>n</i> is not specified, yield all permutations of all elements.
|
3456
|
+
* The implementation makes no guarantees about the order in which
|
3457
|
+
* the permutations are yielded.
|
3458
|
+
*
|
3459
|
+
* When invoked without a block, return an enumerator object instead.
|
3460
|
+
*
|
3461
|
+
* Examples:
|
3462
|
+
*
|
3463
|
+
* a = [1, 2, 3]
|
3464
|
+
* a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
|
3465
|
+
* a.permutation(1).to_a #=> [[1],[2],[3]]
|
3466
|
+
* a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
|
3467
|
+
* a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
|
3468
|
+
* a.permutation(0).to_a #=> [[]] # one permutation of length 0
|
3469
|
+
* a.permutation(4).to_a #=> [] # no permutations of length 4
|
3470
|
+
*/
|
3471
|
+
|
3472
|
+
static VALUE
|
3473
|
+
rb_ary_permutation(int argc, VALUE *argv, VALUE ary)
|
3474
|
+
{
|
3475
|
+
VALUE num;
|
3476
|
+
long r, n, i;
|
3477
|
+
|
3478
|
+
n = RARRAY_LEN(ary); /* Array length */
|
3479
|
+
RETURN_ENUMERATOR(ary, argc, argv); /* Return enumerator if no block */
|
3480
|
+
rb_scan_args(argc, argv, "01", &num);
|
3481
|
+
r = NIL_P(num) ? n : NUM2LONG(num); /* Permutation size from argument */
|
3482
|
+
|
3483
|
+
if (r < 0 || n < r) {
|
3484
|
+
/* no permutations: yield nothing */
|
3485
|
+
}
|
3486
|
+
else if (r == 0) { /* exactly one permutation: the zero-length array */
|
3487
|
+
rb_yield(rb_ary_new2(0));
|
3488
|
+
}
|
3489
|
+
else if (r == 1) { /* this is a special, easy case */
|
3490
|
+
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
3491
|
+
rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i]));
|
3492
|
+
}
|
3493
|
+
}
|
3494
|
+
else { /* this is the general case */
|
3495
|
+
volatile VALUE t0 = tmpbuf(n,sizeof(long));
|
3496
|
+
long *p = (long*)RSTRING_PTR(t0);
|
3497
|
+
volatile VALUE t1 = tmpbuf(n,sizeof(int));
|
3498
|
+
int *used = (int*)RSTRING_PTR(t1);
|
3499
|
+
VALUE ary0 = ary_make_substitution(ary); /* private defensive copy of ary */
|
3500
|
+
RBASIC(ary0)->klass = 0;
|
3501
|
+
|
3502
|
+
for (i = 0; i < n; i++) used[i] = 0; /* initialize array */
|
3503
|
+
|
3504
|
+
permute0(n, r, p, 0, used, ary0); /* compute and yield permutations */
|
3505
|
+
RB_GC_GUARD(t0);
|
3506
|
+
RB_GC_GUARD(t1);
|
3507
|
+
RBASIC(ary0)->klass = rb_cArray;
|
3508
|
+
}
|
3509
|
+
return ary;
|
3510
|
+
}
|
3511
|
+
|
3512
|
+
static long
|
3513
|
+
combi_len(long n, long k)
|
3514
|
+
{
|
3515
|
+
long i, val = 1;
|
3516
|
+
|
3517
|
+
if (k*2 > n) k = n-k;
|
3518
|
+
if (k == 0) return 1;
|
3519
|
+
if (k < 0) return 0;
|
3520
|
+
val = 1;
|
3521
|
+
for (i=1; i <= k; i++,n--) {
|
3522
|
+
long m = val;
|
3523
|
+
val *= n;
|
3524
|
+
if (val < m) {
|
3525
|
+
rb_raise(rb_eRangeError, "too big for combination");
|
3526
|
+
}
|
3527
|
+
val /= i;
|
3528
|
+
}
|
3529
|
+
return val;
|
3530
|
+
}
|
3531
|
+
|
3532
|
+
/*
|
3533
|
+
* call-seq:
|
3534
|
+
* ary.combination(n) { |c| block } -> ary
|
3535
|
+
* ary.combination(n) -> enumerator
|
3536
|
+
*
|
3537
|
+
* When invoked with a block, yields all combinations of length <i>n</i>
|
3538
|
+
* of elements from <i>ary</i> and then returns <i>ary</i> itself.
|
3539
|
+
* The implementation makes no guarantees about the order in which
|
3540
|
+
* the combinations are yielded.
|
3541
|
+
*
|
3542
|
+
* When invoked without a block, returns an enumerator object instead.
|
3543
|
+
*
|
3544
|
+
* Examples:
|
3545
|
+
*
|
3546
|
+
* a = [1, 2, 3, 4]
|
3547
|
+
* a.combination(1).to_a #=> [[1],[2],[3],[4]]
|
3548
|
+
* a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
|
3549
|
+
* a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
|
3550
|
+
* a.combination(4).to_a #=> [[1,2,3,4]]
|
3551
|
+
* a.combination(0).to_a #=> [[]] # one combination of length 0
|
3552
|
+
* a.combination(5).to_a #=> [] # no combinations of length 5
|
3553
|
+
*
|
3554
|
+
*/
|
3555
|
+
|
3556
|
+
static VALUE
|
3557
|
+
rb_ary_combination(VALUE ary, VALUE num)
|
3558
|
+
{
|
3559
|
+
long n, i, len;
|
3560
|
+
|
3561
|
+
n = NUM2LONG(num);
|
3562
|
+
RETURN_ENUMERATOR(ary, 1, &num);
|
3563
|
+
len = RARRAY_LEN(ary);
|
3564
|
+
if (n < 0 || len < n) {
|
3565
|
+
/* yield nothing */
|
3566
|
+
}
|
3567
|
+
else if (n == 0) {
|
3568
|
+
rb_yield(rb_ary_new2(0));
|
3569
|
+
}
|
3570
|
+
else if (n == 1) {
|
3571
|
+
for (i = 0; i < len; i++) {
|
3572
|
+
rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i]));
|
3573
|
+
}
|
3574
|
+
}
|
3575
|
+
else {
|
3576
|
+
volatile VALUE t0 = tmpbuf(n+1, sizeof(long));
|
3577
|
+
long *stack = (long*)RSTRING_PTR(t0);
|
3578
|
+
long nlen = combi_len(len, n);
|
3579
|
+
volatile VALUE cc = rb_ary_new2(n);
|
3580
|
+
VALUE *chosen = RARRAY_PTR(cc);
|
3581
|
+
long lev = 0;
|
3582
|
+
|
3583
|
+
RBASIC(cc)->klass = 0;
|
3584
|
+
MEMZERO(stack, long, n);
|
3585
|
+
stack[0] = -1;
|
3586
|
+
for (i = 0; i < nlen; i++) {
|
3587
|
+
chosen[lev] = RARRAY_PTR(ary)[stack[lev+1]];
|
3588
|
+
for (lev++; lev < n; lev++) {
|
3589
|
+
chosen[lev] = RARRAY_PTR(ary)[stack[lev+1] = stack[lev]+1];
|
3590
|
+
}
|
3591
|
+
rb_yield(rb_ary_new4(n, chosen));
|
3592
|
+
do {
|
3593
|
+
stack[lev--]++;
|
3594
|
+
} while (lev && (stack[lev+1]+n == len+lev+1));
|
3595
|
+
}
|
3596
|
+
}
|
3597
|
+
return ary;
|
3598
|
+
}
|
3599
|
+
|
3600
|
+
/*
|
3601
|
+
* call-seq:
|
3602
|
+
* ary.product(other_ary, ...)
|
3603
|
+
*
|
3604
|
+
* Returns an array of all combinations of elements from all arrays.
|
3605
|
+
* The length of the returned array is the product of the length
|
3606
|
+
* of ary and the argument arrays
|
3607
|
+
*
|
3608
|
+
* [1,2,3].product([4,5]) # => [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
|
3609
|
+
* [1,2].product([1,2]) # => [[1,1],[1,2],[2,1],[2,2]]
|
3610
|
+
* [1,2].product([3,4],[5,6]) # => [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
|
3611
|
+
* # [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
|
3612
|
+
* [1,2].product() # => [[1],[2]]
|
3613
|
+
* [1,2].product([]) # => []
|
3614
|
+
*/
|
3615
|
+
|
3616
|
+
static VALUE
|
3617
|
+
rb_ary_product(int argc, VALUE *argv, VALUE ary)
|
3618
|
+
{
|
3619
|
+
int n = argc+1; /* How many arrays we're operating on */
|
3620
|
+
volatile VALUE t0 = tmpbuf(n, sizeof(VALUE));
|
3621
|
+
volatile VALUE t1 = tmpbuf(n, sizeof(int));
|
3622
|
+
VALUE *arrays = (VALUE*)RSTRING_PTR(t0); /* The arrays we're computing the product of */
|
3623
|
+
int *counters = (int*)RSTRING_PTR(t1); /* The current position in each one */
|
3624
|
+
VALUE result; /* The array we'll be returning */
|
3625
|
+
long i,j;
|
3626
|
+
long resultlen = 1;
|
3627
|
+
|
3628
|
+
RBASIC(t0)->klass = 0;
|
3629
|
+
RBASIC(t1)->klass = 0;
|
3630
|
+
|
3631
|
+
/* initialize the arrays of arrays */
|
3632
|
+
arrays[0] = ary;
|
3633
|
+
for (i = 1; i < n; i++) arrays[i] = to_ary(argv[i-1]);
|
3634
|
+
|
3635
|
+
/* initialize the counters for the arrays */
|
3636
|
+
for (i = 0; i < n; i++) counters[i] = 0;
|
3637
|
+
|
3638
|
+
/* Compute the length of the result array; return [] if any is empty */
|
3639
|
+
for (i = 0; i < n; i++) {
|
3640
|
+
long k = RARRAY_LEN(arrays[i]), l = resultlen;
|
3641
|
+
if (k == 0) return rb_ary_new2(0);
|
3642
|
+
resultlen *= k;
|
3643
|
+
if (resultlen < k || resultlen < l || resultlen / k != l) {
|
3644
|
+
rb_raise(rb_eRangeError, "too big to product");
|
3645
|
+
}
|
3646
|
+
}
|
3647
|
+
|
3648
|
+
/* Otherwise, allocate and fill in an array of results */
|
3649
|
+
result = rb_ary_new2(resultlen);
|
3650
|
+
for (i = 0; i < resultlen; i++) {
|
3651
|
+
int m;
|
3652
|
+
/* fill in one subarray */
|
3653
|
+
VALUE subarray = rb_ary_new2(n);
|
3654
|
+
for (j = 0; j < n; j++) {
|
3655
|
+
rb_ary_push(subarray, rb_ary_entry(arrays[j], counters[j]));
|
3656
|
+
}
|
3657
|
+
|
3658
|
+
/* put it on the result array */
|
3659
|
+
rb_ary_push(result, subarray);
|
3660
|
+
|
3661
|
+
/*
|
3662
|
+
* Increment the last counter. If it overflows, reset to 0
|
3663
|
+
* and increment the one before it.
|
3664
|
+
*/
|
3665
|
+
m = n-1;
|
3666
|
+
counters[m]++;
|
3667
|
+
while (m > 0 && counters[m] == RARRAY_LEN(arrays[m])) {
|
3668
|
+
counters[m] = 0;
|
3669
|
+
m--;
|
3670
|
+
counters[m]++;
|
3671
|
+
}
|
3672
|
+
}
|
3673
|
+
|
3674
|
+
return result;
|
3675
|
+
}
|
3676
|
+
|
3677
|
+
/*
|
3678
|
+
* call-seq:
|
3679
|
+
* ary.take(n) => array
|
3680
|
+
*
|
3681
|
+
* Returns first n elements from <i>ary</i>.
|
3682
|
+
*
|
3683
|
+
* a = [1, 2, 3, 4, 5, 0]
|
3684
|
+
* a.take(3) # => [1, 2, 3]
|
3685
|
+
*
|
3686
|
+
*/
|
3687
|
+
|
3688
|
+
static VALUE
|
3689
|
+
rb_ary_take(VALUE obj, VALUE n)
|
3690
|
+
{
|
3691
|
+
long len = NUM2LONG(n);
|
3692
|
+
if (len < 0) {
|
3693
|
+
rb_raise(rb_eArgError, "attempt to take negative size");
|
3694
|
+
}
|
3695
|
+
return rb_ary_subseq(obj, 0, len);
|
3696
|
+
}
|
3697
|
+
|
3698
|
+
/*
|
3699
|
+
* call-seq:
|
3700
|
+
* ary.take_while {|arr| block } => array
|
3701
|
+
*
|
3702
|
+
* Passes elements to the block until the block returns nil or false,
|
3703
|
+
* then stops iterating and returns an array of all prior elements.
|
3704
|
+
*
|
3705
|
+
* a = [1, 2, 3, 4, 5, 0]
|
3706
|
+
* a.take_while {|i| i < 3 } # => [1, 2]
|
3707
|
+
*
|
3708
|
+
*/
|
3709
|
+
|
3710
|
+
static VALUE
|
3711
|
+
rb_ary_take_while(VALUE ary)
|
3712
|
+
{
|
3713
|
+
long i;
|
3714
|
+
|
3715
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
3716
|
+
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
3717
|
+
if (!RTEST(rb_yield(RARRAY_PTR(ary)[i]))) break;
|
3718
|
+
}
|
3719
|
+
return rb_ary_take(ary, LONG2FIX(i));
|
3720
|
+
}
|
3721
|
+
|
3722
|
+
/*
|
3723
|
+
* call-seq:
|
3724
|
+
* ary.drop(n) => array
|
3725
|
+
*
|
3726
|
+
* Drops first n elements from <i>ary</i>, and returns rest elements
|
3727
|
+
* in an array.
|
3728
|
+
*
|
3729
|
+
* a = [1, 2, 3, 4, 5, 0]
|
3730
|
+
* a.drop(3) # => [4, 5, 0]
|
3731
|
+
*
|
3732
|
+
*/
|
3733
|
+
|
3734
|
+
static VALUE
|
3735
|
+
rb_ary_drop(VALUE ary, VALUE n)
|
3736
|
+
{
|
3737
|
+
VALUE result;
|
3738
|
+
long pos = NUM2LONG(n);
|
3739
|
+
if (pos < 0) {
|
3740
|
+
rb_raise(rb_eArgError, "attempt to drop negative size");
|
3741
|
+
}
|
3742
|
+
|
3743
|
+
result = rb_ary_subseq(ary, pos, RARRAY_LEN(ary));
|
3744
|
+
if (result == Qnil) result = rb_ary_new();
|
3745
|
+
return result;
|
3746
|
+
}
|
3747
|
+
|
3748
|
+
/*
|
3749
|
+
* call-seq:
|
3750
|
+
* ary.drop_while {|arr| block } => array
|
3751
|
+
*
|
3752
|
+
* Drops elements up to, but not including, the first element for
|
3753
|
+
* which the block returns nil or false and returns an array
|
3754
|
+
* containing the remaining elements.
|
3755
|
+
*
|
3756
|
+
* a = [1, 2, 3, 4, 5, 0]
|
3757
|
+
* a.drop_while {|i| i < 3 } # => [3, 4, 5, 0]
|
3758
|
+
*
|
3759
|
+
*/
|
3760
|
+
|
3761
|
+
static VALUE
|
3762
|
+
rb_ary_drop_while(VALUE ary)
|
3763
|
+
{
|
3764
|
+
long i;
|
3765
|
+
|
3766
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
3767
|
+
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
3768
|
+
if (!RTEST(rb_yield(RARRAY_PTR(ary)[i]))) break;
|
3769
|
+
}
|
3770
|
+
return rb_ary_drop(ary, LONG2FIX(i));
|
3771
|
+
}
|
3772
|
+
|
3773
|
+
|
3774
|
+
|
3775
|
+
/* Arrays are ordered, integer-indexed collections of any object.
|
3776
|
+
* Array indexing starts at 0, as in C or Java. A negative index is
|
3777
|
+
* assumed to be relative to the end of the array---that is, an index of -1
|
3778
|
+
* indicates the last element of the array, -2 is the next to last
|
3779
|
+
* element in the array, and so on.
|
3780
|
+
*/
|
3781
|
+
|
3782
|
+
void
|
3783
|
+
Init_Array(void)
|
3784
|
+
{
|
3785
|
+
#undef rb_intern
|
3786
|
+
#define rb_intern(str) rb_intern_const(str)
|
3787
|
+
|
3788
|
+
rb_cArray = rb_define_class("Array", rb_cObject);
|
3789
|
+
rb_include_module(rb_cArray, rb_mEnumerable);
|
3790
|
+
|
3791
|
+
rb_define_alloc_func(rb_cArray, ary_alloc);
|
3792
|
+
rb_define_singleton_method(rb_cArray, "[]", rb_ary_s_create, -1);
|
3793
|
+
rb_define_singleton_method(rb_cArray, "try_convert", rb_ary_s_try_convert, 1);
|
3794
|
+
rb_define_method(rb_cArray, "initialize", rb_ary_initialize, -1);
|
3795
|
+
rb_define_method(rb_cArray, "initialize_copy", rb_ary_replace, 1);
|
3796
|
+
|
3797
|
+
rb_define_method(rb_cArray, "to_s", rb_ary_inspect, 0);
|
3798
|
+
rb_define_method(rb_cArray, "inspect", rb_ary_inspect, 0);
|
3799
|
+
rb_define_method(rb_cArray, "to_a", rb_ary_to_a, 0);
|
3800
|
+
rb_define_method(rb_cArray, "to_ary", rb_ary_to_ary_m, 0);
|
3801
|
+
rb_define_method(rb_cArray, "frozen?", rb_ary_frozen_p, 0);
|
3802
|
+
|
3803
|
+
rb_define_method(rb_cArray, "==", rb_ary_equal, 1);
|
3804
|
+
rb_define_method(rb_cArray, "eql?", rb_ary_eql, 1);
|
3805
|
+
rb_define_method(rb_cArray, "hash", rb_ary_hash, 0);
|
3806
|
+
|
3807
|
+
rb_define_method(rb_cArray, "[]", rb_ary_aref, -1);
|
3808
|
+
rb_define_method(rb_cArray, "[]=", rb_ary_aset, -1);
|
3809
|
+
rb_define_method(rb_cArray, "at", rb_ary_at, 1);
|
3810
|
+
rb_define_method(rb_cArray, "fetch", rb_ary_fetch, -1);
|
3811
|
+
rb_define_method(rb_cArray, "first", rb_ary_first, -1);
|
3812
|
+
rb_define_method(rb_cArray, "last", rb_ary_last, -1);
|
3813
|
+
rb_define_method(rb_cArray, "concat", rb_ary_concat, 1);
|
3814
|
+
rb_define_method(rb_cArray, "<<", rb_ary_push, 1);
|
3815
|
+
rb_define_method(rb_cArray, "push", rb_ary_push_m, -1);
|
3816
|
+
rb_define_method(rb_cArray, "pop", rb_ary_pop_m, -1);
|
3817
|
+
rb_define_method(rb_cArray, "shift", rb_ary_shift_m, -1);
|
3818
|
+
rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1);
|
3819
|
+
rb_define_method(rb_cArray, "insert", rb_ary_insert, -1);
|
3820
|
+
rb_define_method(rb_cArray, "each", rb_ary_each, 0);
|
3821
|
+
rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0);
|
3822
|
+
rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0);
|
3823
|
+
rb_define_method(rb_cArray, "length", rb_ary_length, 0);
|
3824
|
+
rb_define_alias(rb_cArray, "size", "length");
|
3825
|
+
rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0);
|
3826
|
+
rb_define_method(rb_cArray, "find_index", rb_ary_index, -1);
|
3827
|
+
rb_define_method(rb_cArray, "index", rb_ary_index, -1);
|
3828
|
+
rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1);
|
3829
|
+
rb_define_method(rb_cArray, "join", rb_ary_join_m, -1);
|
3830
|
+
rb_define_method(rb_cArray, "reverse", rb_ary_reverse_m, 0);
|
3831
|
+
rb_define_method(rb_cArray, "reverse!", rb_ary_reverse_bang, 0);
|
3832
|
+
rb_define_method(rb_cArray, "sort", rb_ary_sort, 0);
|
3833
|
+
rb_define_method(rb_cArray, "sort!", rb_ary_sort_bang, 0);
|
3834
|
+
rb_define_method(rb_cArray, "collect", rb_ary_collect, 0);
|
3835
|
+
rb_define_method(rb_cArray, "collect!", rb_ary_collect_bang, 0);
|
3836
|
+
rb_define_method(rb_cArray, "map", rb_ary_collect, 0);
|
3837
|
+
rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0);
|
3838
|
+
rb_define_method(rb_cArray, "select", rb_ary_select, 0);
|
3839
|
+
rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1);
|
3840
|
+
rb_define_method(rb_cArray, "delete", rb_ary_delete, 1);
|
3841
|
+
rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at_m, 1);
|
3842
|
+
rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0);
|
3843
|
+
rb_define_method(rb_cArray, "reject", rb_ary_reject, 0);
|
3844
|
+
rb_define_method(rb_cArray, "reject!", rb_ary_reject_bang, 0);
|
3845
|
+
rb_define_method(rb_cArray, "zip", rb_ary_zip, -1);
|
3846
|
+
rb_define_method(rb_cArray, "transpose", rb_ary_transpose, 0);
|
3847
|
+
rb_define_method(rb_cArray, "replace", rb_ary_replace, 1);
|
3848
|
+
rb_define_method(rb_cArray, "clear", rb_ary_clear, 0);
|
3849
|
+
rb_define_method(rb_cArray, "fill", rb_ary_fill, -1);
|
3850
|
+
rb_define_method(rb_cArray, "include?", rb_ary_includes, 1);
|
3851
|
+
rb_define_method(rb_cArray, "<=>", rb_ary_cmp, 1);
|
3852
|
+
|
3853
|
+
rb_define_method(rb_cArray, "slice", rb_ary_aref, -1);
|
3854
|
+
rb_define_method(rb_cArray, "slice!", rb_ary_slice_bang, -1);
|
3855
|
+
|
3856
|
+
rb_define_method(rb_cArray, "assoc", rb_ary_assoc, 1);
|
3857
|
+
rb_define_method(rb_cArray, "rassoc", rb_ary_rassoc, 1);
|
3858
|
+
|
3859
|
+
rb_define_method(rb_cArray, "+", rb_ary_plus, 1);
|
3860
|
+
rb_define_method(rb_cArray, "*", rb_ary_times, 1);
|
3861
|
+
|
3862
|
+
rb_define_method(rb_cArray, "-", rb_ary_diff, 1);
|
3863
|
+
rb_define_method(rb_cArray, "&", rb_ary_and, 1);
|
3864
|
+
rb_define_method(rb_cArray, "|", rb_ary_or, 1);
|
3865
|
+
|
3866
|
+
rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0);
|
3867
|
+
rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0);
|
3868
|
+
rb_define_method(rb_cArray, "compact", rb_ary_compact, 0);
|
3869
|
+
rb_define_method(rb_cArray, "compact!", rb_ary_compact_bang, 0);
|
3870
|
+
rb_define_method(rb_cArray, "flatten", rb_ary_flatten, -1);
|
3871
|
+
rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, -1);
|
3872
|
+
rb_define_method(rb_cArray, "count", rb_ary_count, -1);
|
3873
|
+
rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, 0);
|
3874
|
+
rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0);
|
3875
|
+
rb_define_method(rb_cArray, "sample", rb_ary_sample, -1);
|
3876
|
+
rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1);
|
3877
|
+
rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1);
|
3878
|
+
rb_define_method(rb_cArray, "combination", rb_ary_combination, 1);
|
3879
|
+
rb_define_method(rb_cArray, "product", rb_ary_product, -1);
|
3880
|
+
|
3881
|
+
rb_define_method(rb_cArray, "take", rb_ary_take, 1);
|
3882
|
+
rb_define_method(rb_cArray, "take_while", rb_ary_take_while, 0);
|
3883
|
+
rb_define_method(rb_cArray, "drop", rb_ary_drop, 1);
|
3884
|
+
rb_define_method(rb_cArray, "drop_while", rb_ary_drop_while, 0);
|
3885
|
+
|
3886
|
+
id_cmp = rb_intern("<=>");
|
3887
|
+
}
|