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