summaryrefslogtreecommitdiff
path: root/klm/util/key_value_packing.hh
diff options
context:
space:
mode:
Diffstat (limited to 'klm/util/key_value_packing.hh')
-rw-r--r--klm/util/key_value_packing.hh122
1 files changed, 122 insertions, 0 deletions
diff --git a/klm/util/key_value_packing.hh b/klm/util/key_value_packing.hh
new file mode 100644
index 00000000..450512ac
--- /dev/null
+++ b/klm/util/key_value_packing.hh
@@ -0,0 +1,122 @@
+#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; }
+
+ 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; }
+
+ 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__