]> git.cworth.org Git - vogl/blob - src/extlib/loki/include/loki/yasli/yasli_memory.h
Initial vogl checkin
[vogl] / src / extlib / loki / include / loki / yasli / yasli_memory.h
1 #ifndef YASLI_MEMORY_H_
2 #define YASLI_MEMORY_H_
3
4 // $Id: yasli_memory.h 754 2006-10-17 19:59:11Z syntheticpp $
5
6
7 #include "yasli_traits.h"
8 #include "yasli_protocols.h"//!
9 #include <cassert>
10 #include <cstddef>
11 #include <misc/mojo.h>//NOT A SAFE WAY TO INCLUDE IT
12
13 namespace yasli
14 {
15
16
17 // 20.4.1, the default allocator:
18 template <class T> class allocator;
19 template <> class allocator<void>;
20
21 // 20.4.1.2, allocator globals
22 template <class T, class U>
23 bool operator==(const allocator<T>&, const allocator<U>&) throw()
24 {
25         return true;
26 }
27
28 template <class T, class U>
29 bool operator!=(const allocator<T>&, const allocator<U>&) throw()
30 {
31         return false;
32 }
33
34 // 20.4.2, raw storage iterator:
35 // @@@ not defined, use the std one @@@
36 //template <class OutputIterator, class T> class raw_storage_iterator;
37
38 // 20.4.3, temporary buffers:
39 // @@@ not defined, use the std one @@@
40 //template <class T>
41 //pair<T*,ptrdiff_t> get_temporary_buffer(ptrdiff_t n);
42 // @@@ not defined, use the std one @@@
43 // template <class T>
44 // void return_temporary_buffer(T* p);
45
46 // 20.4.4, specialized algorithms:
47 template <class InputIterator, class ForwardIterator>
48 ForwardIterator
49 uninitialized_copy(InputIterator first, InputIterator last,
50                    ForwardIterator result);
51
52 template <class ForwardIterator, class Size, class T>
53 void uninitialized_fill_n(ForwardIterator first, Size n, const T &x);
54 // 20.4.5, pointers:
55 // @@@ not defined, use the std one @@@
56 // template<class X> class auto_ptr;
57 }
58
59 namespace yasli
60 {
61 template <class T> class allocator;
62 // specialize for void:
63 template <> class allocator<void>
64 {
65 public:
66         typedef void *pointer;
67         typedef const void *const_pointer;
68         // reference-to-void members are impossible.
69         typedef void value_type;
70         template <class U> struct rebind
71         {
72                 typedef allocator<U> other;
73         };
74 };
75
76 template <class T> class allocator
77 {
78 public:
79         typedef size_t                 size_type;
80         typedef std::ptrdiff_t         difference_type;
81         typedef T                     *pointer;
82         typedef const T               *const_pointer;
83         typedef T                     &reference;
84         typedef const T               &const_reference;
85         typedef T                      value_type;
86
87         template <class U> struct rebind
88         {
89                 typedef allocator<U> other;
90         };
91         allocator() throw() {}
92         allocator(const allocator &) throw() {}
93         template <class U> allocator(const allocator<U>&) throw() {}
94         ~allocator() throw() {}
95         pointer address(reference x) const
96         {
97                 return &x;
98         }
99         const_pointer address(const_reference x)
100         {
101                 return &x;
102         }
103         pointer allocate(size_type n, allocator<void>::const_pointer = 0)
104         {
105                 return static_cast<pointer>(::operator new(n * sizeof(T)));
106         }
107         void deallocate(pointer p, size_type)
108         {
109                 ::operator delete(p);
110         }
111         size_type max_size() const throw()
112         {
113                 return size_type(-1);
114         }
115         void construct(pointer p, const T &val)
116         {
117                 new((void *) p) T(val);
118         }
119         void destroy(pointer p)
120         {
121                 ((T *) p)->~T();
122         }
123 };
124 } // namespace yasli
125
126 namespace yasli_nstd
127 {
128 template <class T> class mallocator
129 {
130 public:
131         typedef size_t       size_type;
132         typedef ptrdiff_t    difference_type;
133         typedef T           *pointer;
134         typedef const T     *const_pointer;
135         typedef T           &reference;
136         typedef const T     &const_reference;
137         typedef T            value_type;
138
139         template <class U> struct rebind
140         {
141                 typedef mallocator<U> other;
142         };
143         mallocator() throw() {}
144         mallocator(const mallocator &) throw() {}
145         template <class U> mallocator(const mallocator<U>&) throw() {}
146         ~mallocator() throw() {}
147         pointer address(reference x) const
148         {
149                 return &x;
150         }
151         const_pointer address(const_reference x)
152         {
153                 return &x;
154         }
155         pointer allocate(size_type n, yasli::allocator<void>::const_pointer = 0)
156         {
157                 return static_cast<pointer>(malloc(n * sizeof(T)));
158         }
159         void deallocate(pointer p, size_type)
160         {
161                 free(p);
162         }
163         size_type max_size() const throw()
164         {
165                 return size_type(-1);
166         }
167         void construct(pointer p, const T &val)
168         {
169                 new((void *) p) T(val);
170         }
171         void destroy(pointer p)
172         {
173                 ((T *) p)->~T();
174         }
175 };
176
177 //--------------destroy--------
178
179 namespace _impl
180 {
181 struct non_destroyer
182 {
183         template <class A, class T>
184         static void destroy(A &a, T *p, typename A::size_type n) {}
185
186         template <class ForwardIterator>
187         static void destroy_range(ForwardIterator b, ForwardIterator e) {}
188 };
189
190 struct destroyer
191 {
192         template <class A, class T>
193         static void destroy(A &a, T *p, typename A::size_type n)
194         {
195                 const typename A::pointer p1 = p + n;
196                 for (; p < p1; ++p) a.destroy(p);
197         }
198
199         template <class ForwardIterator>
200         static void destroy_range(ForwardIterator b, ForwardIterator e)
201         {
202                 typedef typename std::iterator_traits<ForwardIterator>::value_type
203                 value_type;
204                 for (; b != e; ++b) (*b).~value_type();
205         }
206 };
207 }
208
209 template <class A, class T>
210 void destroy(A &a, T *p, typename A::size_type n)
211 {
212         yasli_nstd::type_selector<yasli_nstd::is_class<T>::value != 0,
213                    _impl::destroyer,
214                    _impl::non_destroyer
215                    >::result::destroy(a, p, n);
216 }
217
218 template <class ForwardIterator>
219 void destroy_range(ForwardIterator b, ForwardIterator e)
220 {
221         yasli_nstd::type_selector<
222         yasli_nstd::is_class<typename std::iterator_traits<ForwardIterator>
223         ::value_type>::value != 0,
224         _impl::destroyer,
225         _impl::non_destroyer
226         >::result::destroy_range(b, e);
227 }
228
229 //---------------
230
231
232 template <class It1, class It2>
233 It2 uninitialized_move(It1 b, It1 e, It2 d)
234 {
235         return mojo::uninitialized_move(b, e, d);
236 }
237
238 template <class A>
239 struct generic_allocator_traits
240 {
241         static typename A::pointer
242         reallocate(
243             A &a,
244             typename A::pointer b,
245             typename A::pointer e,
246             typename A::size_type newSize)
247         {
248                 typename A::pointer p1 = a.allocate(newSize, b);
249                 const typename A::size_type oldSize = e - b;
250                 if (oldSize <= newSize) // expand
251                 {
252                         yasli_protocols::move_traits<typename A::value_type>::destructive_move(
253                             b, b + oldSize, p1);
254                 }
255                 else // shrink
256                 {
257                         yasli_protocols::move_traits<typename A::value_type>::destructive_move(
258                             b, b + newSize, p1);
259                         yasli_nstd::destroy(a, b + newSize, oldSize - newSize);
260                 }
261                 a.deallocate(b, oldSize);
262                 return p1;
263         }
264
265         static bool reallocate_inplace(
266             A &a,
267             typename A::pointer b,
268             typename A::size_type newSize)
269         {
270                 return false;
271         }
272
273 private:
274         generic_allocator_traits();
275 };
276
277 template <class A>
278 struct allocator_traits : public generic_allocator_traits<A>
279 {
280 };
281
282 template <class T>
283 struct allocator_traits< yasli::allocator<T> >
284                 : public generic_allocator_traits< yasli::allocator<T> >
285 {
286 #if YASLI_NEW_IS_MALLOC != 0
287
288         static bool reallocate_inplace(
289             A &a,
290             typename A::pointer b,
291             typename A::size_type newSize)
292         {
293                 allocator_traits< yasli_nstd::mallocator<T> >
294                 ::reallocate_inplace(a, b, newSize);
295         }
296
297         static typename yasli::allocator<T>::pointer
298         reallocate(
299             yasli::allocator<T>& a,
300             typename yasli::allocator<T>::pointer b,
301             typename yasli::allocator<T>::pointer e,
302             typename yasli::allocator<T>::size_type newSize)
303         {
304                 allocator_traits< yasli_nstd::mallocator<T> >
305                 ::reallocate(a, b, e, newSize);
306         }
307 #endif//yasli_new_is_malloc
308 };
309
310 template <class T>
311 struct allocator_traits< yasli_nstd::mallocator<T> >
312                 : public generic_allocator_traits< yasli_nstd::mallocator<T> >
313 {
314 #if YASLI_HAS_EXPAND && YASLI_HAS_EFFICIENT_MSIZE
315         static bool reallocate_inplace(
316             yasli_nstd::mallocator<T>& a,
317             typename yasli_nstd::mallocator<T>::pointer b,
318             typename yasli_nstd::mallocator<T>::size_type newSize)
319         {
320                 if (b == 0) return malloc(newSize);
321                 if (newSize == 0)
322                 {
323                         free(b);
324                         return false;
325                 }
326                 return b == yasli_platform::expand(b, newSize)
327                        && yasli_platform::msize(b) >= newSize;
328         }
329 #endif
330         static typename yasli_nstd::mallocator<T>::pointer
331         reallocate(
332             yasli_nstd::mallocator<T>& a,
333             typename yasli_nstd::mallocator<T>::pointer b,
334             typename yasli_nstd::mallocator<T>::pointer e,
335             typename yasli_nstd::mallocator<T>::size_type newSize)
336         {
337                 if (yasli_nstd::is_memmoveable<T>::value)
338                 {
339                         return static_cast<T *>(realloc(b, newSize));
340                 }
341                 if(reallocate_inplace(a, b, newSize)) return b;
342                 return generic_allocator_traits< yasli_nstd::mallocator<T> >::
343                        reallocate(a, b, e, newSize);
344         }
345 };
346 }
347
348 namespace yasli
349 {
350 //Here is where type_selector is really much more ugly than
351 //enable_if.
352
353 //----------------UNINIT COPY--------
354 namespace _impl
355 {
356 //safe
357 template <class InputItr, class FwdItr>
358 struct uninitialized_safe_copier
359 {
360         static FwdItr execute(InputItr first, InputItr last, FwdItr result)
361         {
362                 //
363                 struct ScopeGuard
364                 {
365                         FwdItr begin;
366                         FwdItr *current;
367                         ~ScopeGuard()
368                         {
369                                 if (!current) return;
370                                 FwdItr end = *current;
371                                 typedef typename std::iterator_traits<FwdItr>::value_type T;
372                                 for (; begin != end; ++begin) (&*begin)->~T();
373                         }
374                 } guard = { result, &result };
375                 for (; first != last; ++first, ++result)
376                         new(&*result) typename std::iterator_traits<FwdItr>::value_type(*first);
377                 // commit
378                 return result;
379         }
380 };
381
382 template <class T>
383 struct uninitialized_memcopier
384 {
385         static T *execute(const T *first, const T *last, T *result)
386         {
387                 yasli_nstd::is_memcopyable<T>::value;
388                 const size_t s = last - first;
389                 memmove(result, first, s * sizeof(T));
390                 return result + s;
391         }
392 };
393
394 }// _impl
395
396 // @@@ TODO: specialize for yasli_nstd::fill_iterator
397
398 template <class InputItr, class FwdItr>
399 FwdItr uninitialized_copy(InputItr first, InputItr last, FwdItr result)
400 {
401         std::cout<<"neither\n";
402         return _impl::uninitialized_safe_copier<InputItr, FwdItr>::execute(first, last, result);
403 }
404
405 template <class T>
406 T *uninitialized_copy(const T *first, const T *last, T *result)
407 {
408         std::cout<<"const\n";
409         return yasli_nstd::type_selector<yasli_nstd::is_memcopyable<T>::value != 0,
410                _impl::uninitialized_memcopier<T>,
411                _impl::uninitialized_safe_copier<const T *, T *>
412                >::result::execute(first, last, result);
413 }
414
415 template <class T>
416 T *uninitialized_copy(T *first, T *last, T *result)
417 {
418         std::cout<<"non-const\n";
419         return uninitialized_copy(static_cast<const T *>(first),
420                                   static_cast<const T *>(last), result);
421 }
422
423 //-------------------------UNINIT FILL------
424
425 template <class ForwardIterator, class T>
426 void
427 uninitialized_fill(ForwardIterator first, ForwardIterator last,
428                    const T &x)
429 {
430         struct ScopeGuard
431         {
432                 ForwardIterator first;
433                 ForwardIterator *pCrt;
434                 ~ScopeGuard()
435                 {
436                         if (pCrt) yasli_nstd::destroy_range(first, *pCrt);
437                 }
438         } guard = { first, &first };
439         for (; first != last; ++first)
440                 new(&*first) T(x);
441         // Commit
442         guard.pCrt = 0;
443 }
444
445 template <class T, class U>
446 void
447 uninitialized_fill(T *first, T *last, const U &x)
448 {
449         struct ScopeGuard
450         {
451                 T *first;
452                 T **pCrt;
453                 ~ScopeGuard()
454                 {
455                         if (pCrt) yasli_nstd::destroy_range(first, *pCrt);
456                 }
457         } guard = { first, &first };
458         assert(first <= last);
459         switch ((last - first) & 7u)
460         {
461         case 0:
462                 while (first != last)
463                 {
464                         new(first) T(x);
465                         ++first;
466                 case 7:
467                         new(first) T(x);
468                         ++first;
469                 case 6:
470                         new(first) T(x);
471                         ++first;
472                 case 5:
473                         new(first) T(x);
474                         ++first;
475                 case 4:
476                         new(first) T(x);
477                         ++first;
478                 case 3:
479                         new(first) T(x);
480                         ++first;
481                 case 2:
482                         new(first) T(x);
483                         ++first;
484                 case 1:
485                         new(first) T(x);
486                         ++first;
487                         assert(first <= last);
488                 }
489         }
490         // Commit
491         guard.pCrt = 0;
492 }
493
494 }// yasli
495
496 #endif // YASLI_MEMORY_H_