// bdlb_guid.h                                                        -*-C++-*-
#ifndef INCLUDED_BDLB_GUID
#define INCLUDED_BDLB_GUID

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

//@PURPOSE: Provide a value-semantic type for Globally Unique Identifiers.
//
//@CLASSES:
//  bdlb::Guid: value-semantic type to represent Globally Unique Identifiers
//
//@SEE_ALSO: bdlb_guidutil
//
//@DESCRIPTION: This component provides a value-semantic type for Globally
// Unique Identifiers (GUIDs), 'bdlb::Guid', with format as described by RFC
// 4122 ('http://www.ietf.org/rfc/rfc4122.txt').  All equality and comparison
// methods are defined for these GUIDs.  Note that this component does not
// provide the facilities to generate GUIDs, and thus makes no guarantees of
// uniqueness or randomness.
//
///Usage
///-----
// Suppose we are building a utility to create globally unique names which may
// be based on a common base name, such as a code-generator.
//
// First, let us define the core types needed, the first of which is a utility
// to allocate GUIDs.
//..
//  struct MyGuidGeneratorUtil {
//      // This struct provides a namespace for methods to generate GUIDs.
//
//      // CLASS METHODS
//      static int generate(bdlb::Guid *guid);
//          // Generate a version 1 GUID, placing the value into the
//          // specified 'guid' pointer.  Return 0 on success, and non-zero
//          // otherwise.
//  };
//
//  // CLASS METHODS
//  inline
//  int my_GuidGeneratorUtil::generate(bdlb::Guid *guid)
//  {
//      // For brevity, we use a static sequence of pre-generated GUIDs.
//
//      static unsigned char GUIDS[][bdlb::Guid::k_GUID_NUM_BYTES] = {
//          { 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe,
//            0x91, 0x91, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 },
//
//          { 0x5c, 0x9d, 0x4e, 0x51, 0x0d, 0xf1, 0x11, 0xe4,
//            0x91, 0x91, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 },
//
//          { 0x5c, 0x9d, 0x4e, 0x52, 0x0d, 0xf1, 0x11, 0xe4,
//            0x91, 0x91, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 },
//
//          { 0x5c, 0x9d, 0x4e, 0x53, 0x0d, 0xf1, 0x11, 0xe4,
//            0x91, 0x91, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 },
//
//          { 0x5c, 0x9d, 0x4e, 0x54, 0x0d, 0xf1, 0x11, 0xe4,
//            0x91, 0x91, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 },
//
//          { 0x5c, 0x9d, 0x4e, 0x55, 0x0d, 0xf1, 0x11, 0xe4,
//            0x91, 0x91, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 },
//
//          { 0x5c, 0x9d, 0x4e, 0x56, 0x0d, 0xf1, 0x11, 0xe4,
//            0x91, 0x91, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 },
//      };
//
//      const bsl::size_t NUM_GUIDS = sizeof GUIDS / sizeof *GUIDS;
//
//      static bsl::size_t nextGuidIdx = 0;
//
//      int rval = -1;
//      if (nextGuidIdx++ < NUM_GUIDS) {
//          *guid = bdlb::Guid(GUIDS[nextGuidIdx]);
//          rval = 0;
//      }
//      return rval;
// }
//..
//  Next, we create a utility to create unique strings.
//..
//  struct UniqueStringGenerator {
//      // This struct provides methods to create globally unique strings.
//
//      static int uniqueStringFromBase(bsl::string        *unique,
//                                      const bsl::string&  base);
//            // Create a globally unique string from the specified non-unique
//            // 'base' string, placing the result into the specified 'unique'
//            // string pointer.
//
//  };
//
//  int
//  UniqueStringGenerator::uniqueStringFromBase(bsl::string        *unique,
//                                              const bsl::string&  base,)
//  {
//      bdlb::Guid guid;
//
//      int rval = my_GuidGeneratorUtil::generate(&guid);
//      if (rval == 0) {
//      {
//          ostringstream convert;
//          convert << base << "-" << guid;
//          *unique = convert.str();
//      }
//      return rval;
//  }
//..
//  Finally, we implement a program to generate unique names for a code
//  auto-generator.
//..
//  bsl::string baseFileName = "foo.cpp";
//  bsl::string uniqueFileName;
//  bsl::string previousFileName;
//
//  const bsl::size_t NUM_FILES = 5;
//  for (bsl::size_t i = 0; i < NUM_FILES; ++i) {
//      UniqueStringGenerator::uniqueStringFromBase(&uniqueFileName,
//                                                  baseFileName);
//      assert(previousFileName != uniqueFileName);
//       previousFileName = uniqueFileName;
//  }
//..

