public static FrontendClientMetadata readFrom(final DataInput in) throws IOException, ClassNotFoundException { final ClientIdentifier id = ClientIdentifier.readFrom(in); final int purgedSize = in.readInt(); final Builder<UnsignedLong> b = ImmutableRangeSet.builder(); for (int i = 0; i < purgedSize; ++i) { final byte header = WritableObjects.readLongHeader(in); final UnsignedLong lower = UnsignedLong.fromLongBits(WritableObjects.readFirstLong(in, header)); final UnsignedLong upper = UnsignedLong.fromLongBits(WritableObjects.readSecondLong(in, header)); b.add(Range.closed(lower, upper)); } final int currentSize = in.readInt(); final Collection<FrontendHistoryMetadata> currentHistories = new ArrayList<>(currentSize); for (int i = 0; i < currentSize; ++i) { currentHistories.add(FrontendHistoryMetadata.readFrom(in)); } return new FrontendClientMetadata(id, b.build(), currentHistories); }
@SuppressWarnings("unchecked") private static <T extends Number & Comparable<T>> RangeSet<T> ensureTypedRanges(final List<ValueRange> ranges, final Class<? extends Number> clazz) { final Builder<T> builder = ImmutableRangeSet.builder(); for (ValueRange range : ranges) { if (!clazz.isInstance(range.lowerBound()) || !clazz.isInstance(range.upperBound())) { return typedRanges(ranges, clazz); } builder.add(Range.closed((T) range.lowerBound(), (T)range.upperBound())); } return builder.build(); }
@SuppressWarnings("unchecked") private static <T extends Number & Comparable<T>> RangeSet<T> typedRanges(final List<ValueRange> ranges, final Class<? extends Number> clazz) { final Function<Number, ? extends Number> function = NumberUtil.converterTo(clazz); Preconditions.checkArgument(function != null, "Unsupported range class %s", clazz); final Builder<T> builder = ImmutableRangeSet.builder(); for (ValueRange range : ranges) { if (!clazz.isInstance(range.lowerBound()) || !clazz.isInstance(range.upperBound())) { final Number min; final Number max; try { min = function.apply(range.lowerBound()); max = function.apply(range.upperBound()); } catch (NumberFormatException e) { throw new IllegalArgumentException(String.format("Constraint %s does not fit into range of %s", range, clazz.getSimpleName()), e); } builder.add(Range.closed((T)min, (T)max)); } else { builder.add(Range.closed((T) range.lowerBound(), (T)range.upperBound())); } } return builder.build(); }
/** * Set a new length constraint. * * @param constraint Constraint metadata * @param ranges Allowed ranges * @throws IllegalStateException if the constraint has already been set * @throws InvalidLengthConstraintException if one of the proposed ranges does not overlap with supertype * @throws NullPointerException if any of the arguments is null */ public final void setLengthConstraint(final @NonNull ConstraintMetaDefinition constraint, final @NonNull List<ValueRange> ranges) throws InvalidLengthConstraintException { Preconditions.checkState(lengthConstraint == null, "Length constraint already defined as %s", lengthConstraint); final LengthConstraint baseLengths = findLenghts(); if (ranges.isEmpty()) { lengthConstraint = baseLengths; return; } // Run through alternatives and resolve them against the base type requireNonNull(constraint); final Builder<Integer> builder = ImmutableRangeSet.builder(); final Range<Integer> span = baseLengths.getAllowedRanges().span(); for (ValueRange c : ranges) { builder.add(Range.closed(resolveLength(c.lowerBound(), span), resolveLength(c.upperBound(), span))); } // Now verify if new ranges are strict subset of base ranges final RangeSet<Integer> allowed = builder.build(); final RangeSet<Integer> baseRanges = baseLengths.getAllowedRanges(); for (Range<Integer> range : allowed.asRanges()) { if (!baseRanges.encloses(range)) { throw new InvalidLengthConstraintException("Range %s is not a subset of parent constraint %s", range, baseRanges); } } lengthConstraint = new ResolvedLengthConstraint(constraint, allowed); touch(); }