001/* 002 * PermissionsEx 003 * Copyright (C) zml and PermissionsEx contributors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package ca.stellardrift.permissionsex.impl.util; 018 019import org.pcollections.ConsPStack; 020import org.pcollections.HashTreePMap; 021import org.pcollections.HashTreePSet; 022import org.pcollections.PBag; 023import org.pcollections.PMap; 024import org.pcollections.PSet; 025import org.pcollections.PStack; 026import org.pcollections.PVector; 027import org.pcollections.TreePVector; 028 029import java.util.Collection; 030import java.util.Map; 031import java.util.function.BiFunction; 032import java.util.function.Function; 033import java.util.stream.Collector; 034 035/** 036 * Utilities for working with <a href="https://github.com/hrldcpr/pcollections">persistent collections</a>. 037 * 038 * <p>These are in three categories: converting from JDK collections to persistent ones, 039 * Stream helpers, and shorthand factory methods.</p> 040 */ 041public final class PCollections { 042 043 private PCollections() { 044 } 045 046 // Conversions 047 048 public static <K, V> PMap<K, V> asMap(final Map<K, V> map) { 049 if (map instanceof PMap<?, ?>) { 050 return (PMap<K, V>) map; 051 } else { 052 return HashTreePMap.from(map); 053 } 054 } 055 056 public static <KI, VI, KO, VO> PMap<KO, VO> asMap(final Map<KI, VI> map, final BiFunction<KI, VI, KO> keyMapper, final BiFunction<KI, VI, VO> valueMapper) { 057 PMap<KO, VO> out = map(); 058 for (final Map.Entry<KI, VI> entry : map.entrySet()) { 059 out = out.plus( 060 keyMapper.apply(entry.getKey(), entry.getValue()), 061 valueMapper.apply(entry.getKey(), entry.getValue()) 062 ); 063 } 064 return out; 065 } 066 067 // TODO: transforming methods for PMap? 068 069 public static <E> PSet<E> asSet(final Collection<E> set) { 070 if (set instanceof PSet<?>) { 071 return (PSet<E>) set; 072 } else { 073 return HashTreePSet.from(set); 074 } 075 } 076 077 public static <I, O> PSet<O> asSet(final Iterable<I> list, final Function<? super I, ? extends O> xform) { 078 PSet<O> out = HashTreePSet.empty(); 079 for (final I ent : list) { 080 out = out.plus(xform.apply(ent)); 081 } 082 return out; 083 } 084 085 public static <E> PVector<E> asVector(final Collection<E> list) { 086 if (list instanceof PVector<?>) { 087 return (PVector<E>) list; 088 } else { 089 return TreePVector.from(list); 090 } 091 } 092 093 public static <I, O> PVector<O> asVector(final Iterable<I> list, final Function<? super I, ? extends O> xform) { 094 PVector<O> out = TreePVector.empty(); 095 for (final I ent : list) { 096 out = out.plus(xform.apply(ent)); 097 } 098 return out; 099 } 100 101 public static <E> PStack<E> asStack(final Collection<E> stack) { 102 if (stack instanceof PStack<?>) { 103 return (PStack<E>) stack; 104 } else { 105 return ConsPStack.from(stack); 106 } 107 } 108 109 public static <I, O> PStack<O> asStack(final Iterable<I> list, final Function<? super I, ? extends O> xform) { 110 PStack<O> out = ConsPStack.empty(); 111 for (final I ent : list) { 112 out = out.plus(xform.apply(ent)); 113 } 114 return out; 115 } 116 117 // Collectors 118 119 @SuppressWarnings({"unchecked", "rawtypes"}) 120 public static <K, V> Collector<Map.Entry<K, V>, ?, PMap<K, V>> toPMap() { 121 return Collector.<Map.Entry<K, V>, PMap<K, V>[], PMap<K, V>>of( 122 () -> new PMap[] { HashTreePMap.empty() }, 123 (arr, v) -> arr[0] = arr[0].plus(v.getKey(), v.getValue()), 124 (a, b) -> new PMap[] {a[0].plusAll(b[0])}, 125 a -> a[0] 126 ); 127 } 128 129 @SuppressWarnings({"unchecked", "rawtypes"}) 130 public static <E> Collector<E, ?, PSet<E>> toPSet() { 131 return Collector.<E, PSet<E>[], PSet<E>>of( 132 () -> new PSet[] { HashTreePSet.empty() }, 133 (arr, v) -> arr[0] = arr[0].plus(v), 134 (a, b) -> new PSet[] {a[0].plusAll(b[0])}, 135 a -> a[0] 136 ); 137 } 138 139 @SuppressWarnings({"unchecked", "rawtypes"}) 140 public static <E> Collector<E, ?, PVector<E>> toPVector() { 141 return Collector.<E, PVector<E>[], PVector<E>>of( 142 () -> new PVector[] { TreePVector.empty() }, 143 (arr, v) -> arr[0] = arr[0].plus(v), 144 (a, b) -> new PVector[] {a[0].plusAll(b[0])}, 145 a -> a[0] 146 ); 147 } 148 149 @SuppressWarnings({"unchecked", "rawtypes"}) 150 public static <E> Collector<E, ?, PStack<E>> toPStack() { 151 return Collector.<E, PStack<E>[], PStack<E>>of( 152 () -> new PStack[] { ConsPStack.empty() }, 153 (arr, v) -> arr[0] = arr[0].plus(v), 154 (a, b) -> new PStack[] {a[0].plusAll(b[0])}, 155 a -> a[0] 156 ); 157 } 158 159 // narrowing -- valid because we have immutable collections 160 161 @SuppressWarnings("unchecked") 162 public static <K1 extends K2, V1 extends V2, K2, V2> PMap<K2, V2> narrow(final PMap<K1, V1> input) { 163 return (PMap<K2, V2>) input; 164 } 165 166 @SuppressWarnings("unchecked") 167 public static <E1 extends E2, E2> PSet<E2> narrow(final PSet<E1> input) { 168 return (PSet<E2>) input; 169 } 170 171 @SuppressWarnings("unchecked") 172 public static <E1 extends E2, E2> PVector<E2> narrow(final PVector<E1> input) { 173 return (PVector<E2>) input; 174 } 175 176 @SuppressWarnings("unchecked") 177 public static <E1 extends E2, E2> PStack<E2> narrow(final PStack<E1> input) { 178 return (PStack<E2>) input; 179 } 180 181 @SuppressWarnings("unchecked") 182 public static <E1 extends E2, E2> PBag<E2> narrow(final PBag<E1> input) { 183 return (PBag<E2>) input; 184 } 185 186 // factory methods // 187 188 public static <K, V> PMap<K, V> map() { 189 return HashTreePMap.empty(); 190 } 191 192 public static <K, V> PMap<K, V> map(final K key, final V value) { 193 return HashTreePMap.singleton(key, value); 194 } 195 196 public static <E> PSet<E> set() { 197 return HashTreePSet.empty(); 198 } 199 200 public static <E> PSet<E> set(final E element) { 201 return HashTreePSet.singleton(element); 202 } 203 204 @SafeVarargs 205 public static <E> PSet<E> set(final E... elements) { 206 PSet<E> out = set(); 207 for (final E element : elements) { 208 out = out.plus(element); 209 } 210 return out; 211 } 212 213 public static <E> PVector<E> vector() { 214 return TreePVector.empty(); 215 } 216 217 public static <E> PVector<E> vector(final E element) { 218 return TreePVector.singleton(element); 219 } 220 221 @SafeVarargs 222 public static <E> PVector<E> vector(final E... elements) { 223 PVector<E> out = vector(); 224 for (final E element : elements) { 225 out = out.plus(element); 226 } 227 return out; 228 } 229 230 public static <E> PStack<E> stack() { 231 return ConsPStack.empty(); 232 } 233 234 public static <E> PStack<E> stack(final E element) { 235 return ConsPStack.singleton(element); 236 } 237 238 @SafeVarargs 239 public static <E> PStack<E> stack(final E... elements) { 240 PStack<E> out = stack(); 241 for (final E element : elements) { 242 out = out.plus(element); 243 } 244 return out; 245 } 246}