/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.btrace.util; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * * @author Jaroslav Bachorik */ public class Interval implements Comparable<Interval>{ private static final Pattern INTERVAL_PATTERN = Pattern.compile("\\((\\d+)[,;]\\s*(\\d+)\\)"); private static final Pattern COMP_PATTERN = Pattern.compile("(<|>|=|<=|>=|GT|LT|GE|LE|EQ)?(\\d+)"); private int a, b; public Interval(int a, int b) { this.a = a; this.b = b; } public int getA() { return a; } public int getB() { return b; } public static Interval eq(int value) { return new Interval(value, value); } public static Interval ge(int value) { return new Interval(value, Integer.MAX_VALUE); } public static Interval gt(int value) { return new Interval(value != Integer.MAX_VALUE ? value + 1 : Integer.MAX_VALUE, Integer.MAX_VALUE); } public static Interval le(int value) { return new Interval(Integer.MIN_VALUE, value); } public static Interval lt(int value) { return new Interval(Integer.MIN_VALUE, value != Integer.MIN_VALUE ?value - 1 : Integer.MIN_VALUE); } public static Interval all() { return new Interval(Integer.MIN_VALUE, Integer.MAX_VALUE); } public static Interval none() { return new Interval(Integer.MAX_VALUE, Integer.MIN_VALUE); } public boolean isAll() { return a == Integer.MIN_VALUE && b == Integer.MAX_VALUE; } public boolean isNone() { return a == Integer.MAX_VALUE; } public static List<Interval> union(Collection<Interval> intervals) { Set<Interval> itvSet = new TreeSet<>(); itvSet.addAll(intervals); Iterator<Interval> iter = itvSet.iterator(); Interval previous = null; while (iter.hasNext()) { if (previous == null) { previous = iter.next(); continue; } Interval current = iter.next(); if (current.a <= (previous.b != Integer.MAX_VALUE ? previous.b + 1 : Integer.MAX_VALUE)) { previous.b = current.b; iter.remove(); } else { previous = current; } } return new LinkedList<>(itvSet); } public static List<Interval> invert(Collection<Interval> intervals) { Interval remainder = new Interval(Integer.MIN_VALUE, Integer.MAX_VALUE); Set<Interval> sorted = new TreeSet(union(intervals)); List<Interval> result = new LinkedList<>(); for(Interval i : sorted) { if (i.isAll()) { return Collections.singletonList(Interval.none()); } if (i.a <= remainder.a) { if (i.b > remainder.a) remainder.a = i.b != Integer.MAX_VALUE ? i.b + 1 : i.b; } else { result.add(new Interval(remainder.a, i.a - 1)); if (i.b < remainder.b) { remainder.a = i.b != Integer.MAX_VALUE ? i.b + 1 : i.b; } else { remainder = null; break; } } } if (remainder != null) { result.add(remainder); } return result; } @Override public int compareTo(Interval o) { if (a < o.a) { return -1; } else if (a > o.a) { return 1; } else { if (b < o.b) { return -1; } else if (b > o.b) { return 1; } else { return 0; } } } @Override public int hashCode() { int hash = 3; hash = 23 * hash + this.a; hash = 23 * hash + this.b; return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Interval other = (Interval) obj; if (this.a != other.a) { return false; } return this.b == other.b; } @Override public String toString() { if (a == Integer.MIN_VALUE) { if (b != Integer.MAX_VALUE) { return "LE" + b; } } else { if (b == Integer.MAX_VALUE) { return "GE" + a; } } return "(" + a + ";" + b + ")"; } public static Interval fromString(String s) { Matcher m = INTERVAL_PATTERN.matcher(s); if (m.matches()) { int a = Integer.parseInt(m.group(1)); int b = Integer.parseInt(m.group(2)); return new Interval(a, b); } else { m = COMP_PATTERN.matcher(s); if (m.matches()) { String operator = m.group(1) != null ? m.group(1) : ""; String val = m.group(2); int level = Integer.parseInt(val); switch (operator) { case "EQ": case "=": { return eq(level); } case "LT": case "<": { return lt(level); } case "GT": case ">": { return gt(level); } case "LE": case "<=": { return le(level); } case "GE": case ">=": case "": { return ge(level); } default: { throw new IllegalArgumentException("Unrecognized operator: " + operator); } } } } throw new IllegalArgumentException("Invalid level declaration: " + s); } }