// bdlc_flathashtable_groupcontrol.h                                  -*-C++-*-
#ifndef INCLUDED_BDLC_FLATHASHTABLE_GROUPCONTROL
#define INCLUDED_BDLC_FLATHASHTABLE_GROUPCONTROL

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

//@PURPOSE: Provide inquiries to a flat hash table group of control values.
//
//@CLASSES:
//  bdlc::FlatHashTable_GroupControl: flat hash table group control inquiries
//
//@DESCRIPTION: This component implements the class,
// 'bdlc::FlatHashTable_GroupControl', that provides query methods to a group
// of flat hash table control values.  Note that the number of entries in a
// group control and the inquiry performance is platform dependant.
//
// The flat hash map/set/table data structures are inspired by Google's
// flat_hash_map CppCon presentations (available on youtube).  The
// implementations draw from Google's open source 'raw_hash_set.h' file at:
// https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal.
//
///Usage
///-----
// There is no usage example for this component since it is not meant for
// direct client use.

#include <bdlscm_version.h>

#include <bsls_assert.h>
#include <bsls_byteorder.h>
#include <bsls_platform.h>

#include <bsl_cstddef.h>
#include <bsl_cstdint.h>
#include <bsl_cstring.h>

#if defined(BSLS_PLATFORM_CPU_SSE2)
#include <immintrin.h>
#include <emmintrin.h>
#endif

namespace BloombergLP {
namespace bdlc {

                     // ================================
                     // class FlatHashTable_GroupControl
                     // ================================

class FlatHashTable_GroupControl
    // This class provides methods for making inquires to the data of a group
    // control loading during construction.
{
  public:
    // TYPES
#if defined(BSLS_PLATFORM_CPU_SSE2)
    typedef __m128i       Storage;
#else
    typedef bsl::uint64_t Storage;
#endif

  private:
    // CLASS DATA
    static const bsl::uint64_t k_MULT          = 0x0101010101010101ull;
    static const bsl::uint64_t k_DEFLATE       = 0x0002040810204081ull;
    static const int           k_DEFLATE_SHIFT = 56;
    static const bsl::uint64_t k_MSB_MASK      = 0x8080808080808080ull;

    // DATA
    Storage d_value;  // efficiently cached value for inquiries

    // PRIVATE ACCESSORS
    bsl::uint32_t matchRaw(bsl::uint8_t value) const;
        // Return a bit mask of the 'k_SIZE' entries that have the specified
        // 'value'.  The bit at index 'i' corresponds to the result for
        // 'data[i]'.

    // NOT IMPLEMENTED
    FlatHashTable_GroupControl();
    FlatHashTable_GroupControl(const FlatHashTable_GroupControl&);
    FlatHashTable_GroupControl& operator=(const FlatHashTable_GroupControl&);

  public:
    // PUBLIC CLASS DATA
    static const bsl::uint8_t k_EMPTY  = 0x80;  // = 0b10000000
    static const bsl::uint8_t k_ERASED = 0xC0;  // = 0b11000000
    static const bsl::size_t  k_SIZE   = sizeof(Storage);

    // CREATORS
    explicit FlatHashTable_GroupControl(const bsl::uint8_t *data);
        // Create a group control query object using the specified 'data'.  The
        // bytes of 'data' have no alignment requirement.  The behavior is
        // undefined unless 'data' has at least 'k_SIZE' bytes available.

    //! ~FlatHashTable_GroupControl() = default;
        // Destroy this object.

    // ACCESSORS
    bsl::uint32_t available() const;
        // Return a bit mask of the 'k_SIZE' entries that are empty or erased.
        // The bit at index 'i' corresponds to the result for 'data[i]'.

    bsl::uint32_t inUse() const;
        // Return a bit mask of the 'k_SIZE' entries that are in use (i.e., not
        // empty or erased).  The bit at index 'i' corresponds to the result
        // for 'data[i]'.

    bsl::uint32_t match(bsl::uint8_t value) const;
        // Return a bit mask of the 'k_SIZE' entries that have the specified
        // 'value'.  The bit at index 'i' corresponds to the result for
        // 'data[i]'.  The behavior is undefined unless '0 == (0x80 & value)'.

    bool neverFull() const;
        // Return 'true' if this group control was never full (i.e., has a
        // value that is empty, but not erased).
};

// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================

                     // --------------------------------
                     // class FlatHashTable_GroupControl
                     // --------------------------------

// PRIVATE ACCESSORS
inline
bsl::uint32_t FlatHashTable_GroupControl::matchRaw(bsl::uint8_t value) const
{
#if defined(BSLS_PLATFORM_CPU_SSE2)
    return _mm_movemask_epi8(_mm_cmpeq_epi8(
                                       _mm_set1_epi8(static_cast<char>(value)),
                                       d_value));
#else
    Storage t = d_value ^ (k_MULT * value);

    t = t | (t << 4);
    t = t | (t << 2);
    t = t | (t << 1);

    return static_cast<bsl::uint32_t>(
                         (((~t) & k_MSB_MASK) * k_DEFLATE) >> k_DEFLATE_SHIFT);
#endif
}

// CREATORS
inline
FlatHashTable_GroupControl::FlatHashTable_GroupControl(
                                                      const bsl::uint8_t *data)
{
#if defined(BSLS_PLATFORM_CPU_SSE2)
    d_value = _mm_loadu_si128(static_cast<const Storage *>(
                                             static_cast<const void *>(data)));
#else
    bsl::memcpy(&d_value, data, k_SIZE);
    d_value = BSLS_BYTEORDER_HOST_U64_TO_LE(d_value);
#endif
}

// ACCESSORS
inline
bsl::uint32_t FlatHashTable_GroupControl::available() const
{
#if defined(BSLS_PLATFORM_CPU_SSE2)
    return _mm_movemask_epi8(d_value);
#else
    return static_cast<bsl::uint32_t>(
                      ((d_value & k_MSB_MASK) * k_DEFLATE) >> k_DEFLATE_SHIFT);
#endif
}

inline
bsl::uint32_t FlatHashTable_GroupControl::inUse() const
{
#if defined(BSLS_PLATFORM_CPU_SSE2)
    return (~available()) & 0xFFFF;
#else
    return (~available()) & 0xFF;
#endif
}

inline
bsl::uint32_t FlatHashTable_GroupControl::match(bsl::uint8_t value) const
{
    BSLS_ASSERT_SAFE(0 == (value & 0x80));

    return matchRaw(value);
}

inline
bool FlatHashTable_GroupControl::neverFull() const
{
    return 0 != matchRaw(k_EMPTY);
}

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

#endif

// ----------------------------------------------------------------------------
// Copyright 2020 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 ----------------------------------