/** * 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; }
/** * 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 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; }
/** * 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 int size() { return parent.getTargetOpt(source) >= 0 ? parent.size() : parent.size() + 1; }