Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                        Intel License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of Intel Corporation may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 //M*/
     41 #include "_cxcore.h"
     42 
     43 #define ICV_FREE_PTR(storage)  \
     44     ((schar*)(storage)->top + (storage)->block_size - (storage)->free_space)
     45 
     46 #define ICV_ALIGNED_SEQ_BLOCK_SIZE  \
     47     (int)cvAlign(sizeof(CvSeqBlock), CV_STRUCT_ALIGN)
     48 
     49 CV_INLINE int
     50 cvAlignLeft( int size, int align )
     51 {
     52     return size & -align;
     53 }
     54 
     55 #define CV_GET_LAST_ELEM( seq, block ) \
     56     ((block)->data + ((block)->count - 1)*((seq)->elem_size))
     57 
     58 #define CV_SWAP_ELEMS(a,b,elem_size)  \
     59 {                                     \
     60     int k;                            \
     61     for( k = 0; k < elem_size; k++ )  \
     62     {                                 \
     63         char t0 = (a)[k];             \
     64         char t1 = (b)[k];             \
     65         (a)[k] = t1;                  \
     66         (b)[k] = t0;                  \
     67     }                                 \
     68 }
     69 
     70 #define ICV_SHIFT_TAB_MAX 32
     71 static const schar icvPower2ShiftTab[] =
     72 {
     73     0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
     74     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5
     75 };
     76 
     77 /****************************************************************************************\
     78 *            Functions for manipulating memory storage - list of memory blocks           *
     79 \****************************************************************************************/
     80 
     81 /* Initialize allocated storage: */
     82 static void
     83 icvInitMemStorage( CvMemStorage* storage, int block_size )
     84 {
     85     CV_FUNCNAME( "icvInitMemStorage " );
     86 
     87     __BEGIN__;
     88 
     89     if( !storage )
     90         CV_ERROR( CV_StsNullPtr, "" );
     91 
     92     if( block_size <= 0 )
     93         block_size = CV_STORAGE_BLOCK_SIZE;
     94 
     95     block_size = cvAlign( block_size, CV_STRUCT_ALIGN );
     96     assert( sizeof(CvMemBlock) % CV_STRUCT_ALIGN == 0 );
     97 
     98     memset( storage, 0, sizeof( *storage ));
     99     storage->signature = CV_STORAGE_MAGIC_VAL;
    100     storage->block_size = block_size;
    101 
    102     __END__;
    103 }
    104 
    105 
    106 /* Create root memory storage: */
    107 CV_IMPL CvMemStorage*
    108 cvCreateMemStorage( int block_size )
    109 {
    110     CvMemStorage *storage = 0;
    111 
    112     CV_FUNCNAME( "cvCreateMemStorage" );
    113 
    114     __BEGIN__;
    115 
    116     CV_CALL( storage = (CvMemStorage *)cvAlloc( sizeof( CvMemStorage )));
    117     CV_CALL( icvInitMemStorage( storage, block_size ));
    118 
    119     __END__;
    120 
    121     if( cvGetErrStatus() < 0 )
    122         cvFree( &storage );
    123 
    124     return storage;
    125 }
    126 
    127 
    128 /* Create child memory storage: */
    129 CV_IMPL CvMemStorage *
    130 cvCreateChildMemStorage( CvMemStorage * parent )
    131 {
    132     CvMemStorage *storage = 0;
    133     CV_FUNCNAME( "cvCreateChildMemStorage" );
    134 
    135     __BEGIN__;
    136 
    137     if( !parent )
    138         CV_ERROR( CV_StsNullPtr, "" );
    139 
    140     CV_CALL( storage = cvCreateMemStorage(parent->block_size));
    141     storage->parent = parent;
    142 
    143     __END__;
    144 
    145     if( cvGetErrStatus() < 0 )
    146         cvFree( &storage );
    147 
    148     return storage;
    149 }
    150 
    151 
    152 /* Release all blocks of the storage (or return them to parent, if any): */
    153 static void
    154 icvDestroyMemStorage( CvMemStorage* storage )
    155 {
    156     CV_FUNCNAME( "icvDestroyMemStorage" );
    157 
    158     __BEGIN__;
    159 
    160     int k = 0;
    161 
    162     CvMemBlock *block;
    163     CvMemBlock *dst_top = 0;
    164 
    165     if( !storage )
    166         CV_ERROR( CV_StsNullPtr, "" );
    167 
    168     if( storage->parent )
    169         dst_top = storage->parent->top;
    170 
    171     for( block = storage->bottom; block != 0; k++ )
    172     {
    173         CvMemBlock *temp = block;
    174 
    175         block = block->next;
    176         if( storage->parent )
    177         {
    178             if( dst_top )
    179             {
    180                 temp->prev = dst_top;
    181                 temp->next = dst_top->next;
    182                 if( temp->next )
    183                     temp->next->prev = temp;
    184                 dst_top = dst_top->next = temp;
    185             }
    186             else
    187             {
    188                 dst_top = storage->parent->bottom = storage->parent->top = temp;
    189                 temp->prev = temp->next = 0;
    190                 storage->free_space = storage->block_size - sizeof( *temp );
    191             }
    192         }
    193         else
    194         {
    195             cvFree( &temp );
    196         }
    197     }
    198 
    199     storage->top = storage->bottom = 0;
    200     storage->free_space = 0;
    201 
    202     __END__;
    203 }
    204 
    205 
    206 /* Release memory storage: */
    207 CV_IMPL void
    208 cvReleaseMemStorage( CvMemStorage** storage )
    209 {
    210     CvMemStorage *st;
    211     CV_FUNCNAME( "cvReleaseMemStorage" );
    212 
    213     __BEGIN__;
    214 
    215     if( !storage )
    216         CV_ERROR( CV_StsNullPtr, "" );
    217 
    218     st = *storage;
    219     *storage = 0;
    220 
    221     if( st )
    222     {
    223         CV_CALL( icvDestroyMemStorage( st ));
    224         cvFree( &st );
    225     }
    226 
    227     __END__;
    228 }
    229 
    230 
    231 /* Clears memory storage (return blocks to the parent, if any): */
    232 CV_IMPL void
    233 cvClearMemStorage( CvMemStorage * storage )
    234 {
    235     CV_FUNCNAME( "cvClearMemStorage" );
    236 
    237     __BEGIN__;
    238 
    239     if( !storage )
    240         CV_ERROR( CV_StsNullPtr, "" );
    241 
    242     if( storage->parent )
    243     {
    244         icvDestroyMemStorage( storage );
    245     }
    246     else
    247     {
    248         storage->top = storage->bottom;
    249         storage->free_space = storage->bottom ? storage->block_size - sizeof(CvMemBlock) : 0;
    250     }
    251 
    252     __END__;
    253 }
    254 
    255 
    256 /* Moves stack pointer to next block.
    257    If no blocks, allocate new one and link it to the storage: */
    258 static void
    259 icvGoNextMemBlock( CvMemStorage * storage )
    260 {
    261     CV_FUNCNAME( "icvGoNextMemBlock" );
    262 
    263     __BEGIN__;
    264 
    265     if( !storage )
    266         CV_ERROR( CV_StsNullPtr, "" );
    267 
    268     if( !storage->top || !storage->top->next )
    269     {
    270         CvMemBlock *block;
    271 
    272         if( !(storage->parent) )
    273         {
    274             CV_CALL( block = (CvMemBlock *)cvAlloc( storage->block_size ));
    275         }
    276         else
    277         {
    278             CvMemStorage *parent = storage->parent;
    279             CvMemStoragePos parent_pos;
    280 
    281             cvSaveMemStoragePos( parent, &parent_pos );
    282             CV_CALL( icvGoNextMemBlock( parent ));
    283 
    284             block = parent->top;
    285             cvRestoreMemStoragePos( parent, &parent_pos );
    286 
    287             if( block == parent->top )  /* the single allocated block */
    288             {
    289                 assert( parent->bottom == block );
    290                 parent->top = parent->bottom = 0;
    291                 parent->free_space = 0;
    292             }
    293             else
    294             {
    295                 /* cut the block from the parent's list of blocks */
    296                 parent->top->next = block->next;
    297                 if( block->next )
    298                     block->next->prev = parent->top;
    299             }
    300         }
    301 
    302         /* link block */
    303         block->next = 0;
    304         block->prev = storage->top;
    305 
    306         if( storage->top )
    307             storage->top->next = block;
    308         else
    309             storage->top = storage->bottom = block;
    310     }
    311 
    312     if( storage->top->next )
    313         storage->top = storage->top->next;
    314     storage->free_space = storage->block_size - sizeof(CvMemBlock);
    315     assert( storage->free_space % CV_STRUCT_ALIGN == 0 );
    316 
    317     __END__;
    318 }
    319 
    320 
    321 /* Remember memory storage position: */
    322 CV_IMPL void
    323 cvSaveMemStoragePos( const CvMemStorage * storage, CvMemStoragePos * pos )
    324 {
    325     CV_FUNCNAME( "cvSaveMemStoragePos" );
    326 
    327     __BEGIN__;
    328 
    329     if( !storage || !pos )
    330         CV_ERROR( CV_StsNullPtr, "" );
    331 
    332     pos->top = storage->top;
    333     pos->free_space = storage->free_space;
    334 
    335     __END__;
    336 }
    337 
    338 
    339 /* Restore memory storage position: */
    340 CV_IMPL void
    341 cvRestoreMemStoragePos( CvMemStorage * storage, CvMemStoragePos * pos )
    342 {
    343     CV_FUNCNAME( "cvRestoreMemStoragePos" );
    344 
    345     __BEGIN__;
    346 
    347     if( !storage || !pos )
    348         CV_ERROR( CV_StsNullPtr, "" );
    349     if( pos->free_space > storage->block_size )
    350         CV_ERROR( CV_StsBadSize, "" );
    351 
    352     /*
    353     // this breaks icvGoNextMemBlock, so comment it off for now
    354     if( storage->parent && (!pos->top || pos->top->next) )
    355     {
    356         CvMemBlock* save_bottom;
    357         if( !pos->top )
    358             save_bottom = 0;
    359         else
    360         {
    361             save_bottom = storage->bottom;
    362             storage->bottom = pos->top->next;
    363             pos->top->next = 0;
    364             storage->bottom->prev = 0;
    365         }
    366         icvDestroyMemStorage( storage );
    367         storage->bottom = save_bottom;
    368     }*/
    369 
    370     storage->top = pos->top;
    371     storage->free_space = pos->free_space;
    372 
    373     if( !storage->top )
    374     {
    375         storage->top = storage->bottom;
    376         storage->free_space = storage->top ? storage->block_size - sizeof(CvMemBlock) : 0;
    377     }
    378 
    379     __END__;
    380 }
    381 
    382 
    383 /* Allocate continuous buffer of the specified size in the storage: */
    384 CV_IMPL void*
    385 cvMemStorageAlloc( CvMemStorage* storage, size_t size )
    386 {
    387     schar *ptr = 0;
    388 
    389     CV_FUNCNAME( "cvMemStorageAlloc" );
    390 
    391     __BEGIN__;
    392 
    393     if( !storage )
    394         CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
    395 
    396     if( size > INT_MAX )
    397         CV_ERROR( CV_StsOutOfRange, "Too large memory block is requested" );
    398 
    399     assert( storage->free_space % CV_STRUCT_ALIGN == 0 );
    400 
    401     if( (size_t)storage->free_space < size )
    402     {
    403         size_t max_free_space = cvAlignLeft(storage->block_size - sizeof(CvMemBlock), CV_STRUCT_ALIGN);
    404         if( max_free_space < size )
    405             CV_ERROR( CV_StsOutOfRange, "requested size is negative or too big" );
    406 
    407         CV_CALL( icvGoNextMemBlock( storage ));
    408     }
    409 
    410     ptr = ICV_FREE_PTR(storage);
    411     assert( (size_t)ptr % CV_STRUCT_ALIGN == 0 );
    412     storage->free_space = cvAlignLeft(storage->free_space - (int)size, CV_STRUCT_ALIGN );
    413 
    414     __END__;
    415 
    416     return ptr;
    417 }
    418 
    419 
    420 CV_IMPL CvString
    421 cvMemStorageAllocString( CvMemStorage* storage, const char* ptr, int len )
    422 {
    423     CvString str;
    424     CV_FUNCNAME( "cvMemStorageAllocString" );
    425 
    426     __BEGIN__;
    427 
    428     str.len = len >= 0 ? len : (int)strlen(ptr);
    429     CV_CALL( str.ptr = (char*)cvMemStorageAlloc( storage, str.len + 1 ));
    430     memcpy( str.ptr, ptr, str.len );
    431     str.ptr[str.len] = '\0';
    432 
    433     __END__;
    434 
    435     return str;
    436 }
    437 
    438 
    439 /****************************************************************************************\
    440 *                               Sequence implementation                                  *
    441 \****************************************************************************************/
    442 
    443 /* Create empty sequence: */
    444 CV_IMPL CvSeq *
    445 cvCreateSeq( int seq_flags, int header_size, int elem_size, CvMemStorage * storage )
    446 {
    447     CvSeq *seq = 0;
    448 
    449     CV_FUNCNAME( "cvCreateSeq" );
    450 
    451     __BEGIN__;
    452 
    453     if( !storage )
    454         CV_ERROR( CV_StsNullPtr, "" );
    455     if( header_size < (int)sizeof( CvSeq ) || elem_size <= 0 )
    456         CV_ERROR( CV_StsBadSize, "" );
    457 
    458     /* allocate sequence header */
    459     CV_CALL( seq = (CvSeq*)cvMemStorageAlloc( storage, header_size ));
    460     memset( seq, 0, header_size );
    461 
    462     seq->header_size = header_size;
    463     seq->flags = (seq_flags & ~CV_MAGIC_MASK) | CV_SEQ_MAGIC_VAL;
    464     {
    465         int elemtype = CV_MAT_TYPE(seq_flags);
    466         int typesize = CV_ELEM_SIZE(elemtype);
    467 
    468         if( elemtype != CV_SEQ_ELTYPE_GENERIC &&
    469             typesize != 0 && typesize != elem_size )
    470             CV_ERROR( CV_StsBadSize,
    471             "Specified element size doesn't match to the size of the specified element type "
    472             "(try to use 0 for element type)" );
    473     }
    474     seq->elem_size = elem_size;
    475     seq->storage = storage;
    476 
    477     CV_CALL( cvSetSeqBlockSize( seq, (1 << 10)/elem_size ));
    478 
    479     __END__;
    480 
    481     return seq;
    482 }
    483 
    484 
    485 /* adjusts <delta_elems> field of sequence. It determines how much the sequence
    486    grows if there are no free space inside the sequence buffers */
    487 CV_IMPL void
    488 cvSetSeqBlockSize( CvSeq *seq, int delta_elements )
    489 {
    490     int elem_size;
    491     int useful_block_size;
    492 
    493     CV_FUNCNAME( "cvSetSeqBlockSize" );
    494 
    495     __BEGIN__;
    496 
    497     if( !seq || !seq->storage )
    498         CV_ERROR( CV_StsNullPtr, "" );
    499     if( delta_elements < 0 )
    500         CV_ERROR( CV_StsOutOfRange, "" );
    501 
    502     useful_block_size = cvAlignLeft(seq->storage->block_size - sizeof(CvMemBlock) -
    503                                     sizeof(CvSeqBlock), CV_STRUCT_ALIGN);
    504     elem_size = seq->elem_size;
    505 
    506     if( delta_elements == 0 )
    507     {
    508         delta_elements = (1 << 10) / elem_size;
    509         delta_elements = MAX( delta_elements, 1 );
    510     }
    511     if( delta_elements * elem_size > useful_block_size )
    512     {
    513         delta_elements = useful_block_size / elem_size;
    514         if( delta_elements == 0 )
    515             CV_ERROR( CV_StsOutOfRange, "Storage block size is too small "
    516                                         "to fit the sequence elements" );
    517     }
    518 
    519     seq->delta_elems = delta_elements;
    520 
    521     __END__;
    522 }
    523 
    524 
    525 /* Find a sequence element by its index: */
    526 CV_IMPL schar*
    527 cvGetSeqElem( const CvSeq *seq, int index )
    528 {
    529     CvSeqBlock *block;
    530     int count, total = seq->total;
    531 
    532     if( (unsigned)index >= (unsigned)total )
    533     {
    534         index += index < 0 ? total : 0;
    535         index -= index >= total ? total : 0;
    536         if( (unsigned)index >= (unsigned)total )
    537             return 0;
    538     }
    539 
    540     block = seq->first;
    541     if( index + index <= total )
    542     {
    543         while( index >= (count = block->count) )
    544         {
    545             block = block->next;
    546             index -= count;
    547         }
    548     }
    549     else
    550     {
    551         do
    552         {
    553             block = block->prev;
    554             total -= block->count;
    555         }
    556         while( index < total );
    557         index -= total;
    558     }
    559 
    560     return block->data + index * seq->elem_size;
    561 }
    562 
    563 
    564 /* Calculate index of a sequence element: */
    565 CV_IMPL int
    566 cvSeqElemIdx( const CvSeq* seq, const void* _element, CvSeqBlock** _block )
    567 {
    568     const schar *element = (const schar *)_element;
    569     int elem_size;
    570     int id = -1;
    571     CvSeqBlock *first_block;
    572     CvSeqBlock *block;
    573 
    574     CV_FUNCNAME( "cvSeqElemIdx" );
    575 
    576     __BEGIN__;
    577 
    578     if( !seq || !element )
    579         CV_ERROR( CV_StsNullPtr, "" );
    580 
    581     block = first_block = seq->first;
    582     elem_size = seq->elem_size;
    583 
    584     for( ;; )
    585     {
    586         if( (unsigned)(element - block->data) < (unsigned) (block->count * elem_size) )
    587         {
    588             if( _block )
    589                 *_block = block;
    590             if( elem_size <= ICV_SHIFT_TAB_MAX && (id = icvPower2ShiftTab[elem_size - 1]) >= 0 )
    591                 id = (int)((size_t)(element - block->data) >> id);
    592             else
    593                 id = (int)((size_t)(element - block->data) / elem_size);
    594             id += block->start_index - seq->first->start_index;
    595             break;
    596         }
    597         block = block->next;
    598         if( block == first_block )
    599             break;
    600     }
    601 
    602     __END__;
    603 
    604     return id;
    605 }
    606 
    607 
    608 CV_IMPL int
    609 cvSliceLength( CvSlice slice, const CvSeq* seq )
    610 {
    611     int total = seq->total;
    612     int length = slice.end_index - slice.start_index;
    613 
    614     if( length != 0 )
    615     {
    616         if( slice.start_index < 0 )
    617             slice.start_index += total;
    618         if( slice.end_index <= 0 )
    619             slice.end_index += total;
    620 
    621         length = slice.end_index - slice.start_index;
    622     }
    623 
    624     if( length < 0 )
    625     {
    626         length += total;
    627         /*if( length < 0 )
    628             length += total;*/
    629     }
    630     else if( length > total )
    631         length = total;
    632 
    633     return length;
    634 }
    635 
    636 
    637 /* Copy all sequence elements into single continuous array: */
    638 CV_IMPL void*
    639 cvCvtSeqToArray( const CvSeq *seq, void *array, CvSlice slice )
    640 {
    641     CV_FUNCNAME( "cvCvtSeqToArray" );
    642 
    643     __BEGIN__;
    644 
    645     int elem_size, total;
    646     CvSeqReader reader;
    647     char *dst = (char*)array;
    648 
    649     if( !seq || !array )
    650         CV_ERROR( CV_StsNullPtr, "" );
    651 
    652     elem_size = seq->elem_size;
    653     total = cvSliceLength( slice, seq )*elem_size;
    654 
    655     if( total == 0 )
    656         EXIT;
    657 
    658     cvStartReadSeq( seq, &reader, 0 );
    659     CV_CALL( cvSetSeqReaderPos( &reader, slice.start_index, 0 ));
    660 
    661     do
    662     {
    663         int count = (int)(reader.block_max - reader.ptr);
    664         if( count > total )
    665             count = total;
    666 
    667         memcpy( dst, reader.ptr, count );
    668         dst += count;
    669         reader.block = reader.block->next;
    670         reader.ptr = reader.block->data;
    671         reader.block_max = reader.ptr + reader.block->count*elem_size;
    672         total -= count;
    673     }
    674     while( total > 0 );
    675 
    676     __END__;
    677 
    678     return array;
    679 }
    680 
    681 
    682 /* Construct a sequence from an array without copying any data.
    683    NB: The resultant sequence cannot grow beyond its initial size: */
    684 CV_IMPL CvSeq*
    685 cvMakeSeqHeaderForArray( int seq_flags, int header_size, int elem_size,
    686                          void *array, int total, CvSeq *seq, CvSeqBlock * block )
    687 {
    688     CvSeq* result = 0;
    689 
    690     CV_FUNCNAME( "cvMakeSeqHeaderForArray" );
    691 
    692     __BEGIN__;
    693 
    694     if( elem_size <= 0 || header_size < (int)sizeof( CvSeq ) || total < 0 )
    695         CV_ERROR( CV_StsBadSize, "" );
    696 
    697     if( !seq || ((!array || !block) && total > 0) )
    698         CV_ERROR( CV_StsNullPtr, "" );
    699 
    700     memset( seq, 0, header_size );
    701 
    702     seq->header_size = header_size;
    703     seq->flags = (seq_flags & ~CV_MAGIC_MASK) | CV_SEQ_MAGIC_VAL;
    704     {
    705         int elemtype = CV_MAT_TYPE(seq_flags);
    706         int typesize = CV_ELEM_SIZE(elemtype);
    707 
    708         if( elemtype != CV_SEQ_ELTYPE_GENERIC &&
    709             typesize != 0 && typesize != elem_size )
    710             CV_ERROR( CV_StsBadSize,
    711             "Element size doesn't match to the size of predefined element type "
    712             "(try to use 0 for sequence element type)" );
    713     }
    714     seq->elem_size = elem_size;
    715     seq->total = total;
    716     seq->block_max = seq->ptr = (schar *) array + total * elem_size;
    717 
    718     if( total > 0 )
    719     {
    720         seq->first = block;
    721         block->prev = block->next = block;
    722         block->start_index = 0;
    723         block->count = total;
    724         block->data = (schar *) array;
    725     }
    726 
    727     result = seq;
    728 
    729     __END__;
    730 
    731     return result;
    732 }
    733 
    734 
    735 /* The function allocates space for at least one more sequence element.
    736    If there are free sequence blocks (seq->free_blocks != 0)
    737    they are reused, otherwise the space is allocated in the storage: */
    738 static void
    739 icvGrowSeq( CvSeq *seq, int in_front_of )
    740 {
    741     CV_FUNCNAME( "icvGrowSeq" );
    742 
    743     __BEGIN__;
    744 
    745     CvSeqBlock *block;
    746 
    747     if( !seq )
    748         CV_ERROR( CV_StsNullPtr, "" );
    749     block = seq->free_blocks;
    750 
    751     if( !block )
    752     {
    753         int elem_size = seq->elem_size;
    754         int delta_elems = seq->delta_elems;
    755         CvMemStorage *storage = seq->storage;
    756 
    757         if( seq->total >= delta_elems*4 )
    758             cvSetSeqBlockSize( seq, delta_elems*2 );
    759 
    760         if( !storage )
    761             CV_ERROR( CV_StsNullPtr, "The sequence has NULL storage pointer" );
    762 
    763         /* If there is a free space just after last allocated block
    764            and it is big enough then enlarge the last block.
    765            This can happen only if the new block is added to the end of sequence: */
    766         if( (unsigned)(ICV_FREE_PTR(storage) - seq->block_max) < CV_STRUCT_ALIGN &&
    767             storage->free_space >= seq->elem_size && !in_front_of )
    768         {
    769             int delta = storage->free_space / elem_size;
    770 
    771             delta = MIN( delta, delta_elems ) * elem_size;
    772             seq->block_max += delta;
    773             storage->free_space = cvAlignLeft((int)(((schar*)storage->top + storage->block_size) -
    774                                               seq->block_max), CV_STRUCT_ALIGN );
    775             EXIT;
    776         }
    777         else
    778         {
    779             int delta = elem_size * delta_elems + ICV_ALIGNED_SEQ_BLOCK_SIZE;
    780 
    781             /* Try to allocate <delta_elements> elements: */
    782             if( storage->free_space < delta )
    783             {
    784                 int small_block_size = MAX(1, delta_elems/3)*elem_size +
    785                                        ICV_ALIGNED_SEQ_BLOCK_SIZE;
    786                 /* try to allocate smaller part */
    787                 if( storage->free_space >= small_block_size + CV_STRUCT_ALIGN )
    788                 {
    789                     delta = (storage->free_space - ICV_ALIGNED_SEQ_BLOCK_SIZE)/seq->elem_size;
    790                     delta = delta*seq->elem_size + ICV_ALIGNED_SEQ_BLOCK_SIZE;
    791                 }
    792                 else
    793                 {
    794                     CV_CALL( icvGoNextMemBlock( storage ));
    795                     assert( storage->free_space >= delta );
    796                 }
    797             }
    798 
    799             CV_CALL( block = (CvSeqBlock*)cvMemStorageAlloc( storage, delta ));
    800             block->data = (schar*)cvAlignPtr( block + 1, CV_STRUCT_ALIGN );
    801             block->count = delta - ICV_ALIGNED_SEQ_BLOCK_SIZE;
    802             block->prev = block->next = 0;
    803         }
    804     }
    805     else
    806     {
    807         seq->free_blocks = block->next;
    808     }
    809 
    810     if( !(seq->first) )
    811     {
    812         seq->first = block;
    813         block->prev = block->next = block;
    814     }
    815     else
    816     {
    817         block->prev = seq->first->prev;
    818         block->next = seq->first;
    819         block->prev->next = block->next->prev = block;
    820     }
    821 
    822     /* For free blocks the <count> field means
    823      * total number of bytes in the block.
    824      *
    825      * For used blocks it means current number
    826      * of sequence elements in the block:
    827      */
    828     assert( block->count % seq->elem_size == 0 && block->count > 0 );
    829 
    830     if( !in_front_of )
    831     {
    832         seq->ptr = block->data;
    833         seq->block_max = block->data + block->count;
    834         block->start_index = block == block->prev ? 0 :
    835             block->prev->start_index + block->prev->count;
    836     }
    837     else
    838     {
    839         int delta = block->count / seq->elem_size;
    840         block->data += block->count;
    841 
    842         if( block != block->prev )
    843         {
    844             assert( seq->first->start_index == 0 );
    845             seq->first = block;
    846         }
    847         else
    848         {
    849             seq->block_max = seq->ptr = block->data;
    850         }
    851 
    852         block->start_index = 0;
    853 
    854         for( ;; )
    855         {
    856             block->start_index += delta;
    857             block = block->next;
    858             if( block == seq->first )
    859                 break;
    860         }
    861     }
    862 
    863     block->count = 0;
    864 
    865     __END__;
    866 }
    867 
    868 /* Recycle a sequence block: */
    869 static void
    870 icvFreeSeqBlock( CvSeq *seq, int in_front_of )
    871 {
    872     /*CV_FUNCNAME( "icvFreeSeqBlock" );*/
    873 
    874     __BEGIN__;
    875 
    876     CvSeqBlock *block = seq->first;
    877 
    878     assert( (in_front_of ? block : block->prev)->count == 0 );
    879 
    880     if( block == block->prev )  /* single block case */
    881     {
    882         block->count = (int)(seq->block_max - block->data) + block->start_index * seq->elem_size;
    883         block->data = seq->block_max - block->count;
    884         seq->first = 0;
    885         seq->ptr = seq->block_max = 0;
    886         seq->total = 0;
    887     }
    888     else
    889     {
    890         if( !in_front_of )
    891         {
    892             block = block->prev;
    893             assert( seq->ptr == block->data );
    894 
    895             block->count = (int)(seq->block_max - seq->ptr);
    896             seq->block_max = seq->ptr = block->prev->data +
    897                 block->prev->count * seq->elem_size;
    898         }
    899         else
    900         {
    901             int delta = block->start_index;
    902 
    903             block->count = delta * seq->elem_size;
    904             block->data -= block->count;
    905 
    906             /* Update start indices of sequence blocks: */
    907             for( ;; )
    908             {
    909                 block->start_index -= delta;
    910                 block = block->next;
    911                 if( block == seq->first )
    912                     break;
    913             }
    914 
    915             seq->first = block->next;
    916         }
    917 
    918         block->prev->next = block->next;
    919         block->next->prev = block->prev;
    920     }
    921 
    922     assert( block->count > 0 && block->count % seq->elem_size == 0 );
    923     block->next = seq->free_blocks;
    924     seq->free_blocks = block;
    925 
    926     __END__;
    927 }
    928 
    929 
    930 /****************************************************************************************\
    931 *                             Sequence Writer implementation                             *
    932 \****************************************************************************************/
    933 
    934 /* Initialize sequence writer: */
    935 CV_IMPL void
    936 cvStartAppendToSeq( CvSeq *seq, CvSeqWriter * writer )
    937 {
    938     CV_FUNCNAME( "cvStartAppendToSeq" );
    939 
    940     __BEGIN__;
    941 
    942     if( !seq || !writer )
    943         CV_ERROR( CV_StsNullPtr, "" );
    944 
    945     memset( writer, 0, sizeof( *writer ));
    946     writer->header_size = sizeof( CvSeqWriter );
    947 
    948     writer->seq = seq;
    949     writer->block = seq->first ? seq->first->prev : 0;
    950     writer->ptr = seq->ptr;
    951     writer->block_max = seq->block_max;
    952 
    953     __END__;
    954 }
    955 
    956 
    957 /* Initialize sequence writer: */
    958 CV_IMPL void
    959 cvStartWriteSeq( int seq_flags, int header_size,
    960                  int elem_size, CvMemStorage * storage, CvSeqWriter * writer )
    961 {
    962     CvSeq *seq = 0;
    963 
    964     CV_FUNCNAME( "cvStartWriteSeq" );
    965 
    966     __BEGIN__;
    967 
    968     if( !storage || !writer )
    969         CV_ERROR( CV_StsNullPtr, "" );
    970 
    971     CV_CALL( seq = cvCreateSeq( seq_flags, header_size, elem_size, storage ));
    972     cvStartAppendToSeq( seq, writer );
    973 
    974     __END__;
    975 }
    976 
    977 
    978 /* Update sequence header: */
    979 CV_IMPL void
    980 cvFlushSeqWriter( CvSeqWriter * writer )
    981 {
    982     CvSeq *seq = 0;
    983 
    984     CV_FUNCNAME( "cvFlushSeqWriter" );
    985 
    986     __BEGIN__;
    987 
    988     if( !writer )
    989         CV_ERROR( CV_StsNullPtr, "" );
    990 
    991     seq = writer->seq;
    992     seq->ptr = writer->ptr;
    993 
    994     if( writer->block )
    995     {
    996         int total = 0;
    997         CvSeqBlock *first_block = writer->seq->first;
    998         CvSeqBlock *block = first_block;
    999 
   1000         writer->block->count = (int)((writer->ptr - writer->block->data) / seq->elem_size);
   1001         assert( writer->block->count > 0 );
   1002 
   1003         do
   1004         {
   1005             total += block->count;
   1006             block = block->next;
   1007         }
   1008         while( block != first_block );
   1009 
   1010         writer->seq->total = total;
   1011     }
   1012 
   1013     __END__;
   1014 }
   1015 
   1016 
   1017 /* Calls icvFlushSeqWriter and finishes writing process: */
   1018 CV_IMPL CvSeq *
   1019 cvEndWriteSeq( CvSeqWriter * writer )
   1020 {
   1021     CvSeq *seq = 0;
   1022 
   1023     CV_FUNCNAME( "cvEndWriteSeq" );
   1024 
   1025     __BEGIN__;
   1026 
   1027     if( !writer )
   1028         CV_ERROR( CV_StsNullPtr, "" );
   1029 
   1030     CV_CALL( cvFlushSeqWriter( writer ));
   1031     seq = writer->seq;
   1032 
   1033     /* Truncate the last block: */
   1034     if( writer->block && writer->seq->storage )
   1035     {
   1036         CvMemStorage *storage = seq->storage;
   1037         schar *storage_block_max = (schar *) storage->top + storage->block_size;
   1038 
   1039         assert( writer->block->count > 0 );
   1040 
   1041         if( (unsigned)((storage_block_max - storage->free_space)
   1042             - seq->block_max) < CV_STRUCT_ALIGN )
   1043         {
   1044             storage->free_space = cvAlignLeft((int)(storage_block_max - seq->ptr), CV_STRUCT_ALIGN);
   1045             seq->block_max = seq->ptr;
   1046         }
   1047     }
   1048 
   1049     writer->ptr = 0;
   1050 
   1051     __END__;
   1052 
   1053     return seq;
   1054 }
   1055 
   1056 
   1057 /* Create new sequence block: */
   1058 CV_IMPL void
   1059 cvCreateSeqBlock( CvSeqWriter * writer )
   1060 {
   1061     CV_FUNCNAME( "cvCreateSeqBlock" );
   1062 
   1063     __BEGIN__;
   1064 
   1065     CvSeq *seq;
   1066 
   1067     if( !writer || !writer->seq )
   1068         CV_ERROR( CV_StsNullPtr, "" );
   1069 
   1070     seq = writer->seq;
   1071 
   1072     cvFlushSeqWriter( writer );
   1073 
   1074     CV_CALL( icvGrowSeq( seq, 0 ));
   1075 
   1076     writer->block = seq->first->prev;
   1077     writer->ptr = seq->ptr;
   1078     writer->block_max = seq->block_max;
   1079 
   1080     __END__;
   1081 }
   1082 
   1083 
   1084 /****************************************************************************************\
   1085 *                               Sequence Reader implementation                           *
   1086 \****************************************************************************************/
   1087 
   1088 /* Initialize sequence reader: */
   1089 CV_IMPL void
   1090 cvStartReadSeq( const CvSeq *seq, CvSeqReader * reader, int reverse )
   1091 {
   1092     CvSeqBlock *first_block;
   1093     CvSeqBlock *last_block;
   1094 
   1095     CV_FUNCNAME( "cvStartReadSeq" );
   1096 
   1097     if( reader )
   1098     {
   1099         reader->seq = 0;
   1100         reader->block = 0;
   1101         reader->ptr = reader->block_max = reader->block_min = 0;
   1102     }
   1103 
   1104     __BEGIN__;
   1105 
   1106     if( !seq || !reader )
   1107         CV_ERROR( CV_StsNullPtr, "" );
   1108 
   1109     reader->header_size = sizeof( CvSeqReader );
   1110     reader->seq = (CvSeq*)seq;
   1111 
   1112     first_block = seq->first;
   1113 
   1114     if( first_block )
   1115     {
   1116         last_block = first_block->prev;
   1117         reader->ptr = first_block->data;
   1118         reader->prev_elem = CV_GET_LAST_ELEM( seq, last_block );
   1119         reader->delta_index = seq->first->start_index;
   1120 
   1121         if( reverse )
   1122         {
   1123             schar *temp = reader->ptr;
   1124 
   1125             reader->ptr = reader->prev_elem;
   1126             reader->prev_elem = temp;
   1127 
   1128             reader->block = last_block;
   1129         }
   1130         else
   1131         {
   1132             reader->block = first_block;
   1133         }
   1134 
   1135         reader->block_min = reader->block->data;
   1136         reader->block_max = reader->block_min + reader->block->count * seq->elem_size;
   1137     }
   1138     else
   1139     {
   1140         reader->delta_index = 0;
   1141         reader->block = 0;
   1142 
   1143         reader->ptr = reader->prev_elem = reader->block_min = reader->block_max = 0;
   1144     }
   1145 
   1146     __END__;
   1147 }
   1148 
   1149 
   1150 /* Change the current reading block
   1151  * to the previous or to the next:
   1152  */
   1153 CV_IMPL void
   1154 cvChangeSeqBlock( void* _reader, int direction )
   1155 {
   1156     CV_FUNCNAME( "cvChangeSeqBlock" );
   1157 
   1158     __BEGIN__;
   1159 
   1160     CvSeqReader* reader = (CvSeqReader*)_reader;
   1161 
   1162     if( !reader )
   1163         CV_ERROR( CV_StsNullPtr, "" );
   1164 
   1165     if( direction > 0 )
   1166     {
   1167         reader->block = reader->block->next;
   1168         reader->ptr = reader->block->data;
   1169     }
   1170     else
   1171     {
   1172         reader->block = reader->block->prev;
   1173         reader->ptr = CV_GET_LAST_ELEM( reader->seq, reader->block );
   1174     }
   1175     reader->block_min = reader->block->data;
   1176     reader->block_max = reader->block_min + reader->block->count * reader->seq->elem_size;
   1177 
   1178     __END__;
   1179 }
   1180 
   1181 
   1182 /* Return the current reader position: */
   1183 CV_IMPL int
   1184 cvGetSeqReaderPos( CvSeqReader* reader )
   1185 {
   1186     int elem_size;
   1187     int index = -1;
   1188 
   1189     CV_FUNCNAME( "cvGetSeqReaderPos" );
   1190 
   1191     __BEGIN__;
   1192 
   1193     if( !reader || !reader->ptr )
   1194         CV_ERROR( CV_StsNullPtr, "" );
   1195 
   1196     elem_size = reader->seq->elem_size;
   1197     if( elem_size <= ICV_SHIFT_TAB_MAX && (index = icvPower2ShiftTab[elem_size - 1]) >= 0 )
   1198         index = (int)((reader->ptr - reader->block_min) >> index);
   1199     else
   1200         index = (int)((reader->ptr - reader->block_min) / elem_size);
   1201 
   1202     index += reader->block->start_index - reader->delta_index;
   1203 
   1204     __END__;
   1205 
   1206     return index;
   1207 }
   1208 
   1209 
   1210 /* Set reader position to given position,
   1211  * either absolute or relative to the
   1212  *  current one:
   1213  */
   1214 CV_IMPL void
   1215 cvSetSeqReaderPos( CvSeqReader* reader, int index, int is_relative )
   1216 {
   1217     CV_FUNCNAME( "cvSetSeqReaderPos" );
   1218 
   1219     __BEGIN__;
   1220 
   1221     CvSeqBlock *block;
   1222     int elem_size, count, total;
   1223 
   1224     if( !reader || !reader->seq )
   1225         CV_ERROR( CV_StsNullPtr, "" );
   1226 
   1227     total = reader->seq->total;
   1228     elem_size = reader->seq->elem_size;
   1229 
   1230     if( !is_relative )
   1231     {
   1232         if( index < 0 )
   1233         {
   1234             if( index < -total )
   1235                 CV_ERROR( CV_StsOutOfRange, "" );
   1236             index += total;
   1237         }
   1238         else if( index >= total )
   1239         {
   1240             index -= total;
   1241             if( index >= total )
   1242                 CV_ERROR( CV_StsOutOfRange, "" );
   1243         }
   1244 
   1245         block = reader->seq->first;
   1246         if( index >= (count = block->count) )
   1247         {
   1248             if( index + index <= total )
   1249             {
   1250                 do
   1251                 {
   1252                     block = block->next;
   1253                     index -= count;
   1254                 }
   1255                 while( index >= (count = block->count) );
   1256             }
   1257             else
   1258             {
   1259                 do
   1260                 {
   1261                     block = block->prev;
   1262                     total -= block->count;
   1263                 }
   1264                 while( index < total );
   1265                 index -= total;
   1266             }
   1267         }
   1268         reader->ptr = block->data + index * elem_size;
   1269         if( reader->block != block )
   1270         {
   1271             reader->block = block;
   1272             reader->block_min = block->data;
   1273             reader->block_max = block->data + block->count * elem_size;
   1274         }
   1275     }
   1276     else
   1277     {
   1278         schar* ptr = reader->ptr;
   1279         index *= elem_size;
   1280         block = reader->block;
   1281 
   1282         if( index > 0 )
   1283         {
   1284             while( ptr + index >= reader->block_max )
   1285             {
   1286                 int delta = (int)(reader->block_max - ptr);
   1287                 index -= delta;
   1288                 reader->block = block = block->next;
   1289                 reader->block_min = ptr = block->data;
   1290                 reader->block_max = block->data + block->count*elem_size;
   1291             }
   1292             reader->ptr = ptr + index;
   1293         }
   1294         else
   1295         {
   1296             while( ptr + index < reader->block_min )
   1297             {
   1298                 int delta = (int)(ptr - reader->block_min);
   1299                 index += delta;
   1300                 reader->block = block = block->prev;
   1301                 reader->block_min = block->data;
   1302                 reader->block_max = ptr = block->data + block->count*elem_size;
   1303             }
   1304             reader->ptr = ptr + index;
   1305         }
   1306     }
   1307 
   1308     __END__;
   1309 }
   1310 
   1311 
   1312 /* Push element onto the sequence: */
   1313 CV_IMPL schar*
   1314 cvSeqPush( CvSeq *seq, void *element )
   1315 {
   1316     schar *ptr = 0;
   1317     size_t elem_size;
   1318 
   1319     CV_FUNCNAME( "cvSeqPush" );
   1320 
   1321     __BEGIN__;
   1322 
   1323     if( !seq )
   1324         CV_ERROR( CV_StsNullPtr, "" );
   1325 
   1326     elem_size = seq->elem_size;
   1327     ptr = seq->ptr;
   1328 
   1329     if( ptr >= seq->block_max )
   1330     {
   1331         CV_CALL( icvGrowSeq( seq, 0 ));
   1332 
   1333         ptr = seq->ptr;
   1334         assert( ptr + elem_size <= seq->block_max /*&& ptr == seq->block_min */  );
   1335     }
   1336 
   1337     if( element )
   1338         CV_MEMCPY_AUTO( ptr, element, elem_size );
   1339     seq->first->prev->count++;
   1340     seq->total++;
   1341     seq->ptr = ptr + elem_size;
   1342 
   1343     __END__;
   1344 
   1345     return ptr;
   1346 }
   1347 
   1348 
   1349 /* Pop last element off of the sequence: */
   1350 CV_IMPL void
   1351 cvSeqPop( CvSeq *seq, void *element )
   1352 {
   1353     schar *ptr;
   1354     int elem_size;
   1355 
   1356     CV_FUNCNAME( "cvSeqPop" );
   1357 
   1358     __BEGIN__;
   1359 
   1360     if( !seq )
   1361         CV_ERROR( CV_StsNullPtr, "" );
   1362     if( seq->total <= 0 )
   1363         CV_ERROR( CV_StsBadSize, "" );
   1364 
   1365     elem_size = seq->elem_size;
   1366     seq->ptr = ptr = seq->ptr - elem_size;
   1367 
   1368     if( element )
   1369         CV_MEMCPY_AUTO( element, ptr, elem_size );
   1370     seq->ptr = ptr;
   1371     seq->total--;
   1372 
   1373     if( --(seq->first->prev->count) == 0 )
   1374     {
   1375         icvFreeSeqBlock( seq, 0 );
   1376         assert( seq->ptr == seq->block_max );
   1377     }
   1378 
   1379     __END__;
   1380 }
   1381 
   1382 
   1383 /* Push element onto the front of the sequence: */
   1384 CV_IMPL schar*
   1385 cvSeqPushFront( CvSeq *seq, void *element )
   1386 {
   1387     schar* ptr = 0;
   1388     int elem_size;
   1389     CvSeqBlock *block;
   1390 
   1391     CV_FUNCNAME( "cvSeqPushFront" );
   1392 
   1393     __BEGIN__;
   1394 
   1395     if( !seq )
   1396         CV_ERROR( CV_StsNullPtr, "" );
   1397 
   1398     elem_size = seq->elem_size;
   1399     block = seq->first;
   1400 
   1401     if( !block || block->start_index == 0 )
   1402     {
   1403         CV_CALL( icvGrowSeq( seq, 1 ));
   1404 
   1405         block = seq->first;
   1406         assert( block->start_index > 0 );
   1407     }
   1408 
   1409     ptr = block->data -= elem_size;
   1410 
   1411     if( element )
   1412         CV_MEMCPY_AUTO( ptr, element, elem_size );
   1413     block->count++;
   1414     block->start_index--;
   1415     seq->total++;
   1416 
   1417     __END__;
   1418 
   1419     return ptr;
   1420 }
   1421 
   1422 
   1423 /* Shift out first element of the sequence: */
   1424 CV_IMPL void
   1425 cvSeqPopFront( CvSeq *seq, void *element )
   1426 {
   1427     int elem_size;
   1428     CvSeqBlock *block;
   1429 
   1430     CV_FUNCNAME( "cvSeqPopFront" );
   1431 
   1432     __BEGIN__;
   1433 
   1434     if( !seq )
   1435         CV_ERROR( CV_StsNullPtr, "" );
   1436     if( seq->total <= 0 )
   1437         CV_ERROR( CV_StsBadSize, "" );
   1438 
   1439     elem_size = seq->elem_size;
   1440     block = seq->first;
   1441 
   1442     if( element )
   1443         CV_MEMCPY_AUTO( element, block->data, elem_size );
   1444     block->data += elem_size;
   1445     block->start_index++;
   1446     seq->total--;
   1447 
   1448     if( --(block->count) == 0 )
   1449     {
   1450         icvFreeSeqBlock( seq, 1 );
   1451     }
   1452 
   1453     __END__;
   1454 }
   1455 
   1456 /* Insert new element in middle of sequence: */
   1457 CV_IMPL schar*
   1458 cvSeqInsert( CvSeq *seq, int before_index, void *element )
   1459 {
   1460     int elem_size;
   1461     int block_size;
   1462     CvSeqBlock *block;
   1463     int delta_index;
   1464     int total;
   1465     schar* ret_ptr = 0;
   1466 
   1467     CV_FUNCNAME( "cvSeqInsert" );
   1468 
   1469     __BEGIN__;
   1470 
   1471     if( !seq )
   1472         CV_ERROR( CV_StsNullPtr, "" );
   1473 
   1474     total = seq->total;
   1475     before_index += before_index < 0 ? total : 0;
   1476     before_index -= before_index > total ? total : 0;
   1477 
   1478     if( (unsigned)before_index > (unsigned)total )
   1479         CV_ERROR( CV_StsOutOfRange, "" );
   1480 
   1481     if( before_index == total )
   1482     {
   1483         CV_CALL( ret_ptr = cvSeqPush( seq, element ));
   1484     }
   1485     else if( before_index == 0 )
   1486     {
   1487         CV_CALL( ret_ptr = cvSeqPushFront( seq, element ));
   1488     }
   1489     else
   1490     {
   1491         elem_size = seq->elem_size;
   1492 
   1493         if( before_index >= total >> 1 )
   1494         {
   1495             schar *ptr = seq->ptr + elem_size;
   1496 
   1497             if( ptr > seq->block_max )
   1498             {
   1499                 CV_CALL( icvGrowSeq( seq, 0 ));
   1500 
   1501                 ptr = seq->ptr + elem_size;
   1502                 assert( ptr <= seq->block_max );
   1503             }
   1504 
   1505             delta_index = seq->first->start_index;
   1506             block = seq->first->prev;
   1507             block->count++;
   1508             block_size = (int)(ptr - block->data);
   1509 
   1510             while( before_index < block->start_index - delta_index )
   1511             {
   1512                 CvSeqBlock *prev_block = block->prev;
   1513 
   1514                 memmove( block->data + elem_size, block->data, block_size - elem_size );
   1515                 block_size = prev_block->count * elem_size;
   1516                 memcpy( block->data, prev_block->data + block_size - elem_size, elem_size );
   1517                 block = prev_block;
   1518 
   1519                 /* Check that we don't fall into an infinite loop: */
   1520                 assert( block != seq->first->prev );
   1521             }
   1522 
   1523             before_index = (before_index - block->start_index + delta_index) * elem_size;
   1524             memmove( block->data + before_index + elem_size, block->data + before_index,
   1525                      block_size - before_index - elem_size );
   1526 
   1527             ret_ptr = block->data + before_index;
   1528 
   1529             if( element )
   1530                 memcpy( ret_ptr, element, elem_size );
   1531             seq->ptr = ptr;
   1532         }
   1533         else
   1534         {
   1535             block = seq->first;
   1536 
   1537             if( block->start_index == 0 )
   1538             {
   1539                 CV_CALL( icvGrowSeq( seq, 1 ));
   1540 
   1541                 block = seq->first;
   1542             }
   1543 
   1544             delta_index = block->start_index;
   1545             block->count++;
   1546             block->start_index--;
   1547             block->data -= elem_size;
   1548 
   1549             while( before_index > block->start_index - delta_index + block->count )
   1550             {
   1551                 CvSeqBlock *next_block = block->next;
   1552 
   1553                 block_size = block->count * elem_size;
   1554                 memmove( block->data, block->data + elem_size, block_size - elem_size );
   1555                 memcpy( block->data + block_size - elem_size, next_block->data, elem_size );
   1556                 block = next_block;
   1557 
   1558                 /* Check that we don't fall into an infinite loop: */
   1559                 assert( block != seq->first );
   1560             }
   1561 
   1562             before_index = (before_index - block->start_index + delta_index) * elem_size;
   1563             memmove( block->data, block->data + elem_size, before_index - elem_size );
   1564 
   1565             ret_ptr = block->data + before_index - elem_size;
   1566 
   1567             if( element )
   1568                 memcpy( ret_ptr, element, elem_size );
   1569         }
   1570 
   1571         seq->total = total + 1;
   1572     }
   1573 
   1574     __END__;
   1575 
   1576     return ret_ptr;
   1577 }
   1578 
   1579 
   1580 /* Removes element from sequence: */
   1581 CV_IMPL void
   1582 cvSeqRemove( CvSeq *seq, int index )
   1583 {
   1584     schar *ptr;
   1585     int elem_size;
   1586     int block_size;
   1587     CvSeqBlock *block;
   1588     int delta_index;
   1589     int total, front = 0;
   1590 
   1591     CV_FUNCNAME( "cvSeqRemove" );
   1592 
   1593     __BEGIN__;
   1594 
   1595     if( !seq )
   1596         CV_ERROR( CV_StsNullPtr, "" );
   1597 
   1598     total = seq->total;
   1599 
   1600     index += index < 0 ? total : 0;
   1601     index -= index >= total ? total : 0;
   1602 
   1603     if( (unsigned) index >= (unsigned) total )
   1604         CV_ERROR( CV_StsOutOfRange, "Invalid index" );
   1605 
   1606     if( index == total - 1 )
   1607     {
   1608         cvSeqPop( seq, 0 );
   1609     }
   1610     else if( index == 0 )
   1611     {
   1612         cvSeqPopFront( seq, 0 );
   1613     }
   1614     else
   1615     {
   1616         block = seq->first;
   1617         elem_size = seq->elem_size;
   1618         delta_index = block->start_index;
   1619         while( block->start_index - delta_index + block->count <= index )
   1620             block = block->next;
   1621 
   1622         ptr = block->data + (index - block->start_index + delta_index) * elem_size;
   1623 
   1624         front = index < total >> 1;
   1625         if( !front )
   1626         {
   1627             block_size = block->count * elem_size - (int)(ptr - block->data);
   1628 
   1629             while( block != seq->first->prev )  /* while not the last block */
   1630             {
   1631                 CvSeqBlock *next_block = block->next;
   1632 
   1633                 memmove( ptr, ptr + elem_size, block_size - elem_size );
   1634                 memcpy( ptr + block_size - elem_size, next_block->data, elem_size );
   1635                 block = next_block;
   1636                 ptr = block->data;
   1637                 block_size = block->count * elem_size;
   1638             }
   1639 
   1640             memmove( ptr, ptr + elem_size, block_size - elem_size );
   1641             seq->ptr -= elem_size;
   1642         }
   1643         else
   1644         {
   1645             ptr += elem_size;
   1646             block_size = (int)(ptr - block->data);
   1647 
   1648             while( block != seq->first )
   1649             {
   1650                 CvSeqBlock *prev_block = block->prev;
   1651 
   1652                 memmove( block->data + elem_size, block->data, block_size - elem_size );
   1653                 block_size = prev_block->count * elem_size;
   1654                 memcpy( block->data, prev_block->data + block_size - elem_size, elem_size );
   1655                 block = prev_block;
   1656             }
   1657 
   1658             memmove( block->data + elem_size, block->data, block_size - elem_size );
   1659             block->data += elem_size;
   1660             block->start_index++;
   1661         }
   1662 
   1663         seq->total = total - 1;
   1664         if( --block->count == 0 )
   1665             icvFreeSeqBlock( seq, front );
   1666     }
   1667 
   1668     __END__;
   1669 }
   1670 
   1671 
   1672 /* Add several elements to the beginning or end of a sequence: */
   1673 CV_IMPL void
   1674 cvSeqPushMulti( CvSeq *seq, void *_elements, int count, int front )
   1675 {
   1676     char *elements = (char *) _elements;
   1677 
   1678     CV_FUNCNAME( "cvSeqPushMulti" );
   1679 
   1680     __BEGIN__;
   1681     int elem_size;
   1682 
   1683     if( !seq )
   1684         CV_ERROR( CV_StsNullPtr, "NULL sequence pointer" );
   1685     if( count < 0 )
   1686         CV_ERROR( CV_StsBadSize, "number of removed elements is negative" );
   1687 
   1688     elem_size = seq->elem_size;
   1689 
   1690     if( !front )
   1691     {
   1692         while( count > 0 )
   1693         {
   1694             int delta = (int)((seq->block_max - seq->ptr) / elem_size);
   1695 
   1696             delta = MIN( delta, count );
   1697             if( delta > 0 )
   1698             {
   1699                 seq->first->prev->count += delta;
   1700                 seq->total += delta;
   1701                 count -= delta;
   1702                 delta *= elem_size;
   1703                 if( elements )
   1704                 {
   1705                     memcpy( seq->ptr, elements, delta );
   1706                     elements += delta;
   1707                 }
   1708                 seq->ptr += delta;
   1709             }
   1710 
   1711             if( count > 0 )
   1712                 CV_CALL( icvGrowSeq( seq, 0 ));
   1713         }
   1714     }
   1715     else
   1716     {
   1717         CvSeqBlock* block = seq->first;
   1718 
   1719         while( count > 0 )
   1720         {
   1721             int delta;
   1722 
   1723             if( !block || block->start_index == 0 )
   1724             {
   1725                 CV_CALL( icvGrowSeq( seq, 1 ));
   1726 
   1727                 block = seq->first;
   1728                 assert( block->start_index > 0 );
   1729             }
   1730 
   1731             delta = MIN( block->start_index, count );
   1732             count -= delta;
   1733             block->start_index -= delta;
   1734             block->count += delta;
   1735             seq->total += delta;
   1736             delta *= elem_size;
   1737             block->data -= delta;
   1738 
   1739             if( elements )
   1740                 memcpy( block->data, elements + count*elem_size, delta );
   1741         }
   1742     }
   1743 
   1744     __END__;
   1745 }
   1746 
   1747 
   1748 /* Remove several elements from the end of sequence: */
   1749 CV_IMPL void
   1750 cvSeqPopMulti( CvSeq *seq, void *_elements, int count, int front )
   1751 {
   1752     char *elements = (char *) _elements;
   1753 
   1754     CV_FUNCNAME( "cvSeqPopMulti" );
   1755 
   1756     __BEGIN__;
   1757 
   1758     if( !seq )
   1759         CV_ERROR( CV_StsNullPtr, "NULL sequence pointer" );
   1760     if( count < 0 )
   1761         CV_ERROR( CV_StsBadSize, "number of removed elements is negative" );
   1762 
   1763     count = MIN( count, seq->total );
   1764 
   1765     if( !front )
   1766     {
   1767         if( elements )
   1768             elements += count * seq->elem_size;
   1769 
   1770         while( count > 0 )
   1771         {
   1772             int delta = seq->first->prev->count;
   1773 
   1774             delta = MIN( delta, count );
   1775             assert( delta > 0 );
   1776 
   1777             seq->first->prev->count -= delta;
   1778             seq->total -= delta;
   1779             count -= delta;
   1780             delta *= seq->elem_size;
   1781             seq->ptr -= delta;
   1782 
   1783             if( elements )
   1784             {
   1785                 elements -= delta;
   1786                 memcpy( elements, seq->ptr, delta );
   1787             }
   1788 
   1789             if( seq->first->prev->count == 0 )
   1790                 icvFreeSeqBlock( seq, 0 );
   1791         }
   1792     }
   1793     else
   1794     {
   1795         while( count > 0 )
   1796         {
   1797             int delta = seq->first->count;
   1798 
   1799             delta = MIN( delta, count );
   1800             assert( delta > 0 );
   1801 
   1802             seq->first->count -= delta;
   1803             seq->total -= delta;
   1804             count -= delta;
   1805             seq->first->start_index += delta;
   1806             delta *= seq->elem_size;
   1807 
   1808             if( elements )
   1809             {
   1810                 memcpy( elements, seq->first->data, delta );
   1811                 elements += delta;
   1812             }
   1813 
   1814             seq->first->data += delta;
   1815             if( seq->first->count == 0 )
   1816                 icvFreeSeqBlock( seq, 1 );
   1817         }
   1818     }
   1819 
   1820     __END__;
   1821 }
   1822 
   1823 
   1824 /* Remove all elements from a sequence: */
   1825 CV_IMPL void
   1826 cvClearSeq( CvSeq *seq )
   1827 {
   1828     CV_FUNCNAME( "cvClearSeq" );
   1829 
   1830     __BEGIN__;
   1831 
   1832     if( !seq )
   1833         CV_ERROR( CV_StsNullPtr, "" );
   1834     cvSeqPopMulti( seq, 0, seq->total );
   1835 
   1836     __END__;
   1837 }
   1838 
   1839 
   1840 CV_IMPL CvSeq*
   1841 cvSeqSlice( const CvSeq* seq, CvSlice slice, CvMemStorage* storage, int copy_data )
   1842 {
   1843     CvSeq* subseq = 0;
   1844 
   1845     CV_FUNCNAME("cvSeqSlice");
   1846 
   1847     __BEGIN__;
   1848 
   1849     int elem_size, count, length;
   1850     CvSeqReader reader;
   1851     CvSeqBlock *block, *first_block = 0, *last_block = 0;
   1852 
   1853     if( !CV_IS_SEQ(seq) )
   1854         CV_ERROR( CV_StsBadArg, "Invalid sequence header" );
   1855 
   1856     if( !storage )
   1857     {
   1858         storage = seq->storage;
   1859         if( !storage )
   1860             CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
   1861     }
   1862 
   1863     elem_size = seq->elem_size;
   1864     length = cvSliceLength( slice, seq );
   1865     if( slice.start_index < 0 )
   1866         slice.start_index += seq->total;
   1867     else if( slice.start_index >= seq->total )
   1868         slice.start_index -= seq->total;
   1869     if( (unsigned)length > (unsigned)seq->total ||
   1870         ((unsigned)slice.start_index >= (unsigned)seq->total && length != 0) )
   1871         CV_ERROR( CV_StsOutOfRange, "Bad sequence slice" );
   1872 
   1873     CV_CALL( subseq = cvCreateSeq( seq->flags, seq->header_size, elem_size, storage ));
   1874 
   1875     if( length > 0 )
   1876     {
   1877         cvStartReadSeq( seq, &reader, 0 );
   1878         cvSetSeqReaderPos( &reader, slice.start_index, 0 );
   1879         count = (int)((reader.block_max - reader.ptr)/elem_size);
   1880 
   1881         do
   1882         {
   1883             int bl = MIN( count, length );
   1884 
   1885             if( !copy_data )
   1886             {
   1887                 block = (CvSeqBlock*)cvMemStorageAlloc( storage, sizeof(*block) );
   1888                 if( !first_block )
   1889                 {
   1890                     first_block = subseq->first = block->prev = block->next = block;
   1891                     block->start_index = 0;
   1892                 }
   1893                 else
   1894                 {
   1895                     block->prev = last_block;
   1896                     block->next = first_block;
   1897                     last_block->next = first_block->prev = block;
   1898                     block->start_index = last_block->start_index + last_block->count;
   1899                 }
   1900                 last_block = block;
   1901                 block->data = reader.ptr;
   1902                 block->count = bl;
   1903                 subseq->total += bl;
   1904             }
   1905             else
   1906                 cvSeqPushMulti( subseq, reader.ptr, bl, 0 );
   1907             length -= bl;
   1908             reader.block = reader.block->next;
   1909             reader.ptr = reader.block->data;
   1910             count = reader.block->count;
   1911         }
   1912         while( length > 0 );
   1913     }
   1914 
   1915     __END__;
   1916 
   1917     return subseq;
   1918 }
   1919 
   1920 
   1921 // Remove slice from the middle of the sequence.
   1922 // !!! TODO !!! Implement more efficient algorithm
   1923 CV_IMPL void
   1924 cvSeqRemoveSlice( CvSeq* seq, CvSlice slice )
   1925 {
   1926     CV_FUNCNAME("cvSeqRemoveSlice");
   1927 
   1928     __BEGIN__;
   1929 
   1930     int total, length;
   1931 
   1932     if( !CV_IS_SEQ(seq) )
   1933         CV_ERROR( CV_StsBadArg, "Invalid sequence header" );
   1934 
   1935     length = cvSliceLength( slice, seq );
   1936     total = seq->total;
   1937 
   1938     if( slice.start_index < 0 )
   1939         slice.start_index += total;
   1940     else if( slice.start_index >= total )
   1941         slice.start_index -= total;
   1942 
   1943     if( (unsigned)slice.start_index >= (unsigned)total )
   1944         CV_ERROR( CV_StsOutOfRange, "start slice index is out of range" );
   1945 
   1946     slice.end_index = slice.start_index + length;
   1947 
   1948     if( slice.end_index < total )
   1949     {
   1950         CvSeqReader reader_to, reader_from;
   1951         int elem_size = seq->elem_size;
   1952 
   1953         cvStartReadSeq( seq, &reader_to );
   1954         cvStartReadSeq( seq, &reader_from );
   1955 
   1956         if( slice.start_index > total - slice.end_index )
   1957         {
   1958             int i, count = seq->total - slice.end_index;
   1959             cvSetSeqReaderPos( &reader_to, slice.start_index );
   1960             cvSetSeqReaderPos( &reader_from, slice.end_index );
   1961 
   1962             for( i = 0; i < count; i++ )
   1963             {
   1964                 CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
   1965                 CV_NEXT_SEQ_ELEM( elem_size, reader_to );
   1966                 CV_NEXT_SEQ_ELEM( elem_size, reader_from );
   1967             }
   1968 
   1969             cvSeqPopMulti( seq, 0, slice.end_index - slice.start_index );
   1970         }
   1971         else
   1972         {
   1973             int i, count = slice.start_index;
   1974             cvSetSeqReaderPos( &reader_to, slice.end_index );
   1975             cvSetSeqReaderPos( &reader_from, slice.start_index );
   1976 
   1977             for( i = 0; i < count; i++ )
   1978             {
   1979                 CV_PREV_SEQ_ELEM( elem_size, reader_to );
   1980                 CV_PREV_SEQ_ELEM( elem_size, reader_from );
   1981 
   1982                 CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
   1983             }
   1984 
   1985             cvSeqPopMulti( seq, 0, slice.end_index - slice.start_index, 1 );
   1986         }
   1987     }
   1988     else
   1989     {
   1990         cvSeqPopMulti( seq, 0, total - slice.start_index );
   1991         cvSeqPopMulti( seq, 0, slice.end_index - total, 1 );
   1992     }
   1993 
   1994     __END__;
   1995 }
   1996 
   1997 
   1998 // Insert a sequence into the middle of another sequence:
   1999 // !!! TODO !!! Implement more efficient algorithm
   2000 CV_IMPL void
   2001 cvSeqInsertSlice( CvSeq* seq, int index, const CvArr* from_arr )
   2002 {
   2003     CvSeqReader reader_to, reader_from;
   2004     int i, elem_size, total, from_total;
   2005 
   2006     CV_FUNCNAME("cvSeqInsertSlice");
   2007 
   2008     __BEGIN__;
   2009 
   2010     CvSeq from_header, *from = (CvSeq*)from_arr;
   2011     CvSeqBlock block;
   2012 
   2013     if( !CV_IS_SEQ(seq) )
   2014         CV_ERROR( CV_StsBadArg, "Invalid destination sequence header" );
   2015 
   2016     if( !CV_IS_SEQ(from))
   2017     {
   2018         CvMat* mat = (CvMat*)from;
   2019         if( !CV_IS_MAT(mat))
   2020             CV_ERROR( CV_StsBadArg, "Source is not a sequence nor matrix" );
   2021 
   2022         if( !CV_IS_MAT_CONT(mat->type) || (mat->rows != 1 && mat->cols != 1) )
   2023             CV_ERROR( CV_StsBadArg, "The source array must be 1d coninuous vector" );
   2024 
   2025         CV_CALL( from = cvMakeSeqHeaderForArray( CV_SEQ_KIND_GENERIC, sizeof(from_header),
   2026                                                  CV_ELEM_SIZE(mat->type),
   2027                                                  mat->data.ptr, mat->cols + mat->rows - 1,
   2028                                                  &from_header, &block ));
   2029     }
   2030 
   2031     if( seq->elem_size != from->elem_size )
   2032         CV_ERROR( CV_StsUnmatchedSizes,
   2033         "Source and destination sequence element sizes are different." );
   2034 
   2035     from_total = from->total;
   2036 
   2037     if( from_total == 0 )
   2038         EXIT;
   2039 
   2040     total = seq->total;
   2041     index += index < 0 ? total : 0;
   2042     index -= index > total ? total : 0;
   2043 
   2044     if( (unsigned)index > (unsigned)total )
   2045         CV_ERROR( CV_StsOutOfRange, "" );
   2046 
   2047     elem_size = seq->elem_size;
   2048 
   2049     if( index < (total >> 1) )
   2050     {
   2051         cvSeqPushMulti( seq, 0, from_total, 1 );
   2052 
   2053         cvStartReadSeq( seq, &reader_to );
   2054         cvStartReadSeq( seq, &reader_from );
   2055         cvSetSeqReaderPos( &reader_from, from_total );
   2056 
   2057         for( i = 0; i < index; i++ )
   2058         {
   2059             CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
   2060             CV_NEXT_SEQ_ELEM( elem_size, reader_to );
   2061             CV_NEXT_SEQ_ELEM( elem_size, reader_from );
   2062         }
   2063     }
   2064     else
   2065     {
   2066         cvSeqPushMulti( seq, 0, from_total );
   2067 
   2068         cvStartReadSeq( seq, &reader_to );
   2069         cvStartReadSeq( seq, &reader_from );
   2070         cvSetSeqReaderPos( &reader_from, total );
   2071         cvSetSeqReaderPos( &reader_to, seq->total );
   2072 
   2073         for( i = 0; i < total - index; i++ )
   2074         {
   2075             CV_PREV_SEQ_ELEM( elem_size, reader_to );
   2076             CV_PREV_SEQ_ELEM( elem_size, reader_from );
   2077             CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
   2078         }
   2079     }
   2080 
   2081     cvStartReadSeq( from, &reader_from );
   2082     cvSetSeqReaderPos( &reader_to, index );
   2083 
   2084     for( i = 0; i < from_total; i++ )
   2085     {
   2086         CV_MEMCPY_AUTO( reader_to.ptr, reader_from.ptr, elem_size );
   2087         CV_NEXT_SEQ_ELEM( elem_size, reader_to );
   2088         CV_NEXT_SEQ_ELEM( elem_size, reader_from );
   2089     }
   2090 
   2091     __END__;
   2092 }
   2093 
   2094 // Sort the sequence using user-specified comparison function.
   2095 // The semantics is similar to qsort() function.
   2096 // The code is based on BSD system qsort():
   2097 //    * Copyright (c) 1992, 1993
   2098 //    *  The Regents of the University of California.  All rights reserved.
   2099 //    *
   2100 //    * Redistribution and use in source and binary forms, with or without
   2101 //    * modification, are permitted provided that the following conditions
   2102 //    * are met:
   2103 //    * 1. Redistributions of source code must retain the above copyright
   2104 //    *    notice, this list of conditions and the following disclaimer.
   2105 //    * 2. Redistributions in binary form must reproduce the above copyright
   2106 //    *    notice, this list of conditions and the following disclaimer in the
   2107 //    *    documentation and/or other materials provided with the distribution.
   2108 //    * 3. All advertising materials mentioning features or use of this software
   2109 //    *    must display the following acknowledgement:
   2110 //    *  This product includes software developed by the University of
   2111 //    *  California, Berkeley and its contributors.
   2112 //    * 4. Neither the name of the University nor the names of its contributors
   2113 //    *    may be used to endorse or promote products derived from this software
   2114 //    *    without specific prior written permission.
   2115 //    *
   2116 //    * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   2117 //    * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   2118 //    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   2119 //    * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   2120 //    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   2121 //    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   2122 //    * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   2123 //    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   2124 //    * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   2125 //    * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   2126 //    * SUCH DAMAGE.
   2127 
   2128 typedef struct CvSeqReaderPos
   2129 {
   2130     CvSeqBlock* block;
   2131     schar* ptr;
   2132     schar* block_min;
   2133     schar* block_max;
   2134 }
   2135 CvSeqReaderPos;
   2136 
   2137 #define CV_SAVE_READER_POS( reader, pos )   \
   2138 {                                           \
   2139     (pos).block = (reader).block;           \
   2140     (pos).ptr = (reader).ptr;               \
   2141     (pos).block_min = (reader).block_min;   \
   2142     (pos).block_max = (reader).block_max;   \
   2143 }
   2144 
   2145 #define CV_RESTORE_READER_POS( reader, pos )\
   2146 {                                           \
   2147     (reader).block = (pos).block;           \
   2148     (reader).ptr = (pos).ptr;               \
   2149     (reader).block_min = (pos).block_min;   \
   2150     (reader).block_max = (pos).block_max;   \
   2151 }
   2152 
   2153 inline schar*
   2154 icvMed3( schar* a, schar* b, schar* c, CvCmpFunc cmp_func, void* aux )
   2155 {
   2156     return cmp_func(a, b, aux) < 0 ?
   2157       (cmp_func(b, c, aux) < 0 ? b : cmp_func(a, c, aux) < 0 ? c : a)
   2158      :(cmp_func(b, c, aux) > 0 ? b : cmp_func(a, c, aux) < 0 ? a : c);
   2159 }
   2160 
   2161 CV_IMPL void
   2162 cvSeqSort( CvSeq* seq, CvCmpFunc cmp_func, void* aux )
   2163 {
   2164     int elem_size;
   2165     int isort_thresh = 7;
   2166     CvSeqReader left, right;
   2167     int sp = 0;
   2168 
   2169     struct
   2170     {
   2171         CvSeqReaderPos lb;
   2172         CvSeqReaderPos ub;
   2173     }
   2174     stack[48];
   2175 
   2176     CV_FUNCNAME( "cvSeqSort" );
   2177 
   2178     __BEGIN__;
   2179 
   2180     if( !CV_IS_SEQ(seq) )
   2181         CV_ERROR( !seq ? CV_StsNullPtr : CV_StsBadArg, "Bad input sequence" );
   2182 
   2183     if( !cmp_func )
   2184         CV_ERROR( CV_StsNullPtr, "Null compare function" );
   2185 
   2186     if( seq->total <= 1 )
   2187         EXIT;
   2188 
   2189     elem_size = seq->elem_size;
   2190     isort_thresh *= elem_size;
   2191 
   2192     cvStartReadSeq( seq, &left, 0 );
   2193     right = left;
   2194     CV_SAVE_READER_POS( left, stack[0].lb );
   2195     CV_PREV_SEQ_ELEM( elem_size, right );
   2196     CV_SAVE_READER_POS( right, stack[0].ub );
   2197 
   2198     while( sp >= 0 )
   2199     {
   2200         CV_RESTORE_READER_POS( left, stack[sp].lb );
   2201         CV_RESTORE_READER_POS( right, stack[sp].ub );
   2202         sp--;
   2203 
   2204         for(;;)
   2205         {
   2206             int i, n, m;
   2207             CvSeqReader ptr, ptr2;
   2208 
   2209             if( left.block == right.block )
   2210                 n = (int)(right.ptr - left.ptr) + elem_size;
   2211             else
   2212             {
   2213                 n = cvGetSeqReaderPos( &right );
   2214                 n = (n - cvGetSeqReaderPos( &left ) + 1)*elem_size;
   2215             }
   2216 
   2217             if( n <= isort_thresh )
   2218             {
   2219             insert_sort:
   2220                 ptr = ptr2 = left;
   2221                 CV_NEXT_SEQ_ELEM( elem_size, ptr );
   2222                 CV_NEXT_SEQ_ELEM( elem_size, right );
   2223                 while( ptr.ptr != right.ptr )
   2224                 {
   2225                     ptr2.ptr = ptr.ptr;
   2226                     if( ptr2.block != ptr.block )
   2227                     {
   2228                         ptr2.block = ptr.block;
   2229                         ptr2.block_min = ptr.block_min;
   2230                         ptr2.block_max = ptr.block_max;
   2231                     }
   2232                     while( ptr2.ptr != left.ptr )
   2233                     {
   2234                         schar* cur = ptr2.ptr;
   2235                         CV_PREV_SEQ_ELEM( elem_size, ptr2 );
   2236                         if( cmp_func( ptr2.ptr, cur, aux ) <= 0 )
   2237                             break;
   2238                         CV_SWAP_ELEMS( ptr2.ptr, cur, elem_size );
   2239                     }
   2240                     CV_NEXT_SEQ_ELEM( elem_size, ptr );
   2241                 }
   2242                 break;
   2243             }
   2244             else
   2245             {
   2246                 CvSeqReader left0, left1, right0, right1;
   2247                 CvSeqReader tmp0, tmp1;
   2248                 schar *m1, *m2, *m3, *pivot;
   2249                 int swap_cnt = 0;
   2250                 int l, l0, l1, r, r0, r1;
   2251 
   2252                 left0 = tmp0 = left;
   2253                 right0 = right1 = right;
   2254                 n /= elem_size;
   2255 
   2256                 if( n > 40 )
   2257                 {
   2258                     int d = n / 8;
   2259                     schar *p1, *p2, *p3;
   2260                     p1 = tmp0.ptr;
   2261                     cvSetSeqReaderPos( &tmp0, d, 1 );
   2262                     p2 = tmp0.ptr;
   2263                     cvSetSeqReaderPos( &tmp0, d, 1 );
   2264                     p3 = tmp0.ptr;
   2265                     m1 = icvMed3( p1, p2, p3, cmp_func, aux );
   2266                     cvSetSeqReaderPos( &tmp0, (n/2) - d*3, 1 );
   2267                     p1 = tmp0.ptr;
   2268                     cvSetSeqReaderPos( &tmp0, d, 1 );
   2269                     p2 = tmp0.ptr;
   2270                     cvSetSeqReaderPos( &tmp0, d, 1 );
   2271                     p3 = tmp0.ptr;
   2272                     m2 = icvMed3( p1, p2, p3, cmp_func, aux );
   2273                     cvSetSeqReaderPos( &tmp0, n - 1 - d*3 - n/2, 1 );
   2274                     p1 = tmp0.ptr;
   2275                     cvSetSeqReaderPos( &tmp0, d, 1 );
   2276                     p2 = tmp0.ptr;
   2277                     cvSetSeqReaderPos( &tmp0, d, 1 );
   2278                     p3 = tmp0.ptr;
   2279                     m3 = icvMed3( p1, p2, p3, cmp_func, aux );
   2280                 }
   2281                 else
   2282                 {
   2283                     m1 = tmp0.ptr;
   2284                     cvSetSeqReaderPos( &tmp0, n/2, 1 );
   2285                     m2 = tmp0.ptr;
   2286                     cvSetSeqReaderPos( &tmp0, n - 1 - n/2, 1 );
   2287                     m3 = tmp0.ptr;
   2288                 }
   2289 
   2290                 pivot = icvMed3( m1, m2, m3, cmp_func, aux );
   2291                 left = left0;
   2292                 if( pivot != left.ptr )
   2293                 {
   2294                     CV_SWAP_ELEMS( pivot, left.ptr, elem_size );
   2295                     pivot = left.ptr;
   2296                 }
   2297                 CV_NEXT_SEQ_ELEM( elem_size, left );
   2298                 left1 = left;
   2299 
   2300                 for(;;)
   2301                 {
   2302                     while( left.ptr != right.ptr && (r = cmp_func(left.ptr, pivot, aux)) <= 0 )
   2303                     {
   2304                         if( r == 0 )
   2305                         {
   2306                             if( left1.ptr != left.ptr )
   2307                                 CV_SWAP_ELEMS( left1.ptr, left.ptr, elem_size );
   2308                             swap_cnt = 1;
   2309                             CV_NEXT_SEQ_ELEM( elem_size, left1 );
   2310                         }
   2311                         CV_NEXT_SEQ_ELEM( elem_size, left );
   2312                     }
   2313 
   2314                     while( left.ptr != right.ptr && (r = cmp_func(right.ptr,pivot, aux)) >= 0 )
   2315                     {
   2316                         if( r == 0 )
   2317                         {
   2318                             if( right1.ptr != right.ptr )
   2319                                 CV_SWAP_ELEMS( right1.ptr, right.ptr, elem_size );
   2320                             swap_cnt = 1;
   2321                             CV_PREV_SEQ_ELEM( elem_size, right1 );
   2322                         }
   2323                         CV_PREV_SEQ_ELEM( elem_size, right );
   2324                     }
   2325 
   2326                     if( left.ptr == right.ptr )
   2327                     {
   2328                         r = cmp_func(left.ptr, pivot, aux);
   2329                         if( r == 0 )
   2330                         {
   2331                             if( left1.ptr != left.ptr )
   2332                                 CV_SWAP_ELEMS( left1.ptr, left.ptr, elem_size );
   2333                             swap_cnt = 1;
   2334                             CV_NEXT_SEQ_ELEM( elem_size, left1 );
   2335                         }
   2336                         if( r <= 0 )
   2337                         {
   2338                             CV_NEXT_SEQ_ELEM( elem_size, left );
   2339                         }
   2340                         else
   2341                         {
   2342                             CV_PREV_SEQ_ELEM( elem_size, right );
   2343                         }
   2344                         break;
   2345                     }
   2346 
   2347                     CV_SWAP_ELEMS( left.ptr, right.ptr, elem_size );
   2348                     CV_NEXT_SEQ_ELEM( elem_size, left );
   2349                     r = left.ptr == right.ptr;
   2350                     CV_PREV_SEQ_ELEM( elem_size, right );
   2351                     swap_cnt = 1;
   2352                     if( r )
   2353                         break;
   2354                 }
   2355 
   2356                 if( swap_cnt == 0 )
   2357                 {
   2358                     left = left0, right = right0;
   2359                     goto insert_sort;
   2360                 }
   2361 
   2362                 l = cvGetSeqReaderPos( &left );
   2363                 if( l == 0 )
   2364                     l = seq->total;
   2365                 l0 = cvGetSeqReaderPos( &left0 );
   2366                 l1 = cvGetSeqReaderPos( &left1 );
   2367                 if( l1 == 0 )
   2368                     l1 = seq->total;
   2369 
   2370                 n = MIN( l - l1, l1 - l0 );
   2371                 if( n > 0 )
   2372                 {
   2373                     tmp0 = left0;
   2374                     tmp1 = left;
   2375                     cvSetSeqReaderPos( &tmp1, 0-n, 1 );
   2376                     for( i = 0; i < n; i++ )
   2377                     {
   2378                         CV_SWAP_ELEMS( tmp0.ptr, tmp1.ptr, elem_size );
   2379                         CV_NEXT_SEQ_ELEM( elem_size, tmp0 );
   2380                         CV_NEXT_SEQ_ELEM( elem_size, tmp1 );
   2381                     }
   2382                 }
   2383 
   2384                 r = cvGetSeqReaderPos( &right );
   2385                 r0 = cvGetSeqReaderPos( &right0 );
   2386                 r1 = cvGetSeqReaderPos( &right1 );
   2387                 m = MIN( r0 - r1, r1 - r );
   2388                 if( m > 0 )
   2389                 {
   2390                     tmp0 = left;
   2391                     tmp1 = right0;
   2392                     cvSetSeqReaderPos( &tmp1, 1-m, 1 );
   2393                     for( i = 0; i < m; i++ )
   2394                     {
   2395                         CV_SWAP_ELEMS( tmp0.ptr, tmp1.ptr, elem_size );
   2396                         CV_NEXT_SEQ_ELEM( elem_size, tmp0 );
   2397                         CV_NEXT_SEQ_ELEM( elem_size, tmp1 );
   2398                     }
   2399                 }
   2400 
   2401                 n = l - l1;
   2402                 m = r1 - r;
   2403                 if( n > 1 )
   2404                 {
   2405                     if( m > 1 )
   2406                     {
   2407                         if( n > m )
   2408                         {
   2409                             sp++;
   2410                             CV_SAVE_READER_POS( left0, stack[sp].lb );
   2411                             cvSetSeqReaderPos( &left0, n - 1, 1 );
   2412                             CV_SAVE_READER_POS( left0, stack[sp].ub );
   2413                             left = right = right0;
   2414                             cvSetSeqReaderPos( &left, 1 - m, 1 );
   2415                         }
   2416                         else
   2417                         {
   2418                             sp++;
   2419                             CV_SAVE_READER_POS( right0, stack[sp].ub );
   2420                             cvSetSeqReaderPos( &right0, 1 - m, 1 );
   2421                             CV_SAVE_READER_POS( right0, stack[sp].lb );
   2422                             left = right = left0;
   2423                             cvSetSeqReaderPos( &right, n - 1, 1 );
   2424                         }
   2425                     }
   2426                     else
   2427                     {
   2428                         left = right = left0;
   2429                         cvSetSeqReaderPos( &right, n - 1, 1 );
   2430                     }
   2431                 }
   2432                 else if( m > 1 )
   2433                 {
   2434                     left = right = right0;
   2435                     cvSetSeqReaderPos( &left, 1 - m, 1 );
   2436                 }
   2437                 else
   2438                     break;
   2439             }
   2440         }
   2441     }
   2442 
   2443     __END__;
   2444 }
   2445 
   2446 
   2447 CV_IMPL schar*
   2448 cvSeqSearch( CvSeq* seq, const void* _elem, CvCmpFunc cmp_func,
   2449              int is_sorted, int* _idx, void* userdata )
   2450 {
   2451     schar* result = 0;
   2452     const schar* elem = (const schar*)_elem;
   2453     int idx = -1;
   2454 
   2455     CV_FUNCNAME("cvSeqSearch");
   2456 
   2457     __BEGIN__;
   2458 
   2459     int elem_size, i, j, total;
   2460 
   2461     if( !CV_IS_SEQ(seq) )
   2462         CV_ERROR( !seq ? CV_StsNullPtr : CV_StsBadArg, "Bad input sequence" );
   2463 
   2464     if( !elem )
   2465         CV_ERROR( CV_StsNullPtr, "Null element pointer" );
   2466 
   2467     elem_size = seq->elem_size;
   2468     total = seq->total;
   2469 
   2470     if( total == 0 )
   2471         EXIT;
   2472 
   2473     if( !is_sorted )
   2474     {
   2475         CvSeqReader reader;
   2476         cvStartReadSeq( seq, &reader, 0 );
   2477 
   2478         if( cmp_func )
   2479         {
   2480             for( i = 0; i < total; i++ )
   2481             {
   2482                 if( cmp_func( elem, reader.ptr, userdata ) == 0 )
   2483                     break;
   2484                 CV_NEXT_SEQ_ELEM( elem_size, reader );
   2485             }
   2486         }
   2487         else if( (elem_size & (sizeof(int)-1)) == 0 )
   2488         {
   2489             for( i = 0; i < total; i++ )
   2490             {
   2491                 for( j = 0; j < elem_size; j += sizeof(int) )
   2492                 {
   2493                     if( *(const int*)(reader.ptr + j) != *(const int*)(elem + j) )
   2494                         break;
   2495                 }
   2496                 if( j == elem_size )
   2497                     break;
   2498                 CV_NEXT_SEQ_ELEM( elem_size, reader );
   2499             }
   2500         }
   2501         else
   2502         {
   2503             for( i = 0; i < total; i++ )
   2504             {
   2505                 for( j = 0; j < elem_size; j++ )
   2506                 {
   2507                     if( reader.ptr[j] != elem[j] )
   2508                         break;
   2509                 }
   2510                 if( j == elem_size )
   2511                     break;
   2512                 CV_NEXT_SEQ_ELEM( elem_size, reader );
   2513             }
   2514         }
   2515 
   2516         idx = i;
   2517         if( i < total )
   2518             result = reader.ptr;
   2519     }
   2520     else
   2521     {
   2522         if( !cmp_func )
   2523             CV_ERROR( CV_StsNullPtr, "Null compare function" );
   2524 
   2525         i = 0, j = total;
   2526 
   2527         while( j > i )
   2528         {
   2529             int k = (i+j)>>1, code;
   2530             schar* ptr = cvGetSeqElem( seq, k );
   2531             code = cmp_func( elem, ptr, userdata );
   2532             if( !code )
   2533             {
   2534                 result = ptr;
   2535                 idx = k;
   2536                 EXIT;
   2537             }
   2538             if( code < 0 )
   2539                 j = k;
   2540             else
   2541                 i = k+1;
   2542         }
   2543         idx = j;
   2544     }
   2545 
   2546     __END__;
   2547 
   2548     if( _idx )
   2549         *_idx = idx;
   2550 
   2551     return result;
   2552 }
   2553 
   2554 
   2555 CV_IMPL void
   2556 cvSeqInvert( CvSeq* seq )
   2557 {
   2558     CV_FUNCNAME( "cvSeqInvert" );
   2559 
   2560     __BEGIN__;
   2561 
   2562     CvSeqReader left_reader, right_reader;
   2563     int elem_size;
   2564     int i, count;
   2565 
   2566     CV_CALL( cvStartReadSeq( seq, &left_reader, 0 ));
   2567     CV_CALL( cvStartReadSeq( seq, &right_reader, 1 ));
   2568     elem_size = seq->elem_size;
   2569     count = seq->total >> 1;
   2570 
   2571     for( i = 0; i < count; i++ )
   2572     {
   2573         CV_SWAP_ELEMS( left_reader.ptr, right_reader.ptr, elem_size );
   2574         CV_NEXT_SEQ_ELEM( elem_size, left_reader );
   2575         CV_PREV_SEQ_ELEM( elem_size, right_reader );
   2576     }
   2577 
   2578     __END__;
   2579 }
   2580 
   2581 
   2582 typedef struct CvPTreeNode
   2583 {
   2584     struct CvPTreeNode* parent;
   2585     schar* element;
   2586     int rank;
   2587 }
   2588 CvPTreeNode;
   2589 
   2590 
   2591 // This function splits the input sequence or set into one or more equivalence classes.
   2592 // is_equal(a,b,...) returns non-zero if the two sequence elements
   2593 // belong to the same class.  The function returns sequence of integers -
   2594 // 0-based class indexes for each element.
   2595 //
   2596 // The algorithm is described in "Introduction to Algorithms"
   2597 // by Cormen, Leiserson and Rivest, chapter "Data structures for disjoint sets"
   2598 CV_IMPL  int
   2599 cvSeqPartition( const CvSeq* seq, CvMemStorage* storage, CvSeq** labels,
   2600                 CvCmpFunc is_equal, void* userdata )
   2601 {
   2602     CvSeq* result = 0;
   2603     CvMemStorage* temp_storage = 0;
   2604     int class_idx = 0;
   2605 
   2606     CV_FUNCNAME( "cvSeqPartition" );
   2607 
   2608     __BEGIN__;
   2609 
   2610     CvSeqWriter writer;
   2611     CvSeqReader reader, reader0;
   2612     CvSeq* nodes;
   2613     int i, j;
   2614     int is_set;
   2615 
   2616     if( !labels )
   2617         CV_ERROR( CV_StsNullPtr, "" );
   2618 
   2619     if( !seq || !is_equal )
   2620         CV_ERROR( CV_StsNullPtr, "" );
   2621 
   2622     if( !storage )
   2623         storage = seq->storage;
   2624 
   2625     if( !storage )
   2626         CV_ERROR( CV_StsNullPtr, "" );
   2627 
   2628     is_set = CV_IS_SET(seq);
   2629 
   2630     temp_storage = cvCreateChildMemStorage( storage );
   2631 
   2632     nodes = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPTreeNode), temp_storage );
   2633 
   2634     cvStartReadSeq( seq, &reader );
   2635     memset( &writer, 0, sizeof(writer));
   2636     cvStartAppendToSeq( nodes, &writer );
   2637 
   2638     // Initial O(N) pass. Make a forest of single-vertex trees.
   2639     for( i = 0; i < seq->total; i++ )
   2640     {
   2641         CvPTreeNode node = { 0, 0, 0 };
   2642         if( !is_set || CV_IS_SET_ELEM( reader.ptr ))
   2643             node.element = reader.ptr;
   2644         CV_WRITE_SEQ_ELEM( node, writer );
   2645         CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
   2646     }
   2647 
   2648     cvEndWriteSeq( &writer );
   2649 
   2650     // Because in the next loop we will iterate
   2651     // through all the sequence nodes each time,
   2652     // we do not need to initialize reader every time:
   2653     cvStartReadSeq( nodes, &reader );
   2654     cvStartReadSeq( nodes, &reader0 );
   2655 
   2656     // The main O(N^2) pass. Merge connected components.
   2657     for( i = 0; i < nodes->total; i++ )
   2658     {
   2659         CvPTreeNode* node = (CvPTreeNode*)(reader0.ptr);
   2660         CvPTreeNode* root = node;
   2661         CV_NEXT_SEQ_ELEM( nodes->elem_size, reader0 );
   2662 
   2663         if( !node->element )
   2664             continue;
   2665 
   2666         // find root
   2667         while( root->parent )
   2668             root = root->parent;
   2669 
   2670         for( j = 0; j < nodes->total; j++ )
   2671         {
   2672             CvPTreeNode* node2 = (CvPTreeNode*)reader.ptr;
   2673 
   2674             if( node2->element && node2 != node &&
   2675                 is_equal( node->element, node2->element, userdata ))
   2676             {
   2677                 CvPTreeNode* root2 = node2;
   2678 
   2679                 // unite both trees
   2680                 while( root2->parent )
   2681                     root2 = root2->parent;
   2682 
   2683                 if( root2 != root )
   2684                 {
   2685                     if( root->rank > root2->rank )
   2686                         root2->parent = root;
   2687                     else
   2688                     {
   2689                         root->parent = root2;
   2690                         root2->rank += root->rank == root2->rank;
   2691                         root = root2;
   2692                     }
   2693                     assert( root->parent == 0 );
   2694 
   2695                     // Compress path from node2 to the root:
   2696                     while( node2->parent )
   2697                     {
   2698                         CvPTreeNode* temp = node2;
   2699                         node2 = node2->parent;
   2700                         temp->parent = root;
   2701                     }
   2702 
   2703                     // Compress path from node to the root:
   2704                     node2 = node;
   2705                     while( node2->parent )
   2706                     {
   2707                         CvPTreeNode* temp = node2;
   2708                         node2 = node2->parent;
   2709                         temp->parent = root;
   2710                     }
   2711                 }
   2712             }
   2713 
   2714             CV_NEXT_SEQ_ELEM( sizeof(*node), reader );
   2715         }
   2716     }
   2717 
   2718     // Final O(N) pass (Enumerate classes)
   2719     // Reuse reader one more time
   2720     result = cvCreateSeq( 0, sizeof(CvSeq), sizeof(int), storage );
   2721     cvStartAppendToSeq( result, &writer );
   2722 
   2723     for( i = 0; i < nodes->total; i++ )
   2724     {
   2725         CvPTreeNode* node = (CvPTreeNode*)reader.ptr;
   2726         int idx = -1;
   2727 
   2728         if( node->element )
   2729         {
   2730             while( node->parent )
   2731                 node = node->parent;
   2732             if( node->rank >= 0 )
   2733                 node->rank = ~class_idx++;
   2734             idx = ~node->rank;
   2735         }
   2736 
   2737         CV_NEXT_SEQ_ELEM( sizeof(*node), reader );
   2738         CV_WRITE_SEQ_ELEM( idx, writer );
   2739     }
   2740 
   2741     cvEndWriteSeq( &writer );
   2742 
   2743     __END__;
   2744 
   2745     if( labels )
   2746         *labels = result;
   2747 
   2748     cvReleaseMemStorage( &temp_storage );
   2749     return class_idx;
   2750 }
   2751 
   2752 
   2753 /****************************************************************************************\
   2754 *                                      Set implementation                                *
   2755 \****************************************************************************************/
   2756 
   2757 /* Creates empty set: */
   2758 CV_IMPL CvSet*
   2759 cvCreateSet( int set_flags, int header_size, int elem_size, CvMemStorage * storage )
   2760 {
   2761     CvSet *set = 0;
   2762 
   2763     CV_FUNCNAME( "cvCreateSet" );
   2764 
   2765     __BEGIN__;
   2766 
   2767     if( !storage )
   2768         CV_ERROR( CV_StsNullPtr, "" );
   2769     if( header_size < (int)sizeof( CvSet ) ||
   2770         elem_size < (int)sizeof(void*)*2 ||
   2771         (elem_size & (sizeof(void*)-1)) != 0 )
   2772         CV_ERROR( CV_StsBadSize, "" );
   2773 
   2774     set = (CvSet*) cvCreateSeq( set_flags, header_size, elem_size, storage );
   2775     set->flags = (set->flags & ~CV_MAGIC_MASK) | CV_SET_MAGIC_VAL;
   2776 
   2777     __END__;
   2778 
   2779     return set;
   2780 }
   2781 
   2782 
   2783 /* Add new element to the set: */
   2784 CV_IMPL int
   2785 cvSetAdd( CvSet* set, CvSetElem* element, CvSetElem** inserted_element )
   2786 {
   2787     int id = -1;
   2788 
   2789     CV_FUNCNAME( "cvSetAdd" );
   2790 
   2791     __BEGIN__;
   2792 
   2793     CvSetElem *free_elem;
   2794 
   2795     if( !set )
   2796         CV_ERROR( CV_StsNullPtr, "" );
   2797 
   2798     if( !(set->free_elems) )
   2799     {
   2800         int count = set->total;
   2801         int elem_size = set->elem_size;
   2802         schar *ptr;
   2803         CV_CALL( icvGrowSeq( (CvSeq *) set, 0 ));
   2804 
   2805         set->free_elems = (CvSetElem*) (ptr = set->ptr);
   2806         for( ; ptr + elem_size <= set->block_max; ptr += elem_size, count++ )
   2807         {
   2808             ((CvSetElem*)ptr)->flags = count | CV_SET_ELEM_FREE_FLAG;
   2809             ((CvSetElem*)ptr)->next_free = (CvSetElem*)(ptr + elem_size);
   2810         }
   2811         assert( count <= CV_SET_ELEM_IDX_MASK+1 );
   2812         ((CvSetElem*)(ptr - elem_size))->next_free = 0;
   2813         set->first->prev->count += count - set->total;
   2814         set->total = count;
   2815         set->ptr = set->block_max;
   2816     }
   2817 
   2818     free_elem = set->free_elems;
   2819     set->free_elems = free_elem->next_free;
   2820 
   2821     id = free_elem->flags & CV_SET_ELEM_IDX_MASK;
   2822     if( element )
   2823         CV_MEMCPY_INT( free_elem, element, (size_t)set->elem_size/sizeof(int) );
   2824 
   2825     free_elem->flags = id;
   2826     set->active_count++;
   2827 
   2828     if( inserted_element )
   2829         *inserted_element = free_elem;
   2830 
   2831     __END__;
   2832 
   2833     return id;
   2834 }
   2835 
   2836 
   2837 /* Remove element from a set given element index: */
   2838 CV_IMPL void
   2839 cvSetRemove( CvSet* set, int index )
   2840 {
   2841     CV_FUNCNAME( "cvSetRemove" );
   2842 
   2843     __BEGIN__;
   2844 
   2845     CvSetElem* elem = cvGetSetElem( set, index );
   2846     if( elem )
   2847         cvSetRemoveByPtr( set, elem );
   2848     else if( !set )
   2849         CV_ERROR( CV_StsNullPtr, "" );
   2850 
   2851     __END__;
   2852 }
   2853 
   2854 
   2855 /* Remove all elements from a set: */
   2856 CV_IMPL void
   2857 cvClearSet( CvSet* set )
   2858 {
   2859     CV_FUNCNAME( "cvClearSet" );
   2860 
   2861     __BEGIN__;
   2862 
   2863     CV_CALL( cvClearSeq( (CvSeq*)set ));
   2864     set->free_elems = 0;
   2865     set->active_count = 0;
   2866 
   2867     __END__;
   2868 }
   2869 
   2870 
   2871 /****************************************************************************************\
   2872 *                                 Graph  implementation                                  *
   2873 \****************************************************************************************/
   2874 
   2875 /* Create a new graph: */
   2876 CV_IMPL CvGraph *
   2877 cvCreateGraph( int graph_type, int header_size,
   2878                int vtx_size, int edge_size, CvMemStorage * storage )
   2879 {
   2880     CvGraph *graph = 0;
   2881     CvSet *edges = 0;
   2882 
   2883     CV_FUNCNAME( "cvCleateGraph" );
   2884 
   2885     __BEGIN__;
   2886 
   2887     CvSet *vertices = 0;
   2888 
   2889     if( header_size < (int) sizeof( CvGraph     )
   2890     ||  edge_size   < (int) sizeof( CvGraphEdge )
   2891     ||  vtx_size    < (int) sizeof( CvGraphVtx  )
   2892     ){
   2893         CV_ERROR( CV_StsBadSize, "" );
   2894     }
   2895 
   2896     CV_CALL( vertices = cvCreateSet( graph_type, header_size, vtx_size, storage ));
   2897     CV_CALL( edges = cvCreateSet( CV_SEQ_KIND_GENERIC | CV_SEQ_ELTYPE_GRAPH_EDGE,
   2898                                   sizeof( CvSet ), edge_size, storage ));
   2899 
   2900     graph = (CvGraph*)vertices;
   2901     graph->edges = edges;
   2902 
   2903     __END__;
   2904 
   2905     return graph;
   2906 }
   2907 
   2908 
   2909 /* Remove all vertices and edges from a graph: */
   2910 CV_IMPL void
   2911 cvClearGraph( CvGraph * graph )
   2912 {
   2913     CV_FUNCNAME( "cvClearGraph" );
   2914 
   2915     __BEGIN__;
   2916 
   2917     if( !graph )
   2918         CV_ERROR( CV_StsNullPtr, "" );
   2919 
   2920     cvClearSet( graph->edges );
   2921     cvClearSet( (CvSet*)graph );
   2922 
   2923     __END__;
   2924 }
   2925 
   2926 
   2927 /* Add a vertex to a graph: */
   2928 CV_IMPL int
   2929 cvGraphAddVtx( CvGraph* graph, const CvGraphVtx* _vertex, CvGraphVtx** _inserted_vertex )
   2930 {
   2931     CvGraphVtx *vertex = 0;
   2932     int index = -1;
   2933 
   2934     CV_FUNCNAME( "cvGraphAddVtx" );
   2935 
   2936     __BEGIN__;
   2937 
   2938     if( !graph )
   2939         CV_ERROR( CV_StsNullPtr, "" );
   2940 
   2941     vertex = (CvGraphVtx*)cvSetNew((CvSet*)graph);
   2942     if( vertex )
   2943     {
   2944         if( _vertex )
   2945             CV_MEMCPY_INT( vertex + 1, _vertex + 1,
   2946                 (size_t)(graph->elem_size - sizeof(CvGraphVtx))/sizeof(int) );
   2947         vertex->first = 0;
   2948         index = vertex->flags;
   2949     }
   2950 
   2951     if( _inserted_vertex )
   2952         *_inserted_vertex = vertex;
   2953 
   2954     __END__;
   2955 
   2956     return index;
   2957 }
   2958 
   2959 
   2960 /* Remove a vertex from the graph together with its incident edges: */
   2961 CV_IMPL int
   2962 cvGraphRemoveVtxByPtr( CvGraph* graph, CvGraphVtx* vtx )
   2963 {
   2964     int count = -1;
   2965 
   2966     CV_FUNCNAME( "cvGraphRemoveVtxByPtr" );
   2967 
   2968     __BEGIN__;
   2969 
   2970     if( !graph || !vtx )
   2971         CV_ERROR( CV_StsNullPtr, "" );
   2972 
   2973     if( !CV_IS_SET_ELEM(vtx))
   2974         CV_ERROR( CV_StsBadArg, "The vertex does not belong to the graph" );
   2975 
   2976     count = graph->edges->active_count;
   2977     for( ;; )
   2978     {
   2979         CvGraphEdge *edge = vtx->first;
   2980         if( !edge )
   2981             break;
   2982         cvGraphRemoveEdgeByPtr( graph, edge->vtx[0], edge->vtx[1] );
   2983     }
   2984     count -= graph->edges->active_count;
   2985     cvSetRemoveByPtr( (CvSet*)graph, vtx );
   2986 
   2987     __END__;
   2988 
   2989     return count;
   2990 }
   2991 
   2992 
   2993 /* Remove a vertex from the graph together with its incident edges: */
   2994 CV_IMPL int
   2995 cvGraphRemoveVtx( CvGraph* graph, int index )
   2996 {
   2997     int count = -1;
   2998     CvGraphVtx *vtx = 0;
   2999 
   3000     CV_FUNCNAME( "cvGraphRemoveVtx" );
   3001 
   3002     __BEGIN__;
   3003 
   3004     if( !graph )
   3005         CV_ERROR( CV_StsNullPtr, "" );
   3006 
   3007     vtx = cvGetGraphVtx( graph, index );
   3008     if( !vtx )
   3009         CV_ERROR( CV_StsBadArg, "The vertex is not found" );
   3010 
   3011     count = graph->edges->active_count;
   3012     for( ;; )
   3013     {
   3014         CvGraphEdge *edge = vtx->first;
   3015         count++;
   3016 
   3017         if( !edge )
   3018             break;
   3019         cvGraphRemoveEdgeByPtr( graph, edge->vtx[0], edge->vtx[1] );
   3020     }
   3021     count -= graph->edges->active_count;
   3022     cvSetRemoveByPtr( (CvSet*)graph, vtx );
   3023 
   3024     __END__;
   3025 
   3026     return count;
   3027 }
   3028 
   3029 
   3030 /* Find a graph edge given pointers to the ending vertices: */
   3031 CV_IMPL CvGraphEdge*
   3032 cvFindGraphEdgeByPtr( const CvGraph* graph,
   3033                       const CvGraphVtx* start_vtx,
   3034                       const CvGraphVtx* end_vtx )
   3035 {
   3036     CvGraphEdge *edge = 0;
   3037     CV_FUNCNAME( "cvFindGraphEdgeByPtr" );
   3038 
   3039     __BEGIN__;
   3040 
   3041     int ofs = 0;
   3042 
   3043     if( !graph || !start_vtx || !end_vtx )
   3044         CV_ERROR( CV_StsNullPtr, "" );
   3045 
   3046     if( start_vtx == end_vtx )
   3047         EXIT;
   3048 
   3049     if( !CV_IS_GRAPH_ORIENTED( graph ) &&
   3050         (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) )
   3051     {
   3052         const CvGraphVtx* t;
   3053         CV_SWAP( start_vtx, end_vtx, t );
   3054     }
   3055 
   3056     edge = start_vtx->first;
   3057     for( ; edge; edge = edge->next[ofs] )
   3058     {
   3059         ofs = start_vtx == edge->vtx[1];
   3060         assert( ofs == 1 || start_vtx == edge->vtx[0] );
   3061         if( edge->vtx[1] == end_vtx )
   3062             break;
   3063     }
   3064 
   3065     __END__;
   3066 
   3067     return edge;
   3068 }
   3069 
   3070 
   3071 /* Find an edge in the graph given indices of the ending vertices: */
   3072 CV_IMPL CvGraphEdge *
   3073 cvFindGraphEdge( const CvGraph* graph, int start_idx, int end_idx )
   3074 {
   3075     CvGraphEdge *edge = 0;
   3076     CvGraphVtx *start_vtx;
   3077     CvGraphVtx *end_vtx;
   3078 
   3079     CV_FUNCNAME( "cvFindGraphEdge" );
   3080 
   3081     __BEGIN__;
   3082 
   3083     if( !graph )
   3084         CV_ERROR( CV_StsNullPtr, "graph pointer is NULL" );
   3085 
   3086     start_vtx = cvGetGraphVtx( graph, start_idx );
   3087     end_vtx = cvGetGraphVtx( graph, end_idx );
   3088 
   3089     edge = cvFindGraphEdgeByPtr( graph, start_vtx, end_vtx );
   3090 
   3091     __END__;
   3092 
   3093     return edge;
   3094 }
   3095 
   3096 
   3097 /* Given two vertices, return the edge
   3098  * connecting them, creating it if it
   3099  * did not already exist:
   3100  */
   3101 CV_IMPL int
   3102 cvGraphAddEdgeByPtr( CvGraph* graph,
   3103                      CvGraphVtx* start_vtx, CvGraphVtx* end_vtx,
   3104                      const CvGraphEdge* _edge,
   3105                      CvGraphEdge ** _inserted_edge )
   3106 {
   3107     CvGraphEdge *edge = 0;
   3108     int result = -1;
   3109 
   3110     CV_FUNCNAME( "cvGraphAddEdgeByPtr" );
   3111 
   3112     __BEGIN__;
   3113 
   3114     int delta;
   3115 
   3116     if( !graph )
   3117         CV_ERROR( CV_StsNullPtr, "graph pointer is NULL" );
   3118 
   3119     if( !CV_IS_GRAPH_ORIENTED( graph ) &&
   3120         (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) )
   3121     {
   3122         CvGraphVtx* t;
   3123         CV_SWAP( start_vtx, end_vtx, t );
   3124     }
   3125 
   3126     CV_CALL( edge = cvFindGraphEdgeByPtr( graph, start_vtx, end_vtx ));
   3127     if( edge )
   3128     {
   3129         result = 0;
   3130         EXIT;
   3131     }
   3132 
   3133     if( start_vtx == end_vtx )
   3134         CV_ERROR( start_vtx ? CV_StsBadArg : CV_StsNullPtr,
   3135         "vertex pointers coinside (or set to NULL)" );
   3136 
   3137     CV_CALL( edge = (CvGraphEdge*)cvSetNew( (CvSet*)(graph->edges) ));
   3138     assert( edge->flags >= 0 );
   3139 
   3140     edge->vtx[0] = start_vtx;
   3141     edge->vtx[1] = end_vtx;
   3142     edge->next[0] = start_vtx->first;
   3143     edge->next[1] = end_vtx->first;
   3144     start_vtx->first = end_vtx->first = edge;
   3145 
   3146     delta = (graph->edges->elem_size - sizeof(*edge))/sizeof(int);
   3147     if( _edge )
   3148     {
   3149         if( delta > 0 )
   3150             CV_MEMCPY_INT( edge + 1, _edge + 1, delta );
   3151         edge->weight = _edge->weight;
   3152     }
   3153     else
   3154     {
   3155         if( delta > 0 )
   3156             CV_ZERO_INT( edge + 1, delta );
   3157         edge->weight = 1.f;
   3158     }
   3159 
   3160     result = 1;
   3161 
   3162     __END__;
   3163 
   3164     if( _inserted_edge )
   3165         *_inserted_edge = edge;
   3166 
   3167     return result;
   3168 }
   3169 
   3170 /* Given two vertices, return the edge
   3171  * connecting them, creating it if it
   3172  * did not already exist:
   3173  */
   3174 CV_IMPL int
   3175 cvGraphAddEdge( CvGraph* graph,
   3176                 int start_idx, int end_idx,
   3177                 const CvGraphEdge* _edge,
   3178                 CvGraphEdge ** _inserted_edge )
   3179 {
   3180     CvGraphVtx *start_vtx;
   3181     CvGraphVtx *end_vtx;
   3182     int result = -1;
   3183 
   3184     CV_FUNCNAME( "cvGraphAddEdge" );
   3185 
   3186     __BEGIN__;
   3187 
   3188     if( !graph )
   3189         CV_ERROR( CV_StsNullPtr, "" );
   3190 
   3191     start_vtx = cvGetGraphVtx( graph, start_idx );
   3192     end_vtx = cvGetGraphVtx( graph, end_idx );
   3193 
   3194     result = cvGraphAddEdgeByPtr( graph, start_vtx, end_vtx, _edge, _inserted_edge );
   3195 
   3196     __END__;
   3197 
   3198     return result;
   3199 }
   3200 
   3201 
   3202 /* Remove the graph edge connecting two given vertices: */
   3203 CV_IMPL void
   3204 cvGraphRemoveEdgeByPtr( CvGraph* graph, CvGraphVtx* start_vtx, CvGraphVtx* end_vtx )
   3205 {
   3206     CV_FUNCNAME( "cvGraphRemoveEdgeByPtr" );
   3207 
   3208     __BEGIN__;
   3209 
   3210     int ofs, prev_ofs;
   3211     CvGraphEdge *edge, *next_edge, *prev_edge;
   3212 
   3213     if( !graph || !start_vtx || !end_vtx )
   3214         CV_ERROR( CV_StsNullPtr, "" );
   3215 
   3216     if( start_vtx == end_vtx )
   3217         EXIT;
   3218 
   3219     if( !CV_IS_GRAPH_ORIENTED( graph ) &&
   3220         (start_vtx->flags & CV_SET_ELEM_IDX_MASK) > (end_vtx->flags & CV_SET_ELEM_IDX_MASK) )
   3221     {
   3222         CvGraphVtx* t;
   3223         CV_SWAP( start_vtx, end_vtx, t );
   3224     }
   3225 
   3226     for( ofs = prev_ofs = 0, prev_edge = 0, edge = start_vtx->first; edge != 0;
   3227          prev_ofs = ofs, prev_edge = edge, edge = edge->next[ofs] )
   3228     {
   3229         ofs = start_vtx == edge->vtx[1];
   3230         assert( ofs == 1 || start_vtx == edge->vtx[0] );
   3231         if( edge->vtx[1] == end_vtx )
   3232             break;
   3233     }
   3234 
   3235     if( !edge )
   3236         EXIT;
   3237 
   3238     next_edge = edge->next[ofs];
   3239     if( prev_edge )
   3240         prev_edge->next[prev_ofs] = next_edge;
   3241     else
   3242         start_vtx->first = next_edge;
   3243 
   3244     for( ofs = prev_ofs = 0, prev_edge = 0, edge = end_vtx->first; edge != 0;
   3245          prev_ofs = ofs, prev_edge = edge, edge = edge->next[ofs] )
   3246     {
   3247         ofs = end_vtx == edge->vtx[1];
   3248         assert( ofs == 1 || end_vtx == edge->vtx[0] );
   3249         if( edge->vtx[0] == start_vtx )
   3250             break;
   3251     }
   3252 
   3253     assert( edge != 0 );
   3254 
   3255     next_edge = edge->next[ofs];
   3256     if( prev_edge )
   3257         prev_edge->next[prev_ofs] = next_edge;
   3258     else
   3259         end_vtx->first = next_edge;
   3260 
   3261     cvSetRemoveByPtr( graph->edges, edge );
   3262 
   3263     __END__;
   3264 }
   3265 
   3266 
   3267 /* Remove the graph edge connecting two given vertices: */
   3268 CV_IMPL void
   3269 cvGraphRemoveEdge( CvGraph* graph, int start_idx, int end_idx )
   3270 {
   3271     CvGraphVtx *start_vtx;
   3272     CvGraphVtx *end_vtx;
   3273 
   3274     CV_FUNCNAME( "cvGraphRemoveEdge" );
   3275 
   3276     __BEGIN__;
   3277 
   3278     if( !graph )
   3279         CV_ERROR( CV_StsNullPtr, "" );
   3280 
   3281     start_vtx = cvGetGraphVtx( graph, start_idx );
   3282     end_vtx = cvGetGraphVtx( graph, end_idx );
   3283 
   3284     cvGraphRemoveEdgeByPtr( graph, start_vtx, end_vtx );
   3285 
   3286     __END__;
   3287 }
   3288 
   3289 
   3290 /* Count number of edges incident to a given vertex: */
   3291 CV_IMPL int
   3292 cvGraphVtxDegreeByPtr( const CvGraph* graph, const CvGraphVtx* vertex )
   3293 {
   3294     CvGraphEdge *edge;
   3295     int count = -1;
   3296 
   3297     CV_FUNCNAME( "cvGraphVtxDegreeByPtr" );
   3298 
   3299     __BEGIN__;
   3300 
   3301     if( !graph || !vertex )
   3302         CV_ERROR( CV_StsNullPtr, "" );
   3303 
   3304     for( edge = vertex->first, count = 0; edge; )
   3305     {
   3306         count++;
   3307         edge = CV_NEXT_GRAPH_EDGE( edge, vertex );
   3308     }
   3309 
   3310     __END__;
   3311 
   3312     return count;
   3313 }
   3314 
   3315 
   3316 /* Count number of edges incident to a given vertex: */
   3317 CV_IMPL int
   3318 cvGraphVtxDegree( const CvGraph* graph, int vtx_idx )
   3319 {
   3320     CvGraphVtx *vertex;
   3321     CvGraphEdge *edge;
   3322     int count = -1;
   3323 
   3324     CV_FUNCNAME( "cvGraphVtxDegree" );
   3325 
   3326     __BEGIN__;
   3327 
   3328     if( !graph )
   3329         CV_ERROR( CV_StsNullPtr, "" );
   3330 
   3331     vertex = cvGetGraphVtx( graph, vtx_idx );
   3332     if( !vertex )
   3333         CV_ERROR( CV_StsObjectNotFound, "" );
   3334 
   3335     for( edge = vertex->first, count = 0; edge; )
   3336     {
   3337         count++;
   3338         edge = CV_NEXT_GRAPH_EDGE( edge, vertex );
   3339     }
   3340 
   3341     __END__;
   3342 
   3343     return count;
   3344 }
   3345 
   3346 
   3347 typedef struct CvGraphItem
   3348 {
   3349     CvGraphVtx* vtx;
   3350     CvGraphEdge* edge;
   3351 }
   3352 CvGraphItem;
   3353 
   3354 
   3355 static  void
   3356 icvSeqElemsClearFlags( CvSeq* seq, int offset, int clear_mask )
   3357 {
   3358     CV_FUNCNAME("icvStartScanGraph");
   3359 
   3360     __BEGIN__;
   3361 
   3362     CvSeqReader reader;
   3363     int i, total, elem_size;
   3364 
   3365     if( !seq )
   3366         CV_ERROR( CV_StsNullPtr, "" );
   3367 
   3368     elem_size = seq->elem_size;
   3369     total = seq->total;
   3370 
   3371     if( (unsigned)offset > (unsigned)elem_size )
   3372         CV_ERROR( CV_StsBadArg, "" );
   3373 
   3374     CV_CALL( cvStartReadSeq( seq, &reader ));
   3375 
   3376     for( i = 0; i < total; i++ )
   3377     {
   3378         int* flag_ptr = (int*)(reader.ptr + offset);
   3379         *flag_ptr &= ~clear_mask;
   3380 
   3381         CV_NEXT_SEQ_ELEM( elem_size, reader );
   3382     }
   3383 
   3384     __END__;
   3385 }
   3386 
   3387 
   3388 static  schar*
   3389 icvSeqFindNextElem( CvSeq* seq, int offset, int mask,
   3390                     int value, int* start_index )
   3391 {
   3392     schar* elem_ptr = 0;
   3393 
   3394     CV_FUNCNAME("icvStartScanGraph");
   3395 
   3396     __BEGIN__;
   3397 
   3398     CvSeqReader reader;
   3399     int total, elem_size, index;
   3400 
   3401     if( !seq || !start_index )
   3402         CV_ERROR( CV_StsNullPtr, "" );
   3403 
   3404     elem_size = seq->elem_size;
   3405     total = seq->total;
   3406     index = *start_index;
   3407 
   3408     if( (unsigned)offset > (unsigned)elem_size )
   3409         CV_ERROR( CV_StsBadArg, "" );
   3410 
   3411     if( total == 0 )
   3412         EXIT;
   3413 
   3414     if( (unsigned)index >= (unsigned)total )
   3415     {
   3416         index %= total;
   3417         index += index < 0 ? total : 0;
   3418     }
   3419 
   3420     CV_CALL( cvStartReadSeq( seq, &reader ));
   3421 
   3422     if( index != 0 )
   3423         CV_CALL( cvSetSeqReaderPos( &reader, index ));
   3424 
   3425     for( index = 0; index < total; index++ )
   3426     {
   3427         int* flag_ptr = (int*)(reader.ptr + offset);
   3428         if( (*flag_ptr & mask) == value )
   3429             break;
   3430 
   3431         CV_NEXT_SEQ_ELEM( elem_size, reader );
   3432     }
   3433 
   3434     if( index < total )
   3435     {
   3436         elem_ptr = reader.ptr;
   3437         *start_index = index;
   3438     }
   3439 
   3440     __END__;
   3441 
   3442     return  elem_ptr;
   3443 }
   3444 
   3445 #define CV_FIELD_OFFSET( field, structtype ) ((int)(size_t)&((structtype*)0)->field)
   3446 
   3447 CV_IMPL CvGraphScanner*
   3448 cvCreateGraphScanner( CvGraph* graph, CvGraphVtx* vtx, int mask )
   3449 {
   3450     CvGraphScanner* scanner = 0;
   3451     CvMemStorage* child_storage = 0;
   3452 
   3453     CV_FUNCNAME("cvCreateGraphScanner");
   3454 
   3455     __BEGIN__;
   3456 
   3457     if( !graph )
   3458         CV_ERROR( CV_StsNullPtr, "Null graph pointer" );
   3459 
   3460     CV_ASSERT( graph->storage != 0 );
   3461 
   3462     CV_CALL( scanner = (CvGraphScanner*)cvAlloc( sizeof(*scanner) ));
   3463     memset( scanner, 0, sizeof(*scanner));
   3464 
   3465     scanner->graph = graph;
   3466     scanner->mask = mask;
   3467     scanner->vtx = vtx;
   3468     scanner->index = vtx == 0 ? 0 : -1;
   3469 
   3470     CV_CALL( child_storage = cvCreateChildMemStorage( graph->storage ));
   3471 
   3472     CV_CALL( scanner->stack = cvCreateSeq( 0, sizeof(CvSet),
   3473                        sizeof(CvGraphItem), child_storage ));
   3474 
   3475     CV_CALL( icvSeqElemsClearFlags( (CvSeq*)graph,
   3476                                     CV_FIELD_OFFSET( flags, CvGraphVtx),
   3477                                     CV_GRAPH_ITEM_VISITED_FLAG|
   3478                                     CV_GRAPH_SEARCH_TREE_NODE_FLAG ));
   3479 
   3480     CV_CALL( icvSeqElemsClearFlags( (CvSeq*)(graph->edges),
   3481                                     CV_FIELD_OFFSET( flags, CvGraphEdge),
   3482                                     CV_GRAPH_ITEM_VISITED_FLAG ));
   3483 
   3484     __END__;
   3485 
   3486     if( cvGetErrStatus() < 0 )
   3487     {
   3488         cvReleaseMemStorage( &child_storage );
   3489         cvFree( &scanner );
   3490     }
   3491 
   3492     return scanner;
   3493 }
   3494 
   3495 
   3496 CV_IMPL void
   3497 cvReleaseGraphScanner( CvGraphScanner** scanner )
   3498 {
   3499     CV_FUNCNAME("cvReleaseGraphScanner");
   3500 
   3501     __BEGIN__;
   3502 
   3503     if( !scanner )
   3504         CV_ERROR( CV_StsNullPtr, "Null double pointer to graph scanner" );
   3505 
   3506     if( *scanner )
   3507     {
   3508         if( (*scanner)->stack )
   3509             CV_CALL( cvReleaseMemStorage( &((*scanner)->stack->storage)));
   3510         cvFree( scanner );
   3511     }
   3512 
   3513     __END__;
   3514 }
   3515 
   3516 
   3517 CV_IMPL int
   3518 cvNextGraphItem( CvGraphScanner* scanner )
   3519 {
   3520     int code = -1;
   3521 
   3522     CV_FUNCNAME("cvNextGraphItem");
   3523 
   3524     __BEGIN__;
   3525 
   3526     CvGraphVtx* vtx;
   3527     CvGraphVtx* dst;
   3528     CvGraphEdge* edge;
   3529     CvGraphItem item;
   3530 
   3531     if( !scanner || !(scanner->stack))
   3532         CV_ERROR( CV_StsNullPtr, "Null graph scanner" );
   3533 
   3534     dst = scanner->dst;
   3535     vtx = scanner->vtx;
   3536     edge = scanner->edge;
   3537 
   3538     for(;;)
   3539     {
   3540         for(;;)
   3541         {
   3542             if( dst && !CV_IS_GRAPH_VERTEX_VISITED(dst) )
   3543             {
   3544                 scanner->vtx = vtx = dst;
   3545                 edge = vtx->first;
   3546                 dst->flags |= CV_GRAPH_ITEM_VISITED_FLAG;
   3547 
   3548                 if((scanner->mask & CV_GRAPH_VERTEX))
   3549                 {
   3550                     scanner->vtx = vtx;
   3551                     scanner->edge = vtx->first;
   3552                     scanner->dst = 0;
   3553                     code = CV_GRAPH_VERTEX;
   3554                     EXIT;
   3555                 }
   3556             }
   3557 
   3558             while( edge )
   3559             {
   3560                 dst = edge->vtx[vtx == edge->vtx[0]];
   3561 
   3562                 if( !CV_IS_GRAPH_EDGE_VISITED(edge) )
   3563                 {
   3564                     // Check that the edge is outgoing:
   3565                     if( !CV_IS_GRAPH_ORIENTED( scanner->graph ) || dst != edge->vtx[0] )
   3566                     {
   3567                         edge->flags |= CV_GRAPH_ITEM_VISITED_FLAG;
   3568 
   3569                         if( !CV_IS_GRAPH_VERTEX_VISITED(dst) )
   3570                         {
   3571                             item.vtx = vtx;
   3572                             item.edge = edge;
   3573 
   3574                             vtx->flags |= CV_GRAPH_SEARCH_TREE_NODE_FLAG;
   3575 
   3576                             cvSeqPush( scanner->stack, &item );
   3577 
   3578                             if( scanner->mask & CV_GRAPH_TREE_EDGE )
   3579                             {
   3580                                 code = CV_GRAPH_TREE_EDGE;
   3581                                 scanner->vtx = vtx;
   3582                                 scanner->dst = dst;
   3583                                 scanner->edge = edge;
   3584                                 EXIT;
   3585                             }
   3586                             break;
   3587                         }
   3588                         else
   3589                         {
   3590                             if( scanner->mask & (CV_GRAPH_BACK_EDGE|
   3591                                                  CV_GRAPH_CROSS_EDGE|
   3592                                                  CV_GRAPH_FORWARD_EDGE) )
   3593                             {
   3594                                 code = (dst->flags & CV_GRAPH_SEARCH_TREE_NODE_FLAG) ?
   3595                                        CV_GRAPH_BACK_EDGE :
   3596                                        (edge->flags & CV_GRAPH_FORWARD_EDGE_FLAG) ?
   3597                                        CV_GRAPH_FORWARD_EDGE : CV_GRAPH_CROSS_EDGE;
   3598                                 edge->flags &= ~CV_GRAPH_FORWARD_EDGE_FLAG;
   3599                                 if( scanner->mask & code )
   3600                                 {
   3601                                     scanner->vtx = vtx;
   3602                                     scanner->dst = dst;
   3603                                     scanner->edge = edge;
   3604                                     EXIT;
   3605                                 }
   3606                             }
   3607                         }
   3608                     }
   3609                     else if( (dst->flags & (CV_GRAPH_ITEM_VISITED_FLAG|
   3610                              CV_GRAPH_SEARCH_TREE_NODE_FLAG)) ==
   3611                              (CV_GRAPH_ITEM_VISITED_FLAG|
   3612                              CV_GRAPH_SEARCH_TREE_NODE_FLAG))
   3613                     {
   3614                         edge->flags |= CV_GRAPH_FORWARD_EDGE_FLAG;
   3615                     }
   3616                 }
   3617 
   3618                 edge = CV_NEXT_GRAPH_EDGE( edge, vtx );
   3619             }
   3620 
   3621             if( !edge ) /* need to backtrack */
   3622             {
   3623                 if( scanner->stack->total == 0 )
   3624                 {
   3625                     if( scanner->index >= 0 )
   3626                         vtx = 0;
   3627                     else
   3628                         scanner->index = 0;
   3629                     break;
   3630                 }
   3631                 cvSeqPop( scanner->stack, &item );
   3632                 vtx = item.vtx;
   3633                 vtx->flags &= ~CV_GRAPH_SEARCH_TREE_NODE_FLAG;
   3634                 edge = item.edge;
   3635                 dst = 0;
   3636 
   3637                 if( scanner->mask & CV_GRAPH_BACKTRACKING )
   3638                 {
   3639                     scanner->vtx = vtx;
   3640                     scanner->edge = edge;
   3641                     scanner->dst = edge->vtx[vtx == edge->vtx[0]];
   3642                     code = CV_GRAPH_BACKTRACKING;
   3643                     EXIT;
   3644                 }
   3645             }
   3646         }
   3647 
   3648         if( !vtx )
   3649         {
   3650             vtx = (CvGraphVtx*)icvSeqFindNextElem( (CvSeq*)(scanner->graph),
   3651                   CV_FIELD_OFFSET( flags, CvGraphVtx ), CV_GRAPH_ITEM_VISITED_FLAG|INT_MIN,
   3652                   0, &(scanner->index) );
   3653 
   3654             if( !vtx )
   3655             {
   3656                 code = CV_GRAPH_OVER;
   3657                 break;
   3658             }
   3659         }
   3660 
   3661         dst = vtx;
   3662         if( scanner->mask & CV_GRAPH_NEW_TREE )
   3663         {
   3664             scanner->dst = dst;
   3665             scanner->edge = 0;
   3666             scanner->vtx = 0;
   3667             code = CV_GRAPH_NEW_TREE;
   3668             break;
   3669         }
   3670     }
   3671 
   3672     __END__;
   3673 
   3674     return code;
   3675 }
   3676 
   3677 
   3678 CV_IMPL CvGraph*
   3679 cvCloneGraph( const CvGraph* graph, CvMemStorage* storage )
   3680 {
   3681     int* flag_buffer = 0;
   3682     CvGraphVtx** ptr_buffer = 0;
   3683     CvGraph* result = 0;
   3684 
   3685     CV_FUNCNAME( "cvCloneGraph" );
   3686 
   3687     __BEGIN__;
   3688 
   3689     int i, k;
   3690     int vtx_size, edge_size;
   3691     CvSeqReader reader;
   3692 
   3693     if( !CV_IS_GRAPH(graph))
   3694         CV_ERROR( CV_StsBadArg, "Invalid graph pointer" );
   3695 
   3696     if( !storage )
   3697         storage = graph->storage;
   3698 
   3699     if( !storage )
   3700         CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
   3701 
   3702     vtx_size = graph->elem_size;
   3703     edge_size = graph->edges->elem_size;
   3704 
   3705     CV_CALL( flag_buffer = (int*)cvAlloc( graph->total*sizeof(flag_buffer[0])));
   3706     CV_CALL( ptr_buffer = (CvGraphVtx**)cvAlloc( graph->total*sizeof(ptr_buffer[0])));
   3707     CV_CALL( result = cvCreateGraph( graph->flags, graph->header_size,
   3708                                      vtx_size, edge_size, storage ));
   3709     memcpy( result + sizeof(CvGraph), graph + sizeof(CvGraph),
   3710             graph->header_size - sizeof(CvGraph));
   3711 
   3712     // Pass 1.  Save flags, copy vertices:
   3713     cvStartReadSeq( (CvSeq*)graph, &reader );
   3714     for( i = 0, k = 0; i < graph->total; i++ )
   3715     {
   3716         if( CV_IS_SET_ELEM( reader.ptr ))
   3717         {
   3718             CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr;
   3719             CvGraphVtx* dstvtx = 0;
   3720             CV_CALL( cvGraphAddVtx( result, vtx, &dstvtx ));
   3721             flag_buffer[k] = dstvtx->flags = vtx->flags;
   3722             vtx->flags = k;
   3723             ptr_buffer[k++] = dstvtx;
   3724         }
   3725         CV_NEXT_SEQ_ELEM( vtx_size, reader );
   3726     }
   3727 
   3728     // Pass 2.  Copy edges:
   3729     cvStartReadSeq( (CvSeq*)graph->edges, &reader );
   3730     for( i = 0; i < graph->edges->total; i++ )
   3731     {
   3732         if( CV_IS_SET_ELEM( reader.ptr ))
   3733         {
   3734             CvGraphEdge* edge = (CvGraphEdge*)reader.ptr;
   3735             CvGraphEdge* dstedge = 0;
   3736             CvGraphVtx* new_org = ptr_buffer[edge->vtx[0]->flags];
   3737             CvGraphVtx* new_dst = ptr_buffer[edge->vtx[1]->flags];
   3738             CV_CALL( cvGraphAddEdgeByPtr( result, new_org, new_dst, edge, &dstedge ));
   3739             dstedge->flags = edge->flags;
   3740         }
   3741         CV_NEXT_SEQ_ELEM( edge_size, reader );
   3742     }
   3743 
   3744     // Pass 3.  Restore flags:
   3745     cvStartReadSeq( (CvSeq*)graph, &reader );
   3746     for( i = 0, k = 0; i < graph->edges->total; i++ )
   3747     {
   3748         if( CV_IS_SET_ELEM( reader.ptr ))
   3749         {
   3750             CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr;
   3751             vtx->flags = flag_buffer[k++];
   3752         }
   3753         CV_NEXT_SEQ_ELEM( vtx_size, reader );
   3754     }
   3755 
   3756     __END__;
   3757 
   3758     cvFree( &flag_buffer );
   3759     cvFree( &ptr_buffer );
   3760 
   3761     if( cvGetErrStatus() < 0 )
   3762         result = 0;
   3763 
   3764     return result;
   3765 }
   3766 
   3767 
   3768 /****************************************************************************************\
   3769 *                                 Working with sequence tree                             *
   3770 \****************************************************************************************/
   3771 
   3772 // Gather pointers to all the sequences, accessible from the <first>, to the single sequence.
   3773 CV_IMPL CvSeq*
   3774 cvTreeToNodeSeq( const void* first, int header_size, CvMemStorage* storage )
   3775 {
   3776     CvSeq* allseq = 0;
   3777 
   3778     CV_FUNCNAME("cvTreeToNodeSeq");
   3779 
   3780     __BEGIN__;
   3781 
   3782     CvTreeNodeIterator iterator;
   3783 
   3784     if( !storage )
   3785         CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
   3786 
   3787     CV_CALL( allseq = cvCreateSeq( 0, header_size, sizeof(first), storage ));
   3788 
   3789     if( first )
   3790     {
   3791         CV_CALL( cvInitTreeNodeIterator( &iterator, first, INT_MAX ));
   3792 
   3793         for(;;)
   3794         {
   3795             void* node = cvNextTreeNode( &iterator );
   3796             if( !node )
   3797                 break;
   3798             cvSeqPush( allseq, &node );
   3799         }
   3800     }
   3801 
   3802     __END__;
   3803 
   3804     return allseq;
   3805 }
   3806 
   3807 
   3808 typedef struct CvTreeNode
   3809 {
   3810     int       flags;         /* micsellaneous flags */
   3811     int       header_size;   /* size of sequence header */
   3812     struct    CvTreeNode* h_prev; /* previous sequence */
   3813     struct    CvTreeNode* h_next; /* next sequence */
   3814     struct    CvTreeNode* v_prev; /* 2nd previous sequence */
   3815     struct    CvTreeNode* v_next; /* 2nd next sequence */
   3816 }
   3817 CvTreeNode;
   3818 
   3819 
   3820 
   3821 // Insert contour into tree given certain parent sequence.
   3822 // If parent is equal to frame (the most external contour),
   3823 // then added contour will have null pointer to parent:
   3824 CV_IMPL void
   3825 cvInsertNodeIntoTree( void* _node, void* _parent, void* _frame )
   3826 {
   3827     CV_FUNCNAME( "cvInsertNodeIntoTree" );
   3828 
   3829     __BEGIN__;
   3830 
   3831     CvTreeNode* node = (CvTreeNode*)_node;
   3832     CvTreeNode* parent = (CvTreeNode*)_parent;
   3833 
   3834     if( !node || !parent )
   3835         CV_ERROR( CV_StsNullPtr, "" );
   3836 
   3837     node->v_prev = _parent != _frame ? parent : 0;
   3838     node->h_next = parent->v_next;
   3839 
   3840     assert( parent->v_next != node );
   3841 
   3842     if( parent->v_next )
   3843         parent->v_next->h_prev = node;
   3844     parent->v_next = node;
   3845 
   3846     __END__;
   3847 }
   3848 
   3849 
   3850 // Remove contour from tree, together with the contour's children:
   3851 CV_IMPL void
   3852 cvRemoveNodeFromTree( void* _node, void* _frame )
   3853 {
   3854     CV_FUNCNAME( "cvRemoveNodeFromTree" );
   3855 
   3856     __BEGIN__;
   3857 
   3858     CvTreeNode* node = (CvTreeNode*)_node;
   3859     CvTreeNode* frame = (CvTreeNode*)_frame;
   3860 
   3861     if( !node )
   3862         CV_ERROR_FROM_CODE( CV_StsNullPtr );
   3863 
   3864     if( node == frame )
   3865         CV_ERROR( CV_StsBadArg, "frame node could not be deleted" );
   3866 
   3867     if( node->h_next )
   3868         node->h_next->h_prev = node->h_prev;
   3869 
   3870     if( node->h_prev )
   3871         node->h_prev->h_next = node->h_next;
   3872     else
   3873     {
   3874         CvTreeNode* parent = node->v_prev;
   3875         if( !parent )
   3876             parent = frame;
   3877 
   3878         if( parent )
   3879         {
   3880             assert( parent->v_next == node );
   3881             parent->v_next = node->h_next;
   3882         }
   3883     }
   3884 
   3885     __END__;
   3886 }
   3887 
   3888 
   3889 CV_IMPL void
   3890 cvInitTreeNodeIterator( CvTreeNodeIterator* treeIterator,
   3891                         const void* first, int max_level )
   3892 {
   3893     CV_FUNCNAME("icvInitTreeNodeIterator");
   3894 
   3895     __BEGIN__;
   3896 
   3897     if( !treeIterator || !first )
   3898         CV_ERROR( CV_StsNullPtr, "" );
   3899 
   3900     if( max_level < 0 )
   3901         CV_ERROR( CV_StsOutOfRange, "" );
   3902 
   3903     treeIterator->node = (void*)first;
   3904     treeIterator->level = 0;
   3905     treeIterator->max_level = max_level;
   3906 
   3907     __END__;
   3908 }
   3909 
   3910 
   3911 CV_IMPL void*
   3912 cvNextTreeNode( CvTreeNodeIterator* treeIterator )
   3913 {
   3914     CvTreeNode* prevNode = 0;
   3915 
   3916     CV_FUNCNAME("cvNextTreeNode");
   3917 
   3918     __BEGIN__;
   3919 
   3920     CvTreeNode* node;
   3921     int level;
   3922 
   3923     if( !treeIterator )
   3924         CV_ERROR( CV_StsNullPtr, "NULL iterator pointer" );
   3925 
   3926     prevNode = node = (CvTreeNode*)treeIterator->node;
   3927     level = treeIterator->level;
   3928 
   3929     if( node )
   3930     {
   3931         if( node->v_next && level+1 < treeIterator->max_level )
   3932         {
   3933             node = node->v_next;
   3934             level++;
   3935         }
   3936         else
   3937         {
   3938             while( node->h_next == 0 )
   3939             {
   3940                 node = node->v_prev;
   3941                 if( --level < 0 )
   3942                 {
   3943                     node = 0;
   3944                     break;
   3945                 }
   3946             }
   3947             node = node && treeIterator->max_level != 0 ? node->h_next : 0;
   3948         }
   3949     }
   3950 
   3951     treeIterator->node = node;
   3952     treeIterator->level = level;
   3953 
   3954     __END__;
   3955 
   3956     return prevNode;
   3957 }
   3958 
   3959 
   3960 CV_IMPL void*
   3961 cvPrevTreeNode( CvTreeNodeIterator* treeIterator )
   3962 {
   3963     CvTreeNode* prevNode = 0;
   3964 
   3965     CV_FUNCNAME("cvPrevTreeNode");
   3966 
   3967     __BEGIN__;
   3968 
   3969     CvTreeNode* node;
   3970     int level;
   3971 
   3972     if( !treeIterator )
   3973         CV_ERROR( CV_StsNullPtr, "" );
   3974 
   3975     prevNode = node = (CvTreeNode*)treeIterator->node;
   3976     level = treeIterator->level;
   3977 
   3978     if( node )
   3979     {
   3980         if( !node->h_prev )
   3981         {
   3982             node = node->v_prev;
   3983             if( --level < 0 )
   3984                 node = 0;
   3985         }
   3986         else
   3987         {
   3988             node = node->h_prev;
   3989 
   3990             while( node->v_next && level < treeIterator->max_level )
   3991             {
   3992                 node = node->v_next;
   3993                 level++;
   3994 
   3995                 while( node->h_next )
   3996                     node = node->h_next;
   3997             }
   3998         }
   3999     }
   4000 
   4001     treeIterator->node = node;
   4002     treeIterator->level = level;
   4003 
   4004     __END__;
   4005 
   4006     return prevNode;
   4007 }
   4008 
   4009 /* End of file. */
   4010