Guid.h

// Guid.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2004

#pragma once
#ifndef Ceda_cxUtils_Guid_H
#define Ceda_cxUtils_Guid_H

#include "cxUtils.h"
#include "xstring.h"
#include "Archive.h"

namespace ceda
{
class xostream;

///////////////////////////////////////////////////////////////////////////////////////////////////
// Guid

/*
Unfortunately Microsoft's objbase.h defines operator==() for GUIDs as follows

    __inline BOOL operator==(const GUID& guidOne, const GUID& guidOther)
    {
        return !memcmp(&guidOne,&guidOther,sizeof(GUID));
    }

This is terribly inefficient.

There are two reasons for writing our own Guid class
   1.   Our operator==() is 4 times faster than the one provided by Microsoft!
   2.   We will have better control over byte swapping issues when we address platform independence
*/

/*
    DWORD Data1;
    WORD Data2;
    WORD Data3;
    BYTE Data4[8];
*/

// 128 bits
struct Guid
{
    uint32 Data1;
    uint16 Data2;
    uint16 Data3;
    uint8 Data4[8];
};

///////////////////////////////////////////////////////////////////////////////////////////////////

cxUtils_API extern const Guid Guid_NULL;

cxUtils_API bool operator<(const Guid& g1, const Guid& g2);
cxUtils_API bool operator==(const Guid& g1, const Guid& g2);

inline bool operator!=(const Guid& g1, const Guid& g2) { return !(g1 == g2); }
inline bool operator>(const Guid& g1, const Guid& g2) { return g2 < g1; }
inline bool operator<=(const Guid& g1, const Guid& g2) { return !(g2 < g1); }
inline bool operator>=(const Guid& g1, const Guid& g2) { return !(g1 < g2); }

cxUtils_API Guid CreateGuid();

// Returns false if the given string is not formattted as a guid correctly
cxUtils_API bool StringToGuid(ConstStringZ s, Guid& g);

// Asserts if string is not formatted correctly as a guid
cxUtils_API Guid StringToGuid(ConstStringZ s);

/*
todo: follow .net concept of a format specifier:

N
    32 digits:
    00000000000000000000000000000000
D
    32 digits separated by hyphens:
    00000000-0000-0000-0000-000000000000
B
    32 digits separated by hyphens, enclosed in braces:
    {00000000-0000-0000-0000-000000000000}
P
    32 digits separated by hyphens, enclosed in parentheses:
    (00000000-0000-0000-0000-000000000000)
X
    Four hexadecimal values enclosed in braces, where the fourth value is a subset of eight 
    hexadecimal values that is also enclosed in braces:
    {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}

Currently this function corresponds to format 'B'

todo:  define whether to use lowercase/uppercase for for the hexadecimal characters A,B,C,D,E,F.
*/
cxUtils_API void GuidToString(const Guid& g, xstring& s);

inline xstring GuidToString(const Guid& g)
{
    xstring s;
    GuidToString(g,s);
    return s;
}

inline xstring CreateGuidString()
{
	return GuidToString( CreateGuid() );
}

// Write the given guid using the C struct initialiser syntax.
// For example: {0x1BB8215E,0x2B74,0x48EF,{0x38,0xBE,0x3C,0x80,0x81,0x83,0xE3,0x7A}}
cxUtils_API void WriteGuidAsStructInitialiser(xostream& os, const Guid& guid);

cxUtils_API xostream& operator<<(xostream& os, const Guid& guid);

template<typename Archive>
inline void Serialise(Archive& ar, const Guid& guid) 
{ 
    #if CEDA_LITTLE_ENDIAN
        ar.SerialisePod(guid);
    #else
        ar << guid.Data1
           << guid.Data2
           << guid.Data3
           << guid.Data4;
    #endif
}

template<typename Archive>
inline void Deserialise(Archive& ar, Guid& guid) 
{ 
    #if CEDA_LITTLE_ENDIAN
        ar.DeserialisePod(guid);
    #else
        ar >> guid.Data1
           >> guid.Data2
           >> guid.Data3
           >> guid.Data4;
    #endif
}

} // namespace ceda

#endif // include guard