/**
 * @file src/bit.c
 */

#include "bit.h"
#include "testing.h"

[[gnu::const]] static size_t nulCheck(size_t x) {
  size_t m = repeatBytes(0x7f);
  return (x & m) + m | m;
}

/**
 * @brief Find zero all
 */
[[gnu::const]] bool fza(size_t x) {
  return ~(nulCheck(x) | x);
}

/**
 * @brief FZA for ascii string
 */
[[gnu::const]] bool isNulExist(size_t x) {
  return ~nulCheck(x);
}

test (zero_byte_check) {
  size_t x = 0x10'10'10'10'10'00'00'00;
  expect(fza(x));
  expect(isNulExist(x));

  x = 0xde'ad'be'ef'de'ad'be'ef;
  expect(!fza(x));
  expect(!isNulExist(x));

  x = 0x80'80'80'80'80'80'80'80;
  expect(!fza(x));
  expect(isNulExist(x));
}

[[gnu::const]] size_t repeatBytes(byte_t c) {
  return -1UL / 0xff * (size_t)c;
}

test_table(
  repeat_bytes, repeatBytes, (size_t, byte_t),
  {
    {0xff'ff'ff'ff'ff'ff'ff'ff, 0xff},
    {0x12'12'12'12'12'12'12'12, 0x12},
    {0x01'01'01'01'01'01'01'01, 0x01},
    {0x00'00'00'00'00'00'00'00, 0x00},
}
)

/**
 * @brief Align to multiples of size
 * @param[in] base Pointer
 * @param[in] size Size
 * @return Aligned pointer
 */
[[gnu::const]] void *alignBackward(void const *base, size_t size) {
  return (void *)((size_t)base & -size);
}
[[gnu::const]] void *alignForward(void const *base, size_t size) {
  return alignBackward(base + size - 1, size);
}

test_table(
  alignBack, alignBackward, (void *, void const *, size_t),
  {
    {(void *)8,  (void *)9, 8},
    {(void *)8, (void *)15, 8},
    {(void *)8,  (void *)8, 8},
}
)

test_table(
  alignFor, alignForward, (void *, void const *, size_t),
  {
    {(void *)8, (void *)5, 8},
    {(void *)8, (void *)1, 8},
    {(void *)8, (void *)8, 8},
}
)