1/*
2 * Copyright (c) 2008 - 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#ifndef MEMORY_HPP_8501DD7B_0F14_4CA8_B700_3F0C6B1653ED
25#define MEMORY_HPP_8501DD7B_0F14_4CA8_B700_3F0C6B1653ED
26
27#include "platform.h"
28#include "compiler.h"
29
30#if PLATFORM(UNIX)
31#include <unistd.h> // getpagesize
32#endif
33
34#include <stddef.h> // size_t
35#include <cstring> // std::memset
36#include <cstdlib> // std::free
37
38namespace platform {
39
40template <class A> inline
41void zero_memory(A& target)
42{
43    std::memset(&target, 0, sizeof(target));
44}
45
46template <class A, int SZ> inline
47void zero_memory(A (&target)[SZ])
48{
49    std::memset(&target, 0, sizeof(target));
50}
51
52inline
53void zero_memory(void * ptr, size_t nbytes)
54{
55    std::memset(ptr, 0, nbytes);
56}
57
58inline size_t pagesize(void)
59{
60#if PLATFORM(UNIX)
61    return ::getpagesize();
62#else
63    return 4096;
64#endif
65}
66
67/*!
68 * Allocate or extend a buffer to the size given by nbytes.
69 *
70 * If the allocation fails, the installed new_handler is invoked. If the
71 * new handler returns, the allocation is retried.
72 *
73 * The returned pointer must be released by free(3).
74 */
75void * allocate(void *, ::std::size_t);
76
77/*!
78 * Invoke the installed new_handler. The new_handler is installed with
79 * std::set_new_handler and should either make more memory available or
80 * terminate the process (the default new_handler throws std::bad_alloc).
81 */
82void invoke_new_handler(void);
83
84/*!
85 * Round an integral value up to the next boundary. This ought to be an
86 * inline function, but we sometimes need it in constant expressions.
87 */
88#ifndef roundup
89#define roundup(value, boundary) ( \
90        ((value) + ((boundary) - 1)) & ~((boundary) - 1) \
91    )
92#endif
93
94/*!
95 * Align the given pointer to the correct byte boundary for type T.
96 */
97template <typename T, typename P>
98void align_pointer(const P * (&ptr)) {
99    uintptr_t tmp = reinterpret_cast<uintptr_t>(ptr);
100    tmp = roundup(tmp, (uintptr_t)alignof(T));
101    ptr = reinterpret_cast<const P *>(tmp);
102}
103
104/*!
105 * Align the given pointer to the correct byte boundary for type T.
106 */
107template <typename T, typename P>
108void align_pointer(P * (&ptr)) {
109    uintptr_t tmp = reinterpret_cast<uintptr_t>(ptr);
110    tmp = roundup(tmp, (uintptr_t)alignof(T));
111    ptr = reinterpret_cast<P *>(tmp);
112}
113
114/*!
115 * Align the given pointer to an arbitrary boundary.
116 */
117template <typename P>
118void align_pointer(const P * (&ptr), unsigned n) {
119    uintptr_t tmp = reinterpret_cast<uintptr_t>(ptr);
120    tmp = roundup(tmp, (uintptr_t)n);
121    ptr = reinterpret_cast<const P *>(tmp);
122}
123
124/*!
125 * Align the given pointer to an arbitrary boundary.
126 */
127template <typename P>
128void align_pointer(P * (&ptr), int n) {
129    uintptr_t tmp = reinterpret_cast<uintptr_t>(ptr);
130    tmp = roundup(tmp, n);
131    ptr = reinterpret_cast<P *>(tmp);
132}
133
134template <typename T, typename P>
135bool is_aligned(const P * ptr) {
136    return ((uintptr_t)ptr % alignof(T)) == 0;
137}
138
139/*!
140 * @class counted_ptr
141 * @abstract a reference counting pointer for objects that contain their own
142 * reference count.
143 *
144 * counted_ptr contrasts with shared_ptr, in which the reference
145 * count is held outside the object. counted_ptr is preferable for objects
146 * that you have the source for.
147 *
148 * Reference counts are make by doing unqualified calls to
149 *       counted_ptr_addref(T *)
150 *       counted_ptr_release(T *)
151 *
152 * If you need an atomically reference counted object, just inherit from
153 * counted_ptr_base, eg:
154 *      struct my_object : public counted_ptr_base {}
155 *      typedef counted_ptr<my_object> my_object_ptr;
156 *
157 */
158template <class T>
159struct counted_ptr
160{
161    counted_ptr() : t_pointer(0) {}
162
163    counted_ptr(const counted_ptr& p) : t_pointer(p.t_pointer) {
164        if (t_pointer) {
165            counted_ptr_addref(t_pointer);
166        }
167    }
168
169    explicit counted_ptr(T * t) : t_pointer(t) {
170        if (t_pointer) {
171            counted_ptr_addref(t_pointer);
172        }
173    }
174
175    ~counted_ptr() {
176        if (t_pointer) {
177            counted_ptr_release(t_pointer);
178        }
179    }
180
181    template <typename A>
182    counted_ptr& operator=(const counted_ptr<A>& rhs) {
183        T * tmp = t_pointer;
184
185        if ((t_pointer = rhs.t_pointer)) {
186            counted_ptr_addref(t_pointer);
187        }
188
189        if (tmp) {
190            counted_ptr_release(tmp);
191        }
192
193        return *this;
194    }
195
196    counted_ptr& operator=(const counted_ptr& p) {
197        return operator=<T>(p);
198    }
199
200    bool operator==(const counted_ptr& rhs) const {
201        return t_pointer == rhs.t_pointer;
202    }
203
204    bool operator<(const counted_ptr & rhs) const {
205        return t_pointer < rhs.t_pointer;
206    }
207
208    T * get() const { return t_pointer; }
209    operator bool() const { return t_pointer != 0; }
210    T& operator*() const { return *t_pointer; }
211    T * operator->() const { return t_pointer; }
212
213private:
214    T * t_pointer;
215};
216
217// NOTE: We need comparison operators so that counted_ptr objects sort into
218// the standard STL containers correctly. The default sort isn't sufficient
219// and will end up not adding objects to std::set correctly.
220
221template<class T, class U>
222bool operator>(const counted_ptr<T>& lhs, const counted_ptr<U>& rhs) {
223    return rhs < lhs;
224}
225
226template<class T, class U>
227bool operator<=(const counted_ptr<T>& lhs, const counted_ptr<U>& rhs) {
228    return !(rhs < lhs);
229}
230
231template<class T, class U>
232bool operator>=(const counted_ptr<T>& lhs, const counted_ptr<U>& rhs) {
233    return !(lhs < rhs);
234}
235
236template <typename T>
237struct scoped_ptr_delete
238{
239    void operator()(T * t) { delete t; }
240
241};
242
243template <typename T>
244struct scoped_ptr_array_delete
245{
246    void operator()(T * t) { delete [] t; }
247};
248
249template <typename T, void (*D)(T*) >
250struct scoped_ptr_free
251{
252    void operator()(T * t) { D(t); }
253};
254
255typedef scoped_ptr_free<void, std::free> malloc_ptr_free;
256
257/*!
258 * @class scoped_ptr
259 * @abstract just like std::auto_ptr, except that it takes a custom deletor
260 * type.
261 *
262 * The default behavior of scoped_ptr is to use the delete operator
263 * to delete the contained pointer. If you have a custom delete
264 * function (eg, std::free), then you can use scoped_ptr_free as the
265 * deletor object.
266 *
267 * scoped_ptr is intended to be identical to std::auto_ptr, so the
268 * usual auto_ptr caveats apply;
269 */
270template <typename T, typename D = scoped_ptr_delete<T> >
271struct scoped_ptr {
272
273    scoped_ptr() : pointer(0) {}
274    explicit scoped_ptr(T * t) : pointer(t) {}
275    scoped_ptr(scoped_ptr& rhs) : pointer(rhs.release()) {}
276
277    ~scoped_ptr() {
278        D deletor; deletor(pointer);
279    }
280
281    // Release and copy, just like std::auto_ptr.
282    template <typename A>
283    scoped_ptr& operator=(scoped_ptr<A, D>& rhs) throw() {
284        pointer = rhs.release();
285        return *this;
286    }
287
288    scoped_ptr& operator=(scoped_ptr& rhs) throw() {
289        return operator=<T>(rhs);
290    }
291
292    T * get() const { return pointer; }
293    operator bool() const { return pointer != 0; }
294    T& operator*() const { return *pointer; }
295    T * operator->() const { return pointer; }
296
297    T& operator[](unsigned offset) { return pointer[offset]; }
298    const T& operator[](unsigned offset) const { return pointer[offset]; }
299
300    T * release() throw() {
301        T * tmp = pointer;
302        pointer = 0;
303        return tmp;
304    }
305
306    void reset(T * ptr = 0) throw() {
307        if (ptr != pointer) {
308            D destroy; destroy(pointer);
309            pointer = ptr;
310        }
311    }
312
313private:
314
315    T * pointer;
316};
317
318/*!
319 * Convenience class for using scoped_ptr with free(3).
320 *
321 * Instead of:
322 *     typedef platform::scoped_ptr<char, platform::malloc_ptr_free> char_ptr
323 * you can do the shorter, more legible:
324 *     typedef platform::malloc_ptr<char>::scoped_ptr char_ptr;
325 *
326 * This is a partial workaround for the lack of template typedefs.
327 */
328template <typename T>
329struct malloc_ptr
330{
331    typedef scoped_ptr<T, malloc_ptr_free> scoped_ptr;
332};
333
334} // namespace platform
335
336#endif // MEMORY_HPP_8501DD7B_0F14_4CA8_B700_3F0C6B1653ED
337/* vim: set ts=4 sw=4 tw=79 et cindent : */
338