1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkTemplates_DEFINED
11#define SkTemplates_DEFINED
12
13#include "SkTypes.h"
14#include <limits.h>
15#include <new>
16
17/** \file SkTemplates.h
18
19    This file contains light-weight template classes for type-safe and exception-safe
20    resource management.
21*/
22
23/**
24 *  Marks a local variable as known to be unused (to avoid warnings).
25 *  Note that this does *not* prevent the local variable from being optimized away.
26 */
27template<typename T> inline void sk_ignore_unused_variable(const T&) { }
28
29/**
30 *  SkTIsConst<T>::value is true if the type T is const.
31 *  The type T is constrained not to be an array or reference type.
32 */
33template <typename T> struct SkTIsConst {
34    static T* t;
35    static uint16_t test(const volatile void*);
36    static uint32_t test(volatile void *);
37    static const bool value = (sizeof(uint16_t) == sizeof(test(t)));
38};
39
40///@{
41/** SkTConstType<T, CONST>::type will be 'const T' if CONST is true, 'T' otherwise. */
42template <typename T, bool CONST> struct SkTConstType {
43    typedef T type;
44};
45template <typename T> struct SkTConstType<T, true> {
46    typedef const T type;
47};
48///@}
49
50/**
51 *  Returns a pointer to a D which comes immediately after S[count].
52 */
53template <typename D, typename S> static D* SkTAfter(S* ptr, size_t count = 1) {
54    return reinterpret_cast<D*>(ptr + count);
55}
56
57/**
58 *  Returns a pointer to a D which comes byteOffset bytes after S.
59 */
60template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffset) {
61    // The intermediate char* has the same const-ness as D as this produces better error messages.
62    // This relies on the fact that reinterpret_cast can add constness, but cannot remove it.
63    return reinterpret_cast<D*>(
64        reinterpret_cast<typename SkTConstType<char, SkTIsConst<D>::value>::type*>(ptr) + byteOffset
65    );
66}
67
68/** \class SkAutoTCallVProc
69
70    Call a function when this goes out of scope. The template uses two
71    parameters, the object, and a function that is to be called in the destructor.
72    If detach() is called, the object reference is set to null. If the object
73    reference is null when the destructor is called, we do not call the
74    function.
75*/
76template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable {
77public:
78    SkAutoTCallVProc(T* obj): fObj(obj) {}
79    ~SkAutoTCallVProc() { if (fObj) P(fObj); }
80
81    operator T*() const { return fObj; }
82    T* operator->() const { SkASSERT(fObj); return fObj; }
83
84    T* detach() { T* obj = fObj; fObj = NULL; return obj; }
85    void reset(T* obj = NULL) {
86        if (fObj != obj) {
87            if (fObj) {
88                P(fObj);
89            }
90            fObj = obj;
91        }
92    }
93private:
94    T* fObj;
95};
96
97/** \class SkAutoTCallIProc
98
99Call a function when this goes out of scope. The template uses two
100parameters, the object, and a function that is to be called in the destructor.
101If detach() is called, the object reference is set to null. If the object
102reference is null when the destructor is called, we do not call the
103function.
104*/
105template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable {
106public:
107    SkAutoTCallIProc(T* obj): fObj(obj) {}
108    ~SkAutoTCallIProc() { if (fObj) P(fObj); }
109    T* detach() { T* obj = fObj; fObj = NULL; return obj; }
110private:
111    T* fObj;
112};
113
114/** \class SkAutoTDelete
115  An SkAutoTDelete<T> is like a T*, except that the destructor of SkAutoTDelete<T>
116  automatically deletes the pointer it holds (if any).  That is, SkAutoTDelete<T>
117  owns the T object that it points to.  Like a T*, an SkAutoTDelete<T> may hold
118  either NULL or a pointer to a T object.  Also like T*, SkAutoTDelete<T> is
119  thread-compatible, and once you dereference it, you get the threadsafety
120  guarantees of T.
121
122  The size of a SkAutoTDelete is small: sizeof(SkAutoTDelete<T>) == sizeof(T*)
123*/
124template <typename T> class SkAutoTDelete : SkNoncopyable {
125public:
126    SkAutoTDelete(T* obj = NULL) : fObj(obj) {}
127    ~SkAutoTDelete() { SkDELETE(fObj); }
128
129    T* get() const { return fObj; }
130    operator T*() { return fObj; }
131    T& operator*() const { SkASSERT(fObj); return *fObj; }
132    T* operator->() const { SkASSERT(fObj); return fObj; }
133
134    void reset(T* obj) {
135        if (fObj != obj) {
136            SkDELETE(fObj);
137            fObj = obj;
138        }
139    }
140
141    /**
142     *  Delete the owned object, setting the internal pointer to NULL.
143     */
144    void free() {
145        SkDELETE(fObj);
146        fObj = NULL;
147    }
148
149    /**
150     *  Transfer ownership of the object to the caller, setting the internal
151     *  pointer to NULL. Note that this differs from get(), which also returns
152     *  the pointer, but it does not transfer ownership.
153     */
154    T* detach() {
155        T* obj = fObj;
156        fObj = NULL;
157        return obj;
158    }
159
160    void swap(SkAutoTDelete* that) {
161        SkTSwap(fObj, that->fObj);
162    }
163
164private:
165    T*  fObj;
166};
167
168// Calls ~T() in the destructor.
169template <typename T> class SkAutoTDestroy : SkNoncopyable {
170public:
171    SkAutoTDestroy(T* obj = NULL) : fObj(obj) {}
172    ~SkAutoTDestroy() {
173        if (fObj) {
174            fObj->~T();
175        }
176    }
177
178    T* get() const { return fObj; }
179    T& operator*() const { SkASSERT(fObj); return *fObj; }
180    T* operator->() const { SkASSERT(fObj); return fObj; }
181
182private:
183    T*  fObj;
184};
185
186template <typename T> class SkAutoTDeleteArray : SkNoncopyable {
187public:
188    SkAutoTDeleteArray(T array[]) : fArray(array) {}
189    ~SkAutoTDeleteArray() { SkDELETE_ARRAY(fArray); }
190
191    T*      get() const { return fArray; }
192    void    free() { SkDELETE_ARRAY(fArray); fArray = NULL; }
193    T*      detach() { T* array = fArray; fArray = NULL; return array; }
194
195    void reset(T array[]) {
196        if (fArray != array) {
197            SkDELETE_ARRAY(fArray);
198            fArray = array;
199        }
200    }
201
202private:
203    T*  fArray;
204};
205
206/** Allocate an array of T elements, and free the array in the destructor
207 */
208template <typename T> class SkAutoTArray : SkNoncopyable {
209public:
210    SkAutoTArray() {
211        fArray = NULL;
212        SkDEBUGCODE(fCount = 0;)
213    }
214    /** Allocate count number of T elements
215     */
216    explicit SkAutoTArray(int count) {
217        SkASSERT(count >= 0);
218        fArray = NULL;
219        if (count) {
220            fArray = SkNEW_ARRAY(T, count);
221        }
222        SkDEBUGCODE(fCount = count;)
223    }
224
225    /** Reallocates given a new count. Reallocation occurs even if new count equals old count.
226     */
227    void reset(int count) {
228        SkDELETE_ARRAY(fArray);
229        SkASSERT(count >= 0);
230        fArray = NULL;
231        if (count) {
232            fArray = SkNEW_ARRAY(T, count);
233        }
234        SkDEBUGCODE(fCount = count;)
235    }
236
237    ~SkAutoTArray() {
238        SkDELETE_ARRAY(fArray);
239    }
240
241    /** Return the array of T elements. Will be NULL if count == 0
242     */
243    T* get() const { return fArray; }
244
245    /** Return the nth element in the array
246     */
247    T&  operator[](int index) const {
248        SkASSERT((unsigned)index < (unsigned)fCount);
249        return fArray[index];
250    }
251
252private:
253    T*  fArray;
254    SkDEBUGCODE(int fCount;)
255};
256
257/** Wraps SkAutoTArray, with room for up to N elements preallocated
258 */
259template <int N, typename T> class SkAutoSTArray : SkNoncopyable {
260public:
261    /** Initialize with no objects */
262    SkAutoSTArray() {
263        fArray = NULL;
264        fCount = 0;
265    }
266
267    /** Allocate count number of T elements
268     */
269    SkAutoSTArray(int count) {
270        fArray = NULL;
271        fCount = 0;
272        this->reset(count);
273    }
274
275    ~SkAutoSTArray() {
276        this->reset(0);
277    }
278
279    /** Destroys previous objects in the array and default constructs count number of objects */
280    void reset(int count) {
281        T* start = fArray;
282        T* iter = start + fCount;
283        while (iter > start) {
284            (--iter)->~T();
285        }
286
287        if (fCount != count) {
288            if (fCount > N) {
289                // 'fArray' was allocated last time so free it now
290                SkASSERT((T*) fStorage != fArray);
291                sk_free(fArray);
292            }
293
294            if (count > N) {
295                fArray = (T*) sk_malloc_throw(count * sizeof(T));
296            } else if (count > 0) {
297                fArray = (T*) fStorage;
298            } else {
299                fArray = NULL;
300            }
301
302            fCount = count;
303        }
304
305        iter = fArray;
306        T* stop = fArray + count;
307        while (iter < stop) {
308            SkNEW_PLACEMENT(iter++, T);
309        }
310    }
311
312    /** Return the number of T elements in the array
313     */
314    int count() const { return fCount; }
315
316    /** Return the array of T elements. Will be NULL if count == 0
317     */
318    T* get() const { return fArray; }
319
320    /** Return the nth element in the array
321     */
322    T&  operator[](int index) const {
323        SkASSERT(index < fCount);
324        return fArray[index];
325    }
326
327private:
328    int     fCount;
329    T*      fArray;
330    // since we come right after fArray, fStorage should be properly aligned
331    char    fStorage[N * sizeof(T)];
332};
333
334/** Manages an array of T elements, freeing the array in the destructor.
335 *  Does NOT call any constructors/destructors on T (T must be POD).
336 */
337template <typename T> class SkAutoTMalloc : SkNoncopyable {
338public:
339    /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */
340    explicit SkAutoTMalloc(T* ptr = NULL) {
341        fPtr = ptr;
342    }
343
344    /** Allocates space for 'count' Ts. */
345    explicit SkAutoTMalloc(size_t count) {
346        fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
347    }
348
349    ~SkAutoTMalloc() {
350        sk_free(fPtr);
351    }
352
353    /** Resize the memory area pointed to by the current ptr preserving contents. */
354    void realloc(size_t count) {
355        fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T)));
356    }
357
358    /** Resize the memory area pointed to by the current ptr without preserving contents. */
359    void reset(size_t count) {
360        sk_free(fPtr);
361        fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
362    }
363
364    T* get() const { return fPtr; }
365
366    operator T*() {
367        return fPtr;
368    }
369
370    operator const T*() const {
371        return fPtr;
372    }
373
374    T& operator[](int index) {
375        return fPtr[index];
376    }
377
378    const T& operator[](int index) const {
379        return fPtr[index];
380    }
381
382    /**
383     *  Transfer ownership of the ptr to the caller, setting the internal
384     *  pointer to NULL. Note that this differs from get(), which also returns
385     *  the pointer, but it does not transfer ownership.
386     */
387    T* detach() {
388        T* ptr = fPtr;
389        fPtr = NULL;
390        return ptr;
391    }
392
393private:
394    T* fPtr;
395};
396
397template <size_t N, typename T> class SkAutoSTMalloc : SkNoncopyable {
398public:
399    SkAutoSTMalloc() {
400        fPtr = NULL;
401    }
402
403    SkAutoSTMalloc(size_t count) {
404        if (count > N) {
405            fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
406        } else if (count) {
407            fPtr = fTStorage;
408        } else {
409            fPtr = NULL;
410        }
411    }
412
413    ~SkAutoSTMalloc() {
414        if (fPtr != fTStorage) {
415            sk_free(fPtr);
416        }
417    }
418
419    // doesn't preserve contents
420    T* reset(size_t count) {
421        if (fPtr != fTStorage) {
422            sk_free(fPtr);
423        }
424        if (count > N) {
425            fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
426        } else if (count) {
427            fPtr = fTStorage;
428        } else {
429            fPtr = NULL;
430        }
431        return fPtr;
432    }
433
434    T* get() const { return fPtr; }
435
436    operator T*() {
437        return fPtr;
438    }
439
440    operator const T*() const {
441        return fPtr;
442    }
443
444    T& operator[](int index) {
445        return fPtr[index];
446    }
447
448    const T& operator[](int index) const {
449        return fPtr[index];
450    }
451
452private:
453    T*          fPtr;
454    union {
455        uint32_t    fStorage32[(N*sizeof(T) + 3) >> 2];
456        T           fTStorage[1];   // do NOT want to invoke T::T()
457    };
458};
459
460/**
461 * Reserves memory that is aligned on double and pointer boundaries.
462 * Hopefully this is sufficient for all practical purposes.
463 */
464template <size_t N> class SkAlignedSStorage : SkNoncopyable {
465public:
466    void* get() { return fData; }
467private:
468    union {
469        void*   fPtr;
470        double  fDouble;
471        char    fData[N];
472    };
473};
474
475/**
476 * Reserves memory that is aligned on double and pointer boundaries.
477 * Hopefully this is sufficient for all practical purposes. Otherwise,
478 * we have to do some arcane trickery to determine alignment of non-POD
479 * types. Lifetime of the memory is the lifetime of the object.
480 */
481template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
482public:
483    /**
484     * Returns void* because this object does not initialize the
485     * memory. Use placement new for types that require a cons.
486     */
487    void* get() { return fStorage.get(); }
488private:
489    SkAlignedSStorage<sizeof(T)*N> fStorage;
490};
491
492#endif
493