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.

Files changed (121) hide show
  1. data/ChangeLog +585 -1
  2. data/README.md +10 -2
  3. data/benchmarks/yri_cache.rb +19 -0
  4. data/bin/yri +1 -26
  5. data/docs/WhatsNew.md +99 -0
  6. data/lib/rubygems_plugin.rb +2 -0
  7. data/lib/yard.rb +2 -2
  8. data/lib/yard/autoload.rb +9 -4
  9. data/lib/yard/cli/base.rb +26 -0
  10. data/lib/yard/cli/yard_graph.rb +2 -9
  11. data/lib/yard/cli/yardoc.rb +93 -33
  12. data/lib/yard/cli/yri.rb +128 -0
  13. data/lib/yard/code_objects/base.rb +16 -5
  14. data/lib/yard/code_objects/class_object.rb +11 -4
  15. data/lib/yard/code_objects/method_object.rb +11 -1
  16. data/lib/yard/code_objects/proxy.rb +5 -2
  17. data/lib/yard/code_objects/root_object.rb +1 -0
  18. data/lib/yard/core_ext/file.rb +1 -1
  19. data/lib/yard/core_ext/hash.rb +15 -0
  20. data/lib/yard/core_ext/module.rb +2 -2
  21. data/lib/yard/core_ext/string.rb +66 -0
  22. data/lib/yard/core_ext/symbol_hash.rb +1 -1
  23. data/lib/yard/docstring.rb +5 -5
  24. data/lib/yard/handlers/base.rb +10 -4
  25. data/lib/yard/handlers/processor.rb +3 -4
  26. data/lib/yard/handlers/ruby/attribute_handler.rb +3 -2
  27. data/lib/yard/handlers/ruby/legacy/attribute_handler.rb +2 -2
  28. data/lib/yard/handlers/ruby/legacy/method_handler.rb +7 -1
  29. data/lib/yard/handlers/ruby/method_handler.rb +7 -1
  30. data/lib/yard/logging.rb +11 -1
  31. data/lib/yard/parser/c_parser.rb +407 -0
  32. data/lib/yard/parser/ruby/ast_node.rb +2 -2
  33. data/lib/yard/parser/ruby/legacy/ruby_lex.rb +3 -4
  34. data/lib/yard/parser/source_parser.rb +18 -7
  35. data/lib/yard/rake/yardoc_task.rb +1 -1
  36. data/lib/yard/registry.rb +83 -29
  37. data/lib/yard/registry_store.rb +213 -0
  38. data/lib/yard/serializers/base.rb +1 -1
  39. data/lib/yard/serializers/yardoc_serializer.rb +113 -0
  40. data/lib/yard/tags/library.rb +4 -0
  41. data/lib/yard/tags/overload_tag.rb +16 -5
  42. data/lib/yard/tags/tag.rb +1 -2
  43. data/lib/yard/templates/engine.rb +3 -3
  44. data/lib/yard/templates/helpers/html_helper.rb +50 -16
  45. data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +1 -3
  46. data/lib/yard/templates/helpers/html_syntax_highlight_helper18.rb +1 -3
  47. data/lib/yard/templates/helpers/method_helper.rb +11 -4
  48. data/lib/yard/templates/helpers/text_helper.rb +24 -2
  49. data/lib/yard/verifier.rb +3 -3
  50. data/spec/cli/yardoc_spec.rb +33 -6
  51. data/spec/cli/yri_spec.rb +30 -0
  52. data/spec/code_objects/base_spec.rb +7 -0
  53. data/spec/code_objects/class_object_spec.rb +6 -1
  54. data/spec/code_objects/method_object_spec.rb +25 -0
  55. data/spec/core_ext/hash_spec.rb +10 -0
  56. data/spec/core_ext/module_spec.rb +1 -1
  57. data/spec/core_ext/string_spec.rb +50 -12
  58. data/spec/handlers/attribute_handler_spec.rb +4 -0
  59. data/spec/handlers/examples/method_handler_001.rb.txt +9 -0
  60. data/spec/handlers/method_handler_spec.rb +22 -4
  61. data/spec/parser/c_parser_spec.rb +22 -0
  62. data/spec/parser/examples/array.c.txt +3887 -0
  63. data/spec/parser/source_parser_spec.rb +29 -7
  64. data/spec/registry_spec.rb +93 -72
  65. data/spec/registry_store_spec.rb +184 -0
  66. data/spec/serializers/file_system_serializer_spec.rb +96 -75
  67. data/spec/spec_helper.rb +2 -2
  68. data/spec/tags/overload_tag_spec.rb +18 -0
  69. data/spec/templates/examples/class001.html +32 -30
  70. data/spec/templates/examples/method001.html +4 -1
  71. data/spec/templates/examples/method002.html +7 -2
  72. data/spec/templates/examples/method002.txt +1 -1
  73. data/spec/templates/examples/method003.html +30 -8
  74. data/spec/templates/examples/method003.txt +4 -4
  75. data/spec/templates/examples/method004.html +44 -0
  76. data/spec/templates/examples/method004.txt +10 -0
  77. data/spec/templates/examples/method005.html +99 -0
  78. data/spec/templates/examples/method005.txt +33 -0
  79. data/spec/templates/examples/module001.dot +1 -1
  80. data/spec/templates/examples/module001.html +391 -37
  81. data/spec/templates/examples/module001.txt +1 -1
  82. data/spec/templates/helpers/base_helper_spec.rb +2 -2
  83. data/spec/templates/helpers/html_helper_spec.rb +83 -0
  84. data/spec/templates/helpers/method_helper_spec.rb +47 -0
  85. data/spec/templates/helpers/shared_signature_examples.rb +102 -0
  86. data/spec/templates/helpers/text_helper_spec.rb +31 -0
  87. data/spec/templates/method_spec.rb +43 -18
  88. data/spec/templates/module_spec.rb +22 -1
  89. data/spec/templates/spec_helper.rb +10 -1
  90. data/spec/yard_spec.rb +4 -3
  91. data/templates/default/class/html/constructor_details.erb +1 -1
  92. data/templates/default/docstring/html/returns_void.erb +1 -0
  93. data/templates/default/docstring/setup.rb +9 -4
  94. data/templates/default/docstring/text/returns_void.erb +1 -0
  95. data/templates/default/fulldoc/html/css/style.css +4 -2
  96. data/templates/default/fulldoc/html/full_list.erb +2 -2
  97. data/templates/default/fulldoc/html/js/app.js +1 -1
  98. data/templates/default/fulldoc/html/setup.rb +14 -6
  99. data/templates/default/layout/dot/setup.rb +1 -1
  100. data/templates/default/layout/html/breadcrumb.erb +2 -2
  101. data/templates/default/layout/html/index.erb +2 -2
  102. data/templates/default/layout/html/setup.rb +5 -5
  103. data/templates/default/method/html/header.erb +6 -4
  104. data/templates/default/method_details/html/method_signature.erb +2 -1
  105. data/templates/default/method_details/html/source.erb +1 -1
  106. data/templates/default/method_details/setup.rb +2 -1
  107. data/templates/default/method_details/text/setup.rb +1 -1
  108. data/templates/default/module/html/attribute_details.erb +4 -4
  109. data/templates/default/module/html/attribute_summary.erb +3 -3
  110. data/templates/default/module/html/box_info.erb +2 -2
  111. data/templates/default/module/html/defines.erb +1 -1
  112. data/templates/default/module/html/inherited_constants.erb +1 -1
  113. data/templates/default/module/html/inherited_methods.erb +1 -1
  114. data/templates/default/module/html/item_summary.erb +13 -4
  115. data/templates/default/module/html/method_details_list.erb +5 -4
  116. data/templates/default/module/html/method_summary.erb +5 -4
  117. data/templates/default/module/html/methodmissing.erb +1 -1
  118. data/templates/default/module/setup.rb +14 -5
  119. data/templates/default/tags/html/overload.erb +3 -2
  120. data/templates/default/tags/setup.rb +4 -0
  121. metadata +23 -2
@@ -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
- Registry.instance.stub!(:load)
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 == :'hello world'
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.to_sym
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 Object class" do
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.namespace.should == "YARD::CodeObjects"
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, '#underscore' do
7
- it 'should turn HelloWorld into hello_world' do
8
- "HelloWorld".underscore.should == "hello_world"
9
- end
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
- it "should turn Hello::World into hello/world" do
12
- "Hello::World".underscore.should == "hello/world"
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 String, '#camelcase' do
17
- it 'should turn hello_world into HelloWorld' do
18
- "hello_world".camelcase.should == "HelloWorld"
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
- it "should turn hello/world into Hello::World" do
22
- "Hello::World".underscore.should == "hello/world"
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
@@ -59,4 +59,13 @@ end
59
59
  # @return [Fixnum]
60
60
  # @overload bang(d, e)
61
61
  def foo(*args); end
62
+
63
+ # No return tag
64
+ def boolean?; end
65
+
66
+ # @return without type
67
+ def boolean2?; end
68
+
69
+ # @return [NotBoolean, nil]
70
+ def boolean3?; end
62
71
  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 == :foo
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 == :foo
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 == :foo
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 +Foo+"
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
+ }