SkTemplates.h revision d0e402f99949127624b5c5e6d673a44a71940489
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        SkASSERT(count >= 0);
196        if (fCount != count) {
197            if (fCount > kCount) {
198                // 'fArray' was allocated last time so free it now
199                SkASSERT((T*) fStorage != fArray);
200                sk_free(fArray);
201            }
202
203            if (count > kCount) {
204                const uint64_t size64 = sk_64_mul(count, sizeof(T));
205                const size_t size = static_cast<size_t>(size64);
206                if (size != size64) {
207                    sk_out_of_memory();
208                }
209                fArray = (T*) sk_malloc_throw(size);
210            } else if (count > 0) {
211                fArray = (T*) fStorage;
212            } else {
213                fArray = NULL;
214            }
215
216            fCount = count;
217        }
218
219        iter = fArray;
220        T* stop = fArray + count;
221        while (iter < stop) {
222            new (iter++) T;
223        }
224    }
225
226    /** Return the number of T elements in the array
227     */
228    int count() const { return fCount; }
229
230    /** Return the array of T elements. Will be NULL if count == 0
231     */
232    T* get() const { return fArray; }
233
234    /** Return the nth element in the array
235     */
236    T&  operator[](int index) const {
237        SkASSERT(index < fCount);
238        return fArray[index];
239    }
240
241private:
242#if defined(GOOGLE3)
243    // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions
244    // have multiple large stack allocations.
245    static const int kMaxBytes = 4 * 1024;
246    static const int kCount = kCountRequested * sizeof(T) > kMaxBytes
247        ? kMaxBytes / sizeof(T)
248        : kCountRequested;
249#else
250    static const int kCount = kCountRequested;
251#endif
252
253    int     fCount;
254    T*      fArray;
255    // since we come right after fArray, fStorage should be properly aligned
256    char    fStorage[kCount * sizeof(T)];
257};
258
259/** Manages an array of T elements, freeing the array in the destructor.
260 *  Does NOT call any constructors/destructors on T (T must be POD).
261 */
262template <typename T> class SkAutoTMalloc : SkNoncopyable {
263public:
264    /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */
265    explicit SkAutoTMalloc(T* ptr = NULL) {
266        fPtr = ptr;
267    }
268
269    /** Allocates space for 'count' Ts. */
270    explicit SkAutoTMalloc(size_t count) {
271        fPtr = count ? (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW) : nullptr;
272    }
273
274    ~SkAutoTMalloc() {
275        sk_free(fPtr);
276    }
277
278    /** Resize the memory area pointed to by the current ptr preserving contents. */
279    void realloc(size_t count) {
280        if (count) {
281            fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T)));
282        } else {
283            this->reset(0);
284        }
285    }
286
287    /** Resize the memory area pointed to by the current ptr without preserving contents. */
288    T* reset(size_t count = 0) {
289        sk_free(fPtr);
290        fPtr = count ? (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW) : nullptr;
291        return fPtr;
292    }
293
294    T* get() const { return fPtr; }
295
296    operator T*() {
297        return fPtr;
298    }
299
300    operator const T*() const {
301        return fPtr;
302    }
303
304    T& operator[](int index) {
305        return fPtr[index];
306    }
307
308    const T& operator[](int index) const {
309        return fPtr[index];
310    }
311
312    /**
313     *  Transfer ownership of the ptr to the caller, setting the internal
314     *  pointer to NULL. Note that this differs from get(), which also returns
315     *  the pointer, but it does not transfer ownership.
316     */
317    T* release() {
318        T* ptr = fPtr;
319        fPtr = NULL;
320        return ptr;
321    }
322
323private:
324    T* fPtr;
325};
326
327template <size_t kCountRequested, typename T> class SkAutoSTMalloc : SkNoncopyable {
328public:
329    SkAutoSTMalloc() : fPtr(fTStorage) {}
330
331    SkAutoSTMalloc(size_t count) {
332        if (count > kCount) {
333            fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
334        } else if (count) {
335            fPtr = fTStorage;
336        } else {
337            fPtr = nullptr;
338        }
339    }
340
341    ~SkAutoSTMalloc() {
342        if (fPtr != fTStorage) {
343            sk_free(fPtr);
344        }
345    }
346
347    // doesn't preserve contents
348    T* reset(size_t count) {
349        if (fPtr != fTStorage) {
350            sk_free(fPtr);
351        }
352        if (count > kCount) {
353            fPtr = (T*)sk_malloc_throw(count * sizeof(T));
354        } else if (count) {
355            fPtr = fTStorage;
356        } else {
357            fPtr = nullptr;
358        }
359        return fPtr;
360    }
361
362    T* get() const { return fPtr; }
363
364    operator T*() {
365        return fPtr;
366    }
367
368    operator const T*() const {
369        return fPtr;
370    }
371
372    T& operator[](int index) {
373        return fPtr[index];
374    }
375
376    const T& operator[](int index) const {
377        return fPtr[index];
378    }
379
380    // Reallocs the array, can be used to shrink the allocation.  Makes no attempt to be intelligent
381    void realloc(size_t count) {
382        if (count > kCount) {
383            if (fPtr == fTStorage) {
384                fPtr = (T*)sk_malloc_throw(count * sizeof(T));
385                memcpy(fPtr, fTStorage, kCount * sizeof(T));
386            } else {
387                fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
388            }
389        } else if (count) {
390            if (fPtr != fTStorage) {
391                fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
392            }
393        } else {
394            this->reset(0);
395        }
396    }
397
398private:
399    // Since we use uint32_t storage, we might be able to get more elements for free.
400    static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
401#if defined(GOOGLE3)
402    // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions
403    // have multiple large stack allocations.
404    static const size_t kMaxBytes = 4 * 1024;
405    static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
406        ? kMaxBytes / sizeof(T)
407        : kCountWithPadding;
408#else
409    static const size_t kCount = kCountWithPadding;
410#endif
411
412    T*          fPtr;
413    union {
414        uint32_t    fStorage32[SkAlign4(kCount*sizeof(T)) >> 2];
415        T           fTStorage[1];   // do NOT want to invoke T::T()
416    };
417};
418
419//////////////////////////////////////////////////////////////////////////////////////////////////
420
421/**
422 *  Pass the object and the storage that was offered during SkInPlaceNewCheck, and this will
423 *  safely destroy (and free if it was dynamically allocated) the object.
424 */
425template <typename T> void SkInPlaceDeleteCheck(T* obj, void* storage) {
426    if (storage == obj) {
427        obj->~T();
428    } else {
429        delete obj;
430    }
431}
432
433/**
434 *  Allocates T, using storage if it is large enough, and allocating on the heap (via new) if
435 *  storage is not large enough.
436 *
437 *      obj = SkInPlaceNewCheck<Type>(storage, size);
438 *      ...
439 *      SkInPlaceDeleteCheck(obj, storage);
440 */
441template <typename T> T* SkInPlaceNewCheck(void* storage, size_t size) {
442    return (sizeof(T) <= size) ? new (storage) T : new T;
443}
444
445template <typename T, typename A1, typename A2, typename A3>
446T* SkInPlaceNewCheck(void* storage, size_t size, const A1& a1, const A2& a2, const A3& a3) {
447    return (sizeof(T) <= size) ? new (storage) T(a1, a2, a3) : new T(a1, a2, a3);
448}
449
450template <typename T, typename A1, typename A2, typename A3, typename A4>
451T* SkInPlaceNewCheck(void* storage, size_t size,
452                     const A1& a1, const A2& a2, const A3& a3, const A4& a4) {
453    return (sizeof(T) <= size) ? new (storage) T(a1, a2, a3, a4) : new T(a1, a2, a3, a4);
454}
455
456/**
457 * Reserves memory that is aligned on double and pointer boundaries.
458 * Hopefully this is sufficient for all practical purposes.
459 */
460template <size_t N> class SkAlignedSStorage : SkNoncopyable {
461public:
462    size_t size() const { return N; }
463    void* get() { return fData; }
464    const void* get() const { return fData; }
465
466private:
467    union {
468        void*   fPtr;
469        double  fDouble;
470        char    fData[N];
471    };
472};
473
474/**
475 * Reserves memory that is aligned on double and pointer boundaries.
476 * Hopefully this is sufficient for all practical purposes. Otherwise,
477 * we have to do some arcane trickery to determine alignment of non-POD
478 * types. Lifetime of the memory is the lifetime of the object.
479 */
480template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
481public:
482    /**
483     * Returns void* because this object does not initialize the
484     * memory. Use placement new for types that require a cons.
485     */
486    void* get() { return fStorage.get(); }
487    const void* get() const { return fStorage.get(); }
488private:
489    SkAlignedSStorage<sizeof(T)*N> fStorage;
490};
491
492#endif
493