@@ -99,6 +99,21 @@ impl<T> RingBuf<T> {
99
99
/// Returns the index in the underlying buffer for a given logical element index.
100
100
#[ inline]
101
101
fn wrap_index ( & self , idx : uint ) -> uint { wrap_index ( idx, self . cap ) }
102
+
103
+ /// Copies a contiguous block of memory len long from src to dst
104
+ #[ inline]
105
+ fn copy ( & self , dst : uint , src : uint , len : uint ) {
106
+ unsafe {
107
+ debug_assert ! ( dst + len <= self . cap, "dst={} src={} len={} cap={}" , dst, src, len,
108
+ self . cap) ;
109
+ debug_assert ! ( src + len <= self . cap, "dst={} src={} len={} cap={}" , dst, src, len,
110
+ self . cap) ;
111
+ ptr:: copy_memory (
112
+ self . ptr . offset ( dst as int ) ,
113
+ self . ptr . offset ( src as int ) as * const T ,
114
+ len) ;
115
+ }
116
+ }
102
117
}
103
118
104
119
impl < T > RingBuf < T > {
@@ -648,6 +663,213 @@ impl<T> RingBuf<T> {
648
663
unsafe { Some ( self . buffer_read ( head) ) }
649
664
}
650
665
}
666
+
667
+ /// Inserts an element at position `i` within the ringbuf. Whichever
668
+ /// end is closer to the insertion point will be moved to make room,
669
+ /// and all the affected elements will be moved to new positions.
670
+ ///
671
+ /// # Panics
672
+ ///
673
+ /// Panics if `i` is greater than ringbuf's length
674
+ ///
675
+ /// # Example
676
+ /// ```rust
677
+ /// use std::collections::RingBuf;
678
+ ///
679
+ /// let mut buf = RingBuf::new();
680
+ /// buf.push_back(10i);
681
+ /// buf.push_back(12);
682
+ /// buf.insert(1,11);
683
+ /// assert_eq!(Some(&11), buf.get(1));
684
+ /// ```
685
+ pub fn insert ( & mut self , i : uint , t : T ) {
686
+ assert ! ( i <= self . len( ) , "index out of bounds" ) ;
687
+ if self . is_full ( ) {
688
+ self . reserve ( 1 ) ;
689
+ debug_assert ! ( !self . is_full( ) ) ;
690
+ }
691
+
692
+ // Move the least number of elements in the ring buffer and insert
693
+ // the given object
694
+ //
695
+ // At most len/2 - 1 elements will be moved. O(min(n, n-i))
696
+ //
697
+ // There are three main cases:
698
+ // Elements are contiguous
699
+ // - special case when tail is 0
700
+ // Elements are discontiguous and the insert is in the tail section
701
+ // Elements are discontiguous and the insert is in the head section
702
+ //
703
+ // For each of those there are two more cases:
704
+ // Insert is closer to tail
705
+ // Insert is closer to head
706
+ //
707
+ // Key: H - self.head
708
+ // T - self.tail
709
+ // o - Valid element
710
+ // I - Insertion element
711
+ // A - The element that should be after the insertion point
712
+ // M - Indicates element was moved
713
+
714
+ let idx = self . wrap_index ( self . tail + i) ;
715
+
716
+ let distance_to_tail = i;
717
+ let distance_to_head = self . len ( ) - i;
718
+
719
+ let contiguous = self . tail <= self . head ;
720
+
721
+ match ( contiguous, distance_to_tail <= distance_to_head, idx >= self . tail ) {
722
+ ( true , true , _) if i == 0 => {
723
+ // push_front
724
+ //
725
+ // T
726
+ // I H
727
+ // [A o o o o o o . . . . . . . . .]
728
+ //
729
+ // H T
730
+ // [A o o o o o o o . . . . . I]
731
+ //
732
+
733
+ self . tail = self . wrap_index ( self . tail - 1 ) ;
734
+ } ,
735
+ ( true , true , _) => {
736
+ // contiguous, insert closer to tail:
737
+ //
738
+ // T I H
739
+ // [. . . o o A o o o o . . . . . .]
740
+ //
741
+ // T H
742
+ // [. . o o I A o o o o . . . . . .]
743
+ // M M
744
+ //
745
+ // contiguous, insert closer to tail and tail is 0:
746
+ //
747
+ //
748
+ // T I H
749
+ // [o o A o o o o . . . . . . . . .]
750
+ //
751
+ // H T
752
+ // [o I A o o o o o . . . . . . . o]
753
+ // M M
754
+
755
+ let old_tail = self . tail ;
756
+ self . tail = self . wrap_index ( self . tail - 1 ) ;
757
+
758
+ self . copy ( self . tail , old_tail, 1 ) ;
759
+ self . copy ( old_tail, old_tail + 1 , i) ;
760
+ } ,
761
+ ( true , false , _) => {
762
+ // contiguous, insert closer to head:
763
+ //
764
+ // T I H
765
+ // [. . . o o o o A o o . . . . . .]
766
+ //
767
+ // T H
768
+ // [. . . o o o o I A o o . . . . .]
769
+ // M M M
770
+
771
+ let old_head = self . head ;
772
+ self . head = self . wrap_index ( self . head + 1 ) ;
773
+ self . copy ( idx + 1 , idx, old_head - idx) ;
774
+ } ,
775
+ ( false , true , true ) => {
776
+ // discontiguous, tail section, insert closer to tail:
777
+ //
778
+ // H T I
779
+ // [o o o o o o . . . . . o o A o o]
780
+ //
781
+ // H T
782
+ // [o o o o o o . . . . o o I A o o]
783
+ // M M
784
+
785
+ let old_tail = self . tail ;
786
+ self . tail = self . tail - 1 ;
787
+ self . copy ( self . tail , old_tail, i) ;
788
+ } ,
789
+ ( false , false , true ) => {
790
+ // discontiguous, tail section, insert closer to head:
791
+ //
792
+ // H T I
793
+ // [o o . . . . . . . o o o o o A o]
794
+ //
795
+ // H T
796
+ // [o o o . . . . . . o o o o o I A]
797
+ // M M M M
798
+
799
+ let old_head = self . head ;
800
+ self . head = self . head + 1 ;
801
+
802
+ // copy elements up to new head
803
+ self . copy ( 1 , 0 , old_head) ;
804
+
805
+ // copy last element into empty spot at bottom of buffer
806
+ self . copy ( 0 , self . cap - 1 , 1 ) ;
807
+
808
+ // move elements from idx to end forward not including ^ element
809
+ self . copy ( idx + 1 , idx, self . cap - 1 - idx) ;
810
+ } ,
811
+ ( false , true , false ) if idx == 0 => {
812
+ // discontiguous, head section, insert is closer to tail,
813
+ // and is at index zero in the internal buffer:
814
+ //
815
+ // I H T
816
+ // [A o o o o o o o o o . . . o o o]
817
+ //
818
+ // H T
819
+ // [A o o o o o o o o o . . o o o I]
820
+ // M M M
821
+
822
+ let old_tail = self . tail ;
823
+ self . tail = self . tail - 1 ;
824
+ // copy elements up to new tail
825
+ self . copy ( old_tail - 1 , old_tail, i) ;
826
+
827
+ // copy last element into empty spot at bottom of buffer
828
+ self . copy ( self . cap - 1 , 0 , 1 ) ;
829
+ } ,
830
+ ( false , true , false ) => {
831
+ // discontiguous, head section, insert closer to tail:
832
+ //
833
+ // I H T
834
+ // [o o o A o o o o o o . . . o o o]
835
+ //
836
+ // H T
837
+ // [o o I A o o o o o o . . o o o o]
838
+ // M M M M M M
839
+
840
+ let old_tail = self . tail ;
841
+ self . tail = self . tail - 1 ;
842
+ // copy elements up to new tail
843
+ self . copy ( old_tail - 1 , old_tail, i) ;
844
+
845
+ // copy last element into empty spot at bottom of buffer
846
+ self . copy ( self . cap - 1 , 0 , 1 ) ;
847
+
848
+ // move elements from idx-1 to end forward not including ^ element
849
+ self . copy ( 0 , 1 , idx - 1 ) ;
850
+ }
851
+ ( false , false , false ) => {
852
+ // discontiguous, head section, insert closer to head:
853
+ //
854
+ // I H T
855
+ // [o o o o A o o . . . . . . o o o]
856
+ //
857
+ // H T
858
+ // [o o o o I A o o . . . . . o o o]
859
+ // M M M
860
+
861
+ let old_head = self . head ;
862
+ self . head = self . head + 1 ;
863
+ self . copy ( idx + 1 , idx, old_head - idx) ;
864
+ }
865
+ }
866
+
867
+ // tail might've been changed so we need to recalculate
868
+ let new_idx = self . wrap_index ( self . tail + i) ;
869
+ unsafe {
870
+ self . buffer_write ( new_idx, t) ;
871
+ }
872
+ }
651
873
}
652
874
653
875
/// Returns the index in the underlying buffer for a given logical element index.
@@ -878,6 +1100,7 @@ impl<T: fmt::Show> fmt::Show for RingBuf<T> {
878
1100
879
1101
#[ cfg( test) ]
880
1102
mod tests {
1103
+ use core:: iter;
881
1104
use self :: Taggy :: * ;
882
1105
use self :: Taggypar :: * ;
883
1106
use std:: fmt:: Show ;
@@ -1102,7 +1325,6 @@ mod tests {
1102
1325
} )
1103
1326
}
1104
1327
1105
-
1106
1328
#[ deriving( Clone , PartialEq , Show ) ]
1107
1329
enum Taggy {
1108
1330
One ( int ) ,
@@ -1666,4 +1888,48 @@ mod tests {
1666
1888
assert_eq ! ( ring. get_mut( 1 ) , Some ( & mut 2 ) ) ;
1667
1889
assert_eq ! ( ring. get_mut( 2 ) , None ) ;
1668
1890
}
1891
+
1892
+ #[ test]
1893
+ fn test_insert ( ) {
1894
+ // This test checks that every single combination of tail position, length, and
1895
+ // insertion position is tested. Capacity 7 should be large enough to cover every case.
1896
+
1897
+ let mut tester = RingBuf :: with_capacity ( 7 ) ;
1898
+ // can't guarantee we got 7, so have to get what we got.
1899
+ // 7 would be great, but we will definitely get 2^k - 1, for k >= 3, or else
1900
+ // this test isn't covering what it wants to
1901
+ let cap = tester. capacity ( ) ;
1902
+
1903
+
1904
+ // len is the length *after* insertion
1905
+ for len in range ( 1 , cap) {
1906
+ // 0, 1, 2, .., len - 1
1907
+ let expected = iter:: count ( 0 , 1 ) . take ( len) . collect ( ) ;
1908
+ for tail_pos in range ( 0 , cap) {
1909
+ for to_insert in range ( 0 , len) {
1910
+ tester. tail = tail_pos;
1911
+ tester. head = tail_pos;
1912
+ for i in range ( 0 , len) {
1913
+ if i != to_insert {
1914
+ tester. push_back ( i) ;
1915
+ }
1916
+ }
1917
+ tester. insert ( to_insert, to_insert) ;
1918
+ assert_eq ! ( tester, expected) ;
1919
+ }
1920
+ }
1921
+ }
1922
+ }
1923
+
1924
+ #[ test]
1925
+ fn test_front ( ) {
1926
+ let mut ring = RingBuf :: new ( ) ;
1927
+ ring. push_back ( 10 i) ;
1928
+ ring. push_back ( 20 i) ;
1929
+ assert_eq ! ( ring. front( ) , Some ( & 10 ) ) ;
1930
+ ring. pop_front ( ) ;
1931
+ assert_eq ! ( ring. front( ) , Some ( & 20 ) ) ;
1932
+ ring. pop_front ( ) ;
1933
+ assert_eq ! ( ring. front( ) , None ) ;
1934
+ }
1669
1935
}
0 commit comments