// bdlde_crc32c.h                                                     -*-C++-*-
#ifndef INCLUDED_BDLDE_CRC32C
#define INCLUDED_BDLDE_CRC32C

#include <bsls_ident.h>
BSLS_IDENT("$Id$")

//@PURPOSE: Provide utilities to calculate the CRC32-C checksum of a dataset.
//
//@CLASSES:
//  bdlde::Crc32c     : calculates CRC32-C checksum
//  bdlde::Crc32c_Impl: calculates CRC32-C checksum with alternative impl.
//
//@SEE_ALSO: bdlde_crc32
//
//@DESCRIPTION: This component defines a struct, `bdlde::Crc32c` that
// dramatically accelerates (as opposite to the `bdlde::Crc32` component)
// calculation of a CRC32-C checksum (a cyclic redundancy check, comprised of
// 32 bits, that uses the Castagnoli polynomial), using a hardware-accelerated
// implementation if supported or a software implementation otherwise.  It
// additionally defines the struct `bdlde::Crc32c_Impl` to expose alternative
// implementations that should not be used other than to test and benchmark.
// Note that a CRC32-C checksum is a strong and fast technique for determining
// whether or not a message was received without errors.  Also note that a
// CRC-32 checksum does not aid in error correction and is not naively useful
// in any sort of cryptography application.
//
///Thread Safety
///-------------
// Thread safe.
//
///Support for Hardware Acceleration
///---------------------------------
// Hardware-accelerated implementation is enabled at compile time when building
// on a supported architecture with a compatible compiler.  In addition,
// runtime checks are performed to detect whether the running platform has the
// required hardware support:
// * x86:   SSE4.2 instructions are required
// * sparc: runtime check is detected by the `is_sparc_crc32c_avail` system
//   call
//
///Performance
///-----------
// See the test driver for this component in the `.t.cpp` to compare
// performance of the hardware-accelerated and software implementations against
// various alternative implementations that compute a 32-bit CRC checksum.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Computing and updating a checksum
/// - - - - - - - - - - - - - - - - - - - - - -
// The following code illustrates how to calculate and update a CRC32-C
// checksum for a message over the course of building the full message.
//
// First, prepare a message.
// ```
// bsl::string message = "This is a test message.";
// ```
// Now, generate a checksum for `message`.
// ```
// unsigned int checksum = bdlde::Crc32c::calculate(message.c_str(),
//                                                  message.size());
// ```
// Finally, if we learn that our message has grown by another chunk and we want
// to compute the checksum of the original message plus the new chunk, let's
// update the checksum by using it as a starting point.
// ```
// // New chunk
// bsl::string newChunk = "This is a chunk appended to original message";
// message += newChunk;
//
// // Update checksum using previous value as starting point
// checksum = bdlde::Crc32c::calculate(newChunk.c_str(),
//                                     newChunk.size(),
//                                     checksum);
// ```

#include <bdlscm_version.h>

#include <bsl_cstddef.h>

namespace BloombergLP {
namespace bdlde {

                               // =============
                               // struct Crc32c
                               // =============

/// This class provides runtime-efficient utilities to calculate a CRC32-C
/// checksum.
struct Crc32c {

  public:
    // CLASS DATA

    /// CRC32-C value for a 0 length input.  Note that a buffer with this
    /// CRC32-C value need not be a 0 length input.
    static const unsigned int k_NULL_CRC32C = 0U;

    // CLASS METHODS

    /// Return the CRC32-C value calculated for the specified `data` over
    /// the specified `length` number of bytes, using the optionally
    /// specified `crc` value as the starting point for the calculation.
    /// Note that if `data` is 0, then `length` also must be 0.
    static unsigned int calculate(const void   *data,
                                  bsl::size_t   length,
                                  unsigned int  crc = k_NULL_CRC32C);
};

                             // ==================
                             // struct Crc32c_Impl
                             // ==================

/// This class provides alternative implementations of utilities to
/// calculate a CRC32-C checksum.
struct Crc32c_Impl {

  public:
    // CLASS METHODS

    /// Return the CRC32-C value calculated for the specified `data` over
    /// the specified `length` number of bytes, using the optionally
    /// specified `crc` value as the starting point for the calculation.
    /// This utilizes a portable software-based implementation to perform
    /// the calculation.  Note that if `data` is 0, then `length` must also
    /// be 0.
    static
    unsigned int calculateSoftware(const void   *data,
                                   bsl::size_t   length,
                                   unsigned int  crc = Crc32c::k_NULL_CRC32C);

    /// Return the CRC32-C value calculated for the specified `data` over
    /// the specified `length` number of bytes, using the optionally
    /// specified `crc` value as the starting point for the calculation.
    /// This utilizes a hardware-based implementation that does not leverage
    /// instruction level parallelism to perform the calculation (hence it
    /// calculates the crc32c in "serial").  Note that this function will
    /// fall back to the software version when running on unsupported
    /// platforms.  Also note that if `data` is 0, then `length` must also
    /// be 0.
    static
    unsigned int calculateHardwareSerial(
                                    const void   *data,
                                    bsl::size_t   length,
                                    unsigned int  crc = Crc32c::k_NULL_CRC32C);
};

}  // close package namespace
}  // close enterprise namespace


#endif

// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// 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.
// ----------------------------- END-OF-FILE ----------------------------------
