001/* 002 * Copyright (c) 2007-2015 Concurrent, Inc. All Rights Reserved. 003 * 004 * Project and contact information: http://www.cascading.org/ 005 * 006 * This file is part of the Cascading project. 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020 021package cascading.tuple; 022 023import java.beans.ConstructorProperties; 024import java.lang.reflect.Type; 025import java.util.Arrays; 026import java.util.Iterator; 027 028import cascading.tuple.coerce.Coercions; 029import cascading.tuple.type.CoercibleType; 030import cascading.util.ForeverValueIterator; 031 032/** 033 * Class TupleEntry allows a {@link Tuple} instance and its declaring {@link Fields} instance to be used as a single object. 034 * <p/> 035 * Once a TupleEntry is created, its Fields cannot be changed, but the Tuple instance it holds can be replaced or 036 * modified. The managed Tuple should not have elements added or removed, as this will break the relationship with 037 * the associated Fields instance. 038 * <p/> 039 * If type information is provided on the Fields instance, all setters on this class will use that information to 040 * coerce the given object to the expected type. 041 * <p/> 042 * For example, if position is is of type {@code long}, then {@code entry.setString(0, "9" )} will coerce the "9" to a 043 * long {@code 9}. Thus, {@code entry.getObject(0) == 9l}. 044 * <p/> 045 * No coercion is performed with the {@link #getObject(Comparable)} and {@link #getObject(int)} methods. 046 * <p/> 047 * To set a value without coercion, see the {@link #setRaw(Comparable, Object)} and {@link #setRaw(int, Object)} 048 * methods. 049 * 050 * @see Fields 051 * @see Tuple 052 */ 053public class TupleEntry 054 { 055 private static final CoercibleType[] EMPTY_COERCIONS = new CoercibleType[ 0 ]; 056 private static final ForeverValueIterator<CoercibleType> OBJECT_ITERATOR = new ForeverValueIterator<CoercibleType>( Coercions.OBJECT ); 057 058 /** An EMPTY TupleEntry instance for use as a stand in instead of a {@code null}. */ 059 public static final TupleEntry NULL = new TupleEntry( Fields.NONE, Tuple.NULL ); 060 061 /** Field fields */ 062 private Fields fields; 063 064 private CoercibleType[] coercions = EMPTY_COERCIONS; 065 066 /** Field isUnmodifiable */ 067 private boolean isUnmodifiable = false; 068 /** Field tuple */ 069 Tuple tuple; 070 071 /** 072 * Method select will select a new Tuple instance from the given set of entries. Entries order is significant to 073 * the selector. 074 * 075 * @param selector of type Fields 076 * @param entries of type TupleEntry 077 * @return Tuple 078 */ 079 public static Tuple select( Fields selector, TupleEntry... entries ) 080 { 081 // todo: consider just appending tuples values and just peeking those values 082 Tuple result = null; 083 084 // does not do field checks 085 if( selector.isAll() ) 086 { 087 for( TupleEntry entry : entries ) 088 { 089 if( result == null ) 090 result = entry.getTuple(); 091 else 092 result = result.append( entry.getTuple() ); 093 } 094 095 return result; 096 } 097 098 int size = 0; 099 100 for( TupleEntry entry : entries ) 101 size += entry.size(); 102 103 result = Tuple.size( selector.size() ); 104 105 int offset = 0; 106 107 for( TupleEntry entry : entries ) 108 { 109 for( int i = 0; i < selector.size(); i++ ) 110 { 111 Comparable field = selector.get( i ); 112 113 int pos; 114 115 if( field instanceof String ) 116 { 117 pos = entry.fields.indexOfSafe( field ); 118 119 if( pos == -1 ) 120 continue; 121 } 122 else 123 { 124 pos = entry.fields.translatePos( (Integer) field, size ) - offset; 125 126 if( pos >= entry.size() || pos < 0 ) 127 continue; 128 } 129 130 result.set( i, entry.getObject( pos ) ); // last in wins 131 } 132 133 offset += entry.size(); 134 } 135 136 return result; 137 } 138 139 /** Constructor TupleEntry creates a new TupleEntry instance. */ 140 public TupleEntry() 141 { 142 this.fields = Fields.NONE; 143 144 setCoercions(); 145 } 146 147 /** 148 * Constructor TupleEntry creates a new TupleEntry instance. 149 * 150 * @param isUnmodifiable of type boolean 151 */ 152 @ConstructorProperties({"isUnmodifiable"}) 153 public TupleEntry( boolean isUnmodifiable ) 154 { 155 this.fields = Fields.NONE; 156 this.isUnmodifiable = isUnmodifiable; 157 158 setCoercions(); 159 } 160 161 /** 162 * Constructor TupleEntry creates a new TupleEntry instance. 163 * 164 * @param fields of type Fields 165 */ 166 @ConstructorProperties({"fields"}) 167 public TupleEntry( Fields fields ) 168 { 169 this.fields = fields; 170 171 setCoercions(); 172 } 173 174 /** 175 * Constructor TupleEntry creates a new TupleEntry instance. 176 * 177 * @param fields of type Fields 178 * @param isUnmodifiable of type boolean 179 */ 180 @ConstructorProperties({"fields", "isUnmodifiable"}) 181 public TupleEntry( Fields fields, boolean isUnmodifiable ) 182 { 183 this.fields = fields; 184 this.isUnmodifiable = isUnmodifiable; 185 186 setCoercions(); 187 } 188 189 /** 190 * Constructor TupleEntry creates a new TupleEntry instance. 191 * 192 * @param fields of type Fields 193 * @param tuple of type Tuple 194 * @param isUnmodifiable of type boolean 195 */ 196 @ConstructorProperties({"fields", "tuple", "isUnmodifiable"}) 197 public TupleEntry( Fields fields, Tuple tuple, boolean isUnmodifiable ) 198 { 199 this.fields = fields; 200 this.isUnmodifiable = isUnmodifiable; 201 setTuple( tuple ); 202 203 setCoercions(); 204 } 205 206 /** 207 * Constructor TupleEntry creates a new TupleEntry instance. 208 * 209 * @param fields of type Fields 210 * @param tuple of type Tuple 211 */ 212 @ConstructorProperties({"fields", "tuple"}) 213 public TupleEntry( Fields fields, Tuple tuple ) 214 { 215 this.fields = fields; 216 this.tuple = tuple; 217 218 setCoercions(); 219 } 220 221 /** 222 * Constructor TupleEntry creates a new TupleEntry instance that is a safe copy of the given tupleEntry. 223 * <p/> 224 * The new instance is safe to cache and will be modifiable regardless of the given tupleEntry state. 225 * 226 * @param tupleEntry of type TupleEntry 227 */ 228 @ConstructorProperties({"tupleEntry"}) 229 public TupleEntry( TupleEntry tupleEntry ) 230 { 231 this.fields = tupleEntry.getFields(); 232 this.tuple = tupleEntry.getTupleCopy(); 233 234 setCoercions(); 235 } 236 237 /** 238 * Constructor TupleEntry creates a new TupleEntry instance. 239 * 240 * @param tuple of type Tuple 241 */ 242 @ConstructorProperties({"tuple"}) 243 public TupleEntry( Tuple tuple ) 244 { 245 this.fields = Fields.size( tuple.size() ); 246 this.tuple = tuple; 247 248 setCoercions(); 249 } 250 251 private void setCoercions() 252 { 253 if( coercions != EMPTY_COERCIONS ) 254 return; 255 256 coercions = getCoercions( getFields(), tuple ); 257 } 258 259 static CoercibleType[] getCoercions( Fields fields, Tuple tuple ) 260 { 261 Type[] types = fields.types; // safe to not get a copy 262 int size = fields.size(); 263 264 size = size == 0 && tuple != null ? tuple.size() : size; 265 266 if( size == 0 ) 267 return EMPTY_COERCIONS; 268 269 return Coercions.coercibleArray( size, types ); 270 } 271 272 /** 273 * Method isUnmodifiable returns true if this TupleEntry is unmodifiable. 274 * 275 * @return boolean 276 */ 277 public boolean isUnmodifiable() 278 { 279 return isUnmodifiable; 280 } 281 282 /** 283 * Method getFields returns the fields of this TupleEntry object. 284 * 285 * @return the fields (type Fields) of this TupleEntry object. 286 */ 287 public Fields getFields() 288 { 289 return fields; 290 } 291 292 /** 293 * Returns true if there are types associated with this instance. 294 * 295 * @return boolean 296 */ 297 public boolean hasTypes() 298 { 299 return fields.hasTypes(); 300 } 301 302 /** 303 * Method getTuple returns the tuple of this TupleEntry object. 304 * 305 * @return the tuple (type Tuple) of this TupleEntry object. 306 */ 307 public Tuple getTuple() 308 { 309 return tuple; 310 } 311 312 /** 313 * Method getTupleCopy returns a copy of the tuple of this TupleEntry object. 314 * 315 * @return a copy of the tuple (type Tuple) of this TupleEntry object. 316 */ 317 public Tuple getTupleCopy() 318 { 319 return new Tuple( tuple ); 320 } 321 322 /** 323 * Method getCoercedTuple is a helper method for copying the current tuple elements into a new Tuple, 324 * of the same size, as the requested coerced types. 325 * 326 * @param types of type Type[] 327 * @return returns the a new Tuple instance with coerced values 328 */ 329 public Tuple getCoercedTuple( Type[] types ) 330 { 331 return getCoercedTuple( types, Tuple.size( types.length ) ); 332 } 333 334 /** 335 * Method getCoercedTuple is a helper method for copying the current tuple elements into the new Tuple, 336 * of the same size, as the requested coerced types. 337 * 338 * @param types of type Type[] 339 * @param into of type Tuple 340 * @return returns the given into Tuple instance with coerced values 341 */ 342 public Tuple getCoercedTuple( Type[] types, Tuple into ) 343 { 344 if( into == null ) 345 throw new IllegalArgumentException( "into argument Tuple may not be null" ); 346 347 if( coercions.length != types.length || types.length != into.size() ) 348 throw new IllegalArgumentException( "current entry and given tuple and types must be same length" ); 349 350 for( int i = 0; i < coercions.length; i++ ) 351 { 352 Object element = tuple.getObject( i ); 353 into.set( i, Coercions.coerce( coercions[ i ], element, types[ i ] ) ); 354 } 355 356 return into; 357 } 358 359 /** 360 * Method setTuple sets the tuple of this TupleEntry object, no copy will be performed. 361 * <p/> 362 * If the given tuple is "unmodifiable" ({@code Tuple.isUnmodifiable() == true}) and this TupleEntry is 363 * not "unmodifiable", an exception will be thrown. 364 * <p/> 365 * Unmodifiable tuples are generally owned by the system and cannot be be changed and must not be cached. 366 * 367 * @param tuple the tuple of this TupleEntry object. 368 */ 369 public void setTuple( Tuple tuple ) 370 { 371 if( !isUnmodifiable && tuple != null && tuple.isUnmodifiable() ) 372 throw new IllegalArgumentException( "current entry is modifiable but given tuple is not modifiable, make copy of given Tuple first" ); 373 374 if( tuple != null && isUnmodifiable ) 375 this.tuple = Tuples.asUnmodifiable( tuple ); 376 else 377 this.tuple = tuple; 378 379 setCoercions(); 380 } 381 382 /** 383 * Method setCanonicalTuple replaces each value of the current tuple with the given tuple elements after 384 * they are coerced. 385 * <p/> 386 * This method will modify the existing Tuple wrapped by this TupleEntry instance even 387 * if it is marked as unmodifiable. 388 * <p/> 389 * If tuple argument is {@code null}, the current tuple will be set to {@code null}. 390 * 391 * @param tuple to replace the current wrapped Tuple instance 392 */ 393 public void setCanonicalTuple( Tuple tuple ) 394 { 395 if( tuple == null ) 396 { 397 this.tuple = null; 398 return; 399 } 400 401 if( isUnmodifiable ) 402 tuple = Tuples.asUnmodifiable( tuple ); 403 404 if( fields.size() != tuple.size() ) 405 throw new IllegalArgumentException( "current entry and given tuple must be same length" ); 406 407 for( int i = 0; i < coercions.length; i++ ) 408 { 409 Object element = tuple.getObject( i ); 410 411 this.tuple.set( i, coercions[ i ].canonical( element ) ); // force read type to the expected type 412 } 413 } 414 415 /** 416 * Method setCanonicalValues replaces each value of the current tuple with th give Object[] 417 * after they are coerced. 418 * 419 * @param values to replace the current wrapped tuple instance values 420 */ 421 public void setCanonicalValues( Object[] values ) 422 { 423 if( fields.size() != values.length ) 424 throw new IllegalArgumentException( "current entry and given array must be same length" ); 425 426 for( int i = 0; i < coercions.length; i++ ) 427 { 428 Object element = values[ i ]; 429 430 this.tuple.set( i, coercions[ i ].canonical( element ) ); // force read type to the expected type 431 } 432 } 433 434 /** 435 * Method size returns the number of values in this instance. 436 * 437 * @return int 438 */ 439 public int size() 440 { 441 return tuple.size(); 442 } 443 444 /** 445 * Method getObject returns the value in the given position pos. 446 * <p/> 447 * No coercion is performed if there is an associated coercible type. 448 * 449 * @param pos position of the element to return. 450 * @return Object 451 */ 452 public Object getObject( int pos ) 453 { 454 return tuple.getObject( pos ); 455 } 456 457 /** 458 * Method getObject returns the value in the given field or position as the requested type. 459 * <p/> 460 * Coercion is performed to the given type. 461 * 462 * @param pos position of the element to return. 463 * @return Object 464 */ 465 public Object getObject( int pos, Type type ) 466 { 467 return Coercions.coerce( coercions[ pos ], tuple.getObject( pos ), type ); 468 } 469 470 /** 471 * Method getObject returns the value in the given field or position. 472 * <br/> 473 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 474 * be considered. 475 * <p/> 476 * No coercion is performed if there is an associated coercible type. 477 * 478 * @param fieldName field name or position to return 479 * @return Comparable 480 */ 481 public Object getObject( Comparable fieldName ) 482 { 483 int pos = fields.getPos( asFieldName( fieldName ) ); 484 return tuple.getObject( pos ); 485 } 486 487 /** 488 * Method getObject returns the value in the given field or position as the requested type. 489 * <br/> 490 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 491 * be considered. 492 * <p/> 493 * Coercion is performed to the given type. 494 * 495 * @param fieldName field name or position to return 496 * @return Comparable 497 */ 498 public Object getObject( Comparable fieldName, Type type ) 499 { 500 int pos = fields.getPos( asFieldName( fieldName ) ); 501 return Coercions.coerce( coercions[ pos ], tuple.getObject( pos ), type ); 502 } 503 504 /** 505 * Method set sets the value in the given position. 506 * <p/> 507 * No coercion is performed if there is an associated coercible type. 508 * 509 * @param pos position to set 510 * @param value of type Comparable 511 */ 512 public void setRaw( int pos, Object value ) 513 { 514 tuple.set( pos, value ); 515 } 516 517 /** 518 * Method set sets the value in the given field or position. 519 * <p/> 520 * No coercion is performed if there is an associated coercible type. 521 * 522 * @param fieldName field name or position to set 523 * @param value of type Comparable 524 */ 525 public void setRaw( Comparable fieldName, Object value ) 526 { 527 tuple.set( fields.getPos( asFieldName( fieldName ) ), value ); 528 } 529 530 /** 531 * Method set sets the value in the given field or position. 532 * 533 * @param fieldName field name or position to set 534 * @param value of type Comparable 535 */ 536 public void setObject( Comparable fieldName, Object value ) 537 { 538 int pos = fields.getPos( asFieldName( fieldName ) ); 539 540 tuple.set( pos, coercions[ pos ].canonical( value ) ); 541 } 542 543 /** 544 * Method setBoolean sets the value in the given field or position. 545 * 546 * @param fieldName field name or position to set 547 * @param value of type boolean 548 */ 549 public void setBoolean( Comparable fieldName, boolean value ) 550 { 551 int pos = fields.getPos( asFieldName( fieldName ) ); 552 553 tuple.set( pos, coercions[ pos ].canonical( value ) ); 554 } 555 556 /** 557 * Method setShort sets the value in the given field or position. 558 * 559 * @param fieldName field name or position to set 560 * @param value of type short 561 */ 562 public void setShort( Comparable fieldName, short value ) 563 { 564 int pos = fields.getPos( asFieldName( fieldName ) ); 565 566 tuple.set( pos, coercions[ pos ].canonical( value ) ); 567 } 568 569 /** 570 * Method setInteger sets the value in the given field or position. 571 * 572 * @param fieldName field name or position to set 573 * @param value of type int 574 */ 575 public void setInteger( Comparable fieldName, int value ) 576 { 577 int pos = fields.getPos( asFieldName( fieldName ) ); 578 579 tuple.set( pos, coercions[ pos ].canonical( value ) ); 580 } 581 582 /** 583 * Method setLong sets the value in the given field or position. 584 * 585 * @param fieldName field name or position to set 586 * @param value of type long 587 */ 588 public void setLong( Comparable fieldName, long value ) 589 { 590 int pos = fields.getPos( asFieldName( fieldName ) ); 591 592 tuple.set( pos, coercions[ pos ].canonical( value ) ); 593 } 594 595 /** 596 * Method setFloat sets the value in the given field or position. 597 * 598 * @param fieldName field name or position to set 599 * @param value of type float 600 */ 601 public void setFloat( Comparable fieldName, float value ) 602 { 603 int pos = fields.getPos( asFieldName( fieldName ) ); 604 605 tuple.set( pos, coercions[ pos ].canonical( value ) ); 606 } 607 608 /** 609 * Method setDouble sets the value in the given field or position. 610 * 611 * @param fieldName field name or position to set 612 * @param value of type double 613 */ 614 public void setDouble( Comparable fieldName, double value ) 615 { 616 int pos = fields.getPos( asFieldName( fieldName ) ); 617 618 tuple.set( pos, coercions[ pos ].canonical( value ) ); 619 } 620 621 /** 622 * Method setString sets the value in the given field or position. 623 * 624 * @param fieldName field name or position to set 625 * @param value of type String 626 */ 627 public void setString( Comparable fieldName, String value ) 628 { 629 int pos = fields.getPos( asFieldName( fieldName ) ); 630 tuple.set( pos, coercions[ pos ].canonical( value ) ); 631 } 632 633 /** 634 * Method getString returns the element for the given field name or position as a String. 635 * <br/> 636 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 637 * be considered. 638 * 639 * @param fieldName field name or position to return 640 * @return String 641 */ 642 public String getString( Comparable fieldName ) 643 { 644 return (String) getObject( fieldName, String.class ); 645 } 646 647 /** 648 * Method getFloat returns the element for the given field name or position as a float. Zero if null. 649 * <br/> 650 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 651 * be considered. 652 * 653 * @param fieldName field name or position to return 654 * @return float 655 */ 656 public float getFloat( Comparable fieldName ) 657 { 658 return (Float) getObject( fieldName, float.class ); 659 } 660 661 /** 662 * Method getDouble returns the element for the given field name or position as a double. Zero if null. 663 * <br/> 664 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 665 * be considered. 666 * 667 * @param fieldName field name or position to return 668 * @return double 669 */ 670 public double getDouble( Comparable fieldName ) 671 { 672 return (Double) getObject( fieldName, double.class ); 673 } 674 675 /** 676 * Method getInteger returns the element for the given field name or position as an int. Zero if null. 677 * <br/> 678 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 679 * be considered. 680 * 681 * @param fieldName field name or position to return 682 * @return int 683 */ 684 public int getInteger( Comparable fieldName ) 685 { 686 return (Integer) getObject( fieldName, int.class ); 687 } 688 689 /** 690 * Method getLong returns the element for the given field name or position as a long. Zero if null. 691 * <br/> 692 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 693 * be considered. 694 * 695 * @param fieldName field name or position to return 696 * @return long 697 */ 698 public long getLong( Comparable fieldName ) 699 { 700 return (Long) getObject( fieldName, long.class ); 701 } 702 703 /** 704 * Method getShort returns the element for the given field name or position as a short. Zero if null. 705 * <br/> 706 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 707 * be considered. 708 * 709 * @param fieldName field name or position to return 710 * @return short 711 */ 712 public short getShort( Comparable fieldName ) 713 { 714 return (Short) getObject( fieldName, short.class ); 715 } 716 717 /** 718 * Method getBoolean returns the element for the given field name or position as a boolean. 719 * If the value is (case ignored) the string 'true', a {@code true} value will be returned. {@code false} if null. 720 * <br/> 721 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 722 * be considered. 723 * 724 * @param fieldName field name or position to return 725 * @return boolean 726 */ 727 public boolean getBoolean( Comparable fieldName ) 728 { 729 return (Boolean) getObject( fieldName, boolean.class ); 730 } 731 732 private Comparable asFieldName( Comparable fieldName ) 733 { 734 return Fields.asFieldName( fieldName ); 735 } 736 737 /** 738 * Method selectEntry selects the fields specified in the selector from this instance. If {@link Fields#ALL} or the 739 * same fields as declared are given, {@code this} will be returned. 740 * <p/> 741 * The returned TupleEntry will be either modifiable or unmodifiable, depending on the state of this TupleEntry instance. 742 * <p/> 743 * See {@link #selectEntryCopy(Fields)} to guarantee a copy suitable for modifying or caching/storing in a collection. 744 * <p/> 745 * Note this is a bug fix and change from 2.0 and 2.1. In previous versions the modifiable state was dependent 746 * on the given selector. 747 * 748 * @param selector Fields selector that selects the values to return 749 * @return TupleEntry 750 */ 751 public TupleEntry selectEntry( Fields selector ) 752 { 753 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 754 return this; 755 756 if( selector.isNone() ) 757 return isUnmodifiable ? TupleEntry.NULL : new TupleEntry(); 758 759 return new TupleEntry( Fields.asDeclaration( selector ), tuple.get( this.fields, selector ), isUnmodifiable ); 760 } 761 762 /** 763 * Method selectEntry selects the fields specified in selector from this instance. 764 * <p/> 765 * It is guaranteed to return a new modifiable TupleEntry instance at a cost of copying data. 766 * <p/> 767 * The returned instance is safe to cache. 768 * 769 * @param selector Fields selector that selects the values to return 770 * @return TupleEntry 771 */ 772 public TupleEntry selectEntryCopy( Fields selector ) 773 { 774 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 775 return new TupleEntry( this ); 776 777 if( selector.isNone() ) 778 return new TupleEntry(); 779 780 return new TupleEntry( Fields.asDeclaration( selector ), tuple.get( this.fields, selector ) ); 781 } 782 783 /** 784 * Method selectTuple selects the fields specified in the selector from this instance. If {@link Fields#ALL} or the 785 * same fields as declared are given, {@code this.getTuple()} will be returned. 786 * <p/> 787 * The returned Tuple will be either modifiable or unmodifiable, depending on the state of this TupleEntry instance. 788 * <p/> 789 * See {@link #selectTupleCopy(Fields)} to guarantee a copy suitable for modifying or caching/storing in a collection. 790 * <p/> 791 * Note this is a bug fix and change from 2.0 and 2.1. In previous versions the modifiable state was dependent 792 * on the given selector. 793 * 794 * @param selector Fields selector that selects the values to return 795 * @return Tuple 796 */ 797 public Tuple selectTuple( Fields selector ) 798 { 799 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 800 return this.tuple; 801 802 if( selector.isNone() ) 803 return Tuple.NULL; 804 805 Tuple result = tuple.get( fields, selector ); 806 807 if( isUnmodifiable ) 808 Tuples.asUnmodifiable( result ); 809 810 return result; 811 } 812 813 /** 814 * Method selectTupleCopy selects the fields specified in selector from this instance. 815 * <p/> 816 * It is guaranteed to return a new modifiable Tuple instance at a cost of copying data. 817 * <p/> 818 * The returned instance is safe to cache. 819 * 820 * @param selector Fields selector that selects the values to return 821 * @return Tuple 822 */ 823 public Tuple selectTupleCopy( Fields selector ) 824 { 825 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 826 return new Tuple( this.tuple ); 827 828 if( selector.isNone() ) 829 return new Tuple(); 830 831 return tuple.get( fields, selector ); 832 } 833 834 /** 835 * Method selectInto selects the fields specified in the selector from this instance and copies 836 * them into the given tuple argument. 837 * 838 * @param selector of type Fields 839 * @param tuple of type Tuple 840 * @return returns the given tuple argument with new values added 841 */ 842 public Tuple selectInto( Fields selector, Tuple tuple ) 843 { 844 if( selector.isNone() ) 845 return tuple; 846 847 int[] pos = this.tuple.getPos( fields, selector ); 848 849 if( pos == null || pos.length == 0 ) 850 { 851 tuple.addAll( this.tuple ); 852 } 853 else 854 { 855 for( int i : pos ) 856 tuple.add( this.tuple.getObject( i ) ); 857 } 858 859 return tuple; 860 } 861 862 /** 863 * Method setTuple sets the values specified by the selector to the values given by the given tuple, the given 864 * values will always be copied into this TupleEntry. 865 * 866 * @param selector of type Fields 867 * @param tuple of type Tuple 868 */ 869 public void setTuple( Fields selector, Tuple tuple ) 870 { 871 if( selector == null || selector.isAll() ) 872 this.tuple.setAll( tuple ); 873 else 874 this.tuple.set( fields, selector, tuple ); 875 } 876 877 /** 878 * Method set sets the values from the given tupleEntry into this TupleEntry instance based on the given 879 * tupleEntry field names. 880 * <p/> 881 * If type information is given, each incoming value will be coerced from its canonical type to the current type. 882 * 883 * @param tupleEntry of type TupleEntry 884 */ 885 public void set( TupleEntry tupleEntry ) 886 { 887 this.tuple.set( fields, tupleEntry.getFields(), tupleEntry.getTuple(), tupleEntry.coercions ); 888 } 889 890 /** 891 * Method appendNew appends the given TupleEntry instance to this instance. 892 * 893 * @param entry of type TupleEntry 894 * @return TupleEntry 895 */ 896 public TupleEntry appendNew( TupleEntry entry ) 897 { 898 Fields appendedFields = fields.append( entry.fields.isUnknown() ? Fields.size( entry.tuple.size() ) : entry.fields ); 899 Tuple appendedTuple = tuple.append( entry.tuple ); 900 901 return new TupleEntry( appendedFields, appendedTuple ); 902 } 903 904 @Override 905 public boolean equals( Object object ) 906 { 907 if( this == object ) 908 return true; 909 910 if( !( object instanceof TupleEntry ) ) 911 return false; 912 913 TupleEntry that = (TupleEntry) object; 914 915 if( fields != null ? !fields.equals( that.fields ) : that.fields != null ) 916 return false; 917 918 // use comparators if in the this side fields instance 919 if( tuple != null ? fields.compare( tuple, that.tuple ) != 0 : that.tuple != null ) 920 return false; 921 922 return true; 923 } 924 925 @Override 926 public int hashCode() 927 { 928 int result = fields != null ? fields.hashCode() : 0; 929 result = 31 * result + ( tuple != null ? tuple.hashCode() : 0 ); 930 return result; 931 } 932 933 @Override 934 public String toString() 935 { 936 if( fields == null ) 937 return "empty"; 938 else if( tuple == null ) 939 return "fields: " + fields.print(); 940 else 941 return "fields: " + fields.print() + " tuple: " + tuple.print(); 942 } 943 944 /** 945 * Method asIterableOf returns an {@link Iterable} instance that will coerce all Tuple elements 946 * into the given {@code type} parameter. 947 * <p/> 948 * This method honors any {@link cascading.tuple.type.CoercibleType} instances on the internal 949 * Fields instance for the specified Tuple element. 950 * 951 * @param type of type Class 952 * @return an Iterable 953 */ 954 public <T> Iterable<T> asIterableOf( final Class<T> type ) 955 { 956 return new Iterable<T>() 957 { 958 @Override 959 public Iterator<T> iterator() 960 { 961 final Iterator<CoercibleType> coercibleIterator = coercions.length == 0 ? 962 OBJECT_ITERATOR : 963 Arrays.asList( coercions ).iterator(); 964 965 final Iterator valuesIterator = tuple.iterator(); 966 967 return new Iterator<T>() 968 { 969 @Override 970 public boolean hasNext() 971 { 972 return valuesIterator.hasNext(); 973 } 974 975 @Override 976 public T next() 977 { 978 Object next = valuesIterator.next(); 979 980 return (T) coercibleIterator.next().coerce( next, type ); 981 } 982 983 @Override 984 public void remove() 985 { 986 valuesIterator.remove(); 987 } 988 }; 989 } 990 }; 991 } 992 }