11package org .reactfx .inhibeans .collection ;
22
3- import java .util .ArrayList ;
4- import java .util .Arrays ;
53import java .util .Collection ;
64import java .util .Iterator ;
75import java .util .List ;
1210import javafx .collections .ListChangeListener .Change ;
1311
1412import org .reactfx .Guard ;
13+ import org .reactfx .util .ListChangeAccumulator ;
1514import org .reactfx .util .ListHelper ;
15+ import org .reactfx .util .TransientListChange ;
1616
1717class ObservableListWrapper <E > implements ObservableList <E > {
1818 private final javafx .collections .ObservableList <E > delegate ;
@@ -21,7 +21,7 @@ class ObservableListWrapper<E> implements ObservableList<E> {
2121 private ListHelper <ListChangeListener <? super E >> listListeners = null ;
2222
2323 private boolean blocked ;
24- private final List < SingleListChange < E >> pendingChanges = new ArrayList <>();
24+ private final ListChangeAccumulator < E > pendingChanges = new ListChangeAccumulator <>();
2525
2626 ObservableListWrapper (javafx .collections .ObservableList <E > delegate ) {
2727 this .delegate = delegate ;
@@ -47,17 +47,16 @@ public Guard block() {
4747 private void release () {
4848 blocked = false ;
4949 if (!pendingChanges .isEmpty ()) {
50- Change <E > change = squash (pendingChanges );
51- pendingChanges .clear ();
50+ Change <E > change = squash (pendingChanges .fetch ());
5251 notifyListeners (change );
5352 }
5453 }
5554
56- private Change <E > squash (List <SingleListChange < E >> changeList ) {
55+ private Change <E > squash (List <TransientListChange <? extends E >> changeList ) {
5756 return new Change <E >(this ) {
5857 @ SuppressWarnings ("unchecked" )
59- private final SingleListChange < E >[] changes =
60- (SingleListChange < E >[]) changeList .toArray (new SingleListChange <?>[changeList .size ()]);
58+ private final TransientListChange <? extends E >[] changes =
59+ (TransientListChange <? extends E >[]) changeList .toArray (new TransientListChange <?>[changeList .size ()]);
6160
6261 private int current = -1 ;
6362
@@ -68,22 +67,14 @@ public int getFrom() {
6867
6968 @ Override
7069 protected int [] getPermutation () {
71- throw new AssertionError ("Unreachable code" );
72- }
73-
74- @ Override
75- public boolean wasPermutated () {
76- return changes [current ].isPermutation ();
77- }
78-
79- @ Override
80- public int getPermutation (int i ) {
81- return changes [current ].getPermutation (i );
70+ return new int [0 ]; // not a permutation
8271 }
8372
8473 @ Override
74+ @ SuppressWarnings ("unchecked" )
8575 public List <E > getRemoved () {
86- return changes [current ].getRemoved ();
76+ // cast is safe, because the list is unmodifiable
77+ return (List <E >) changes [current ].getRemoved ();
8778 }
8879
8980 @ Override
@@ -110,127 +101,8 @@ public void reset() {
110101
111102 private void incorporateChange (Change <? extends E > change ) {
112103 while (change .next ()) {
113- int from = change .getFrom ();
114- if (change .wasPermutated ()) {
115- int len = change .getTo () - from ;
116- int [] permutation = new int [len ];
117- List <E > replaced = new ArrayList <>(len );
118- for (int i = 0 ; i < len ; ++i ) {
119- int pi = change .getPermutation (from + i );
120- permutation [i ] = pi - from ;
121- replaced .add (delegate .get (pi ));
122- }
123- incorporateChange (new Permutation <>(from , permutation , replaced ));
124- } else {
125- @ SuppressWarnings ("unchecked" ) // cast is safe because the list is unmodifiable
126- List <E > removed = (List <E >) change .getRemoved ();
127- incorporateChange (new Replacement <>(from , removed , change .getAddedSize ()));
128- }
129- }
130- }
131-
132- private void incorporateChange (SingleListChange <E > change ) {
133- if (pendingChanges .isEmpty ()) {
134- pendingChanges .add (change );
135- } else {
136- // find first and last overlapping change
137- int from = change .getFrom ();
138- int to = from + change .getOldLength ();
139- int firstOverlapping = 0 ;
140- for (; firstOverlapping < pendingChanges .size (); ++firstOverlapping ) {
141- if (pendingChanges .get (firstOverlapping ).getTo () >= from ) {
142- break ;
143- }
144- }
145- int lastOverlapping = pendingChanges .size () - 1 ;
146- for (; lastOverlapping >= 0 ; --lastOverlapping ) {
147- if (pendingChanges .get (lastOverlapping ).getFrom () <= to ) {
148- break ;
149- }
150- }
151-
152- // offset changes farther in the list
153- int diff = change .getTo () - change .getFrom () - change .getOldLength ();
154- offsetPendingChanges (lastOverlapping + 1 , diff );
155-
156- // combine overlapping changes into one
157- if (lastOverlapping < firstOverlapping ) { // no overlap
158- pendingChanges .add (firstOverlapping , change );
159- } else { // overlaps one or more former changes
160- List <SingleListChange <E >> overlapping = pendingChanges .subList (firstOverlapping , lastOverlapping + 1 );
161- SingleListChange <E > joined = join (overlapping , change .getReplaced (), change .getFrom ());
162- SingleListChange <E > newChange = combine (joined , change );
163- overlapping .clear ();
164- pendingChanges .add (firstOverlapping , newChange );
165- }
166- }
167- }
168-
169- private void offsetPendingChanges (int from , int offset ) {
170- pendingChanges .subList (from , pendingChanges .size ())
171- .replaceAll (change -> change .offset (offset ));
172- }
173-
174- private SingleListChange <E > join (List <SingleListChange <E >> changes , List <E > gone , int goneOffset ) {
175- if (changes .size () == 1 ) {
176- return changes .get (0 );
177- }
178-
179- List <E > removed = new ArrayList <>();
180- SingleListChange <E > prev = changes .get (0 );
181- int from = prev .getFrom ();
182- removed .addAll (prev .getReplaced ());
183- for (int i = 1 ; i < changes .size (); ++i ) {
184- SingleListChange <E > ch = changes .get (i );
185- removed .addAll (gone .subList (prev .getTo () - goneOffset , ch .getFrom () - goneOffset ));
186- removed .addAll (ch .getReplaced ());
187- prev = ch ;
188- }
189- return new Replacement <>(from , removed , prev .getTo () - from );
190- }
191-
192- private SingleListChange <E > combine (
193- SingleListChange <E > former ,
194- SingleListChange <E > latter ) {
195-
196- if (latter .getFrom () >= former .getFrom () && latter .getFrom () + latter .getOldLength () <= former .getTo ()) {
197- // latter is within former
198- List <E > removed = former .getReplaced ();
199- int addedSize = former .getNewLength () - latter .getOldLength () + latter .getNewLength ();
200- return new Replacement <>(former .getFrom (), removed , addedSize );
201- } else if (latter .getFrom () <= former .getFrom () && latter .getFrom () + latter .getOldLength () >= former .getTo ()) {
202- // former is within latter
203- List <E > removed = concat (
204- latter .getReplaced ().subList (0 , former .getFrom () - latter .getFrom ()),
205- former .getReplaced (),
206- latter .getReplaced ().subList (former .getTo () - latter .getFrom (), latter .getOldLength ()));
207- int addedSize = latter .getNewLength ();
208- return new Replacement <>(latter .getFrom (), removed , addedSize );
209- } else if (latter .getFrom () >= former .getFrom ()) {
210- // latter overlaps to the right
211- List <E > removed = concat (
212- former .getReplaced (),
213- latter .getReplaced ().subList (former .getTo () - latter .getFrom (), latter .getOldLength ()));
214- int addedSize = latter .getFrom () - former .getFrom () + latter .getNewLength ();
215- return new Replacement <>(former .getFrom (), removed , addedSize );
216- } else {
217- // latter overlaps to the left
218- List <E > removed = concat (
219- latter .getReplaced ().subList (0 , former .getFrom () - latter .getFrom ()),
220- former .getReplaced ());
221- int addedSize = former .getTo () - (latter .getFrom () + latter .getOldLength ()) + latter .getNewLength ();
222- return new Replacement <>(latter .getFrom (), removed , addedSize );
223- }
224- }
225-
226- @ SafeVarargs
227- private static <T > List <T > concat (List <T >... lists ) {
228- int n = Arrays .asList (lists ).stream ().mapToInt (List ::size ).sum ();
229- List <T > res = new ArrayList <>(n );
230- for (List <T > l : lists ) {
231- res .addAll (l );
104+ pendingChanges .add (TransientListChange .fromCurrentStateOf (change ));
232105 }
233- return res ;
234106 }
235107
236108 private void notifyListeners (Change <? extends E > change ) {
0 commit comments