#include <bslmf_assert.h>
#include <bslmf_isbitwiseequalitycomparable.h>
#include <bslmf_istriviallycopyable.h>
#include <bslmf_nestedtraitdeclaration.h>

#include <bsls_alignedbuffer.h>
#include <bsls_alignmentfromtype.h>
#include <bsls_assert.h>
#include <bsls_review.h>
#include <bsls_types.h>

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

namespace BloombergLP {
namespace bdlb {
                                // ==========
                                // bdlb::Guid
                                // ==========
class Guid {
    // This class implements a value-semantic 'Guid' type.  Each object
    // represents an unconstrained 'Guid' object, but its uniqueness is *not*
    // guaranteed, and this component provides no ability to generate a GUID.
    //
    // This class provides a constructor and several accessors with names and
    // parameters phrased using RFC 4122 field names.  These names are used (by
    // RFC 4122 and this component) as designators for parts of the GUID even
    // when those names do not accurately describe the parts (for example,
    // 'time low' names bytes 0-3 of the GUID regardless of whether the values
    // of those bytes come from a clock or are generated randomly).

  public:
    // CLASS DATA
    enum { k_GUID_NUM_BYTES  = 16 };           // number of bytes in a guid
    enum { k_GUID_NUM_32BITS =  4 };           // number of 32-bits in a guid

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(Guid, bslmf::IsBitwiseEqualityComparable)
    BSLMF_NESTED_TRAIT_DECLARATION(Guid, bsl::is_trivially_copyable)

  private:
    // DATA
    bsls::AlignedBuffer<k_GUID_NUM_BYTES,
                        bsls::AlignmentFromType<bsl::uint32_t>::VALUE>
        d_alignedBuffer;
        // byte array to hold the guid

    // FRIENDS
    friend bool operator==(const Guid& lhs, const Guid& rhs);
    friend bool operator!=(const Guid& lhs, const Guid& rhs);

    // PRIVATE MANIPULATORS
    unsigned char *modifiableData();
        // Return a pointer offering modifiable access to the most significant
        // byte of this guid object.

  public:
    // CREATORS
    Guid();
        // Construct a zero-initialized guid object.  Note that a zero-
        // initialized guid object is not a GUID according to RFC 4122.

    //! ~Guid() = default;
        // Destroy this object

    explicit Guid(const unsigned char (&buffer)[k_GUID_NUM_BYTES]);
        // Construct a guid object with the internal buffer set equal to the
        // specified 'buffer' with the first byte representing the most
        // significant byte.  Note that this method does guarantee that the
        // created guid object is a GUID.

    Guid(unsigned long       timeLow,
         unsigned short      timeMid,
         unsigned short      timeHiAndVersion,
         unsigned char       clockSeqHiRes,
         unsigned char       clockSeqLow,
         bsls::Types::Uint64 node);
        // Construct a guid object with an internal buffer composed from the
        // specified 'timeLow', 'timeMid', 'timeHiAndVersion', 'clockSeqHiRes',
        // 'clockSeqLow', and 'node' as specified by RFC 4122.  Note that only
        // the least significant 48 bits of 'node' are used in constructing
        // the guid.

    //! Guid(const Guid& original) = default;
        // Construct a guid object having the same value as the specified
        // 'original' object.

    // MANIPULATORS
    //! Guid& operator=(const Guid& rhs) = default;
        // Assign to this guid object the value of the specified 'rhs' and
        // return a reference to this modifiable object.

