/**
 * @file src/mem.c
 */

#include "mem.h"
#include "bit.h"
#include "chore.h"
#include "exproriented.h"
#include "testing.h"

/**
 * @brief Skip index to first non-white-space char
 */
size_t skipByteDirectly(char const *restrict str, byte_t b, size_t len) {
  size_t i = 0;
  for (; i < len && str[i] == b; i++);
  return i;
}

[[gnu::const]] static size_t skipByteSize(size_t s, byte_t c) {
  return stdc_trailing_zeros(s ^ repeatBytes(c)) / p_size;
}

size_t skipByte(char const *restrict str, byte_t b) {
  char const *s = alignForward(str, p_size);
  size_t i = skipByteDirectly(str, b, -(size_t)str & p_size - 1);
  if (str + i < s) return i;

  while (!isNulExist(*bit_cast(size_t const *, s))) {
    size_t skip = skipByteSize(*bit_cast(size_t const *, s), b);
    i += skip;
    if (skip < p_size) return i;
    s += p_size;
  }
  return i + skipByteDirectly(s, b, -1UL);
}

test (skip) {
  char const *s = "             a";
  for (size_t i = 13; 0 < i; i--, s++) expecteq(i, skipByte(s, ' '));
}

/**
 * @brief Skip pointer to the char following the comma
 * @param[in,out] s String pointer
 */
size_t skipUntil(char const *restrict s, byte_t b) {
  char const *str = strchr(s, b) ?: p$return(strlen(s));
  return (size_t)(str - s + 1);
}

char *memrchr(char const *restrict s, int c, size_t n) {
  size_t i = n;
  for (; 0 < i && s[i] != c; i--);
  return (char *)($if(i != 0) s + i $else $if(*s == c) s $else nullptr);
}