string-pad.tq 3.41 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include 'src/builtins/builtins-string-gen.h'

namespace string {

9 10
extern transitioning builtin
StringSubstring(implicit context: Context)(String, intptr, intptr): String;
11

12 13
const kStringPadStart: constexpr int31 = 0;
const kStringPadEnd: constexpr int31 = 1;
14

15 16 17 18 19
transitioning macro StringPad(implicit context: Context)(
    receiver: JSAny, arguments: Arguments, methodName: constexpr string,
    variant: constexpr int31): String {
  const receiverString: String = ToThisString(receiver, methodName);
  const stringLength: Smi = receiverString.length_smi;
20

21 22 23 24
  if (arguments.length == 0) {
    return receiverString;
  }
  const maxLength: Number = ToLength_Inline(arguments[0]);
25
  dcheck(IsNumberNormalized(maxLength));
26

27 28 29 30
  typeswitch (maxLength) {
    case (smiMaxLength: Smi): {
      if (smiMaxLength <= stringLength) {
        return receiverString;
31 32
      }
    }
33
    case (Number): {
34
    }
35
  }
36

37 38 39 40 41 42 43 44 45 46
  let fillString: String = ' ';
  let fillLength: intptr = 1;

  if (arguments.length != 1) {
    const fill = arguments[1];
    if (fill != Undefined) {
      fillString = ToString_Inline(fill);
      fillLength = fillString.length_intptr;
      if (fillLength == 0) {
        return receiverString;
47 48
      }
    }
49
  }
50

51
  // Pad.
52
  dcheck(fillLength > 0);
53 54 55
  // Throw if max_length is greater than String::kMaxLength.
  if (!TaggedIsSmi(maxLength)) {
    ThrowInvalidStringLength(context);
56 57
  }

58 59 60 61
  const smiMaxLength: Smi = UnsafeCast<Smi>(maxLength);
  if (smiMaxLength > SmiConstant(kStringMaxLength)) {
    ThrowInvalidStringLength(context);
  }
62
  dcheck(smiMaxLength > stringLength);
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
  const padLength: Smi = smiMaxLength - stringLength;

  let padding: String;
  if (fillLength == 1) {
    // Single char fill.
    // Fast path for a single character fill.  No need to calculate number of
    // repetitions or remainder.
    padding = StringRepeat(context, fillString, padLength);
  } else {
    // Multi char fill.
    const fillLengthWord32: int32 = TruncateIntPtrToInt32(fillLength);
    const padLengthWord32: int32 = Convert<int32>(padLength);
    const repetitionsWord32: int32 = padLengthWord32 / fillLengthWord32;
    const remainingWord32: int32 = padLengthWord32 % fillLengthWord32;
    padding =
        StringRepeat(context, fillString, Convert<Smi>(repetitionsWord32));

    if (remainingWord32 != 0) {
      const remainderString =
          StringSubstring(fillString, 0, Convert<intptr>(remainingWord32));
      padding = padding + remainderString;
    }
85 86
  }

87
  // Return result.
88
  dcheck(padLength == padding.length_smi);
89 90
  if (variant == kStringPadStart) {
    return padding + receiverString;
91
  }
92
  dcheck(variant == kStringPadEnd);
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
  return receiverString + padding;
}

// ES6 #sec-string.prototype.padstart
transitioning javascript builtin
StringPrototypePadStart(
    js-implicit context: NativeContext, receiver: JSAny)(...arguments): String {
  const methodName: constexpr string = 'String.prototype.padStart';
  return StringPad(receiver, arguments, methodName, kStringPadStart);
}

// ES6 #sec-string.prototype.padend
transitioning javascript builtin
StringPrototypePadEnd(
    js-implicit context: NativeContext, receiver: JSAny)(...arguments): String {
  const methodName: constexpr string = 'String.prototype.padEnd';
  return StringPad(receiver, arguments, methodName, kStringPadEnd);
}
111
}