summaryrefslogtreecommitdiff
path: root/klm/util/sized_iterator.hh
blob: 75f6886f77e29628942ecc9da519b763c7d6d2d2 (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
#ifndef UTIL_SIZED_ITERATOR_H
#define UTIL_SIZED_ITERATOR_H

#include "util/proxy_iterator.hh"

#include <algorithm>
#include <functional>
#include <string>

#include <stdint.h>
#include <string.h>

namespace util {

class SizedInnerIterator {
  public:
    SizedInnerIterator() {}

    SizedInnerIterator(void *ptr, std::size_t size) : ptr_(static_cast<uint8_t*>(ptr)), size_(size) {}

    bool operator==(const SizedInnerIterator &other) const {
      return ptr_ == other.ptr_;
    }
    bool operator<(const SizedInnerIterator &other) const {
      return ptr_ < other.ptr_;
    }
    SizedInnerIterator &operator+=(std::ptrdiff_t amount) {
      ptr_ += amount * size_;
      return *this;
    }
    std::ptrdiff_t operator-(const SizedInnerIterator &other) const {
      return (ptr_ - other.ptr_) / size_;
    }

    const void *Data() const { return ptr_; }
    void *Data() { return ptr_; }
    std::size_t EntrySize() const { return size_; }

    friend void swap(SizedInnerIterator &first, SizedInnerIterator &second) {
      std::swap(first.ptr_, second.ptr_);
      std::swap(first.size_, second.size_);
    }

  private:
    uint8_t *ptr_;
    std::size_t size_;
};

class SizedProxy {
  public:
    SizedProxy() {}

    SizedProxy(void *ptr, std::size_t size) : inner_(ptr, size) {}

    operator std::string() const {
      return std::string(reinterpret_cast<const char*>(inner_.Data()), inner_.EntrySize());
    }

    SizedProxy &operator=(const SizedProxy &from) {
      memcpy(inner_.Data(), from.inner_.Data(), inner_.EntrySize());
      return *this;
    }

    SizedProxy &operator=(const std::string &from) {
      memcpy(inner_.Data(), from.data(), inner_.EntrySize());
      return *this;
    }

    const void *Data() const { return inner_.Data(); }
    void *Data() { return inner_.Data(); }

    friend void swap(SizedProxy first, SizedProxy second) {
      std::swap_ranges(
          static_cast<char*>(first.inner_.Data()),
          static_cast<char*>(first.inner_.Data()) + first.inner_.EntrySize(),
          static_cast<char*>(second.inner_.Data()));
    }

  private:
    friend class util::ProxyIterator<SizedProxy>;

    typedef std::string value_type;

    typedef SizedInnerIterator InnerIterator;

    InnerIterator &Inner() { return inner_; }
    const InnerIterator &Inner() const { return inner_; }
    InnerIterator inner_;
};

typedef ProxyIterator<SizedProxy> SizedIterator;

inline SizedIterator SizedIt(void *ptr, std::size_t size) { return SizedIterator(SizedProxy(ptr, size)); }

// Useful wrapper for a comparison function i.e. sort.
template <class Delegate, class Proxy = SizedProxy> class SizedCompare : public std::binary_function<const Proxy &, const Proxy &, bool> {
  public:
    explicit SizedCompare(const Delegate &delegate = Delegate()) : delegate_(delegate) {}

    bool operator()(const Proxy &first, const Proxy &second) const {
      return delegate_(first.Data(), second.Data());
    }
    bool operator()(const Proxy &first, const std::string &second) const {
      return delegate_(first.Data(), second.data());
    }
    bool operator()(const std::string &first, const Proxy &second) const {
      return delegate_(first.data(), second.Data());
    }
    bool operator()(const std::string &first, const std::string &second) const {
      return delegate_(first.data(), second.data());
    }

    const Delegate &GetDelegate() const { return delegate_; }

  private:
    const Delegate delegate_;
};

} // namespace util
#endif // UTIL_SIZED_ITERATOR_H