summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAry Borenszweig <asterite@gmail.com>2019-11-29 17:59:47 -0300
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-12-29 13:12:42 +0900
commite5c441a4a2885da61df9894ac17b69cb3c5811f2 (patch)
tree1c997ff3749cde5d8a1d73d799a51e0ad91ae3b3
parenta0d1fd16d156d289d5ea46327a98517a9b31f860 (diff)
Optimize Array#rotate!(n) for n = 1 and n = -1
For the most common cases of `rotate!` one place to the right or to the left, instead of doing some reversals of the array we just keep a single value in a temporary value, use memmove and then put the temporary value where it should be.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2710
-rw-r--r--array.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/array.c b/array.c
index 9846320f00..16321e186d 100644
--- a/array.c
+++ b/array.c
@@ -2618,10 +2618,20 @@ rotate_count(long cnt, long len)
static void
ary_rotate_ptr(VALUE *ptr, long len, long cnt)
{
- --len;
- if (cnt < len) ary_reverse(ptr + cnt, ptr + len);
- if (--cnt > 0) ary_reverse(ptr, ptr + cnt);
- if (len > 0) ary_reverse(ptr, ptr + len);
+ if (cnt == 1) {
+ VALUE tmp = *ptr;
+ memmove(ptr, ptr + 1, sizeof(VALUE)*(len - 1));
+ *(ptr + len - 1) = tmp;
+ } else if (cnt == len - 1) {
+ VALUE tmp = *(ptr + len - 1);
+ memmove(ptr + 1, ptr, sizeof(VALUE)*(len - 1));
+ *ptr = tmp;
+ } else {
+ --len;
+ if (cnt < len) ary_reverse(ptr + cnt, ptr + len);
+ if (--cnt > 0) ary_reverse(ptr, ptr + cnt);
+ if (len > 0) ary_reverse(ptr, ptr + len);
+ }
}
VALUE
@@ -2631,7 +2641,7 @@ rb_ary_rotate(VALUE ary, long cnt)
if (cnt != 0) {
long len = RARRAY_LEN(ary);
- if (len > 0 && (cnt = rotate_count(cnt, len)) > 0) {
+ if (len > 1 && (cnt = rotate_count(cnt, len)) > 0) {
RARRAY_PTR_USE_TRANSIENT(ary, ptr, ary_rotate_ptr(ptr, len, cnt));
return ary;
}