/** * Creates a mapping that consists of a set of contiguous ranges. * * <p>For example, * * <pre>createShiftMapping(60, * 100, 0, 3, * 200, 50, 5); * </pre> * * <p>creates * * <table> * <caption>Example mapping</caption> * <tr><th>Source</th><th>Target</th></tr> * <tr><td>0</td><td>100</td></tr> * <tr><td>1</td><td>101</td></tr> * <tr><td>2</td><td>102</td></tr> * <tr><td>3</td><td>-1</td></tr> * <tr><td>...</td><td>-1</td></tr> * <tr><td>50</td><td>200</td></tr> * <tr><td>51</td><td>201</td></tr> * <tr><td>52</td><td>202</td></tr> * <tr><td>53</td><td>203</td></tr> * <tr><td>54</td><td>204</td></tr> * <tr><td>55</td><td>-1</td></tr> * <tr><td>...</td><td>-1</td></tr> * <tr><td>59</td><td>-1</td></tr> * </table> * * @param sourceCount Maximum value of {@code source} * @param ints Collection of ranges, each {@code (target, source, count)} * @return Mapping that maps from source ranges to target ranges */ public static TargetMapping createShiftMapping(int sourceCount, int... ints) { int targetCount = 0; assert ints.length % 3 == 0; for (int i = 0; i < ints.length; i += 3) { final int target = ints[i]; final int length = ints[i + 2]; final int top = target + length; targetCount = Math.max(targetCount, top); } final TargetMapping mapping = create( MappingType.INVERSE_SURJECTION, sourceCount, // aCount + bCount + cCount, targetCount); // cCount + bCount for (int i = 0; i < ints.length; i += 3) { final int target = ints[i]; final int source = ints[i + 1]; final int length = ints[i + 2]; assert source + length <= sourceCount; for (int j = 0; j < length; j++) { assert mapping.getTargetOpt(source + j) == -1; mapping.set(source + j, target + j); } } return mapping; }
/** Returns whether a mapping is the identity. */ public static boolean isIdentity(TargetMapping mapping) { if (mapping.getSourceCount() != mapping.getTargetCount()) { return false; } for (int i = 0; i < mapping.getSourceCount(); i++) { if (mapping.getTargetOpt(i) != i) { return false; } } return true; }
/** * Returns a mapping that shifts a given mapping's target by a given offset. * * <p>For example, given {@code mapping} with sourceCount=2, targetCount=8, and (source, target) * entries {[0: 5], [1: 7]}, offsetTarget(mapping, 3) returns a mapping with sourceCount=2, * targetCount=11, and (source, target) entries {[0: 8], [1: 10]}. * * @param mapping Input mapping * @param offset Offset to be applied to each target * @param targetCount New target count; must be at least {@code mapping}'s target count plus * {@code offset} * @return Shifted mapping */ public static TargetMapping offsetTarget( final TargetMapping mapping, final int offset, final int targetCount) { if (targetCount < mapping.getTargetCount() + offset) { throw new IllegalArgumentException("new target count too low"); } return target( new Function1<Integer, Integer>() { public Integer apply(Integer source) { int target = mapping.getTargetOpt(source); return target < 0 ? null : target + offset; } }, mapping.getSourceCount(), targetCount); }
public int getTarget(int source) { if (source == this.source) { return this.target; } else { return parent.getTarget(source); } }
/** * Returns a mapping that shifts a given mapping's source by a given offset. * * <p>For example, given {@code mapping} with sourceCount=2, targetCount=8, and (source, target) * entries {[0: 5], [1: 7]}, offsetSource(mapping, 3) returns a mapping with sourceCount=5, * targetCount=8, and (source, target) entries {[3: 5], [4: 7]}. * * @param mapping Input mapping * @param offset Offset to be applied to each source * @param sourceCount New source count; must be at least {@code mapping}'s source count plus * {@code offset} * @return Shifted mapping */ public static TargetMapping offsetSource( final TargetMapping mapping, final int offset, final int sourceCount) { if (sourceCount < mapping.getSourceCount() + offset) { throw new IllegalArgumentException("new source count too low"); } return target( new Function1<Integer, Integer>() { public Integer apply(Integer source) { int source2 = source - offset; return source2 < 0 || source2 >= mapping.getSourceCount() ? null : mapping.getTargetOpt(source2); } }, sourceCount, mapping.getTargetCount()); }
/** * Creates a mapping by appending two mappings. * * <p>Sources and targets of the second mapping are shifted to the right. * * <p>For example, * * <pre>append({0:0, 1:1}, {0:0, 1:1, 2:2})</pre> * * yields * * <pre>{0:0, 1:1, 2:2, 3:3, 4:4}</pre> * * . * * @see #merge */ public static TargetMapping append(TargetMapping mapping0, TargetMapping mapping1) { final int s0 = mapping0.getSourceCount(); final int s1 = mapping1.getSourceCount(); final int t0 = mapping0.getTargetCount(); final int t1 = mapping1.getTargetCount(); final TargetMapping mapping = create(MappingType.INVERSE_SURJECTION, s0 + s1, t0 + t1); for (int s = 0; s < s0; s++) { int t = mapping0.getTargetOpt(s); if (t >= 0) { mapping.set(s, t); } } for (int s = 0; s < s1; s++) { int t = mapping1.getTargetOpt(s); if (t >= 0) { mapping.set(s0 + s, t0 + t); } } return mapping; }
/** * Returns a mapping that shifts a given mapping's target by a given offset, incrementing the * number of targets by the minimum possible. * * @param mapping Input mapping * @param offset Offset to be applied to each target * @return Shifted mapping */ public static TargetMapping offsetTarget(final TargetMapping mapping, final int offset) { return offsetTarget(mapping, offset, mapping.getTargetCount() + offset); }
/** * Creates a mapping by merging two mappings. There must be no clashes. * * <p>Unlike {@link #append}, sources and targets are not shifted. * * <p>For example, <code>merge({0:0, 1:1}, {2:2, 3:3, 4:4})</code> yields <code> * {0:0, 1:1, 2:2, 3:3, 4:4}</code>. <code>merge({0:0, 1:1}, {1:2, 2:3})</code> throws, because * there are two entries with source=1. */ public static TargetMapping merge(TargetMapping mapping0, TargetMapping mapping1) { final int s0 = mapping0.getSourceCount(); final int s1 = mapping1.getSourceCount(); final int sMin = Math.min(s0, s1); final int sMax = Math.max(s0, s1); final int t0 = mapping0.getTargetCount(); final int t1 = mapping1.getTargetCount(); final int tMax = Math.max(t0, t1); final TargetMapping mapping = create(MappingType.INVERSE_SURJECTION, sMax, tMax); for (int s = 0; s < sMin; s++) { int t = mapping0.getTargetOpt(s); if (t >= 0) { mapping.set(s, t); assert mapping1.getTargetOpt(s) < 0; } else { t = mapping1.getTargetOpt(s); if (t >= 0) { mapping.set(s, t); } } } for (int s = sMin; s < sMax; s++) { int t = s < s0 ? mapping0.getTargetOpt(s) : -1; if (t >= 0) { mapping.set(s, t); assert mapping1.getTargetOpt(s) < 0; } else { t = s < s1 ? mapping1.getTargetOpt(s) : -1; if (t >= 0) { mapping.set(s, t); } } } return mapping; }
public MappingType getMappingType() { // FIXME: Mapping type might be weaker than parent. return parent.getMappingType(); }
public Mapping inverse() { return new OverridingSourceMapping(parent.inverse(), source, target); }
public void set(int source, int target) { parent.set(source, target); }
public int size() { return parent.getTargetOpt(source) >= 0 ? parent.size() : parent.size() + 1; }