Skip to content

Commit e1d966d

Browse files
committed
Add rb_arithmetic_sequence_beg_len_step function
1 parent 5d1748b commit e1d966d

2 files changed

Lines changed: 174 additions & 0 deletions

File tree

optional/capi/ext/range_spec.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,49 @@ VALUE range_spec_rb_range_beg_len(VALUE self, VALUE range, VALUE begpv, VALUE le
3838
return ary;
3939
}
4040

41+
VALUE range_spec_rb_arithmetic_sequence_extract(VALUE self, VALUE object) {
42+
VALUE ary = rb_ary_new();
43+
rb_arithmetic_sequence_components_t components;
44+
45+
int status = rb_arithmetic_sequence_extract(object, &components);
46+
47+
if (!status) {
48+
rb_ary_store(ary, 0, LONG2FIX(status));
49+
return ary;
50+
}
51+
52+
rb_ary_store(ary, 0, LONG2FIX(status));
53+
rb_ary_store(ary, 1, components.begin);
54+
rb_ary_store(ary, 2, components.end);
55+
rb_ary_store(ary, 3, components.step);
56+
rb_ary_store(ary, 4, components.exclude_end ? Qtrue : Qfalse);
57+
return ary;
58+
}
59+
60+
VALUE range_spec_rb_arithmetic_sequence_beg_len_step(VALUE self, VALUE aseq, VALUE lenv, VALUE errv) {
61+
long begp, lenp, stepp;
62+
63+
long len = FIX2LONG(lenv);
64+
int err = FIX2INT(errv);
65+
66+
VALUE success = rb_arithmetic_sequence_beg_len_step(aseq, &begp, &lenp, &stepp, len, err);
67+
68+
VALUE ary = rb_ary_new();
69+
rb_ary_store(ary, 0, success);
70+
rb_ary_store(ary, 1, LONG2FIX(begp));
71+
rb_ary_store(ary, 2, LONG2FIX(lenp));
72+
rb_ary_store(ary, 3, LONG2FIX(stepp));
73+
74+
return ary;
75+
}
76+
4177
void Init_range_spec(void) {
4278
VALUE cls = rb_define_class("CApiRangeSpecs", rb_cObject);
4379
rb_define_method(cls, "rb_range_new", range_spec_rb_range_new, -1);
4480
rb_define_method(cls, "rb_range_values", range_spec_rb_range_values, 1);
4581
rb_define_method(cls, "rb_range_beg_len", range_spec_rb_range_beg_len, 5);
82+
rb_define_method(cls, "rb_arithmetic_sequence_extract", range_spec_rb_arithmetic_sequence_extract, 1);
83+
rb_define_method(cls, "rb_arithmetic_sequence_beg_len_step", range_spec_rb_arithmetic_sequence_beg_len_step, 3);
4684
}
4785

4886
#ifdef __cplusplus

optional/capi/range_spec.rb

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,140 @@ def range_like.exclude_end?
9292
result.should be_nil
9393
end
9494
end
95+
96+
describe "rb_arithmetic_sequence_extract" do
97+
it "returns begin, end, step, exclude end of an instance of an Enumerator::ArithmeticSequence" do
98+
enum = (10..20).step(5)
99+
enum.should.kind_of?(Enumerator::ArithmeticSequence)
100+
101+
@s.rb_arithmetic_sequence_extract(enum).should == [1, 10, 20, 5, false]
102+
end
103+
104+
it "returns begin, end, step, exclude end of an instance of a Range" do
105+
range = (10..20)
106+
@s.rb_arithmetic_sequence_extract(range).should == [1, 10, 20, 1, false]
107+
end
108+
109+
it "returns begin, end, step, exclude end of a non-Range object with Range properties" do
110+
object = Object.new
111+
def object.begin
112+
10
113+
end
114+
def object.end
115+
20
116+
end
117+
def object.exclude_end?
118+
false
119+
end
120+
121+
@s.rb_arithmetic_sequence_extract(object).should == [1, 10, 20, 1, false]
122+
end
123+
124+
it "returns failed status if given object is not Enumerator::ArithmeticSequence or Range or Range-like object" do
125+
object = Object.new
126+
@s.rb_arithmetic_sequence_extract(object).should == [0]
127+
end
128+
end
129+
130+
describe "rb_arithmetic_sequence_beg_len_step" do
131+
it "returns correct begin, length, step and result" do
132+
as = (2..5).step(5)
133+
error_code = 0
134+
135+
success, beg, len, step = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
136+
success.should be_true
137+
138+
beg.should == 2
139+
len.should == 4
140+
step.should == 5
141+
end
142+
143+
it "takes into account excluded end boundary" do
144+
as = (2...5).step(1)
145+
error_code = 0
146+
147+
success, _, len, _ = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
148+
success.should be_true
149+
len.should == 3
150+
end
151+
152+
it "adds length to negative begin boundary" do
153+
as = (-2..5).step(1)
154+
error_code = 0
155+
156+
success, beg, len, _ = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
157+
success.should be_true
158+
159+
beg.should == 4
160+
len.should == 2
161+
end
162+
163+
it "adds length to negative end boundary" do
164+
as = (2..-1).step(1)
165+
error_code = 0
166+
167+
success, beg, len, _ = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
168+
success.should be_true
169+
170+
beg.should == 2
171+
len.should == 4
172+
end
173+
174+
it "truncates arithmetic sequence length if end boundary greater than specified length value" do
175+
as = (2..10).step(1)
176+
error_code = 0
177+
178+
success, _, len, _ = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
179+
success.should be_true
180+
len.should == 4
181+
end
182+
183+
it "returns inverted begin and end boundaries when step is negative" do
184+
as = (2..5).step(-2)
185+
error_code = 0
186+
187+
success, beg, len, step = @s.rb_arithmetic_sequence_beg_len_step(as, 6, error_code)
188+
success.should be_true
189+
190+
beg.should == 5
191+
len.should == 0
192+
step.should == -2
193+
end
194+
195+
it "returns nil when not in range and error code = 0" do
196+
as = (2..5).step(1)
197+
error_code = 0
198+
199+
success, = @s.rb_arithmetic_sequence_beg_len_step(as, 1, error_code)
200+
success.should be_nil
201+
end
202+
203+
it "returns nil when not in range, negative boundaries and error code = 0" do
204+
as = (-5..-1).step(1)
205+
error_code = 0
206+
207+
success, = @s.rb_arithmetic_sequence_beg_len_step(as, 1, 0)
208+
success.should be_nil
209+
end
210+
211+
it "returns begin, length and step and doesn't raise a RangeError when not in range and error code = 1" do
212+
as = (2..5).step(1)
213+
error_code = 1
214+
215+
success, beg, len, step = @s.rb_arithmetic_sequence_beg_len_step(as, 1, error_code)
216+
success.should be_true
217+
218+
beg.should == 2
219+
len.should == 4
220+
step.should == 1
221+
end
222+
223+
it "returns nil and doesn't raise a RangeError when not in range, negative boundaries and error code = 1" do
224+
as = (-5..-1).step(1)
225+
error_code = 1
226+
227+
success, = @s.rb_arithmetic_sequence_beg_len_step(as, 1, error_code)
228+
success.should be_nil
229+
end
230+
end
95231
end

0 commit comments

Comments
 (0)