/**
   * Returns a stream of code point values (as {@code Integer} objects) from this sequence. Any
   * surrogate pairs encountered in the sequence are combined as if by {@linkplain
   * Character#toCodePoint Character.toCodePoint} and the result is passed to the stream. Any other
   * code units, including ordinary BMP characters, unpaired surrogates, and undefined code units,
   * are zero-extended to @{code int} values which are then passed to the stream.
   *
   * <p>If the sequence is mutated while the stream is being read, the result is undefined.
   *
   * @return an Iterable of Unicode code points from this sequence
   */
  public default IntStream codePoints() {
    class CodePointIterator implements IntStream.IntIterator {
      int cur = 0;

      @Override
      public void forEachInt(IntConsumer block) {
        while (cur < length()) {
          int cp = Character.codePointAt(CharSequence.this, cur);
          cur += Character.charCount(cp);
          block.accept(cp);
        }
      }

      public boolean hasNext() {
        return cur < length();
      }

      public int nextInt() {
        if (!hasNext()) throw new NoSuchElementException();
        // TODO: It probably would be faster if the logic from
        // the following two methods were inlined and simplified.
        int cp = Character.codePointAt(CharSequence.this, cur);
        cur += Character.charCount(cp);
        return cp;
      }
    }

    return Streams.intStream(
        () -> Streams.intSpliteratorUnknownSize(new CodePointIterator(), Spliterator.ORDERED),
        Spliterator.UNIFORM | Spliterator.SIZED | Spliterator.ORDERED);
  }
  /**
   * Returns a stream of char values from this sequence. If the sequence is mutated while the stream
   * is being read, the result is undefined.
   *
   * @return an Iterable of Character values from this sequence
   */
  public default IntStream chars() {
    class CharIterator implements IntStream.IntIterator {
      int cur = 0;

      public boolean hasNext() {
        return cur < length();
      }

      public int nextInt() {
        if (hasNext()) return charAt(cur++);
        else throw new NoSuchElementException();
      }

      @Override
      public void forEachInt(IntConsumer block) {
        for (; cur < length(); cur++) block.accept(charAt(cur));
      }
    }

    return Streams.intStream(
        () -> Streams.intSpliterator(new CharIterator(), length(), Spliterator.ORDERED),
        Spliterator.UNIFORM | Spliterator.SIZED | Spliterator.ORDERED);
  }