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

Changeset 1713

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

Made Appender a reference type by encoding capacity at the end of the store

Files:

Legend:

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

    r1711 r1713  
    642642int[] a = [ 1, 2 ]; 
    643643auto app2 = appender(&a); 
    644644app2.put(3); 
    645645app2.put([ 4, 5, 6 ]); 
    646646assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); 
    647647---- 
    648648 */ 
    649649 
    650650struct Appender(A : T[], T) 
    651651{ 
    652 private: 
    653     Unqual!(T)[] * pArray; 
    654     size_t _capacity; 
    655  
    656 public: 
    657 /** 
    658 Initialize an $(D Appender) with a pointer to an existing array. The 
    659 $(D Appender) object will append to this array. If $(D null) is passed 
    660 (or the default constructor gets called), the $(D Appender) object 
    661 will allocate and use a new array. 
    662  */ 
     652    private Unqual!(T)[] * pArray; 
     653    private enum size_t extraSize = (size_t.sizeof * 2) - 1; 
     654 
     655    private void allocateCapacity() 
     656    { 
     657        assert(pArray); 
     658        // make room for capacity 
     659        immutable len = pArray.length; 
     660        *pArray = (cast(Unqual!(T)*) GC.realloc(pArray.ptr, 
     661                        len * T.sizeof + extraSize)) 
     662            [0 .. len]; 
     663        capacity() = (GC.sizeOf(pArray.ptr) - extraSize) 
     664            / T.sizeof; 
     665    } 
     666 
     667    /** 
     668       Initialize an $(D Appender) with a pointer to an existing 
     669       array. The $(D Appender) object will append to this array. If 
     670       $(D null) is passed (or the default constructor gets called), 
     671       the $(D Appender) object will allocate and use a new array. 
     672    */ 
    663673    this(T[] * p) 
    664674    { 
    665         pArray = cast(Unqual!(T)[] *) p; 
    666         if (!pArray) pArray = (new typeof(*pArray)[1]).ptr; 
    667         _capacity = GC.sizeOf(pArray.ptr) / T.sizeof; 
     675        pArray = p ? cast(Unqual!(T)[] *) p : (new typeof(*pArray)[1]).ptr; 
     676        // make room for capacity 
     677        allocateCapacity(); 
     678    } 
     679 
     680    /** 
     681       Returns the capacity of the array (the maximum number of 
     682       elements the managed array can accommodate before triggering a 
     683       reallocation). 
     684    */ 
     685    @property ref size_t capacity() 
     686    { 
     687        enforce(pArray); 
     688        auto p = cast(ubyte*) (pArray.ptr + pArray.length); 
     689        while (cast(size_t) p & 3) ++p; 
     690        return *cast(size_t *) p; 
    668691    } 
    669692 
    670693/** 
    671694Returns the managed array. 
    672695 */ 
    673696    T[] data() 
    674697    { 
    675698        return cast(typeof(return)) (pArray ? *pArray : null); 
    676699    } 
    677  
    678 /** 
    679 Returns the capacity of the array (the maximum number of elements the 
    680 managed array can accommodate before triggering a reallocation). 
    681  */ 
    682     size_t capacity() const { return _capacity; } 
    683700 
    684701/** 
    685702Appends one item to the managed array. 
    686703 */ 
    687704    void put(U)(U item) if (isImplicitlyConvertible!(U, T) || 
    688705            isSomeChar!T && isSomeChar!U) 
    689706    { 
    690707        static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof) 
    691708        { 
    692709            // must do some transcoding around here 
    693710            Unqual!T[T.sizeof == 1 ? 4 : 2] encoded; 
    694711            auto len = std.utf.encode(encoded, item); 
    695712            put(encoded[0 .. len]); 
    696713        } 
    697714        else 
    698715        { 
    699             if (!pArray) pArray = (new typeof(*pArray)[1]).ptr; 
     716            if (!pArray) 
     717            { 
     718                pArray = (new typeof(*pArray)[1]).ptr; 
     719                goto APPEND; 
     720            } 
    700721            immutable len = pArray.length; 
    701             if (len < _capacity) 
     722            if (len < capacity) 
    702723            { 
    703                 // Should do in-place construction here 
    704                 pArray.ptr[len] = item
     724                emplace!(Unqual!T) 
     725                    (cast(void[]) pArray.ptr[len .. len + 1], item)
    705726                *pArray = pArray.ptr[0 .. len + 1]; 
    706727            } 
    707728            else 
    708729            { 
     730              APPEND: 
    709731                // Time to reallocate, do it and cache capacity 
    710732                *pArray ~= item; 
    711                 _capacity = GC.sizeOf(pArray.ptr) / T.sizeof
     733                allocateCapacity()
    712734            } 
    713735        } 
    714736    } 
    715737 
    716738/** 
    717739Appends an entire range to the managed array. 
    718740 */ 
    719741    void put(Range)(Range items) if (isForwardRange!Range 
    720742            && is(typeof(Appender.init.put(items.front)))) 
    721743    { 
    722744        static if (is(typeof(*pArray ~= items))) 
    723745        { 
    724746            if (!pArray) pArray = (new typeof(*pArray)[1]).ptr; 
    725747            *pArray ~= items; 
     748            allocateCapacity(); 
    726749        } 
    727750        else 
    728751        { 
    729752            //pragma(msg, Range.stringof); 
    730753            // Generic input range 
    731754            for (; !items.empty; items.popFront) 
    732755            { 
    733756                put(items.front()); 
    734757            } 
    735758        } 
    736759    } 
    737760 
    738761/** 
    739762Clears the managed array. 
    740763*/ 
    741764    void clear() 
    742765    { 
    743766        if (!pArray) return; 
    744767        pArray.length = 0; 
    745         //_capacity = .capacity(pArray.ptr) / T.sizeof; 
    746         _capacity = GC.sizeOf(pArray.ptr) / T.sizeof; 
     768        allocateCapacity(); 
    747769    } 
    748770} 
    749771 
    750772/** 
    751773Convenience function that returns an $(D Appender!(T)) object 
    752774initialized with $(D t). 
    753775 */ 
    754776Appender!(E[]) appender(A : E[], E)(A * array = null) 
    755777{ 
    756     return Appender!(E[])(array); 
     778    return Appender!(E[])(array ? array : (new A[1]).ptr); 
    757779} 
    758780 
    759781unittest 
    760782{ 
    761783    auto arr = new char[0]; 
    762784    auto app = appender(&arr); 
    763785    string b = "abcdefg"; 
    764786    foreach (char c; b) app.put(c); 
    765787    assert(app.data == "abcdefg"); 
    766788 
    767789    int[] a = [ 1, 2 ]; 
    768790    auto app2 = appender(&a); 
     791    assert(app2.data == [ 1, 2 ]); 
    769792    app2.put(3); 
    770793    app2.put([ 4, 5, 6 ][]); 
    771794    assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); 
    772795} 
    773796 
    774797/* 
    775798A simple slice type only holding pointers to the beginning and the end 
    776799of an array. Experimental duplication of the built-in slice - do not 
    777800use yet. 
    778801 */