    Guid& operator=(const unsigned char (&buffer)[k_GUID_NUM_BYTES]);
        // Assign to the buffer of this guid the byte sequence in the specified
        // 'buffer'.

    Guid& operator=(const bsl::uint32_t (&buffer)[k_GUID_NUM_32BITS]);
        // Assign to the buffer of this guid the byte sequence in the specified
        // 'buffer'. Note that 'buffer' is treated as purely a sequence of
        // bytes, and no account is taken of endianness.

    // ACCESSORS
    const unsigned char& operator[](bsl::size_t offset) const;
        // Return a reference offering unmodifiable access to the byte at the
        // specified 'offset' from the most significant byte of this guid
        // object.  The behavior is undefined unless
        // '0 <= offset < k_GUID_NUM_BYTES'.

    const unsigned char *begin() const;
    const unsigned char *data() const;
        // Return a pointer offering unmodifiable access to the most
        // significant byte of this guid object.

    const unsigned char *end() const;
        // Return a pointer one past the end of the least significant byte of
        // this guid object.

                        // RFC 4122 FIELD ACCESSORS

    unsigned char clockSeqHi() const;
        // Return the 5-bit value of the 'clk_seq_hi_res' field of this guid as
        // specified in RFC 4122, excluding the variant bits.

    unsigned char clockSeqHiRes() const;
        // Return the 8-bit 'clk_seq_hi_res' field of this guid as specified in
        // RFC 4122.

    unsigned char clockSeqLow() const;
        // Return the 8-bit 'clk_seq_low' field of this guid as specified in
        // RFC 4122.

    bsls::Types::Uint64 node() const;
        // Return the 48-bit 'node' field of this guid as specified in RFC
        // 4122.

    unsigned short timeHi() const;
        // Return the 12-bit value of the 'time_hi_and_version' field of this
        // guid as specified in RFC 4122, excluding the 'version' bits.

    unsigned short timeHiAndVersion() const;
        // Return the 16-bit 'time_hi_and_version' field of this guid as
        // specified in RFC 4122.

    unsigned long timeLow() const;
        // Return the 32-bit 'time_low' field of this guid as specified in RFC
        // 4122.

    unsigned short timeMid() const;
        // Return the 16-bit 'time_mid' field of this guid as specified in RFC
        // 4122.

    unsigned char variant() const;
        // Return the 3-bit 'variant' portion of the 'clk_seq_hi_res' field of
        // this guid as specified in RFC 4122.

    unsigned char version() const;
        // Return the four-bit 'version' portion of the 'time_hi_and_version'
        // field of this guid as specified in RFC 4122.

