<commit_before>/*
 * Copyright 2016-2018 libfpta authors: please see AUTHORS file.
 *
 * This file is part of libfpta, aka "Fast Positive Tables".
 *
 * libfpta is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libfpta is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libfpta.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "details.h"

//----------------------------------------------------------------------------

#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
    !defined(__ORDER_BIG_ENDIAN__)
#error __BYTE_ORDER__ should be defined.
#endif

#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ &&                               \
    __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
#error Unsupported byte order.
#endif

#ifndef UNALIGNED_OK
#error UNALIGNED_OK should be defined.
#endif

static int __hot fpta_idxcmp_binary_last2first(const MDBX_val *a,
                                               const MDBX_val *b) {
  const uint8_t *pa = (const uint8_t *)a->iov_base + a->iov_len;
  const uint8_t *pb = (const uint8_t *)b->iov_base + b->iov_len;
  const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
  const uint8_t *const stopper = pa - shortest;

#if UNALIGNED_OK && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
  if (shortest >= sizeof(size_t)) {
    do {
      pa -= sizeof(size_t);
      pb -= sizeof(size_t);
      int diff = fptu_cmp2int(*(size_t *)pa, *(size_t *)pb);
      if (likely(diff))
        return diff;
    } while (pa - sizeof(size_t) >= stopper);
  }
  if (sizeof(unsigned) < sizeof(size_t) && pa >= stopper + sizeof(unsigned)) {
    pa -= sizeof(unsigned);
    pb -= sizeof(unsigned);
    int diff = fptu_cmp2int(*(unsigned *)pa, *(unsigned *)pb);
    if (likely(diff))
      return diff;
  }
  if (sizeof(unsigned short) < sizeof(unsigned) &&
      pa >= stopper + sizeof(unsigned short)) {
    pa -= sizeof(unsigned short);
    pb -= sizeof(unsigned short);
    int diff = *(unsigned short *)pa - *(unsigned short *)pb;
    if (likely(diff))
      return diff;
  }
#endif

  while (pa != stopper) {
    int diff = *--pa - *--pb;
    if (likely(diff))
      return diff;
  }
  return fptu_cmp2int(a->iov_len, b->iov_len);
}

static int __hot fpta_idxcmp_binary_first2last(const MDBX_val *a,
                                               const MDBX_val *b) {
  size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
  int diff = memcmp(a->iov_base, b->iov_base, shortest);
  return likely(diff) ? diff : fptu_cmp2int(a->iov_len, b->iov_len);
}

template <typename T>
static int __hot fpta_idxcmp_type(const MDBX_val *a, const MDBX_val *b) {
  assert(a->iov_len == sizeof(T) && b->iov_len == sizeof(T));
  if (UNALIGNED_OK || sizeof(T) < 4) {
    const T va = *(const T *)a->iov_base;
    const T vb = *(const T *)b->iov_base;
    return fptu_cmp2int(va, vb);
  } else if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) {
    const uint8_t *pa = (const uint8_t *)a->iov_base;
    const uint8_t *pb = (const uint8_t *)b->iov_base;
    int diff, i = sizeof(T) - 1;
    do
      diff = pa[i] - pb[i];
    while (diff == 0 && --i >= 0);
    return diff;
  } else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) {
    return memcmp(a->iov_base, b->iov_base, sizeof(T));
  }
  return 0;
}

static int __hot fpta_idxcmp_fp32(const MDBX_val *a, const MDBX_val *b) {
  assert(a->iov_len == 4 && b->iov_len == 4);
  int32_t va, vb;

#if UNALIGNED_OK
  va = *(const int32_t *)a->iov_base;
  vb = *(const int32_t *)b->iov_base;
#else
  memcpy(va, a->iov_base, 4);
  memcpy(vb, b->iov_base, 4);
#endif

  int32_t negative = va & (1 << 31);
  if ((negative ^ vb) < 0)
    return negative ? -1 : 1;

  int32_t cmp = (va & INT32_C(0x7fffFFFF)) - (vb & INT32_C(0x7fffFFFF));
  return negative ? -cmp : cmp;
}

static int __hot fpta_idxcmp_fp64(const MDBX_val *a, const MDBX_val *b) {
  assert(a->iov_len == 8 && b->iov_len == 8);
  int64_t va, vb;

#if UNALIGNED_OK
  va = *(const int64_t *)a->iov_base;
  vb = *(const int64_t *)b->iov_base;
#else
  memcpy(va, a->iov_base, 8);
  memcpy(vb, b->iov_base, 8);
#endif

  int64_t negative = va & UINT64_C(0x8000000000000000);
  if ((negative ^ vb) < 0)
    return negative ? -1 : 1;

  int cmp = fptu_cmp2int(va & UINT64_C(0x7fffFFFFffffFFFF),
                         vb & UINT64_C(0x7fffFFFFffffFFFF));
  return negative ? -cmp : cmp;
}

static int fpta_idxcmp_tuple(const MDBX_val *a, const MDBX_val *b) {<commit_msg>fpta: fix idxcmp_fp32() and idxcmp_fp64() for UNALIGNED_OK == FALSE.<commit_after>/*
 * Copyright 2016-2018 libfpta authors: please see AUTHORS file.
 *
 * This file is part of libfpta, aka "Fast Positive Tables".
 *
 * libfpta is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libfpta is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libfpta.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "details.h"

//----------------------------------------------------------------------------

#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) ||           \
    !defined(__ORDER_BIG_ENDIAN__)
#error __BYTE_ORDER__ should be defined.
#endif

#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ &&                               \
    __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
#error Unsupported byte order.
#endif

#ifndef UNALIGNED_OK
#error UNALIGNED_OK should be defined.
#endif

static int __hot fpta_idxcmp_binary_last2first(const MDBX_val *a,
                                               const MDBX_val *b) {
  const uint8_t *pa = (const uint8_t *)a->iov_base + a->iov_len;
  const uint8_t *pb = (const uint8_t *)b->iov_base + b->iov_len;
  const size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
  const uint8_t *const stopper = pa - shortest;

#if UNALIGNED_OK && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
  if (shortest >= sizeof(size_t)) {
    do {
      pa -= sizeof(size_t);
      pb -= sizeof(size_t);
      int diff = fptu_cmp2int(*(size_t *)pa, *(size_t *)pb);
      if (likely(diff))
        return diff;
    } while (pa - sizeof(size_t) >= stopper);
  }
  if (sizeof(unsigned) < sizeof(size_t) && pa >= stopper + sizeof(unsigned)) {
    pa -= sizeof(unsigned);
    pb -= sizeof(unsigned);
    int diff = fptu_cmp2int(*(unsigned *)pa, *(unsigned *)pb);
    if (likely(diff))
      return diff;
  }
  if (sizeof(unsigned short) < sizeof(unsigned) &&
      pa >= stopper + sizeof(unsigned short)) {
    pa -= sizeof(unsigned short);
    pb -= sizeof(unsigned short);
    int diff = *(unsigned short *)pa - *(unsigned short *)pb;
    if (likely(diff))
      return diff;
  }
#endif

  while (pa != stopper) {
    int diff = *--pa - *--pb;
    if (likely(diff))
      return diff;
  }
  return fptu_cmp2int(a->iov_len, b->iov_len);
}

static int __hot fpta_idxcmp_binary_first2last(const MDBX_val *a,
                                               const MDBX_val *b) {
  size_t shortest = (a->iov_len < b->iov_len) ? a->iov_len : b->iov_len;
  int diff = memcmp(a->iov_base, b->iov_base, shortest);
  return likely(diff) ? diff : fptu_cmp2int(a->iov_len, b->iov_len);
}

template <typename T>
static int __hot fpta_idxcmp_type(const MDBX_val *a, const MDBX_val *b) {
  assert(a->iov_len == sizeof(T) && b->iov_len == sizeof(T));
  if (UNALIGNED_OK || sizeof(T) < 4) {
    const T va = *(const T *)a->iov_base;
    const T vb = *(const T *)b->iov_base;
    return fptu_cmp2int(va, vb);
  } else if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) {
    const uint8_t *pa = (const uint8_t *)a->iov_base;
    const uint8_t *pb = (const uint8_t *)b->iov_base;
    int diff, i = sizeof(T) - 1;
    do
      diff = pa[i] - pb[i];
    while (diff == 0 && --i >= 0);
    return diff;
  } else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) {
    return memcmp(a->iov_base, b->iov_base, sizeof(T));
  }
  return 0;
}

static int __hot fpta_idxcmp_fp32(const MDBX_val *a, const MDBX_val *b) {
  assert(a->iov_len == 4 && b->iov_len == 4);
  int32_t va, vb;

#if UNALIGNED_OK
  va = *(const int32_t *)a->iov_base;
  vb = *(const int32_t *)b->iov_base;
#else
  memcpy(&va, a->iov_base, 4);
  memcpy(&vb, b->iov_base, 4);
#endif

  int32_t negative = va & (1 << 31);
  if ((negative ^ vb) < 0)
    return negative ? -1 : 1;

  int32_t cmp = (va & INT32_C(0x7fffFFFF)) - (vb & INT32_C(0x7fffFFFF));
  return negative ? -cmp : cmp;
}

static int __hot fpta_idxcmp_fp64(const MDBX_val *a, const MDBX_val *b) {
  assert(a->iov_len == 8 && b->iov_len == 8);
  int64_t va, vb;

#if UNALIGNED_OK
  va = *(const int64_t *)a->iov_base;
  vb = *(const int64_t *)b->iov_base;
#else
  memcpy(&va, a->iov_base, 8);
  memcpy(&vb, b->iov_base, 8);
#endif

  int64_t negative = va & UINT64_C(0x8000000000000000);
  if ((negative ^ vb) < 0)
    return negative ? -1 : 1;

  int cmp = fptu_cmp2int(va & UINT64_C(0x7fffFFFFffffFFFF),
                         vb & UINT64_C(0x7fffFFFFffffFFFF));
  return negative ? -cmp : cmp;
}

static int fpta_idxcmp_tuple(const MDBX_val *a, const MDBX_val *b) {
{'fraction_non_alphanumeric': 0.14877875747440966, 'fraction_numerical': 0.021688456471065168, 'mean_word_length': 2.944044764188649, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4758393', 'n_tokens_mistral': 3762, 'n_tokens_neox': 3662, 'n_words': 989}