summaryrefslogtreecommitdiff
path: root/klm/util/key_value_packing.hh
blob: b84a5aadf0e9609cecadc06286b9b5047b4ecf94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#ifndef UTIL_KEY_VALUE_PACKING__
#define UTIL_KEY_VALUE_PACKING__

/* Why such a general interface?  I'm planning on doing bit-level packing. */

#include <algorithm>
#include <cstddef>
#include <cstring>

#include <inttypes.h>

namespace util {

template <class Key, class Value> struct Entry {
  Key key;
  Value value;

  const Key &GetKey() const { return key; }
  const Value &GetValue() const { return value; }

  Value &MutableValue() { return value; }

  void Set(const Key &key_in, const Value &value_in) {
    SetKey(key_in);
    SetValue(value_in);
  }
  void SetKey(const Key &key_in) { key = key_in; }
  void SetValue(const Value &value_in) { value = value_in; }

  bool operator<(const Entry<Key, Value> &other) const { return GetKey() < other.GetKey(); }
};

// And now for a brief interlude to specialize std::swap.  
} // namespace util
namespace std {
template <class Key, class Value> void swap(util::Entry<Key, Value> &first, util::Entry<Key, Value> &second) {
  swap(first.key, second.key);
  swap(first.value, second.value);
}
}// namespace std
namespace util {

template <class KeyT, class ValueT> class AlignedPacking {
  public:
    typedef KeyT Key;
    typedef ValueT Value;
    
  public:
    static const std::size_t kBytes = sizeof(Entry<Key, Value>);
    static const std::size_t kBits = kBytes * 8;

    typedef Entry<Key, Value> * MutableIterator;
    typedef const Entry<Key, Value> * ConstIterator;
    typedef const Entry<Key, Value> & ConstReference;

    static MutableIterator FromVoid(void *start) {
      return reinterpret_cast<MutableIterator>(start);
    }

    static Entry<Key, Value> Make(const Key &key, const Value &value) {
      Entry<Key, Value> ret;
      ret.Set(key, value);
      return ret;
    }
};

template <class KeyT, class ValueT> class ByteAlignedPacking {
  public:
    typedef KeyT Key;
    typedef ValueT Value;

  private:
#pragma pack(push)
#pragma pack(1)
    struct RawEntry {
      Key key;
      Value value;

      const Key &GetKey() const { return key; }
      const Value &GetValue() const { return value; }

      Value &MutableValue() { return value; }

      void Set(const Key &key_in, const Value &value_in) {
        SetKey(key_in);
        SetValue(value_in);
      }
      void SetKey(const Key &key_in) { key = key_in; }
      void SetValue(const Value &value_in) { value = value_in; }

      bool operator<(const RawEntry &other) const { return GetKey() < other.GetKey(); }
    };
#pragma pack(pop)

    friend void std::swap<>(RawEntry&, RawEntry&);

  public:
    typedef RawEntry *MutableIterator;
    typedef const RawEntry *ConstIterator;
    typedef RawEntry &ConstReference;

    static const std::size_t kBytes = sizeof(RawEntry);
    static const std::size_t kBits = kBytes * 8;

    static MutableIterator FromVoid(void *start) {
      return MutableIterator(reinterpret_cast<RawEntry*>(start));
    }

    static RawEntry Make(const Key &key, const Value &value) {
      RawEntry ret;
      ret.Set(key, value);
      return ret;
    }
};

} // namespace util
namespace std {
template <class Key, class Value> void swap(
    typename util::ByteAlignedPacking<Key, Value>::RawEntry &first,
    typename util::ByteAlignedPacking<Key, Value>::RawEntry &second) {
  swap(first.key, second.key);
  swap(first.value, second.value);
}
}// namespace std

#endif // UTIL_KEY_VALUE_PACKING__