ldpk
ldpk_line_cache.h
Go to the documentation of this file.
1 #pragma once
2 
4 
5 #ifdef _WINDOWS
6 #else
7 #include <pthread.h>
8 #endif
9 
10 #include <string.h>
11 #include <stdexcept>
12 #include <vector>
13 #include <map>
14 #include <iostream>
15 
16 namespace ldpk
17  {
18  template <class T>
20  {
21  public:
23  typedef std::vector<T> vec_type;
24  typedef typename vec_type::const_iterator const_iterator;
25  typedef typename vec_type::const_reverse_iterator const_reverse_iterator;
26  private:
27  int _a,_b;
28  vec_type _val;
29  public:
30  extendible_vector():_a((1LL << 31) - 1),_b(-(1LL << 31))
31  { }
32  extendible_vector(const this_type& c):_a(c._a),_b(c._b)
33  { _val = c._val; }
34  void clear()
35  {
36  _a = (1LL << 31) - 1;
37  _b = -(1LL << 31);
38  _val.clear();
39  }
43  this_type& resize(int a,int b)
44  {
45 // Invalid, ignore.
46  if(a >= b)
47  { return *this; }
48 // New interval within old interval, nothing to do.
49  if((a >= _a) && (b <= _b))
50  { return *this; }
51 // Is this the first call?
52  if(_a > _b)
53  {
54  _a = a;
55  _b = b;
56  _val.resize(_b - _a,T());
57  return *this;
58  }
59  else
60  {
61 // This part might be expensive. We insert at front and back, as needed.
62  if(a < _a)
63  { _val.insert(_val.begin(),_a - a,T()); }
64  if(b > _b)
65  { _val.insert(_val.end(),b - _b,T()); }
66  _a = std::min(a,_a);
67  _b = std::max(b,_b);
68  return *this;
69  }
70 // unreachable
71  return *this;
72  }
74  void extend(int i)
75  {
76  int a_new = _a;
77  int b_new = _b;
78  if(i < _a)
79  { a_new = i; }
80  if(i >= _b)
81  { b_new = i + 1; }
82  resize(a_new,b_new);
83  }
85  int a() const
86  { return _a; }
87  int b() const
88  { return _b; }
90  const T& operator[](int i) const
91  { return _val[i - _a]; }
92  T& operator[](int i)
93  { return _val[i - _a]; }
94  const T& at(int i) const
95  { return _val.at(i - _a); }
96  T& at(int i)
97  { return _val.at(i - _a); }
99  const_iterator begin() const
100  { return _val.begin(); }
101  const_iterator end() const
102  { return _val.end(); }
103  bool empty() const
104  { return _val.empty(); }
106  int size() const
107  { return _val.size(); }
108  };
109  template <class T>
111  {
112  public:
115  private:
116  public:
118  { }
119  cache_line_buffer(const this_type& c):base_type(c)
120  { }
121  };
122 
125  template <class T>
126  class line_ref
127  {
128  public:
130 // private:
131  cache_line_buffer_type *_buffer;
132  public:
133  line_ref(cache_line_buffer_type& b):_buffer(&b)
134  { }
135  int a() const
136  { return _buffer->a(); }
137  int b() const
138  { return _buffer->b(); }
139  const T& operator[](int i) const
140  { return (*_buffer)[i]; }
141  T& operator[](int i)
142  { return (*_buffer)[i]; }
143  bool exists(int i) const
144  { return (a() <= i) && (i < b()); }
146  operator bool() const
147  { return _buffer; }
148  };
149 
154  template <class T>
156  {
157  public:
158  typedef line_cache this_type;
159  typedef line_ref<T> line_ref_type;
161  private:
162 #ifdef _WINDOWS
163  mutable CRITICAL_SECTION _critsec;
164 #else
165  mutable pthread_mutex_t _mutex;
166 #endif
167  typedef std::map<int,cache_line_buffer_type> buffers_type;
168  buffers_type _buffers;
169 // Fast access
171  buffer_refs_type _buffer_refs;
172  public:
173  line_cache()
174  {
175 #ifdef _WINDOWS
176  InitializeCriticalSection(&_critsec);
177 #else
178  int r = pthread_mutex_init(&_mutex,NULL);
179  if(r)
180  { std::cerr << "ldpk::ldp_builtin::pthread_mutex_init: " << strerror(r) << std::endl; }
181 #endif
182  }
183  ~line_cache()
184  {
185 #ifdef _WINDOWS
186  DeleteCriticalSection(&_critsec);
187 #else
188  int r = pthread_mutex_destroy(&_mutex);
189  if(r)
190  { std::cerr << "ldpk::ldp_builtin::pthread_mutex_destroy: " << strerror(r) << std::endl; }
191 #endif
192  }
193  void clear()
194  {
195  _buffers.clear();
196  _buffer_refs.clear();
197  }
198  bool line_exists(int iy) const
199  {
200  return _buffer_refs.at(iy);
201  }
203  line_ref_type resize_line(int iy,int a,int b)
204  {
205 #ifdef _WINDOWS
206  EnterCriticalSection(&_critsec);
207 #else
208  pthread_mutex_lock(&_mutex);
209 #endif
210  try
211  {
212 // Create buffer if not exists.
213  cache_line_buffer_type& buffer = static_cast<cache_line_buffer_type&>(_buffers[iy].resize(a,b));
214 // Insert into array for fast access.
215  _buffer_refs.extend(iy);
216  _buffer_refs.at(iy) = &buffer;
217 // Done. Return line reference, so threads can work on buffer.
218 #ifdef _WINDOWS
219  LeaveCriticalSection(&_critsec);
220 #else
221  pthread_mutex_unlock(&_mutex);
222 #endif
223  return line_ref_type(buffer);
224  }
225  catch(const std::exception& e)
226  {
227  std::cerr << "ldpk::line_cache::resize_line(" << iy << "," << a << "," << b << ") failed: " << e.what() << std::endl;
228 #ifdef _WINDOWS
229  LeaveCriticalSection(&_critsec);
230 #else
231  pthread_mutex_unlock(&_mutex);
232 #endif
233  throw;
234  }
235  catch(...)
236  {
237  std::cerr << "ldpk::line_cache::resize_line(" << iy << "," << a << "," << b << ") failed: unknown exception" << std::endl;
238 #ifdef _WINDOWS
239  LeaveCriticalSection(&_critsec);
240 #else
241  pthread_mutex_unlock(&_mutex);
242 #endif
243  throw;
244  }
245  }
247  line_ref_type get_line(int iy) const
248  {
249 #ifdef _WINDOWS
250  EnterCriticalSection(&_critsec);
251 #else
252  pthread_mutex_lock(&_mutex);
253 #endif
254  try
255  {
256 // Fast access.
257  cache_line_buffer_type *buffer = _buffer_refs.at(iy);
258  if(!buffer)
259  { throw std::range_error("ldpk::line_cache::get_line"); }
260 #ifdef _WINDOWS
261  LeaveCriticalSection(&_critsec);
262 #else
263  pthread_mutex_unlock(&_mutex);
264 #endif
265  return line_ref_type(*buffer);
266  }
267  catch(const std::exception& e)
268  {
269  std::cerr << "ldpk::line_cache::get_line(" << iy << ") failed: " << e.what() << std::endl;
270 #ifdef _WINDOWS
271  LeaveCriticalSection(&_critsec);
272 #else
273  pthread_mutex_unlock(&_mutex);
274 #endif
275  throw;
276  }
277  catch(...)
278  {
279  std::cerr << "ldpk::line_cache::resize_line(" << iy << ") failed: unknown exception" << std::endl;
280 #ifdef _WINDOWS
281  LeaveCriticalSection(&_critsec);
282 #else
283  pthread_mutex_unlock(&_mutex);
284 #endif
285  throw;
286  }
287  }
289  int size() const
290  { return _buffer_refs.size(); }
291  friend std::ostream& operator<<(std::ostream& cout,const this_type& c)
292  {
293  for(int i = c._buffer_refs.a();i < c._buffer_refs.b();++i)
294  {
295  if(c.line_exists(i))
296  {
297  line_ref_type l = c.get_line(i);
298  cout << "line " << i << ": " << l.a() << "," << l.b() << std::endl;
299  }
300  }
301  return cout;
302  }
303  };
304  }
const_iterator begin() const
Iterate over the entire container, not just [a,b[.
Definition: ldpk_line_cache.h:99
void extend(int i)
After this call (*this)[i] is valid.
Definition: ldpk_line_cache.h:74
const T & operator[](int i) const
Since resize() will move elements around, the access methods are fast.
Definition: ldpk_line_cache.h:90
int size() const
Entire size, not just [a,b[.
Definition: ldpk_line_cache.h:106
In Multithreading, more than one thread may work on the same line reading and writing, however resizing is not allowed.
Definition: ldpk_line_cache.h:126
Definition: ldpk_line_cache.h:19
The namespace of (most of the) things related to the Lens Distortion Plugin Kit.
Definition: ldpk.h:180
this_type & resize(int a, int b)
After this call (*this)[i] is valid for a <= i < b. Expensive. This method will only do something if ...
Definition: ldpk_line_cache.h:43
int a() const
Minimum and maximum values ever set with resize() since object was created.
Definition: ldpk_line_cache.h:85
int size() const
Number of Buffer-Refs.
Definition: ldpk_line_cache.h:289
The class is thread-safe in the following sense:
Definition: ldpk_line_cache.h:155
line_ref_type get_line(int iy) const
Return reference to line_buffer if exists, otherwise exception.
Definition: ldpk_line_cache.h:247
Definition: ldpk_line_cache.h:110
line_ref_type resize_line(int iy, int a, int b)
Protected by mutex. By this method, line iy is created -if not exists- and initialized.
Definition: ldpk_line_cache.h:203