001/* 002 * ==================================================================== 003 * 004 * The Apache Software License, Version 1.1 005 * 006 * Copyright (c) 1999-2003 The Apache Software Foundation. All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions are met: 010 * 011 * 1. Redistributions of source code must retain the above copyright notice, 012 * this list of conditions and the following disclaimer. 013 * 014 * 2. Redistributions in binary form must reproduce the above copyright notice, 015 * this list of conditions and the following disclaimer in the documentation 016 * and/or other materials provided with the distribution. 017 * 018 * 3. The end-user documentation included with the redistribution, if any, must 019 * include the following acknowledgement: "This product includes software 020 * developed by the Apache Software Foundation (http://www.apache.org/)." 021 * Alternately, this acknowledgement may appear in the software itself, if and 022 * wherever such third-party acknowledgements normally appear. 023 * 024 * 4. The names "The Jakarta Project", "Commons", and "Apache Software 025 * Foundation" must not be used to endorse or promote products derived from this 026 * software without prior written permission. For written permission, please 027 * contact [email protected]. 028 * 029 * 5. Products derived from this software may not be called "Apache" nor may 030 * "Apache" appear in their names without prior written permission of the Apache 031 * Software Foundation. 032 * 033 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, 034 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 035 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE 036 * SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 037 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 038 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 039 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 040 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 041 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 042 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 043 * ==================================================================== 044 * 045 * This software consists of voluntary contributions made by many individuals on 046 * behalf of the Apache Software Foundation. For more information on the Apache 047 * Software Foundation, please see <http://www.apache.org/>. 048 * 049 */ 050 051package org.apache.wicket.util.diff; 052 053import java.util.ArrayList; 054import java.util.Arrays; 055import java.util.List; 056 057/** 058 * Holds a information about a part of the text involved in a differencing or patching operation. 059 * 060 * @version $Id: Chunk.java,v 1.1 2006/03/12 00:24:21 juanca Exp $ 061 * @author <a href="mailto:[email protected]">Juanco Anez</a> 062 * @see Diff 063 * @see Delta 064 */ 065public class Chunk extends ToString 066{ 067 068 protected int anchor; 069 070 protected int count; 071 072 protected List<Object> chunk; 073 074 /** 075 * Creates a chunk that doesn't copy the original text. 076 * 077 * @param pos 078 * the start position in the text. 079 * @param count 080 * the size of the chunk. 081 */ 082 public Chunk(final int pos, final int count) 083 { 084 anchor = pos; 085 this.count = (count >= 0 ? count : 0); 086 } 087 088 /** 089 * Creates a chunk and saves a copy the original chunk's text. 090 * 091 * @param iseq 092 * the original text. 093 * @param pos 094 * the start position in the text. 095 * @param count 096 * the size of the chunk. 097 */ 098 public Chunk(final Object[] iseq, final int pos, final int count) 099 { 100 this(pos, count); 101 chunk = slice(iseq, pos, count); 102 } 103 104 /** 105 * Creates a chunk that will be displaced in the resulting text, and saves a copy the original 106 * chunk's text. 107 * 108 * @param iseq 109 * the original text. 110 * @param pos 111 * the start position in the text. 112 * @param count 113 * the size of the chunk. 114 * @param offset 115 * the position the chunk should have in the resulting text. 116 */ 117 public Chunk(final Object[] iseq, final int pos, final int count, final int offset) 118 { 119 this(offset, count); 120 chunk = slice(iseq, pos, count); 121 } 122 123 /** 124 * Creates a chunk and saves a copy the original chunk's text. 125 * 126 * @param iseq 127 * the original text. 128 * @param pos 129 * the start position in the text. 130 * @param count 131 * the size of the chunk. 132 */ 133 public Chunk(final List<Object> iseq, final int pos, final int count) 134 { 135 this(pos, count); 136 chunk = slice(iseq, pos, count); 137 } 138 139 /** 140 * Creates a chunk that will be displaced in the resulting text, and saves a copy the original 141 * chunk's text. 142 * 143 * @param iseq 144 * the original text. 145 * @param pos 146 * the start position in the text. 147 * @param count 148 * the size of the chunk. 149 * @param offset 150 * the position the chunk should have in the resulting text. 151 */ 152 public Chunk(final List<Object> iseq, final int pos, final int count, final int offset) 153 { 154 this(offset, count); 155 chunk = slice(iseq, pos, count); 156 } 157 158 /** 159 * Returns the anchor position of the chunk. 160 * 161 * @return the anchor position. 162 */ 163 public int anchor() 164 { 165 return anchor; 166 } 167 168 /** 169 * Returns the size of the chunk. 170 * 171 * @return the size. 172 */ 173 public int size() 174 { 175 return count; 176 } 177 178 /** 179 * Returns the index of the first line of the chunk. 180 * 181 * @return int 182 */ 183 public int first() 184 { 185 return anchor(); 186 } 187 188 /** 189 * Returns the index of the last line of the chunk. 190 * 191 * @return int 192 */ 193 public int last() 194 { 195 return anchor() + size() - 1; 196 } 197 198 /** 199 * Returns the <i>from</i> index of the chunk in RCS terms. 200 * 201 * @return int 202 */ 203 public int rcsfrom() 204 { 205 return anchor + 1; 206 } 207 208 /** 209 * Returns the <i>to</i> index of the chunk in RCS terms. 210 * 211 * @return int 212 */ 213 public int rcsto() 214 { 215 return anchor + count; 216 } 217 218 /** 219 * Returns the text saved for this chunk. 220 * 221 * @return the text. 222 */ 223 public List<Object> chunk() 224 { 225 return chunk; 226 } 227 228 /** 229 * Verifies that this chunk's saved text matches the corresponding text in the given sequence. 230 * 231 * @param target 232 * the sequence to verify against. 233 * @return true if the texts match. 234 */ 235 public boolean verify(final List<Object> target) 236 { 237 if (chunk == null) 238 { 239 return true; 240 } 241 if (last() > target.size()) 242 { 243 return false; 244 } 245 for (int i = 0; i < count; i++) 246 { 247 if (!target.get(anchor + i).equals(chunk.get(i))) 248 { 249 return false; 250 } 251 } 252 return true; 253 } 254 255 /** 256 * Delete this chunk from he given text. 257 * 258 * @param target 259 * the text to delete from. 260 */ 261 public void applyDelete(final List<Object> target) 262 { 263 for (int i = last(); i >= first(); i--) 264 { 265 target.remove(i); 266 } 267 } 268 269 /** 270 * Add the text of this chunk to the target at the given position. 271 * 272 * @param start 273 * where to add the text. 274 * @param target 275 * the text to add to. 276 */ 277 public void applyAdd(int start, final List<Object> target) 278 { 279 for (Object aChunk : chunk) 280 { 281 target.add(start++, aChunk); 282 } 283 } 284 285 /** 286 * Provide a string image of the chunk using the an empty prefix and postfix. 287 * 288 * @param s 289 */ 290 @Override 291 public void toString(final StringBuilder s) 292 { 293 toString(s, "", ""); 294 } 295 296 /** 297 * Provide a string image of the chunk using the given prefix and postfix. 298 * 299 * @param s 300 * where the string image should be appended. 301 * @param prefix 302 * the text that should prefix each line. 303 * @param postfix 304 * the text that should end each line. 305 * @return StringBuilder 306 */ 307 public StringBuilder toString(final StringBuilder s, final String prefix, final String postfix) 308 { 309 if (chunk != null) 310 { 311 for (Object aChunk : chunk) 312 { 313 s.append(prefix); 314 s.append(aChunk); 315 s.append(postfix); 316 } 317 } 318 return s; 319 } 320 321 /** 322 * Retrieves the specified part from a {@link List List}. 323 * 324 * @param <T> 325 * the type of objects contained in <code>seq</code> 326 * 327 * @param seq 328 * the list to retrieve a slice from. 329 * @param pos 330 * the start position. 331 * @param count 332 * the number of items in the slice. 333 * @return a {@link List List} containing the specified items. 334 */ 335 public static <T> List<T> slice(final List<T> seq, final int pos, final int count) 336 { 337 if (count <= 0) 338 { 339 return new ArrayList<>(); 340 } 341 else 342 { 343 return new ArrayList<>(seq.subList(pos, pos + count)); 344 } 345 } 346 347 /** 348 * Retrieves a slice from an {@link Object Object} array. 349 * 350 * @param seq 351 * the list to retrieve a slice from. 352 * @param pos 353 * the start position. 354 * @param count 355 * the number of items in the slice. 356 * @return a {@link List List} containing the specified items. 357 */ 358 public static List<Object> slice(final Object[] seq, final int pos, final int count) 359 { 360 return slice(Arrays.asList(seq), pos, count); 361 } 362 363 /** 364 * Provide a string representation of the numeric range of this chunk. 365 * 366 * @return String 367 */ 368 public String rangeString() 369 { 370 StringBuilder result = new StringBuilder(); 371 rangeString(result); 372 return result.toString(); 373 } 374 375 /** 376 * Provide a string representation of the numeric range of this chunk. 377 * 378 * @param s 379 * where the string representation should be appended. 380 */ 381 public void rangeString(final StringBuilder s) 382 { 383 rangeString(s, ","); 384 } 385 386 /** 387 * Provide a string representation of the numeric range of this chunk. 388 * 389 * @param s 390 * where the string representation should be appended. 391 * @param separ 392 * what to use as line separator. 393 */ 394 public void rangeString(final StringBuilder s, final String separ) 395 { 396 if (size() <= 1) 397 { 398 s.append(Integer.toString(rcsfrom())); 399 } 400 else 401 { 402 s.append(Integer.toString(rcsfrom())); 403 s.append(separ); 404 s.append(Integer.toString(rcsto())); 405 } 406 } 407}