001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the License. 004 * 005 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 006 * specific language governing permission and limitations under the License. 007 * 008 * When distributing Covered Software, include this CDDL Header Notice in each file and include 009 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 010 * Header, with the fields enclosed by brackets [] replaced by your own identifying 011 * information: "Portions copyright [year] [name of copyright owner]". 012 * 013 * Copyright 2015 ForgeRock AS. 014 */ 015 016package org.forgerock.util; 017 018// Java SE 019import java.io.Serializable; 020import java.util.AbstractSet; 021import java.util.Iterator; 022import java.util.NoSuchElementException; 023 024/** 025 * Exposes a range of integer values as a set. Avoids the allocation of storage for all 026 * values. Order of elements is guaranteed to be in the order from the specified start and 027 * stop values. 028 * <p> 029 * If combination of start/stop/step values are not mathematically possible to represent 030 * as a set of values, it is represented by this implementation as an empty set. 031 */ 032public class RangeSet extends AbstractSet<Integer> implements Cloneable, Serializable { 033 034 /** Establishes serialized object compatibility. */ 035 private static final long serialVersionUID = 1L; 036 037 /** The start of the range, inclusive. */ 038 private final int start; 039 040 /** The end of the range, inclusive. */ 041 private final int stop; 042 043 /** TODO: Description. */ 044 private final int step; 045 046 /** 047 * Constructs a range set for a sequence of numbers, starting at {@code 0} with 048 * the value to stop. Equivalent to constructing the range set with: 049 * {@code RangeSet(0, stop, 1)}. 050 * @param stop the point at which to stop the range (exclusive). 051 */ 052 public RangeSet(int stop) { 053 this(0, stop, 1); 054 } 055 056 /** 057 * Constructs a range set for the specified range of integers with a step of {@code 1}. 058 * Equivalent to constructing the range set with: {@code RangeSet(start, stop, 1)}. 059 * 060 * @param start the start of the range (inclusive). 061 * @param stop the point at which to stop the range (exclusive). 062 */ 063 public RangeSet(int start, int stop) { 064 this(start, stop, 1); 065 } 066 067 /** 068 * Constructs a range set for the specified range of integers and increment. 069 * 070 * @param start the start of the range, inclusive. 071 * @param stop the point at which to stop the range (exclusive). 072 * @param step the step to increment for each value in the range. 073 * @throws IllegalArgumentException if {@code step} is {@code 0}. 074 */ 075 public RangeSet(int start, int stop, int step) { 076 if (step == 0) { 077 throw new IllegalArgumentException(); 078 } 079 this.start = start; 080 this.stop = stop; 081 this.step = step; 082 } 083 084 /** 085 * Returns the number of elements in this set. 086 */ 087 @Override 088 public int size() { 089 int difference = (stop - start); // show all work 090 int count = (difference / step); 091 int remainder = Math.abs(difference % step); 092 return (count > 0 ? count + remainder : 0); 093 } 094 095 /** 096 * Returns {@code true} if this set contains no elements. 097 */ 098 @Override 099 public boolean isEmpty() { 100 return (size() == 0); 101 } 102 103 /** 104 * Returns {@code true} if this set contains the specified element. 105 * 106 * @param o element whose presence in this set is to be tested. 107 * @return {@code true} if this set contains the specified element. 108 */ 109 @Override 110 public boolean contains(Object o) { 111 boolean result = false; 112 if (o != null && o instanceof Integer && size() != 0) { 113 int contains = ((Number)o).intValue(); 114 if ((step > 0 && contains >= start && contains < stop) 115 || (step < 0 && contains >= start && contains > stop)) { 116 result = ((contains - start) % step == 0); 117 } 118 } 119 return result; 120 } 121 122 /** 123 * Returns an iterator over the elements in this set. The elements are returned in 124 * the order they are specified from start to stop. 125 */ 126 @Override 127 public Iterator<Integer> iterator() { 128 return new Iterator<Integer>() { 129 int cursor = start; 130 @Override public boolean hasNext() { 131 boolean result; 132 if (step > 0) { 133 result = (cursor < stop); 134 } else { 135 result = (cursor > stop); 136 } 137 return result; 138 } 139 @Override public Integer next() { 140 if (!hasNext()) { 141 throw new NoSuchElementException(); 142 } 143 int result = cursor; 144 cursor += step; 145 return result; 146 } 147 @Override public void remove() { 148 throw new UnsupportedOperationException(); 149 } 150 }; 151 } 152}