gfx/skia/trunk/include/core/SkTLazy.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/include/core/SkTLazy.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,192 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2011 Google Inc.
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +
    1.14 +#ifndef SkTLazy_DEFINED
    1.15 +#define SkTLazy_DEFINED
    1.16 +
    1.17 +#include "SkTypes.h"
    1.18 +#include <new>
    1.19 +
    1.20 +template <typename T> class SkTLazy;
    1.21 +template <typename T> void* operator new(size_t, SkTLazy<T>* lazy);
    1.22 +
    1.23 +/**
    1.24 + *  Efficient way to defer allocating/initializing a class until it is needed
    1.25 + *  (if ever).
    1.26 + */
    1.27 +template <typename T> class SkTLazy {
    1.28 +public:
    1.29 +    SkTLazy() : fPtr(NULL) {}
    1.30 +
    1.31 +    explicit SkTLazy(const T* src) : fPtr(NULL) {
    1.32 +        if (src) {
    1.33 +            fPtr = new (fStorage) T(*src);
    1.34 +        }
    1.35 +    }
    1.36 +
    1.37 +    SkTLazy(const SkTLazy<T>& src) : fPtr(NULL) {
    1.38 +        if (src.isValid()) {
    1.39 +            fPtr = new (fStorage) T(*src->get());
    1.40 +        } else {
    1.41 +            fPtr = NULL;
    1.42 +        }
    1.43 +    }
    1.44 +
    1.45 +    ~SkTLazy() {
    1.46 +        if (this->isValid()) {
    1.47 +            fPtr->~T();
    1.48 +        }
    1.49 +    }
    1.50 +
    1.51 +    /**
    1.52 +     *  Return a pointer to a default-initialized instance of the class. If a
    1.53 +     *  previous instance had been initialized (either from init() or set()) it
    1.54 +     *  will first be destroyed, so that a freshly initialized instance is
    1.55 +     *  always returned.
    1.56 +     */
    1.57 +    T* init() {
    1.58 +        if (this->isValid()) {
    1.59 +            fPtr->~T();
    1.60 +        }
    1.61 +        fPtr = new (SkTCast<T*>(fStorage)) T;
    1.62 +        return fPtr;
    1.63 +    }
    1.64 +
    1.65 +    /**
    1.66 +     *  Copy src into this, and return a pointer to a copy of it. Note this
    1.67 +     *  will always return the same pointer, so if it is called on a lazy that
    1.68 +     *  has already been initialized, then this will copy over the previous
    1.69 +     *  contents.
    1.70 +     */
    1.71 +    T* set(const T& src) {
    1.72 +        if (this->isValid()) {
    1.73 +            *fPtr = src;
    1.74 +        } else {
    1.75 +            fPtr = new (SkTCast<T*>(fStorage)) T(src);
    1.76 +        }
    1.77 +        return fPtr;
    1.78 +    }
    1.79 +
    1.80 +    /**
    1.81 +     * Destroy the lazy object (if it was created via init() or set())
    1.82 +     */
    1.83 +    void reset() {
    1.84 +        if (this->isValid()) {
    1.85 +            fPtr->~T();
    1.86 +            fPtr = NULL;
    1.87 +        }
    1.88 +    }
    1.89 +
    1.90 +    /**
    1.91 +     *  Returns true if a valid object has been initialized in the SkTLazy,
    1.92 +     *  false otherwise.
    1.93 +     */
    1.94 +    bool isValid() const { return NULL != fPtr; }
    1.95 +
    1.96 +    /**
    1.97 +     * Returns the object. This version should only be called when the caller
    1.98 +     * knows that the object has been initialized.
    1.99 +     */
   1.100 +    T* get() const { SkASSERT(this->isValid()); return fPtr; }
   1.101 +
   1.102 +    /**
   1.103 +     * Like above but doesn't assert if object isn't initialized (in which case
   1.104 +     * NULL is returned).
   1.105 +     */
   1.106 +    T* getMaybeNull() const { return fPtr; }
   1.107 +
   1.108 +private:
   1.109 +    friend void* operator new<T>(size_t, SkTLazy* lazy);
   1.110 +
   1.111 +    T*   fPtr; // NULL or fStorage
   1.112 +    char fStorage[sizeof(T)];
   1.113 +};
   1.114 +
   1.115 +// Use the below macro (SkNEW_IN_TLAZY) rather than calling this directly
   1.116 +template <typename T> void* operator new(size_t, SkTLazy<T>* lazy) {
   1.117 +    SkASSERT(!lazy->isValid());
   1.118 +    lazy->fPtr = reinterpret_cast<T*>(lazy->fStorage);
   1.119 +    return lazy->fPtr;
   1.120 +}
   1.121 +
   1.122 +// Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete
   1.123 +// to match the op new silences warnings about missing op delete when a constructor throws an
   1.124 +// exception.
   1.125 +template <typename T> void operator delete(void*, SkTLazy<T>*) { SK_CRASH(); }
   1.126 +
   1.127 +// Use this to construct a T inside an SkTLazy using a non-default constructor.
   1.128 +#define SkNEW_IN_TLAZY(tlazy_ptr, type_name, args) (new (tlazy_ptr) type_name args)
   1.129 +
   1.130 +/**
   1.131 + * A helper built on top of SkTLazy to do copy-on-first-write. The object is initialized
   1.132 + * with a const pointer but provides a non-const pointer accessor. The first time the
   1.133 + * accessor is called (if ever) the object is cloned.
   1.134 + *
   1.135 + * In the following example at most one copy of constThing is made:
   1.136 + *
   1.137 + * SkTCopyOnFirstWrite<Thing> thing(&constThing);
   1.138 + * ...
   1.139 + * function_that_takes_a_const_thing_ptr(thing); // constThing is passed
   1.140 + * ...
   1.141 + * if (need_to_modify_thing()) {
   1.142 + *    thing.writable()->modifyMe(); // makes a copy of constThing
   1.143 + * }
   1.144 + * ...
   1.145 + * x = thing->readSomething();
   1.146 + * ...
   1.147 + * if (need_to_modify_thing_now()) {
   1.148 + *    thing.writable()->changeMe(); // makes a copy of constThing if we didn't call modifyMe()
   1.149 + * }
   1.150 + *
   1.151 + * consume_a_thing(thing); // could be constThing or a modified copy.
   1.152 + */
   1.153 +template <typename T>
   1.154 +class SkTCopyOnFirstWrite {
   1.155 +public:
   1.156 +    SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {}
   1.157 +
   1.158 +    // Constructor for delayed initialization.
   1.159 +    SkTCopyOnFirstWrite() : fObj(NULL) {}
   1.160 +
   1.161 +    // Should only be called once, and only if the default constructor was used.
   1.162 +    void init(const T& initial) {
   1.163 +        SkASSERT(NULL == fObj);
   1.164 +        SkASSERT(!fLazy.isValid());
   1.165 +        fObj = &initial;
   1.166 +    }
   1.167 +
   1.168 +    /**
   1.169 +     * Returns a writable T*. The first time this is called the initial object is cloned.
   1.170 +     */
   1.171 +    T* writable() {
   1.172 +        SkASSERT(NULL != fObj);
   1.173 +        if (!fLazy.isValid()) {
   1.174 +            fLazy.set(*fObj);
   1.175 +            fObj = fLazy.get();
   1.176 +        }
   1.177 +        return const_cast<T*>(fObj);
   1.178 +    }
   1.179 +
   1.180 +    /**
   1.181 +     * Operators for treating this as though it were a const pointer.
   1.182 +     */
   1.183 +
   1.184 +    const T *operator->() const { return fObj; }
   1.185 +
   1.186 +    operator const T*() const { return fObj; }
   1.187 +
   1.188 +    const T& operator *() const { return *fObj; }
   1.189 +
   1.190 +private:
   1.191 +    const T*    fObj;
   1.192 +    SkTLazy<T>  fLazy;
   1.193 +};
   1.194 +
   1.195 +#endif

mercurial