| // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| package com.google.dart.compiler.util; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| |
| /** |
| * Utility methods for operating on memory-efficient lists. All lists of size 0 |
| * or 1 are assumed to be immutable. All lists of size greater than 1 are |
| * assumed to be mutable. |
| */ |
| public class Lists { |
| |
| private static final Class<?> MULTI_LIST_CLASS = ArrayList.class; |
| private static final Class<?> SINGLETON_LIST_CLASS = Collections.singletonList(null).getClass(); |
| |
| public static <T> List<T> add(List<T> list, int index, T toAdd) { |
| switch (list.size()) { |
| case 0: |
| // Empty -> Singleton |
| if (index != 0) { |
| throw newIndexOutOfBounds(list, index); |
| } |
| return Collections.singletonList(toAdd); |
| case 1: { |
| // Singleton -> ArrayList |
| List<T> result = new ArrayList<T>(2); |
| switch (index) { |
| case 0: |
| result.add(toAdd); |
| result.add(list.get(0)); |
| return result; |
| case 1: |
| result.add(list.get(0)); |
| result.add(toAdd); |
| return result; |
| default: |
| throw newIndexOutOfBounds(list, index); |
| } |
| } |
| default: |
| // ArrayList |
| list.add(index, toAdd); |
| return list; |
| } |
| } |
| |
| public static <T> List<T> add(List<T> list, T toAdd) { |
| switch (list.size()) { |
| case 0: |
| // Empty -> Singleton |
| return Collections.singletonList(toAdd); |
| case 1: { |
| // Singleton -> ArrayList |
| List<T> result = new ArrayList<T>(2); |
| result.add(list.get(0)); |
| result.add(toAdd); |
| return result; |
| } |
| default: |
| // ArrayList |
| list.add(toAdd); |
| return list; |
| } |
| } |
| |
| public static <T> List<T> addAll(List<T> list, int index, List<T> toAdd) { |
| switch (toAdd.size()) { |
| case 0: |
| // No-op. |
| return list; |
| case 1: |
| // Add one element. |
| return add(list, index, toAdd.get(0)); |
| default: |
| // True list merge, result >= 2. |
| switch (list.size()) { |
| case 0: |
| if (index != 0) { |
| throw newIndexOutOfBounds(list, index); |
| } |
| return new ArrayList<T>(toAdd); |
| case 1: { |
| List<T> result = new ArrayList<T>(1 + toAdd.size()); |
| switch (index) { |
| case 0: |
| result.addAll(toAdd); |
| result.add(list.get(0)); |
| return result; |
| case 1: |
| result.add(list.get(0)); |
| result.addAll(toAdd); |
| return result; |
| default: |
| throw newIndexOutOfBounds(list, index); |
| } |
| } |
| default: |
| list.addAll(index, toAdd); |
| return list; |
| } |
| } |
| } |
| |
| public static <T> List<T> addAll(List<T> list, List<T> toAdd) { |
| switch (toAdd.size()) { |
| case 0: |
| // No-op. |
| return list; |
| case 1: |
| // Add one element. |
| return add(list, toAdd.get(0)); |
| default: |
| // True list merge, result >= 2. |
| switch (list.size()) { |
| case 0: |
| return new ArrayList<T>(toAdd); |
| case 1: { |
| List<T> result = new ArrayList<T>(1 + toAdd.size()); |
| result.add(list.get(0)); |
| result.addAll(toAdd); |
| return result; |
| } |
| default: |
| list.addAll(toAdd); |
| return list; |
| } |
| } |
| } |
| |
| public static <T> List<T> addAll(List<T> list, T... toAdd) { |
| switch (toAdd.length) { |
| case 0: |
| // No-op. |
| return list; |
| case 1: |
| // Add one element. |
| return add(list, toAdd[0]); |
| default: |
| // True list merge, result >= 2. |
| switch (list.size()) { |
| case 0: |
| return new ArrayList<T>(Arrays.asList(toAdd)); |
| case 1: { |
| List<T> result = new ArrayList<T>(1 + toAdd.length); |
| result.add(list.get(0)); |
| result.addAll(Arrays.asList(toAdd)); |
| return result; |
| } |
| default: |
| list.addAll(Arrays.asList(toAdd)); |
| return list; |
| } |
| } |
| } |
| |
| public static <T> List<T> create() { |
| return Collections.emptyList(); |
| } |
| |
| public static <T> List<T> create(Collection<T> collection) { |
| switch (collection.size()) { |
| case 0: |
| return create(); |
| default: |
| return new ArrayList<T>(collection); |
| } |
| } |
| |
| public static <T> List<T> create(List<T> list) { |
| switch (list.size()) { |
| case 0: |
| return create(); |
| case 1: |
| return create(list.get(0)); |
| default: |
| return new ArrayList<T>(list); |
| } |
| } |
| |
| public static <T> List<T> create(T item) { |
| return Collections.singletonList(item); |
| } |
| |
| public static <T> List<T> create(T... items) { |
| switch (items.length) { |
| case 0: |
| return create(); |
| case 1: |
| return create(items[0]); |
| default: |
| return new ArrayList<T>(Arrays.asList(items)); |
| } |
| } |
| |
| public static <T> List<T> normalize(List<T> list) { |
| switch (list.size()) { |
| case 0: |
| return create(); |
| case 1: { |
| if (list.getClass() == SINGLETON_LIST_CLASS) { |
| return list; |
| } |
| return create(list.get(0)); |
| } |
| default: |
| if (list.getClass() == MULTI_LIST_CLASS) { |
| return list; |
| } |
| return new ArrayList<T>(list); |
| } |
| } |
| |
| public static <T> List<T> normalizeUnmodifiable(List<T> list) { |
| if (list.size() < 2) { |
| return normalize(list); |
| } else { |
| List<T> copy = new ArrayList<T>(list.size()); |
| Collections.copy(copy, list); |
| return copy; |
| } |
| } |
| |
| public static <T> List<T> remove(List<T> list, int toRemove) { |
| switch (list.size()) { |
| case 0: |
| // Empty |
| throw newIndexOutOfBounds(list, toRemove); |
| case 1: |
| // Singleton -> Empty |
| if (toRemove == 0) { |
| return Collections.emptyList(); |
| } else { |
| throw newIndexOutOfBounds(list, toRemove); |
| } |
| case 2: |
| // ArrayList -> Singleton |
| switch (toRemove) { |
| case 0: |
| return Collections.singletonList(list.get(1)); |
| case 1: |
| return Collections.singletonList(list.get(0)); |
| default: |
| throw newIndexOutOfBounds(list, toRemove); |
| } |
| default: |
| // ArrayList |
| list.remove(toRemove); |
| return list; |
| } |
| } |
| |
| public static <T> List<T> set(List<T> list, int index, T e) { |
| switch (list.size()) { |
| case 0: |
| // Empty |
| throw newIndexOutOfBounds(list, index); |
| case 1: |
| // Singleton |
| if (index == 0) { |
| return Collections.singletonList(e); |
| } else { |
| throw newIndexOutOfBounds(list, index); |
| } |
| default: |
| // ArrayList |
| list.set(index, e); |
| return list; |
| } |
| } |
| |
| public static <T extends Comparable<? super T>> List<T> sort(List<T> list) { |
| if (list.size() > 1) { |
| Collections.sort(list); |
| } |
| return list; |
| } |
| |
| public static <T> List<T> sort(List<T> list, Comparator<? super T> sort) { |
| if (list.size() > 1) { |
| Collections.sort(list, sort); |
| } |
| return list; |
| } |
| |
| private static <T> IndexOutOfBoundsException newIndexOutOfBounds(List<T> list, int index) { |
| return new IndexOutOfBoundsException("Index: " + index + ", Size: " + list.size()); |
| } |
| } |