DeviceAtlas C++ Api documentation
util.h
1 #ifndef MOBI_MTLD_UTIL
2 #define MOBI_MTLD_UTIL
3 
4 #if defined(_WIN32)
5  #pragma warning(disable: 4996 4251)
6  #if !defined(DEVATLAS_STATIC)
7  #ifdef devatlas_EXPORTS
8  #define DA_EXPORT __declspec(dllexport)
9  #else
10  #define DA_EXPORT __declspec(dllimport)
11  #endif
12  #endif
13 #endif
14 #ifndef DA_EXPORT
15 #if __GNUC__ >= 4
16 #define DA_EXPORT __attribute__((visibility("default")))
17 #define DA_PRIVATE __attribute__((visibility("hidden")))
18 #else
19 #define DA_EXPORT
20 #define DA_PRIVATE
21 #endif
22 #endif
23 
24 #include <algorithm>
25 #include <cassert>
26 #include <bitset>
27 #include <ostream>
28 #include <utility>
29 #include <memory>
30 #include <iostream>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <mtld/exception.h>
35 
36 #if defined(__linux__) || defined(_WIN32)
37 size_t strlcpy(char *, const char *, size_t);
38 #endif
39 
40 namespace Mobi { namespace Mtld { namespace Util {
41 
42 
43 /*
44  * A block of objects extending from start to finish,
45  * with a marker to a current position
46  */
47 template <typename T>
48 struct Buf {
49  size_t avail() { return finish - cur; }
50  Buf *next;
51  T *start;
52  T *finish;
53  T *cur;
54  Buf(size_t capacity_, T *start_)
55  : next(0)
56  , start(start_)
57  , finish(start_ + capacity_)
58  , cur(start)
59  {
60  }
61 
62  virtual ~Buf() { }
63 };
64 
65 /*
66  * A buffer with backing data allocated from the heap
67  */
68 template <typename T>
69 struct HeapBuf : public Buf<T> {
70  HeapBuf(size_t capacity)
71  : Buf<T>(capacity, new T[capacity]) {}
72  ~HeapBuf() {
73  delete [] this->start;
74  }
75 };
76 
77 /*
78  * A buffer of a fixed size allocated inline
79  */
80 template <size_t size, typename T>
81 struct FixedBuf : public Buf<T> {
82  T buf[size];
83  FixedBuf() : Buf<T>(size, buf) {}
84  ~FixedBuf() { }
85 };
86 
87 
88 /*
89  * An allocator that supports multiple allocations
90  * that are all freed when the allocator is freed.
91  * Consists of a chain of Buffers. Allocations
92  * are satisfied from existing buffers if there
93  * is room, or else a new buffer is created.
94  */
95 template <size_t Size>
96 class Alloc {
98  Buf<char> *chain;
99 public:
100  inline Alloc<Size>();
101  inline ~Alloc<Size>();
102  template <typename ObjectType> inline ObjectType *allocate(size_t count = 1);
103  template <typename ObjectType> inline void allocate(ObjectType *&ptr, size_t count = 1) { ptr = allocate<ObjectType>(count); }
104 };
105 
106 template <size_t Size>
108  : chain(&first)
109 { }
110 
111 template <size_t Size>
112 Alloc<Size>::~Alloc()
113 {
114  Buf<char> *next;
115  for (Buf<char> *buf = chain; buf != &first; buf = next) {
116  next = buf->next;
117  delete buf;
118  }
119 }
120 
121 template <size_t Size>
122 template <typename ObjectType>
123 ObjectType *
124 Alloc<Size>::allocate(size_t count)
125 {
126  static const size_t align = std::min(size_t(8), sizeof (ObjectType));
127  int space = count * sizeof (ObjectType);
128 
129  Buf<char> *buf;
130 
131  /*
132  * Find an existing buffer on the chain that can meet our
133  * allocation demand, or allocate a new one if needed.
134  */
135  char *p;
136  for (buf = chain;; buf = buf->next) {
137  if (buf == 0) {
138  buf = new HeapBuf<char>(std::max(int(Size), space));
139  buf->next = chain;
140  chain = buf;
141  p = buf->cur;
142  break;
143  }
144  p = buf->cur;
145  int misalign = (intptr_t)p % align;
146  if (misalign)
147  p += align - misalign;
148  if (buf->finish - p >= space)
149  break;
150  }
151 
152  ObjectType *t = reinterpret_cast<ObjectType *>(p);
153  buf->cur = p + space;
154  assert(buf->cur <= buf->finish); // buf had space for our allocation
155  return t;
156 }
157 
158 template <typename El, typename Container> class templ_iterator {
159  Container *container;
160  size_t offset;
161 public:
162  std::pair<int, El> operator *() const {
163  return std::make_pair(int(offset + container->first), container->elements.get()[offset]);
164  }
165  templ_iterator &operator++() { ++offset; return *this; }
166  bool operator==(const templ_iterator &rhs) { return rhs.offset == offset; }
167  bool operator!=(const templ_iterator &rhs) { return rhs.offset != offset; }
168  templ_iterator(Container *this_, int offset_) : container(this_), offset(offset_) {}
169  templ_iterator() : container(0), offset(0) {}
170 };
171 
172 // Array-like container that limits itself to minimal contiguous spanned array for the non-null indexes.
173 // Eg: the set 9, 10, 30 will have an array of size (30 - 9 + 1) = 22, with the "9" occupying index 0 of the array.
174 
175 template <typename Element> class CharacterIndex {
176  int first;
177  size_t count;
178  std::unique_ptr<Element[]> elements;
179 public:
180  Element &operator[](int index) {
181  int off = index - first;
182 
183  if (elements == 0) {
184  first = off;
185  count = 1;
186  elements.reset(new Element[1]);
187  } else if (off < 0) {
188  off = -off;
189  // need "off" extra elements at start.
190  size_t newCount = count + off;
191  Element *newElements = new Element[newCount];
192  memset(newElements, 0, off * sizeof(Element));
193  memcpy(newElements + off, elements.get(), count * sizeof(Element));
194  elements.reset(newElements);
195  count = newCount;
196  first = index;
197  } else if (size_t(off) >= count) {
198  size_t newCount = static_cast<size_t>(off) + 1;
199  Element *newElements = new Element[newCount];
200  memset(newElements, 0, newCount * sizeof(Element));
201  memcpy(newElements, elements.get(), count * sizeof(Element));
202  count = newCount;
203  elements.reset(newElements);
204  }
205 
206  return elements.get()[index - first];
207  }
208 
209 
210 
211  friend class templ_iterator<Element, const CharacterIndex<Element> >;
212  friend class templ_iterator<Element, CharacterIndex<Element> >;
215 
216  iterator begin() { return iterator(this, 0); }
217  iterator find(int idx)
218  { return idx >= first && idx < first + count ? iterator(this, idx - first) : iterator(this, count); }
219  iterator end() { return iterator(this, count); }
220 
221  const_iterator begin() const { return const_iterator(this, 0); }
222  const_iterator find(int idx) const
223  { return idx >= first && idx < int(first + count) ? const_iterator(this, idx - first) : const_iterator(this, count); }
224  const_iterator end() const { return const_iterator(this, count); }
225 
226  CharacterIndex()
227  : first(0)
228  , count(0)
229  {
230  }
231 
232  bool empty() const { return count == 0; }
233 };
234 
235 enum CharFlags {
236  SKIPQUOTE = 1 << 0,
237  NULLOK = 1 << 1
238 };
239 
240 DA_EXPORT inline const char *
241 pad(unsigned depth)
242 {
243  static constexpr char spaces[] =
244  " "
245  " "
246  " ";
247  if (depth > sizeof spaces - 1)
248  depth = sizeof spaces - 1;
249  return spaces + sizeof spaces - 1 - depth;
250 }
251 
252 DA_EXPORT inline char
253 nextchar(const char *&p, int flags)
254 {
255  for (;;) {
256  switch (*p) {
257  case 0: {
258  if (flags & NULLOK)
259  return 0;
260  Exception e;
261  e << "invalid encoding";
262  throw e;
263  }
264 
265  case '"':
266  if (flags & SKIPQUOTE) {
267  p++;
268  continue;
269  }
270  // fallthrough
271  default:
272  return *p++;
273  }
274  }
275 }
276 
277 DA_EXPORT inline char
278 nextword(char *result, const char *&p, const char *terms, int flags)
279 {
280  for (;;) {
281  char c = nextchar(p, flags);
282  if (strchr(terms, c) != 0) {
283  *result = 0;
284  return c;
285  }
286  *result++ = c;
287  }
288  *result = 0;
289 }
290 
291 
292 }}}
293 
294 #endif
Definition: util.h:48
Definition: util.h:175
Definition: binary.h:13
Definition: util.h:69
Definition: util.h:81
Definition: util.h:158
Definition: util.h:96