    // ASPECTS
    bsl::ostream& print(bsl::ostream& stream,
                        int           level = 0,
                        int           spacesPerLevel = 4) const;
        // Write the value of this object to the specified output 'stream' in a
        // human-readable format, and return a reference to 'stream'.
        // Optionally specify an initial indentation 'level', whose absolute
        // value is incremented recursively for nested objects.  If 'level' is
        // specified, optionally specify 'spacesPerLevel', whose absolute value
        // indicates the number of spaces per indentation level for this and
        // all of its nested objects.  If 'level' is negative, suppress
        // indentation of the first line.  If 'spacesPerLevel' is negative,
        // format the entire output on one line, suppressing all but the
        // initial indentation (as governed by 'level').  If 'stream' is not
        // valid on entry, this operation has no effect.  Note that this
        // human-readable format is not fully specified, and can change without
        // notice.
};

// FREE OPERATORS
bool operator==(const Guid& lhs, const Guid& rhs);
    // Return 'true' if the specified 'lhs' and specified 'rhs' guid objects
    // have the same value, and 'false' otherwise.  Two guid objects have the
    // same value if each corresponding byte in their internal buffers are
    // equal.

bool operator!=(const Guid& lhs, const Guid& rhs);
    // Return 'true' if the specified 'lhs' and specified 'rhs' guid objects
    // have different values, and 'false' otherwise.  Two guid objects have
    // different value if any of corresponding byte in their internal buffers
    // differ.

bool operator< (const Guid& lhs, const Guid& rhs);
    // Return 'true' if the value of the specified 'lhs' guid object is less
    // than the value of the specified 'rhs' guid object, and 'false'
    // otherwise.  Note that the comparison is accomplished using a
    // lexicographic comparison of the internal representations.

bool operator<=(const Guid& lhs, const Guid& rhs);
    // Return 'true' if the value of the specified 'lhs' guid object is less
    // than or equal to the value of the specified 'rhs' guid object, and
    // 'false' otherwise.  Note that the comparison is accomplished using  a
    // lexicographic comparison of the internal representations.

bool operator> (const Guid& lhs, const Guid& rhs);
    // Return 'true' if the value of the specified 'lhs' guid object is greater
    // than the value of the specified 'rhs' guid object, and 'false'
    // otherwise.  Note that the comparison is accomplished using a
    // lexicographic comparison of the internal representations.

bool operator>=(const Guid& lhs, const Guid& rhs);
    // Return 'true' if the value of the specified 'lhs' guid object is greater
    // than or equal to the value of the specified 'rhs' guid object, and
    // 'false' otherwise.  Note that the comparison is accomplished using a
    // lexicographic comparison of the internal representations.

bsl::ostream& operator<<(bsl::ostream& stream, const Guid& guid);
    // Write the value of the specified 'guid' object to the specified output
    // 'stream' in a single-line format, and return a reference to 'stream'.
    // If 'stream' is not valid on entry, this operation has no effect.  Note
    // that this human-readable format is not fully specified, can change
    // without notice, and is logically equivalent to:
    //..
    //  print(stream, 0, -1);
    //..

template <class HASH_ALGORITHM>
void hashAppend(HASH_ALGORITHM& hashAlgorithm, const Guid& guid);
    // Invoke the specified 'hashAlgorithm' on the underlying buffer held by
    // the specified 'guid' object.

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

                                // ----------
                                // bdlb::Guid
                                // ----------
// CREATORS
inline
Guid::Guid()
{
    BSLMF_ASSERT(sizeof(d_alignedBuffer) >= k_GUID_NUM_BYTES);

    bsl::fill(modifiableData(), modifiableData() + k_GUID_NUM_BYTES, 0);
}

inline
Guid::Guid(const unsigned char (&buffer)[k_GUID_NUM_BYTES])
{
    BSLMF_ASSERT(sizeof(d_alignedBuffer) >= k_GUID_NUM_BYTES);

    bsl::copy(buffer, buffer + k_GUID_NUM_BYTES, modifiableData());
}

inline Guid::Guid(unsigned long       timeLow,
                  unsigned short      timeMid,
                  unsigned short      timeHiAndVersion,
                  unsigned char       clockSeqHiRes,
                  unsigned char       clockSeqLow,
                  bsls::Types::Uint64 node)
{
    typedef unsigned char uc;

    modifiableData()[ 0] = uc(timeLow >> 24);
    modifiableData()[ 1] = uc(timeLow >> 16);
    modifiableData()[ 2] = uc(timeLow >>  8);
    modifiableData()[ 3] = uc(timeLow);

    modifiableData()[ 4] = uc(timeMid >> 8);
    modifiableData()[ 5] = uc(timeMid);

    modifiableData()[ 6] = uc(timeHiAndVersion >> 8);
    modifiableData()[ 7] = uc(timeHiAndVersion);

    modifiableData()[ 8] = uc(clockSeqHiRes);

    modifiableData()[ 9] = uc(clockSeqLow);

    modifiableData()[10] = uc(node >> 40);
    modifiableData()[11] = uc(node >> 32);
    modifiableData()[12] = uc(node >> 24);
    modifiableData()[13] = uc(node >> 16);
    modifiableData()[14] = uc(node >>  8);
    modifiableData()[15] = uc(node);
}

// PRIVATE MANIPULATORS
inline
unsigned char *Guid::modifiableData()
{
    return reinterpret_cast<unsigned char *>(d_alignedBuffer.buffer());
}

// MANIPULATORS
inline
Guid& Guid::operator=(const unsigned char (&buffer)[k_GUID_NUM_BYTES])
{
    BSLMF_ASSERT(sizeof(d_alignedBuffer) >= k_GUID_NUM_BYTES);

    memcpy(modifiableData(), buffer, k_GUID_NUM_BYTES);
    return *this;
}

inline
Guid& Guid::operator=(const bsl::uint32_t (&buffer)[k_GUID_NUM_32BITS])
{
    BSLMF_ASSERT(sizeof(d_alignedBuffer) >= sizeof(uint32_t) *
                                                k_GUID_NUM_32BITS);

    memcpy(modifiableData(), buffer, k_GUID_NUM_BYTES);
    return *this;
}

// ACCESSORS
inline
const unsigned char& Guid::operator[](bsl::size_t offset) const
{
    BSLS_ASSERT(offset < k_GUID_NUM_BYTES);
    return data()[offset];
}

inline
const unsigned char *Guid::begin() const
{
    return data();
}

inline
const unsigned char *Guid::data() const
{
    return reinterpret_cast<const unsigned char *>(d_alignedBuffer.buffer());
}

inline
const unsigned char *Guid::end() const
{
    return data() + k_GUID_NUM_BYTES;
}

