X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Futil%2FRange.java;fp=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Futil%2FRange.java;h=4488ed7056802a0c96c767298d537dd5801dd132;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/util/Range.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/util/Range.java new file mode 100644 index 000000000..4488ed705 --- /dev/null +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/util/Range.java @@ -0,0 +1,322 @@ +/******************************************************************************* + * Copyright (c) 2010 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.databoard.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + + +/** + * Number range. + * + * Examples: + * Inclusive "[0..100]" + * Exclusive "[0..100)" + * Unlimited "[..]" + * No upper limit "[0..)" + * No lower limit "(..0]" + * Exact value "0" + * Exclude all "()" + * + * Inclusive "[0.5..100.5]" + * Exclusive "[0.5..100.5)" + * Unlimited "[..]" + * No upper limit "[0.5..)" + * No lower limit "(..0.5]" + * Exact value "[0.5]" + * + * Inclusive "[0e..100]" + * Exclusive "[0..100)" + * Unlimited "" + * No upper limit "[0..)" + * No lower limit "(..0]" + * Exact value "0" + * + * @author Toni Kalajainen + */ +public class Range { + + Limit lower; + Limit upper; + + public static Range create(Byte lower, Byte upper, boolean lowerInclusive, boolean upperInclusive) + { + Limit ll = lowerInclusive ? Limit.inclusive(lower) : Limit.exclusive(lower); + Limit ul = upperInclusive ? Limit.inclusive(upper) : Limit.exclusive(upper); + return new Range(ll, ul); + } + + public static Range create(Integer lower, Integer upper, boolean lowerInclusive, boolean upperInclusive) + { + Limit ll = lowerInclusive ? Limit.inclusive(lower) : Limit.exclusive(lower); + Limit ul = upperInclusive ? Limit.inclusive(upper) : Limit.exclusive(upper); + return new Range(ll, ul); + } + + public static Range create(Long lower, Long upper, boolean lowerInclusive, boolean upperInclusive) + { + Limit ll = lowerInclusive ? Limit.inclusive(lower) : Limit.exclusive(lower); + Limit ul = upperInclusive ? Limit.inclusive(upper) : Limit.exclusive(upper); + return new Range(ll, ul); + } + + public static Range create(Float lower, Float upper, boolean lowerInclusive, boolean upperInclusive) + { + Limit ll = lowerInclusive ? Limit.inclusive(lower) : Limit.exclusive(lower); + Limit ul = upperInclusive ? Limit.inclusive(upper) : Limit.exclusive(upper); + return new Range(ll, ul); + } + + public static Range create(Double lower, Double upper, boolean lowerInclusive, boolean upperInclusive) + { + Limit ll = lowerInclusive ? Limit.inclusive(lower) : Limit.exclusive(lower); + Limit ul = upperInclusive ? Limit.inclusive(upper) : Limit.exclusive(upper); + return new Range(ll, ul); + } + + public static Range create(Byte exact) + { + Limit l = Limit.inclusive(exact); + return new Range(l, l); + } + + public static Range create(Integer exact) + { + Limit l = Limit.inclusive(exact); + return new Range(l, l); + } + + public static Range create(Long exact) + { + Limit l = Limit.inclusive(exact); + return new Range(l, l); + } + + public static Range create(Float exact) + { + Limit l = Limit.inclusive(exact); + return new Range(l, l); + } + + public static Range create(Double exact) + { + Limit l = Limit.inclusive(exact); + return new Range(l, l); + } + + public static Range includeAll() + { + Limit l = Limit.nolimit(); + return new Range(l, l); + } + + public static Range excludeAll() + { + Limit l = Limit.exclusive(0); + return new Range(l, l); + } + + public static Range between(Limit limit1, Limit limit2) { + Number l = limit1.getValue(); + Number u = limit2.getValue(); + if (l!=null && u!=null) { + if (NumberComparator.INSTANCE.compare(l, u)<0) + return new Range(limit2, limit1); + } + return new Range(limit1, limit2); + } + + public Range(Limit lower, Limit upper) + { + this.lower = lower; + this.upper = upper; + + // Ensure lower < upper + Number l = lower.getValue(); + Number u = upper.getValue(); + if (l!=null && u!=null) { + if (NumberComparator.INSTANCE.compare(l, u)<0) + throw new IllegalArgumentException("Lower limit must be less-or-equal to upper limit"); + } + + // Exact value + if (l!=null && u!=null && l.equals(u)) { + if (lower.isExclusive() || upper.isExclusive()) + this.lower = this.upper = Limit.exclusive(0); + } + + } + + public Limit getLower() { + return lower; + } + + public Limit getUpper() { + return upper; + } + + @Override + public String toString() { + if (lower instanceof Limit.Nolimit && upper instanceof Limit.Nolimit) return "[..]"; + + // Range + StringBuilder sb = new StringBuilder(); + + + Number l = lower.getValue(); + Number u = upper.getValue(); + + if (l!=null && u!=null && l.equals(u)) + { + if (lower.isExclusive() || upper.isExclusive()) + return "()"; + + // Exact value + return l.toString(); + } + + sb.append( !lower.isInclusive() ? '(' : "[" ); + // Range + if (lower instanceof Limit.Nolimit == false) sb.append( l ); + sb.append( ".." ); + if (upper instanceof Limit.Nolimit == false) sb.append( u ); + sb.append( !upper.isInclusive() ? ')' : "]" ); + + return sb.toString(); + } + + /** + * Double pattern + * + * This pattern is not perfect as it accepts strings such as + * "e0", "", and ".", but its good enough as Double class does the final + * parsing. + */ +// static Pattern DOUBLE_PATTERN = Pattern.compile("-?+\\d*(?:\\.\\d*)?(?:[eE]\\d++)?"); + static Pattern RANGE_PATTERN = Pattern.compile( + "(?:([\\(\\[])(-?\\d*(?:\\.\\d*)?(?:[eE]-?\\d+)?)??\\.\\.(-?\\d*(?:\\.\\d*)?(?:[eE]-?\\d+)?)??([\\)\\]]))|"+ // [x..y] [x..y) (x..y) + "(-?+\\d*(?:\\.\\d*)?(?:[eE]-?\\d+)?)|"+ // x + "\\(\\)"); // () + + public static Range valueOfUnchecked(String txt) { + try { + return valueOf(txt); + } catch (RangeException e) { + throw new IllegalArgumentException(e); + } + } + + public static Range valueOf(String txt) + throws RangeException + { + Matcher m = RANGE_PATTERN.matcher(txt); + if (!m.matches()) throw new RangeException("Illegal range '" + txt + "'"); + + if ( (m.group(1)!=null) || (m.group(2)!=null) || (m.group(3)!=null) || (m.group(4)!=null) ) { + + Limit l1, l2; + if (m.group(2)==null && m.group(3)==null) { + return new Range(Limit.nolimit(), Limit.nolimit()); + } else if (m.group(2)==null) { + l1 = Limit.nolimit(); + } else { + try { + Long l = Long.parseLong( m.group(2) ); + l1 = m.group(1).equals("[") ? Limit.inclusive(l) : Limit.exclusive(l); + } catch (NumberFormatException nfe) { + try { + Double d = Double.parseDouble( m.group(2) ); + l1 = m.group(1).equals("[") ? Limit.inclusive(d) : Limit.exclusive(d); + } catch (NumberFormatException e) { + throw new RangeException(e); + } + } + } + + if (m.group(3)==null) { + l2 = Limit.nolimit(); + } else { + try { + Long l = Long.parseLong( m.group(3) ); + l2 = m.group(4).equals("]") ? Limit.inclusive(l) : Limit.exclusive(l); + } catch (NumberFormatException nfe) { + try { + Double d = Double.parseDouble( m.group(3) ); + l2 = m.group(4).equals("]") ? Limit.inclusive(d) : Limit.exclusive(d); + } catch (NumberFormatException e) { + throw new RangeException(e); + } + } + } + + return new Range(l1, l2); + } + + if ( (m.group(5)!=null) ) { + try { + Long l = Long.parseLong( m.group(5) ); + Limit l1 = Limit.inclusive(l); + return new Range(l1, l1); + } catch (NumberFormatException nfe) { + try { + Double d = Double.parseDouble( m.group(5) ); + Limit l1 = Limit.inclusive(d); + return new Range(l1, l1); + } catch (NumberFormatException e) { + throw new RangeException(e); + } + } + } + + Range result = new Range(Limit.exclusive(0), Limit.exclusive(0)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Range == false) return false; + Range other = (Range) obj; + return + ( other.upper == null ? upper == null : other.upper.equals( upper ) ) && + ( other.lower == null ? lower == null : other.lower.equals( lower ) ); + } + + @Override + public int hashCode() { + return + ObjectUtils.hashCode(upper) * 13 + + ObjectUtils.hashCode(lower); + } + + public boolean contains(Number value) + { + if (lower instanceof Limit.Nolimit==false) + { + int compare = NumberComparator.INSTANCE.compare(lower.getValue(), value); + if (compare==0 && lower.isExclusive()) return false; + if (compare<0) return false; + } + + if (upper instanceof Limit.Nolimit==false) + { + int compare = NumberComparator.INSTANCE.compare(upper.getValue(), value); + if (compare==0 && upper.isExclusive()) return false; + if (compare>0) return false; + } + + return true; + } + + +} +