virtmem
virtual memory library for Arduino
vptr_utils.hpp
Go to the documentation of this file.
1 #ifndef VIRTMEM_UTILS_HPP
2 #define VIRTMEM_UTILS_HPP
3 
9 #include "config/config.h"
10 #include "utils.h"
11 #include "vptr.h"
12 
13 #include <stdlib.h>
14 #include <string.h>
15 
16 namespace virtmem {
17 
18 namespace private_utils {
19 
20 template <typename T, typename T2> struct TSameType { static const bool flag = false; };
21 template <typename T> struct TSameType<T, T> { static const bool flag = true; };
22 
23 template <typename T> struct TVirtPtrTraits { };
24 
25 template <typename T, typename A> struct TVirtPtrTraits<VPtr<T, A> >
26 {
27  typedef VPtrLock<VPtr<T, A> > Lock;
28 
29  static bool isWrapped(VPtr<T, A> p) { return p.isWrapped(); }
30  static T *unwrap(VPtr<T, A> p) { return p.unwrap(); }
31  static bool isVirtPtr(void) { return true; }
32  static Lock makeLock(VPtr<T, A> w, VirtPageSize s, bool ro=false)
33  { return makeVirtPtrLock(w, s, ro); }
34  static VirtPageSize getLockSize(Lock &l) { return l.getLockSize(); }
35  static VirtPageSize getPageSize(void)
36  { return A::getInstance()->getBigPageSize(); }
37 
38 };
39 
40 template <typename T> struct TVirtPtrTraits<T *>
41 {
42  typedef T** Lock;
43 
44  static bool isWrapped(T *) { return false; }
45  static T *unwrap(T *p) { return p; }
46  static bool isVirtPtr(void) { return false; }
47  static Lock makeLock(T *&p, VirtPageSize, __attribute__ ((unused)) bool ro=false) { return &p; }
48  static VirtPageSize getLockSize(Lock &) { return (VirtPageSize)-1; }
49  static VirtPageSize getPageSize(void) { return (VirtPageSize)-1; }
50 };
51 
52 template <typename T1, typename T2, typename A> int ptrDiff(VPtr<T1, A> p1, VPtr<T2, A> p2) { return p2 - p1; }
53 template <typename T1, typename T2> int ptrDiff(T1 *p1, T2 *p2) { return p2 - p1; }
54 template <typename T1, typename T2> int ptrDiff(T1, T2) { return 0; } // dummy, not used (for mix of regular and virt pointers)
55 template <typename T1, typename T2, typename A> bool ptrEqual(VPtr<T1, A> p1, VPtr<T2, A> p2) { return p1 == p2; }
56 template <typename T1, typename T2> bool ptrEqual(T1 *p1, T2 *p2) { return p1 == p2; }
57 template <typename T1, typename T2> bool ptrEqual(T1, T2) { return false; } // mix of virt and regular pointers
58 
59 template <typename T1, typename T2> VirtPageSize getMaxLockSize(T1 p1, T2 p2)
60 {
61  VirtPageSize ret = minimal(TVirtPtrTraits<T1>::getPageSize(), TVirtPtrTraits<T2>::getPageSize());
62 
63  // check for overlap in case both p1 and p2 are virtual pointers from the same allocator
64  if (TSameType<T1, T2>::flag && TVirtPtrTraits<T1>::isVirtPtr())
65  ret = minimal(ret, static_cast<VirtPageSize>(abs(ptrDiff(p1, p2))));
66 
67  return ret;
68 }
69 
70 
71 // copier function that works with raw pointers for rawCopy, returns false if copying should be aborted
72 typedef bool (*RawCopier)(char *, const char *, VPtrSize);
73 
74 // Generalized copy for memcpy and strncpy
75 template <typename T1, typename T2> T1 rawCopy(T1 dest, T2 src, VPtrSize size,
76  RawCopier copier)
77 {
78  if (size == 0 || ptrEqual(dest, src))
79  return dest;
80 
81 #ifdef VIRTMEM_WRAP_CPOINTERS
82  if (!TVirtPtrTraits<T1>::isVirtPtr() && !TVirtPtrTraits<T2>::isVirtPtr())
83  {
84  // Even though both are pointers, we must unwrap to avoid compile errors with other types
85  copier(TVirtPtrTraits<T1>::unwrap(dest), TVirtPtrTraits<T2>::unwrap(src), size);
86  return dest;
87  }
88  else if (TVirtPtrTraits<T1>::isWrapped(dest) && TVirtPtrTraits<T2>::isWrapped(src))
89  {
90  copier(TVirtPtrTraits<T1>::unwrap(dest), TVirtPtrTraits<T2>::unwrap(src), size);
91  return dest;
92  }
93  else if (TVirtPtrTraits<T1>::isWrapped(dest))
94  {
95  rawCopy(TVirtPtrTraits<T1>::unwrap(dest), src, size, copier);
96  return dest;
97  }
98  else if (TVirtPtrTraits<T2>::isWrapped(src))
99  return rawCopy(dest, TVirtPtrTraits<T2>::unwrap(src), size, copier);
100 #endif
101 
102  VPtrSize sizeleft = size;
103  const VirtPageSize maxlocksize = getMaxLockSize(dest, src);
104  T1 p1 = dest;
105  T2 p2 = src;
106 
107  while (sizeleft)
108  {
109  VirtPageSize cpsize = minimal(static_cast<VPtrSize>(maxlocksize), sizeleft);
110 
111  typename TVirtPtrTraits<T1>::Lock l1 = TVirtPtrTraits<T1>::makeLock(p1, cpsize);
112  cpsize = minimal(cpsize, TVirtPtrTraits<T1>::getLockSize(l1));
113  typename TVirtPtrTraits<T2>::Lock l2 = TVirtPtrTraits<T2>::makeLock(p2, cpsize, true);
114  cpsize = minimal(cpsize, TVirtPtrTraits<T2>::getLockSize(l2));
115 
116  if (!copier(*l1, *l2, cpsize))
117  return dest;
118 
119  p1 += cpsize; p2 += cpsize;
120  sizeleft -= cpsize;
121  ASSERT(sizeleft <= size);
122  }
123 
124  return dest;
125 }
126 
127 // comparison function for rawCompare
128 typedef int (*RawComparator)(const char *, const char *, VPtrSize, bool &);
129 
130 // Generalized compare for memcmp/strncmp
131 template <typename T1, typename T2> int rawCompare(T1 p1, T2 p2, VPtrSize n, RawComparator comparator)
132 {
133  if (n == 0 || ptrEqual(p1, p2))
134  return 0;
135 
136  bool done = false;
137 
138 #ifdef VIRTMEM_WRAP_CPOINTERS
139  if (!TVirtPtrTraits<T1>::isVirtPtr() && !TVirtPtrTraits<T2>::isVirtPtr())
140  {
141  // Even though both are pointers, we must unwrap to avoid compile errors with other types
142  return comparator(TVirtPtrTraits<T1>::unwrap(p1), TVirtPtrTraits<T2>::unwrap(p2), n, done);
143  }
144  else if (TVirtPtrTraits<T1>::isWrapped(p1) && TVirtPtrTraits<T2>::isWrapped(p2))
145  return comparator(TVirtPtrTraits<T1>::unwrap(p1), TVirtPtrTraits<T2>::unwrap(p2), n, done);
146  else if (TVirtPtrTraits<T1>::isWrapped(p1))
147  return rawCompare(TVirtPtrTraits<T1>::unwrap(p1), p2, n, comparator);
148  else if (TVirtPtrTraits<T2>::isWrapped(p2))
149  return rawCompare(p1, TVirtPtrTraits<T2>::unwrap(p2), n, comparator);
150 #endif
151 
152  VPtrSize sizeleft = n;
153  const VirtPageSize maxlocksize = getMaxLockSize(p1, p2);
154 
155  while (sizeleft)
156  {
157  VirtPageSize cmpsize = minimal(static_cast<VPtrSize>(maxlocksize), sizeleft);
158  typename TVirtPtrTraits<T1>::Lock l1 = TVirtPtrTraits<T1>::makeLock(p1, cmpsize, true);
159  cmpsize = minimal(cmpsize, TVirtPtrTraits<T1>::getLockSize(l1));
160  typename TVirtPtrTraits<T2>::Lock l2 = TVirtPtrTraits<T2>::makeLock(p2, cmpsize, true);
161  cmpsize = minimal(cmpsize, TVirtPtrTraits<T2>::getLockSize(l2));
162 
163  int cmp = comparator(*l1, *l2, cmpsize, done);
164  if (cmp != 0 || done)
165  return cmp;
166 
167  p1 += cmpsize; p2 += cmpsize;
168  sizeleft -= cmpsize;
169  ASSERT(sizeleft <= n);
170  }
171 
172  return 0;
173 }
174 
175 inline bool memCopier(char *dest, const char *src, VPtrSize n)
176 {
177  memcpy(dest, src, n);
178  return true;
179 }
180 
181 inline bool strnCopier(char *dest, const char *src, VPtrSize n)
182 {
183  return n && (strncpy(dest, src, n))[n-1] != 0; // strncpy pads with zero
184 }
185 
186 inline bool strCopier(char *dest, const char *src, VPtrSize n)
187 {
188  // can't use strcpy since it doesn't take into account specified size, cannot take
189  // strncpy either since it pads and since we don't actually know size of dest
190  // it could pad too much... well could you just use something else then strcpy?
191 
192  if (n == 0)
193  return false;
194 
195  char *d = dest;
196  const char *s = src;
197  for (; n; --n, ++d, ++s)
198  {
199  *d = *s;
200  if (*d == 0)
201  return false; // abort if 0 found
202  }
203 
204  return true;
205 }
206 
207 inline int memComparator(const char *p1, const char *p2, VPtrSize n, bool &)
208 { return ::memcmp(p1, p2, n); }
209 inline int strnComparator(const char *p1, const char *p2, VPtrSize n, bool &)
210 { return ::strncmp(p1, p2, n); }
211 inline int strComparator(const char *p1, const char *p2, VPtrSize n, bool &done)
212 {
213  const int ret = ::strncmp(p1, p2, n);
214  if (ret == 0)
215  {
216  // did we encounter a zero?
217  for (; n && *p1; --n, ++p1)
218  ;
219  done = (n != 0); // we're done if there was a string terminator
220  }
221  return ret;
222 }
223 
224 }
225 
226 
227 // Specialize memcpy/memset/memcmp for char types: we may have to convert to this type anyway,
228 // and this saves some template code duplication for other types. A general template function will just
229 // cast and call the specialized function.
230 
231 
242 template <typename T1, typename A1, typename T2, typename A2>
243 VPtr<T1, A1> memcpy(VPtr<T1, A1> dest, const VPtr<T2, A2> src, VPtrSize size)
244 {
245  return static_cast<VPtr<T1, A1> >(
246  private_utils::rawCopy(static_cast<VPtr<char, A1> >(dest),
247  static_cast<const VPtr<const char, A2> >(src), size,
248  private_utils::memCopier));
249 }
250 
251 template <typename T, typename A> VPtr<T, A> memcpy(VPtr<T, A> dest, const void *src, VPtrSize size)
252 {
253  return static_cast<VPtr<T, A> >(
254  private_utils::rawCopy(static_cast<VPtr<char, A> >(dest),
255  static_cast<const char *>(src), size,
256  private_utils::memCopier));
257 }
258 
259 template <typename T, typename A> void *memcpy(void *dest, VPtr<T, A> src, VPtrSize size)
260 {
261  return private_utils::rawCopy(static_cast<char *>(dest),
262  static_cast<const VPtr<const char, A> >(src), size,
263  private_utils::memCopier);
264 }
265 
266 template <typename A> VPtr<char, A> memset(VPtr<char, A> dest, int c, VPtrSize size)
267 {
268  if (size == 0)
269  return dest;
270 
271 #ifdef VIRTMEM_WRAP_CPOINTERS
272  if (dest.isWrapped())
273  {
274  ::memset(dest.unwrap(), c, size);
275  return dest;
276  }
277 #endif
278 
279  VPtrSize sizeleft = size;
280  VPtr<char, A> p = dest;
281 
282  while (sizeleft)
283  {
284  VirtPageSize setsize = private_utils::minimal((VPtrSize)A::getInstance()->getBigPageSize(), sizeleft);
285  VPtrLock<VPtr<char, A> > l = makeVirtPtrLock(p, setsize);
286  setsize = l.getLockSize();
287  ::memset(*l, c, setsize);
288  p += setsize; sizeleft -= setsize;
289  }
290 
291  return dest;
292 }
293 
294 template <typename T, typename A> VPtr<T, A> memset(VPtr<T, A> dest, int c, VPtrSize size)
295 {
296  return static_cast<VPtr<T, A> >(memset(static_cast<VPtr<char, A> >(dest), c, size));
297 }
298 
299 template <typename T1, typename A1, typename T2, typename A2> int memcmp(VPtr<T1, A1> s1, const VPtr<T2, A2> s2,
300  VPtrSize n)
301 {
302 #ifdef VIRTMEM_WRAP_CPOINTERS
303  if (s1.isWrapped() && s2.isWrapped())
304  return ::memcmp(s1.unwrap(), s2.unwrap(), n);
305 #endif
306 
307  return private_utils::rawCompare(static_cast<VPtr<const char, A1> >(s1),
308  static_cast<VPtr<const char, A2> >(s2), n, private_utils::memComparator);
309 }
310 
311 template <typename T, typename A> int memcmp(VPtr<T, A> s1, const void *s2, VPtrSize n)
312 {
313  return private_utils::rawCompare(static_cast<VPtr<const char, A> >(s1),
314  static_cast<const char *>(s2), n, private_utils::memComparator);
315 }
316 
317 template <typename T, typename A> int memcmp(const void *s1, const VPtr<T, A> s2, VPtrSize n)
318 {
319  return private_utils::rawCompare(static_cast<const char *>(s1),
320  static_cast<VPtr<const char, A> >(s2), n, private_utils::memComparator);
321 }
322 
323 template <typename A1, typename A2> VPtr<char, A1> strncpy(VPtr<char, A1> dest, const VPtr<const char, A2> src,
324  VPtrSize n)
325 {
326  return private_utils::rawCopy(dest, src, n, private_utils::strnCopier);
327 }
328 
329 template <typename A> VPtr<char, A> strncpy(VPtr<char, A> dest, const char *src, VPtrSize n)
330 {
331  return private_utils::rawCopy(dest, src, n, private_utils::strnCopier);
332 }
333 
334 template <typename A> char *strncpy(char *dest, const VPtr<const char, A> src, VPtrSize n)
335 {
336  return private_utils::rawCopy(dest, src, n, private_utils::strnCopier);
337 }
338 
339 template <typename A1, typename A2> VPtr<char, A1> strcpy(VPtr<char, A1> dest, const VPtr<const char, A2> src)
340 {
341  return private_utils::rawCopy(dest, src, (VPtrSize)-1, private_utils::strCopier);
342 }
343 
344 template <typename A> VPtr<char, A> strcpy(VPtr<char, A> dest, const char *src)
345 {
346  return private_utils::rawCopy(dest, src, (VPtrSize)-1, private_utils::strCopier);
347 }
348 
349 template <typename A> char *strcpy(char *dest, const VPtr<const char, A> src)
350 {
351  return private_utils::rawCopy(dest, src, (VPtrSize)-1, private_utils::strCopier);
352 }
353 
354 template <typename A1, typename A2> int strncmp(VPtr<const char, A1> dest, VPtr<const char, A2> src, VPtrSize n)
355 { return private_utils::rawCompare(dest, src, n, private_utils::strnComparator);}
356 template <typename A> int strncmp(VPtr<const char, A> dest, const char *src, VPtrSize n)
357 { return private_utils::rawCompare(dest, src, n, private_utils::strnComparator); }
358 template <typename A> int strncmp(const char *dest, VPtr<const char, A> src, VPtrSize n)
359 { return private_utils::rawCompare(dest, src, n, private_utils::strnComparator); }
360 
361 template <typename A1, typename A2> int strcmp(VPtr<const char, A1> dest, VPtr<const char, A2> src)
362 { return private_utils::rawCompare(dest, src, (VPtrSize)-1, private_utils::strComparator); }
363 template <typename A> int strcmp(const char *dest, VPtr<const char, A> src)
364 { return private_utils::rawCompare(dest, src, (VPtrSize)-1, private_utils::strComparator); }
365 template <typename A> int strcmp(VPtr<const char, A> dest, const char *src)
366 { return private_utils::rawCompare(dest, src, (VPtrSize)-1, private_utils::strComparator); }
367 
368 template <typename A> int strlen(VPtr<const char, A> str)
369 {
370 #ifdef VIRTMEM_WRAP_CPOINTERS
371  if (str.isWrapped())
372  return ::strlen(str.unwrap());
373 #endif
374 
375  int ret = 0;
376  for (; *str != 0; ++str)
377  ++ret;
378  return ret;
379 }
380 
381 // const <--> non const madness
382 // -----
383 
384 template <typename A1, typename A2> VPtr<char, A1> strncpy(VPtr<char, A1> dest, const VPtr<char, A2> src,
385  VPtrSize n)
386 { return strncpy(dest, static_cast<const VPtr<const char, A2> >(src), n); }
387 template <typename A> char *strncpy(char *dest, const VPtr<char, A> src, VPtrSize n)
388 { return strncpy(dest, static_cast<const VPtr<const char, A> >(src), n); }
389 
390 template <typename A1, typename A2> VPtr<char, A1> strcpy(VPtr<char, A1> dest, const VPtr<char, A2> src)
391 { return strcpy(dest, static_cast<const VPtr<const char, A2> >(src)); }
392 template <typename A> char *strcpy(char *dest, const VPtr<char, A> src)
393 { return strcpy(dest, static_cast<const VPtr<const char, A> >(src)); }
394 
395 template <typename A1, typename A2> int strncmp(VPtr<char, A1> dest, VPtr<char, A2> src, VPtrSize n)
396 { return strncmp(static_cast<VPtr<const char, A1> >(dest), static_cast<VPtr<const char, A2> >(src), n); }
397 template <typename A1, typename A2> int strncmp(VPtr<const char, A1> dest, VPtr<char, A2> src, VPtrSize n)
398 { return strncmp(dest, static_cast<VPtr<const char, A2> >(src), n); }
399 template <typename A1, typename A2> int strncmp(VPtr<char, A1> dest, VPtr<const char, A2> src, VPtrSize n)
400 { return strncmp(static_cast<VPtr<const char, A1> >(dest), src, n); }
401 template <typename A> int strncmp(const char *dest, VPtr<char, A> src, VPtrSize n)
402 { return strncmp(dest, static_cast<VPtr<const char, A> >(src), n); }
403 template <typename A> int strncmp(VPtr<char, A> dest, const char *src, VPtrSize n)
404 { return strncmp(static_cast<VPtr<const char, A> >(dest), src, n); }
405 
406 template <typename A1, typename A2> int strcmp(VPtr<char, A1> dest, VPtr<char, A2> src)
407 { return strcmp(static_cast<VPtr<const char, A1> >(dest), static_cast<VPtr<const char, A2> >(src)); }
408 template <typename A1, typename A2> int strcmp(VPtr<const char, A1> dest, VPtr<char, A2> src)
409 { return strcmp(dest, static_cast<VPtr<const char, A2> >(src)); }
410 template <typename A1, typename A2> int strcmp(VPtr<char, A1> dest, VPtr<const char, A2> src)
411 { return strcmp(static_cast<VPtr<const char, A1> >(dest), src); }
412 template <typename A> int strcmp(const char *dest, VPtr<char, A> src)
413 { return strcmp(dest, static_cast<VPtr<const char, A> >(src)); }
414 template <typename A> int strcmp(VPtr<char, A> dest, const char *src)
415 { return strcmp(static_cast<VPtr<const char, A> >(dest), src); }
416 
417 template <typename A> int strlen(VPtr<char, A> str) { return strlen(static_cast<VPtr<const char, A> >(str)); }
418 
419 // @}
420 
421 }
422 
423 #endif // VIRTMEM_UTILS_HPP
contains all code from virtmem
Definition: base_alloc.cpp:22
This header file contains several variables that can be used to customize virtmem.
uint16_t VirtPageSize
Numeric type used to store the size of a virtual memory page.
Definition: base_alloc.h:23
This header contains the class definition of the VPtr class.
VPtrLock< T > makeVirtPtrLock(const T &w, VirtPageSize s, bool ro=false)
Creates a virtual lock (shortcut)
Definition: vptr_utils.h:175
uint32_t VPtrSize
Numeric type used to store the size of a virtual memory block.
Definition: base_alloc.h:22