                        // RFC 4122 FIELD ACCESSORS

inline
unsigned char Guid::clockSeqHi() const
{
    return clockSeqHiRes() & 0x1F;
}

inline
unsigned char Guid::clockSeqHiRes() const
{
    return data()[8];
}

inline
unsigned char Guid::clockSeqLow() const
{
    return data()[9];
}

inline
bsls::Types::Uint64 Guid::node() const
{
    return bsls::Types::Uint64(data()[10]) << 40 |
           bsls::Types::Uint64(data()[11]) << 32 |
           bsls::Types::Uint64(data()[12]) << 24 |
           bsls::Types::Uint64(data()[13]) << 16 |
           bsls::Types::Uint64(data()[14]) <<  8 |
                               data()[15];
}

inline
unsigned short Guid::timeHi() const
{
    return timeHiAndVersion() & 0x0FFF;
}

inline
unsigned short Guid::timeHiAndVersion() const
{
    typedef unsigned short us;
    return us(data()[6] << 8 |
              data()[7]);
}

inline
unsigned long Guid::timeLow() const {
    typedef unsigned long ul;
    return ul(data()[0]) << 24 |
              data()[1]  << 16 |
              data()[2]  <<  8 |
              data()[3];
}

inline
unsigned short Guid::timeMid() const {
    typedef unsigned short us;
    return us(data()[4] << 8 |
              data()[5]);
}

inline
unsigned char Guid::variant() const {
    typedef unsigned char uc;
    return uc(clockSeqHiRes() >> 5);
}

inline
unsigned char Guid::version() const {
    typedef unsigned char uc;
    return uc(timeHiAndVersion() >> 12);
}

}  // close package namespace

// FREE OPERATORS
inline
bsl::ostream& bdlb::operator<<(bsl::ostream& stream, const bdlb::Guid& guid)
{
    return guid.print(stream, 0, -1);
}

inline
bool bdlb::operator==(const bdlb::Guid& lhs, const bdlb::Guid& rhs)
{
    return bsl::equal(
        lhs.data(), lhs.data() + lhs.k_GUID_NUM_BYTES, rhs.data());
}

inline
bool bdlb::operator!=(const bdlb::Guid& lhs, const bdlb::Guid& rhs)
{
    return !bsl::equal(
        lhs.data(), lhs.data() + lhs.k_GUID_NUM_BYTES, rhs.data());
}

template <class HASH_ALGORITHM>
void bdlb::hashAppend(HASH_ALGORITHM& hashAlgorithm, const Guid& guid)
{
    hashAlgorithm(guid.data(), Guid::k_GUID_NUM_BYTES);
}

}  // close enterprise namespace

#endif

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