Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changeset 1743

Show
Ignore:
Timestamp:
07/09/10 04:21:10 (14 years ago)
Author:
andrei
Message:

Improvements to RefCounted?. Better names (no clashes) and also defined a debug mode. Compiling with debug=RefCounted? gives access to a bool property debugging that allows tracking the lifetime of the refcounted object.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/phobos/std/typecons.d

    r1725 r1743  
    20292029// Reference semantics 
    20302030rc2 = 42; 
    20312031assert(rc1 == 42); 
    20322032// the pair will be freed when rc1 and rc2 go out of scope 
    20332033---- 
    20342034 */ 
    20352035struct RefCounted(T, RefCountedAutoInitialize autoInit = 
    20362036        RefCountedAutoInitialize.yes) 
    20372037if (!is(T == class)) 
    20382038{ 
    2039     private Tuple!(T, "_payload", size_t, "_count") * _refCountedStore; 
    2040  
    2041     private void refCountedInitialize(A...)(A args) 
    2042     { 
    2043         const sz = (*_refCountedStore).sizeof; 
    2044         auto p = malloc(sz)[0 .. sz]; 
    2045         if (sz >= size_t.sizeof && p.ptr) 
    2046             GC.addRange(p.ptr, sz); 
    2047         emplace!T(p[0 .. T.sizeof], args); 
    2048         _refCountedStore = cast(typeof(_refCountedStore)) p; 
    2049         _refCountedStore._count = 1; 
    2050     } 
    2051  
    2052 /** 
    2053 Returns $(D true) if and only if the underlying store has been 
    2054 allocated and initialized. 
    2055  */ 
    2056     @property bool refCountedIsInitialized() const 
    2057     { 
    2058         return _refCountedStore !is null; 
    2059     } 
    2060  
    2061 /** 
    2062 Makes sure the payload was properly initialized. Such a call is 
    2063 typically inserted before using the payload. 
    2064  */ 
    2065     void refCountedEnsureInitialized() 
    2066     { 
    2067         if (refCountedIsInitialized) return; 
    2068         refCountedInitialize(); 
    2069     } 
     2039    struct _RefCounted 
     2040    { 
     2041        private Tuple!(T, "_payload", size_t, "_count") * _store; 
     2042        debug(RefCounted) 
     2043        { 
     2044            private bool _debugging = false; 
     2045            @property bool debugging() const 
     2046            { 
     2047                return _debugging; 
     2048            } 
     2049            @property void debugging(bool d) 
     2050            { 
     2051                if (d != _debugging) 
     2052                { 
     2053                    writeln(typeof(this).stringof, "@", 
     2054                            cast(void*) _store, 
     2055                            d ? ": starting debug" : ": ending debug"); 
     2056                } 
     2057                _debugging = d; 
     2058            } 
     2059        } 
     2060 
     2061        private void initialize(A...)(A args) 
     2062        { 
     2063            const sz = (*_store).sizeof; 
     2064            auto p = malloc(sz)[0 .. sz]; 
     2065            if (sz >= size_t.sizeof && p.ptr) 
     2066            { 
     2067                GC.addRange(p.ptr, sz); 
     2068            } 
     2069            emplace!T(p[0 .. T.sizeof], args); 
     2070            _store = cast(typeof(_store)) p.ptr; 
     2071            _store._count = 1; 
     2072            debug(RefCounted) if (debugging) writeln(typeof(this).stringof, 
     2073                "@", cast(void*) _store, ": initialized with ", 
     2074                    A.stringof); 
     2075        } 
     2076 
     2077        /** 
     2078           Returns $(D true) if and only if the underlying store has been 
     2079           allocated and initialized. 
     2080        */ 
     2081        @property bool isInitialized() const 
     2082        { 
     2083            return _store !is null; 
     2084        } 
     2085 
     2086        /** 
     2087           Makes sure the payload was properly initialized. Such a 
     2088           call is typically inserted before using the payload. 
     2089        */ 
     2090        void ensureInitialized() 
     2091        { 
     2092            if (!isInitialized) initialize(); 
     2093        } 
     2094 
     2095    } 
     2096    _RefCounted RefCounted; 
    20702097 
    20712098/** 
    20722099Constructor that initializes the payload. 
    20732100 
    20742101Postcondition: $(D refCountedIsInitialized) 
    20752102 */ 
    20762103    this(A...)(A args) if (A.length > 0) 
    20772104    { 
    2078         refCountedInitialize(args); 
     2105        RefCounted.initialize(args); 
    20792106    } 
    20802107 
    20812108/** 
    20822109Constructor that tracks the reference count appropriately. If $(D 
    20832110!refCountedIsInitialized), does nothing. 
    20842111 */ 
    20852112    this(this) 
    20862113    { 
    2087         if (!refCountedIsInitialized) return; 
    2088         ++_refCountedStore._count; 
     2114        if (!RefCounted.isInitialized) return; 
     2115        ++RefCounted._store._count; 
     2116        debug(RefCounted) if (RefCounted.debugging) 
     2117                 writeln(typeof(this).stringof, 
     2118                "@", cast(void*) RefCounted._store, ": bumped refcount to ", 
     2119                RefCounted._store._count); 
    20892120    } 
    20902121 
    20912122/** 
    20922123Destructor that tracks the reference count appropriately. If $(D 
    20932124!refCountedIsInitialized), does nothing. When the reference count goes 
    20942125down to zero, calls $(D clear) agaist the payload and calls $(D free) 
    20952126to deallocate the corresponding resource. 
    20962127 */ 
    20972128    ~this() 
    20982129    { 
    2099         if (!_refCountedStore || --_refCountedStore._count) return; 
     2130        if (!RefCounted._store) return; 
     2131        assert(RefCounted._store._count > 0); 
     2132        if (--RefCounted._store._count) 
     2133        { 
     2134            debug(RefCounted) if (RefCounted.debugging) 
     2135                     writeln(typeof(this).stringof, 
     2136                    "@", cast(void*)RefCounted._store, 
     2137                    ": decrement refcount to ", RefCounted._store._count); 
     2138            return; 
     2139        } 
     2140        debug(RefCounted) if (RefCounted.debugging) 
     2141        { 
     2142            write(typeof(this).stringof, 
     2143                    "@", cast(void*)RefCounted._store, ": freeing... "); 
     2144            stdout.flush(); 
     2145        } 
    21002146        // Done, deallocate 
    2101         clear(*_refCountedStore); 
    2102         if (hasIndirections!T && _refCountedStore) 
    2103             GC.removeRange(_refCountedStore); 
    2104         free(_refCountedStore); 
    2105         _refCountedStore = null; 
     2147        assert(RefCounted._store); 
     2148        clear(RefCounted._store._payload); 
     2149        if (hasIndirections!T && RefCounted._store) 
     2150            GC.removeRange(RefCounted._store); 
     2151        free(RefCounted._store); 
     2152        RefCounted._store = null; 
     2153        debug(RefCounted) if (RefCounted.debugging) writeln("done!"); 
    21062154    } 
    21072155 
    21082156/** 
    21092157Assignment operators 
    21102158 */ 
    2111     void opAssign(RefCounted rhs) 
    2112     { 
    2113         swap(_refCountedStore, rhs._refCountedStore); 
     2159    void opAssign(typeof(this) rhs) 
     2160    { 
     2161        swap(RefCounted._store, rhs.RefCounted._store); 
    21142162    } 
    21152163 
    21162164/// Ditto 
    21172165    void opAssign(T rhs) 
    21182166    { 
    2119         refCountedPayload() = move(rhs); 
     2167        RefCounted._store._payload = move(rhs); 
    21202168    } 
    21212169 
    21222170/** 
    21232171Returns a reference to the payload. If (autoInit == 
    21242172RefCountedAutoInitialize.yes), calls $(D 
    21252173refCountedEnsureInitialized). Otherwise, just issues $(D 
    21262174assert(refCountedIsInitialized)). 
    21272175 */ 
    21282176    alias refCountedPayload this; 
    21292177 
    21302178/** 
    21312179Returns a reference to the payload. If (autoInit == 
    21322180RefCountedAutoInitialize.yes), calls $(D 
    21332181refCountedEnsureInitialized). Otherwise, just issues $(D 
    21342182assert(refCountedIsInitialized)). Used with $(D alias 
    21352183refCountedPayload this;), so callers can just use the $(D RefCounted) 
    21362184object as a $(D T). 
    21372185 */ 
    2138     @property ref T refCountedPayload() { 
     2186    @property ref T refCountedPayload() 
     2187    { 
    21392188        static if (autoInit == RefCountedAutoInitialize.yes) 
    21402189        { 
    2141             refCountedEnsureInitialized(); 
     2190            RefCounted.ensureInitialized(); 
    21422191        } 
    21432192        else 
    21442193        { 
    2145             assert(refCountedIsInitialized); 
    2146         } 
    2147         return _refCountedStore._payload; 
     2194            assert(RefCounted.isInitialized); 
     2195        } 
     2196        return RefCounted._store._payload; 
    21482197    } 
    21492198 
    21502199// 
    2151     @property ref const(T) refCountedPayload() const { 
     2200    @property ref const(T) refCountedPayload() const 
     2201    { 
    21522202        static if (autoInit == RefCountedAutoInitialize.yes) 
    21532203        { 
    21542204            // @@@ 
    21552205            //refCountedEnsureInitialized(); 
    2156             assert(refCountedIsInitialized); 
     2206            assert(RefCounted.isInitialized); 
    21572207        } 
    21582208        else 
    21592209        { 
    2160             assert(refCountedIsInitialized); 
    2161         } 
    2162         return _refCountedStore._payload; 
     2210            assert(RefCounted.isInitialized); 
     2211        } 
     2212        return RefCounted._store._payload; 
    21632213    } 
    21642214} 
    21652215 
    21662216unittest 
    21672217{ 
    21682218    RefCounted!int* p; 
    21692219    { 
    21702220        auto rc1 = RefCounted!int(5); 
    21712221        p = &rc1; 
    21722222        assert(rc1 == 5); 
    2173         assert(rc1._refCountedStore._count == 1); 
     2223        assert(rc1.RefCounted._store._count == 1); 
    21742224        auto rc2 = rc1; 
    2175         assert(rc1._refCountedStore._count == 2); 
     2225        assert(rc1.RefCounted._store._count == 2); 
    21762226        // Reference semantics 
    21772227        rc2 = 42; 
    21782228        assert(rc1 == 42); 
    21792229        rc2 = rc2; 
    2180         assert(rc2._refCountedStore._count == 2); 
     2230        assert(rc2.RefCounted._store._count == 2); 
    21812231        rc1 = rc2; 
    2182         assert(rc1._refCountedStore._count == 2); 
    2183     } 
    2184     assert(p._refCountedStore == null); 
     2232        assert(rc1.RefCounted._store._count == 2); 
     2233    } 
     2234    assert(p.RefCounted._store == null); 
    21852235 
    21862236    // RefCounted as a member 
    21872237    struct A 
    21882238    { 
    21892239        RefCounted!int x; 
    21902240        this(int y) 
    21912241        { 
    2192             x.refCountedInitialize(y); 
     2242            x.RefCounted.initialize(y); 
    21932243        } 
    21942244        A copy() 
    21952245        { 
    21962246            auto another = this; 
    21972247            return another; 
    21982248        } 
    21992249    } 
    22002250    auto a = A(4); 
    22012251    auto b = a.copy(); 
    2202     if (a.x._refCountedStore._count != 2) { 
     2252    if (a.x.RefCounted._store._count != 2) { 
    22032253        stderr.writeln("*** BUG 4356 still unfixed"); 
    22042254    } 
    22052255} 
    22062256