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