Guava的Strings.repeat

如果要自己实现一个repeat的话,最容易想到的可能会这样(示例不考虑int溢出的情况):

public static String repeat(String string, int count) {
    int length = string.length() * count;
    StringBuilder sb = new StringBuilder(length);
    for (int i = 0; i < count; i++) {
        sb.append(string);
    }
    return sb.toString();
}

用图画出来应该是这个样子的:

guava-strings-repeat (1).png

看到guava的实现,在位运算的时候还是小愣了一下,性能是比上面的实现好多了:

public static String repeat(String string, int count) {
  // 先去掉检测相关的判断,只看核心的实现
  final int len = string.length();
  final long longSize = (long) len * (long) count;
  final int size = (int) longSize;

  final char[] array = new char[size];
  string.getChars(0, len, array, 0);
  int n;
  for (n = len; n < size - n; n <<= 1) {
    System.arraycopy(array, 0, array, n, n);
  }
  System.arraycopy(array, 0, array, n, size - n);
  return new String(array);
}

用图画出来是这个样子的:

guava-strings-repeat.png

重点是这段代码:

  for (n = len; n < size - n; n <<= 1) {
    System.arraycopy(array, 0, array, n, n);
  }
  System.arraycopy(array, 0, array, n, size - n);

看下php的内核实现,其实原理一样,就是把现有的字串翻倍,当 [达到一半的长度, count为偶数] 或者 [刚超过一半的长度时, count为奇数] 做最后一次连接,只是写法不太一样:

// sed -n '5012,5058p' /usr/local/src/php-7.0.9/ext/standard/string.c
PHP_FUNCTION(str_repeat)
{
    zend_string        *input_str;        /* Input string */
    zend_long         mult;            /* Multiplier */
    zend_string    *result;        /* Resulting string */
    size_t        result_len;        /* Length of the resulting string */

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl", &input_str, &mult) == FAILURE) {
        return;
    }

    if (mult < 0) {
        php_error_docref(NULL, E_WARNING, "Second argument has to be greater than or equal to 0");
        return;
    }

    /* Don't waste our time if it's empty */
    /* ... or if the multiplier is zero */
    if (ZSTR_LEN(input_str) == 0 || mult == 0)
        RETURN_EMPTY_STRING();

    /* Initialize the result string */
    result = zend_string_safe_alloc(ZSTR_LEN(input_str), mult, 0, 0);
    result_len = ZSTR_LEN(input_str) * mult;

    /* Heavy optimization for situations where input string is 1 byte long */
    if (ZSTR_LEN(input_str) == 1) {
        memset(ZSTR_VAL(result), *ZSTR_VAL(input_str), mult);
    } else {
        char *s, *e, *ee;
        ptrdiff_t l=0;
        memcpy(ZSTR_VAL(result), ZSTR_VAL(input_str), ZSTR_LEN(input_str));
        s = ZSTR_VAL(result);
        e = ZSTR_VAL(result) + ZSTR_LEN(input_str);
        ee = ZSTR_VAL(result) + result_len;

        while (e<ee) {
            l = (e-s) < (ee-e) ? (e-s) : (ee-e);
            memmove(e, s, l);
            e += l;
        }
    }

    ZSTR_VAL(result)[result_len] = '\0';

    RETURN_NEW_STR(result);
}

标签: none

已有 7 条评论

  1. 梦想清澈高远,究竟哪儿才是适合远方的田野?张凯博客特来拜访!

  2. 感谢你提供的工具,貌似html不能压缩了,忘博主修复

    1. 我这边简单的测试是可以的;你提供一下你的html给我吧

      1. 已经发送至你的邮箱,请查收

  3. 徐向博 徐向博

    博主代码高亮是什么插件么?还是自己写的,求分享

    1. 已经在博客里分享过了

  4. 不错

添加新评论