#ifndef KEY_H
#define KEY_H
#include <new>
#include <stdio.h>
#include <SupportDefs.h>
#include "Debug.h"
#include "endianess.h"
using std::nothrow;
class Key : private key {
public:
Key() {}
Key(const Key &k) : key(k) {}
~Key() {}
static Key* CastFrom(key* k)
{ return static_cast<Key*>(k); }
static const Key* CastFrom(const key* k)
{ return static_cast<const Key*>(k); }
void SetTo(uint32 dirID, uint32 objectID, uint64 offset, uint32 type,
uint16 version)
{
k_dir_id = h2le(dirID);
k_objectid = h2le(objectID);
if (version == KEY_FORMAT_3_5) {
u.k_offset_v1.k_offset = h2le((uint32)offset);
u.k_offset_v1.k_uniqueness = h2le(type);
} else
_SetOffsetAndType(offset, type);
}
uint16 GuessVersion() const
{
switch (_GetType()) {
case TYPE_DIRECT:
case TYPE_INDIRECT:
case TYPE_DIRENTRY:
return KEY_FORMAT_3_6;
default:
return KEY_FORMAT_3_5;
}
}
uint32 GetDirID() const { return le2h(k_dir_id); }
uint32 GetObjectID() const { return le2h(k_objectid); }
uint64 GetOffset(uint16 version) const
{
return (version == KEY_FORMAT_3_6 ? _GetOffset()
: le2h(u.k_offset_v1.k_offset));
}
void SetOffset(uint64 offset, uint16 version)
{
if (version == KEY_FORMAT_3_6)
_SetOffsetAndType(offset, _GetType());
else
u.k_offset_v1.k_offset = h2le(offset);
}
uint16 GetType(uint16 version) const
{
if (version == KEY_FORMAT_3_6)
return _GetType();
switch (le2h(u.k_offset_v1.k_uniqueness)) {
case V1_SD_UNIQUENESS:
return TYPE_STAT_DATA;
case V1_INDIRECT_UNIQUENESS:
return TYPE_INDIRECT;
case V1_DIRECT_UNIQUENESS:
return TYPE_DIRECT;
case V1_DIRENTRY_UNIQUENESS:
return TYPE_DIRENTRY;
case V1_ANY_UNIQUENESS:
default:
return TYPE_ANY;
}
}
Key &operator=(const Key &k)
{
*static_cast<key*>(this) = k;
return *this;
}
private:
uint64 _GetOffset() const
{
#if LITTLE_ENDIAN
return u.k_offset_v2.k_type;
#else
offset_v2 temp;
*(uint64*)&temp = h2le(*(uint64*)&u.k_offset_v2);
return temp.k_offset;
#endif
}
uint32 _GetType() const
{
#if LITTLE_ENDIAN
return u.k_offset_v2.k_type;
#else
offset_v2 temp;
*(uint64*)&temp = h2le(*(uint64*)&u.k_offset_v2);
return temp.k_type;
#endif
}
void _SetOffsetAndType(uint64 offset, uint32 type)
{
u.k_offset_v2.k_offset = offset;
u.k_offset_v2.k_type = type;
#if !LITTLE_ENDIAN
*(uint64*)&u.k_offset_v2 = h2le(*(uint64*)&u.k_offset_v2);
#endif
}
};
class VKey {
private:
void _Unset() { if (fVersion & ALLOCATED) delete fKey; fKey = NULL; }
public:
VKey() : fKey(NULL), fVersion(KEY_FORMAT_3_5) {}
VKey(const Key *k, uint32 version)
: fKey(const_cast<Key*>(k)), fVersion(version) {}
VKey(const Key *k) : fKey(NULL), fVersion(KEY_FORMAT_3_5) { SetTo(k); }
VKey(uint32 dirID, uint32 objectID, uint64 offset, uint32 type,
uint16 version)
: fKey(NULL), fVersion(KEY_FORMAT_3_5)
{
SetTo(dirID, objectID, offset, type, version);
}
VKey(const VKey &k)
: fKey(new(nothrow) Key(*k.fKey)), fVersion(k.fVersion | ALLOCATED) {}
~VKey() { _Unset(); }
void SetTo(const Key *k, uint32 version)
{
_Unset();
fKey = const_cast<Key*>(k);
fVersion = version;
}
void SetTo(const Key *k)
{
_Unset();
fKey = const_cast<Key*>(k);
fVersion = fKey->GuessVersion();
}
void SetTo(uint32 dirID, uint32 objectID, uint64 offset, uint32 type,
uint16 version)
{
_Unset();
fKey = new(nothrow) Key;
if (version == KEY_FORMAT_3_5)
fVersion = KEY_FORMAT_3_5 | ALLOCATED;
else
fVersion = KEY_FORMAT_3_6 | ALLOCATED;
fKey->SetTo(dirID, objectID, offset, type, fVersion);
}
uint16 GetVersion() const { return fVersion & VERSION_MASK; }
uint32 GetDirID() const { return fKey->GetDirID(); }
uint32 GetObjectID() const { return fKey->GetObjectID(); }
uint64 GetOffset() const { return fKey->GetOffset(GetVersion()); }
uint16 GetType() const { return fKey->GetType(GetVersion()); }
void SetOffset(uint64 offset)
{ return fKey->SetOffset(offset, GetVersion()); }
int Compare(const VKey &k, bool compareTypes = false) const
{
if (GetDirID() < k.GetDirID())
return -1;
if (GetDirID() > k.GetDirID())
return 1;
if (GetObjectID() < k.GetObjectID())
return -1;
if (GetObjectID() > k.GetObjectID())
return 1;
int64 dOffset = (int64)GetOffset() - (int64)k.GetOffset();
if (dOffset < 0)
return -1;
if (dOffset > 0)
return 1;
if (compareTypes) {
int32 dType = (int32)GetType() - (int32)k.GetType();
if (dType < 0)
return -1;
if (dType > 0)
return 1;
}
return 0;
}
bool operator==(const VKey &k) const { return (Compare(k) == 0); }
bool operator!=(const VKey &k) const { return (Compare(k) != 0); }
bool operator<(const VKey &k) const { return (Compare(k) < 0); }
bool operator>(const VKey &k) const { return (Compare(k) > 0); }
bool operator<=(const VKey &k) const { return (Compare(k) <= 0); }
bool operator>=(const VKey &k) const { return (Compare(k) >= 0); }
VKey &operator=(const VKey &k)
{
if (!(fVersion & ALLOCATED))
fKey = new(nothrow) Key;
*fKey = *k.fKey;
fVersion |= ALLOCATED;
return *this;
}
void Dump() const
{
TPRINT(("key: {%" B_PRIu32 ", %" B_PRIu32 ", %" B_PRIu64 ", %hu}\n",
GetDirID(), GetObjectID(), GetOffset(), GetType()));
}
private:
enum {
VERSION_MASK = KEY_FORMAT_3_5 | KEY_FORMAT_3_6,
ALLOCATED = 0x8000
};
private:
Key *fKey;
uint16 fVersion;
};
#endif