benchmark silo added
[c11concurrency-benchmarks.git] / silo / record / cursor.h
1 #pragma once
2
3 #include <cstdint>
4 #include "../macros.h"
5 #include "../counter.h"
6 #include "../util.h"
7
8 // cursors can only move forward, or reset completely
9 template <typename T>
10 struct read_record_cursor {
11 public:
12   typedef typename T::value value_type;
13   typedef typename T::value_descriptor value_descriptor_type;
14
15   // [px, px+nbytes) is assumed to be valid memory
16   read_record_cursor(const uint8_t *px, size_t nbytes)
17     : px_begin(px), nbytes(nbytes), px_cur(px), n(0) {}
18
19   // returns true on success, false on fail
20   inline bool
21   skip_to(size_t i)
22   {
23     INVARIANT(i >= n);
24     INVARIANT(i < value_descriptor_type::nfields());
25     while (n < i) {
26       const size_t sz = value_descriptor_type::failsafe_skip_fn(n++)(px_cur, nbytes, nullptr);
27       if (unlikely(!sz))
28         return false;
29       px_cur += sz;
30       nbytes -= sz;
31     }
32     return true;
33   }
34
35   inline void
36   reset()
37   {
38     INVARIANT(px_cur >= px_begin);
39     nbytes += (px_cur - px_begin);
40     px_cur = px_begin;
41     n = 0;
42   }
43
44   inline size_t
45   field() const
46   {
47     return n;
48   }
49
50   // returns 0 on failure
51   inline size_t
52   read_current_and_advance(value_type *v)
53   {
54     INVARIANT(n < value_descriptor_type::nfields());
55     uint8_t * const buf = reinterpret_cast<uint8_t *>(v) +
56       value_descriptor_type::cstruct_offsetof(n);
57     const uint8_t * const px_skip =
58       value_descriptor_type::failsafe_read_fn(n++)(px_cur, nbytes, buf);
59     if (unlikely(!px_skip))
60       return 0;
61     const size_t rawsz = px_skip - px_cur;
62     INVARIANT(rawsz <= value_descriptor_type::max_nbytes(n - 1));
63     nbytes -= rawsz;
64     px_cur = px_skip;
65     return rawsz;
66   }
67
68   // returns 0 on failure
69   inline size_t
70   read_current_raw_size_and_advance()
71   {
72     INVARIANT(n < value_descriptor_type::nfields());
73     const size_t rawsz =
74       value_descriptor_type::failsafe_skip_fn(n++)(px_cur, nbytes, nullptr);
75     if (unlikely(!nbytes))
76       return 0;
77     INVARIANT(rawsz <= value_descriptor_type::max_nbytes(n - 1));
78     nbytes -= rawsz;
79     px_cur += rawsz;
80     return rawsz;
81   }
82
83 private:
84   const uint8_t *px_begin;
85
86   // the 3 fields below are kept in sync:
87   // [px_cur, px_cur+nbytes) is valid memory
88   // px_cur points to the start of the n-th field
89   size_t nbytes;
90   const uint8_t *px_cur;
91   size_t n; // current field position in cursor
92 };
93
94
95 template <typename T>
96 struct write_record_cursor {
97 public:
98   typedef typename T::value value_type;
99   typedef typename T::value_descriptor value_descriptor_type;
100
101   write_record_cursor(uint8_t *px)
102     : px_begin(px), px_cur(px), px_end(nullptr), n(0)
103   {
104     INVARIANT(px);
105   }
106
107   inline void
108   skip_to(size_t i)
109   {
110     INVARIANT(i >= n);
111     INVARIANT(i < value_descriptor_type::nfields());
112     while (n < i)
113       px_cur += value_descriptor_type::skip_fn(n++)(px_cur, nullptr);
114   }
115
116   inline void
117   reset()
118   {
119     px_cur = px_begin;
120     n = 0;
121   }
122
123   inline size_t
124   field() const
125   {
126     return n;
127   }
128
129   inline void
130   write_current_and_advance(const value_type *v, uint8_t *old_v = nullptr)
131   {
132     static event_counter evt_write_memmove(
133         util::cxx_typename<T>::value() + std::string("_write_memmove"));
134     const uint8_t * const buf = reinterpret_cast<const uint8_t *>(v) +
135       value_descriptor_type::cstruct_offsetof(n);
136     const size_t newsz = value_descriptor_type::nbytes_fn(n)(buf);
137     INVARIANT(newsz <= value_descriptor_type::max_nbytes(n));
138     uint8_t stack_buf[value_descriptor_type::max_nbytes(n)];
139     uint8_t * const old_buf = old_v ? old_v : &stack_buf[0];
140     const size_t oldsz = value_descriptor_type::skip_fn(n)(px_cur, old_buf);
141     INVARIANT(oldsz <= value_descriptor_type::max_nbytes(n));
142     if (unlikely(oldsz != newsz)) {
143       ++evt_write_memmove;
144       compute_end();
145       memmove(px_cur + newsz, px_cur + oldsz, px_end - px_cur - oldsz);
146       if (oldsz > newsz)
147         // shrink
148         px_end -= (oldsz - newsz);
149       else
150         // grow
151         px_end += (newsz - oldsz);
152     }
153     px_cur = value_descriptor_type::write_fn(n++)(px_cur, buf);
154   }
155
156 private:
157
158   inline void
159   compute_end()
160   {
161     if (px_end)
162       return;
163     uint8_t *px = px_cur;
164     size_t i = n;
165     while (i < value_descriptor_type::nfields())
166       px += value_descriptor_type::skip_fn(i++)(px, nullptr);
167     px_end = px;
168   }
169
170   uint8_t *px_begin;
171   uint8_t *px_cur;
172   uint8_t *px_end;
173   size_t n; // current field position in cursor
174 };