/*
 * Copyright 2021 ByteDance Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "native.h"

size_t lspace(const char *sp, size_t nb, size_t p) {
    const char * ss = sp;

    /* seek to `p` */
    sp += p;
    nb -= p;

    /* likely to run into non-spaces within a few characters, try scalar code first */
#if USE_AVX2
    __m256i space_tab = _mm256_setr_epi8(
        '\x20', 0, 0, 0, 0, 0, 0, 0,
         0, '\x09', '\x0A', 0, 0, '\x0D', 0, 0,
        '\x20', 0, 0, 0, 0, 0, 0, 0,
         0, '\x09', '\x0A', 0, 0, '\x0D', 0, 0
    );

    /* 32-byte loop */
    while (likely(nb >= 32)) {
        __m256i input = _mm256_loadu_si256((__m256i*)sp);
        __m256i shuffle = _mm256_shuffle_epi8(space_tab, input);
        __m256i result = _mm256_cmpeq_epi8(input, shuffle);
        int32_t mask = _mm256_movemask_epi8(result);
        if (mask != -1) {
            return sp - ss + __builtin_ctzll(~(uint64_t)mask);
        }
        sp += 32;
        nb -= 32;
    }
#endif

    /* remaining bytes, do with scalar code */
    while (nb-- > 0) {
        switch (*sp++) {
            case ' '  : break;
            case '\r' : break;
            case '\n' : break;
            case '\t' : break;
            default   : return sp - ss - 1;
        }
    }

    /* all the characters are spaces */
    return sp - ss;
}