diff options
author | Ary Borenszweig <[email protected]> | 2019-11-29 17:59:47 -0300 |
---|---|---|
committer | Nobuyoshi Nakada <[email protected]> | 2019-12-29 13:12:42 +0900 |
commit | e5c441a4a2885da61df9894ac17b69cb3c5811f2 (patch) | |
tree | 1c997ff3749cde5d8a1d73d799a51e0ad91ae3b3 /array.c | |
parent | a0d1fd16d156d289d5ea46327a98517a9b31f860 (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
Diffstat (limited to 'array.c')
-rw-r--r-- | array.c | 20 |
1 files changed, 15 insertions, 5 deletions
@@ -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; } |