michael@0: // michael@0: // SkTRefArray.h michael@0: // core michael@0: // michael@0: // Created by Mike Reed on 7/17/12. michael@0: // Copyright (c) 2012 __MyCompanyName__. All rights reserved. michael@0: // michael@0: michael@0: #ifndef SkTRefArray_DEFINED michael@0: #define SkTRefArray_DEFINED michael@0: michael@0: #include "SkRefCnt.h" michael@0: #include michael@0: michael@0: /** michael@0: * Wrapper to manage thread-safe sharing of an array of T objects. The array michael@0: * cannot be grown or shrunk. michael@0: */ michael@0: template class SkTRefArray : public SkRefCnt { michael@0: /* michael@0: * Shared factory to allocate the space needed for our instance plus N michael@0: * T entries at the end. We call our constructor, but not the constructors michael@0: * for the elements. Those are called by the proper Create method. michael@0: */ michael@0: static SkTRefArray* Alloc(int count) { michael@0: // space for us, and our [count] elements michael@0: size_t size = sizeof(SkTRefArray) + count * sizeof(T); michael@0: SkTRefArray* obj = (SkTRefArray*)sk_malloc_throw(size); michael@0: michael@0: SkNEW_PLACEMENT(obj, SkTRefArray); michael@0: obj->fCount = count; michael@0: return obj; michael@0: } michael@0: michael@0: public: michael@0: /** michael@0: * Return a new array with 'count' elements, initialized to their default michael@0: * value. To change them to some other value, use writableBegin/End or michael@0: * writableAt(), but do that before this array is given to another thread. michael@0: */ michael@0: static SkTRefArray* Create(int count) { michael@0: SkTRefArray* obj = Alloc(count); michael@0: T* array = const_cast(obj->begin()); michael@0: for (int i = 0; i < count; ++i) { michael@0: SkNEW_PLACEMENT(&array[i], T); michael@0: } michael@0: return obj; michael@0: } michael@0: michael@0: /** michael@0: * Return a new array with 'count' elements, initialized from the provided michael@0: * src array. To change them to some other value, use writableBegin/End or michael@0: * writableAt(), but do that before this array is given to another thread. michael@0: */ michael@0: static SkTRefArray* Create(const T src[], int count) { michael@0: SkTRefArray* obj = Alloc(count); michael@0: T* array = const_cast(obj->begin()); michael@0: for (int i = 0; i < count; ++i) { michael@0: SkNEW_PLACEMENT_ARGS(&array[i], T, (src[i])); michael@0: } michael@0: return obj; michael@0: } michael@0: michael@0: int count() const { return fCount; } michael@0: const T* begin() const { return (const T*)(this + 1); } michael@0: const T* end() const { return this->begin() + fCount; } michael@0: const T& at(int index) const { michael@0: SkASSERT((unsigned)index < (unsigned)fCount); michael@0: return this->begin()[index]; michael@0: } michael@0: const T& operator[](int index) const { return this->at(index); } michael@0: michael@0: // For the writable methods, we assert that we are the only owner if we michael@0: // call these, since other owners are not informed if we change an element. michael@0: michael@0: T* writableBegin() { michael@0: SkASSERT(this->unique()); michael@0: return (T*)(this + 1); michael@0: } michael@0: T* writableEnd() { michael@0: return this->writableBegin() + fCount; michael@0: } michael@0: T& writableAt(int index) { michael@0: SkASSERT((unsigned)index < (unsigned)fCount); michael@0: return this->writableBegin()[index]; michael@0: } michael@0: michael@0: protected: michael@0: virtual void internal_dispose() const SK_OVERRIDE { michael@0: T* array = const_cast(this->begin()); michael@0: int n = fCount; michael@0: michael@0: for (int i = 0; i < n; ++i) { michael@0: array->~T(); michael@0: array += 1; michael@0: } michael@0: michael@0: this->internal_dispose_restore_refcnt_to_1(); michael@0: this->~SkTRefArray(); michael@0: sk_free((void*)this); michael@0: } michael@0: michael@0: private: michael@0: int fCount; michael@0: michael@0: // hide this michael@0: virtual ~SkTRefArray() {} michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: #endif