Changeset 1713
- Timestamp:
- 07/04/10 19:57:04 (14 years ago)
- Files:
-
- trunk/phobos/std/array.d (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/phobos/std/array.d
r1711 r1713 642 642 int[] a = [ 1, 2 ]; 643 643 auto app2 = appender(&a); 644 644 app2.put(3); 645 645 app2.put([ 4, 5, 6 ]); 646 646 assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); 647 647 ---- 648 648 */ 649 649 650 650 struct Appender(A : T[], T) 651 651 { 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 */ 663 673 this(T[] * p) 664 674 { 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; 668 691 } 669 692 670 693 /** 671 694 Returns the managed array. 672 695 */ 673 696 T[] data() 674 697 { 675 698 return cast(typeof(return)) (pArray ? *pArray : null); 676 699 } 677 678 /**679 Returns the capacity of the array (the maximum number of elements the680 managed array can accommodate before triggering a reallocation).681 */682 size_t capacity() const { return _capacity; }683 700 684 701 /** 685 702 Appends one item to the managed array. 686 703 */ 687 704 void put(U)(U item) if (isImplicitlyConvertible!(U, T) || 688 705 isSomeChar!T && isSomeChar!U) 689 706 { 690 707 static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof) 691 708 { 692 709 // must do some transcoding around here 693 710 Unqual!T[T.sizeof == 1 ? 4 : 2] encoded; 694 711 auto len = std.utf.encode(encoded, item); 695 712 put(encoded[0 .. len]); 696 713 } 697 714 else 698 715 { 699 if (!pArray) pArray = (new typeof(*pArray)[1]).ptr; 716 if (!pArray) 717 { 718 pArray = (new typeof(*pArray)[1]).ptr; 719 goto APPEND; 720 } 700 721 immutable len = pArray.length; 701 if (len < _capacity)722 if (len < capacity) 702 723 { 703 // Should do in-place construction here704 pArray.ptr[len] = item;724 emplace!(Unqual!T) 725 (cast(void[]) pArray.ptr[len .. len + 1], item); 705 726 *pArray = pArray.ptr[0 .. len + 1]; 706 727 } 707 728 else 708 729 { 730 APPEND: 709 731 // Time to reallocate, do it and cache capacity 710 732 *pArray ~= item; 711 _capacity = GC.sizeOf(pArray.ptr) / T.sizeof;733 allocateCapacity(); 712 734 } 713 735 } 714 736 } 715 737 716 738 /** 717 739 Appends an entire range to the managed array. 718 740 */ 719 741 void put(Range)(Range items) if (isForwardRange!Range 720 742 && is(typeof(Appender.init.put(items.front)))) 721 743 { 722 744 static if (is(typeof(*pArray ~= items))) 723 745 { 724 746 if (!pArray) pArray = (new typeof(*pArray)[1]).ptr; 725 747 *pArray ~= items; 748 allocateCapacity(); 726 749 } 727 750 else 728 751 { 729 752 //pragma(msg, Range.stringof); 730 753 // Generic input range 731 754 for (; !items.empty; items.popFront) 732 755 { 733 756 put(items.front()); 734 757 } 735 758 } 736 759 } 737 760 738 761 /** 739 762 Clears the managed array. 740 763 */ 741 764 void clear() 742 765 { 743 766 if (!pArray) return; 744 767 pArray.length = 0; 745 //_capacity = .capacity(pArray.ptr) / T.sizeof; 746 _capacity = GC.sizeOf(pArray.ptr) / T.sizeof; 768 allocateCapacity(); 747 769 } 748 770 } 749 771 750 772 /** 751 773 Convenience function that returns an $(D Appender!(T)) object 752 774 initialized with $(D t). 753 775 */ 754 776 Appender!(E[]) appender(A : E[], E)(A * array = null) 755 777 { 756 return Appender!(E[])(array );778 return Appender!(E[])(array ? array : (new A[1]).ptr); 757 779 } 758 780 759 781 unittest 760 782 { 761 783 auto arr = new char[0]; 762 784 auto app = appender(&arr); 763 785 string b = "abcdefg"; 764 786 foreach (char c; b) app.put(c); 765 787 assert(app.data == "abcdefg"); 766 788 767 789 int[] a = [ 1, 2 ]; 768 790 auto app2 = appender(&a); 791 assert(app2.data == [ 1, 2 ]); 769 792 app2.put(3); 770 793 app2.put([ 4, 5, 6 ][]); 771 794 assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); 772 795 } 773 796 774 797 /* 775 798 A simple slice type only holding pointers to the beginning and the end 776 799 of an array. Experimental duplication of the built-in slice - do not 777 800 use yet. 778 801 */
