/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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.
 */

#pragma once

#include <folly/Portability.h>

#if FOLLY_SSE_PREREQ(4, 2)
#include <immintrin.h>
#endif

#include <stdint.h>

#include <cstddef>

namespace folly {
namespace detail {

/**
 * Compute a CRC-32C checksum of a buffer using a hardware-accelerated
 * implementation.
 *
 * @note This function is exposed to support special cases where the
 *       calling code is absolutely certain it ought to invoke a hardware-
 *       accelerated CRC-32C implementation - unit tests, for example.  For
 *       all other scenarios, please call crc32c() and let it pick an
 *       implementation based on the capabilities of the underlying CPU.
 */
uint32_t crc32c_hw(
    const uint8_t* data, size_t nbytes, uint32_t startingChecksum = ~0U);

/**
 * Check whether a SSE4.2 hardware-accelerated CRC-32C implementation is
 * supported on the current CPU.
 */
bool crc32c_hw_supported_sse42();

/**
 * Check whether a hardware-accelerated CRC-32C implementation is
 * supported on the current CPU.
 */
bool crc32c_hw_supported();

/**
 * Check whether an AVX512VL hardware-accelerated CRC-32C implementation is
 * supported on the current CPU.
 */
bool crc32c_hw_supported_avx512();

/**
 * Check whether a NEON hardware-accelerated CRC-32C implementation is
 * supported on the current CPU.
 */
bool crc32c_hw_supported_neon();

/**
 * Check whether a NEON+EOR3+SHA3 hardware-accelerated CRC-32C implementation
 * is supported on the current CPU.
 */
bool crc32c_hw_supported_neon_eor3_sha3();

/**
 * Compute a CRC-32C checksum of a buffer using a portable,
 * software-only implementation.
 *
 * @note This function is exposed to support special cases where the
 *       calling code is absolutely certain it wants to use the software
 *       implementation instead of the hardware-accelerated code - unit
 *       tests, for example.  For all other scenarios, please call crc32c()
 *       and let it pick an implementation based on the capabilities of
 *       the underlying CPU.
 */
uint32_t crc32c_sw(
    const uint8_t* data, size_t nbytes, uint32_t startingChecksum = ~0U);

/**
 * Compute a CRC-32 checksum of a buffer using a hardware-accelerated
 * implementation.
 *
 * @note This function is exposed to support special cases where the
 *       calling code is absolutely certain it ought to invoke a hardware-
 *       accelerated CRC-32 implementation - unit tests, for example.  For
 *       all other scenarios, please call crc32() and let it pick an
 *       implementation based on the capabilities of the underlying CPU.
 */
uint32_t crc32_hw(
    const uint8_t* data, size_t nbytes, uint32_t startingChecksum = ~0U);

#if FOLLY_SSE_PREREQ(4, 2)
uint32_t crc32_hw_aligned(
    uint32_t remainder, const __m128i* p, size_t vec_count);
#endif

/**
 * Check whether a hardware-accelerated CRC-32 implementation is
 * supported on the current CPU.
 */
bool crc32_hw_supported();

/**
 * Compute a CRC-32 checksum of a buffer using a portable,
 * software-only implementation.
 *
 * @note This function is exposed to support special cases where the
 *       calling code is absolutely certain it wants to use the software
 *       implementation instead of the hardware-accelerated code - unit
 *       tests, for example.  For all other scenarios, please call crc32()
 *       and let it pick an implementation based on the capabilities of
 *       the underlying CPU.
 */
uint32_t crc32_sw(
    const uint8_t* data, size_t nbytes, uint32_t startingChecksum = ~0U);

/* See Checksum.h for details.
 *
 * crc2len *must* be a power of two >= 4.
 */
uint32_t crc32_combine_sw(uint32_t crc1, uint32_t crc2, size_t crc2len);
uint32_t crc32_combine_hw(uint32_t crc1, uint32_t crc2, size_t crc2len);
uint32_t crc32c_combine_sw(uint32_t crc1, uint32_t crc2, size_t crc2len);
uint32_t crc32c_combine_hw(uint32_t crc1, uint32_t crc2, size_t crc2len);

} // namespace detail
} // namespace folly
