View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.spf4j.base;
33  
34  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35  import java.util.ArrayDeque;
36  import java.util.Deque;
37  import java.util.Set;
38  import java.util.function.BiConsumer;
39  import java.util.function.BinaryOperator;
40  import java.util.function.Function;
41  import java.util.function.Predicate;
42  import java.util.function.Supplier;
43  import java.util.stream.Collector;
44  
45  /**
46   * @author Zoltan Farkas
47   */
48  public final class XCollectors {
49  
50    private XCollectors() {
51    }
52  
53    public static <T> Collector<T, ?, ArrayDeque<T>> last(final int limit) {
54      return Collector.of(
55              ArrayDeque<T>::new,
56              (l, e) -> {
57                if (l.size() >= limit) {
58                  l.removeFirst();
59                }
60                l.addLast(e);
61              },
62              (l1, l2) -> {
63                throw new UnsupportedOperationException("Limiting collectors do not support combining");
64              }
65      );
66    }
67  
68    public static <T, X extends T> Collector<T, ArrayDeque<T>,
69           ArrayDeque<T>> last(final int limit, final X addIfLimited) {
70      return  last(() -> new ArrayDeque<T>(), limit, addIfLimited);
71    }
72  
73    public static <T, X extends T, D extends Deque<T>> Collector<T, D, D> last(final Supplier<D> dqSupp,
74            final int limit, final X addIfLimited) {
75      return Collector.of(dqSupp,
76              (l, e) -> {
77                l.addLast(e);
78                limitDequeue(l, limit, addIfLimited);
79              }, new BinaryOperator<D>() {
80        @Override
81        @SuppressFBWarnings("CFS_CONFUSING_FUNCTION_SEMANTICS")
82        // Agree with FB here, however this confusing behavior is documented in Collector javadoc...
83        public D apply(final D l1, final D l2) {
84          l1.addAll(l2);
85          limitDequeue(l1, limit, addIfLimited);
86          return l1;
87        }
88      }, Collector.Characteristics.IDENTITY_FINISH);
89    }
90  
91    public static <T> void limitDequeue(final Deque<T> l1, final int limit, final T addIfLimited) {
92      int extra = l1.size() - limit;
93      if (extra > 0) {
94        for (int i = 0, m = extra + 1; i < m; i++) {
95          l1.removeFirst();
96        }
97        l1.addFirst(addIfLimited);
98      }
99    }
100 
101   /**
102    * THis is a backport from JDK9.
103    */
104   public static <T, A, R>
105           Collector<T, ?, R> filtering(final Predicate<? super T> predicate,
106                   final Collector<? super T, A, R> downstream) {
107     BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
108     return new CollectorImpl<>(downstream.supplier(),
109             (r, t) -> {
110               if (predicate.test(t)) {
111                 downstreamAccumulator.accept(r, t);
112               }
113             },
114             downstream.combiner(), downstream.finisher(),
115             downstream.characteristics());
116   }
117 
118   @SuppressWarnings("unchecked")
119   private static <I, R> Function<I, R> castingIdentity() {
120     return (Function<I, R>) Function.identity();
121   }
122 
123   static final class CollectorImpl<T, A, R> implements Collector<T, A, R> {
124 
125     private final Supplier<A> supplier;
126     private final BiConsumer<A, T> accumulator;
127     private final BinaryOperator<A> combiner;
128     private final Function<A, R> finisher;
129     private final Set<Collector.Characteristics> characteristics;
130 
131     CollectorImpl(final Supplier<A> supplier,
132             final BiConsumer<A, T> accumulator,
133             final BinaryOperator<A> combiner,
134             final Function<A, R> finisher,
135             final Set<Collector.Characteristics> characteristics) {
136       this.supplier = supplier;
137       this.accumulator = accumulator;
138       this.combiner = combiner;
139       this.finisher = finisher;
140       this.characteristics = characteristics;
141     }
142 
143     CollectorImpl(final Supplier<A> supplier,
144             final BiConsumer<A, T> accumulator,
145             final BinaryOperator<A> combiner,
146             final Set<Collector.Characteristics> characteristics) {
147       this(supplier, accumulator, combiner, castingIdentity(), characteristics);
148     }
149 
150     @Override
151     public BiConsumer<A, T> accumulator() {
152       return accumulator;
153     }
154 
155     @Override
156     public Supplier<A> supplier() {
157       return supplier;
158     }
159 
160     @Override
161     public BinaryOperator<A> combiner() {
162       return combiner;
163     }
164 
165     @Override
166     public Function<A, R> finisher() {
167       return finisher;
168     }
169 
170     @Override
171     public Set<Collector.Characteristics> characteristics() {
172       return characteristics;
173     }
174   }
175 
176 }