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