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