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