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