001/* 002 * Copyright (C) 2009-2011 Mathias Doenitz 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.parboiled.support; 018 019import static org.parboiled.common.Preconditions.checkArgNotNull; 020import static org.parboiled.common.Preconditions.checkArgument; 021 022/** 023 * A simple immutable container for a range of indices into an underlying InputBuffer. 024 */ 025public final class IndexRange { 026 027 public static final IndexRange EMPTY = new IndexRange(0, 0); 028 029 /** 030 * The index of the first character in the range. 031 */ 032 public final int start; 033 034 /** 035 * The index of the character following the last character of the range. 036 */ 037 public final int end; 038 039 public IndexRange(int start, int end) { 040 checkArgument(start >= 0, "start must be >= 0"); 041 checkArgument(end >= start, "end must be >= start"); 042 this.start = start; 043 this.end = end; 044 } 045 046 /** 047 * Determines whether this range contains no characters. 048 * 049 * @return true if the end matches the start of the range. 050 */ 051 public boolean isEmpty() { 052 return start == end; 053 } 054 055 /** 056 * @return the number of characters covered by this range 057 */ 058 public int length() { 059 return end - start; 060 } 061 062 /** 063 * Determines whether this range overlaps with the given other one. 064 * 065 * @param other the other range 066 * @return true if there is at least one index that is contained in both ranges 067 */ 068 public boolean overlapsWith(IndexRange other) { 069 checkArgNotNull(other, "other"); 070 return end > other.start && other.end > start; 071 } 072 073 /** 074 * Determines whether this range immediated follows the given other one. 075 * 076 * @param other the other range 077 * @return true if this range immediated follows the given other one 078 */ 079 public boolean isPrecededBy(IndexRange other) { 080 checkArgNotNull(other, "other"); 081 return other.end == start; 082 } 083 084 /** 085 * Determines whether this range is immediated followed by the given other one. 086 * 087 * @param other the other range 088 * @return true if this range is immediated followed by the given other one 089 */ 090 public boolean isFollowedBy(IndexRange other) { 091 checkArgNotNull(other, "other"); 092 return end == other.start; 093 } 094 095 /** 096 * Determines whether this range immediated follows or precedes the given other one. 097 * 098 * @param other the other range 099 * @return true if this range immediated follows or precedes the given other one. 100 */ 101 public boolean touches(IndexRange other) { 102 checkArgNotNull(other, "other"); 103 return other.end == start || end == other.start; 104 } 105 106 /** 107 * Created a new IndexRange that spans all characters between the smallest and the highest index of the two ranges. 108 * 109 * @param other the other range 110 * @return a new IndexRange instance 111 */ 112 public IndexRange mergedWith(IndexRange other) { 113 checkArgNotNull(other, "other"); 114 return new IndexRange(Math.min(start, other.start), Math.max(end, other.end)); 115 } 116 117 @Override 118 public boolean equals(Object o) { 119 if (this == o) return true; 120 if (!(o instanceof IndexRange)) return false; 121 IndexRange that = (IndexRange) o; 122 return end == that.end && start == that.start; 123 } 124 125 @Override 126 public int hashCode() { 127 int result = start; 128 result = 31 * result + end; 129 return result; 130 } 131 132 @Override 133 public String toString() { 134 return "IndexRange{" + 135 "start=" + start + 136 ", end=" + end + 137 '}'; 138 } 139}