MOAB: Mesh Oriented datABase  (version 5.4.1)
MeshSet.cpp
Go to the documentation of this file.
00001 #ifdef WIN32
00002 #ifdef _DEBUG
00003 // turn off warnings that say they debugging identifier has been truncated
00004 // this warning comes up when using some STL containers
00005 #pragma warning( disable : 4786 )
00006 #endif
00007 #endif
00008 
00009 #include "MeshSet.hpp"
00010 #include "AEntityFactory.hpp"
00011 
00012 namespace moab
00013 {
00014 
00015 /*****************************************************************************************
00016  *                          Helper Function Declarations                                 *
00017  *****************************************************************************************/
00018 
00019 /**\brief Insert into parent/child list */
00020 static inline MeshSet::Count insert_in_vector( const MeshSet::Count count,
00021                                                MeshSet::CompactList& list,
00022                                                const EntityHandle h,
00023                                                int& result );
00024 
00025 /**\brief Remvoe from parent/child list */
00026 static inline MeshSet::Count remove_from_vector( const MeshSet::Count count,
00027                                                  MeshSet::CompactList& list,
00028                                                  const EntityHandle h,
00029                                                  int& result );
00030 
00031 /**\brief Resize MeshSet::CompactList.  Returns pointer to storage */
00032 static EntityHandle* resize_compact_list( MeshSet::Count& count, MeshSet::CompactList& clist, size_t new_list_size );
00033 /**\brief Methods to insert/remove range-based data from contents list.
00034  *        Templatized to operate on both Range and set-based MeshSets.
00035  */
00036 template < typename pair_iter_t >
00037 class range_tool
00038 {
00039   public:
00040     /** Insert range-based data into range-based MeshSet */
00041     inline static ErrorCode ranged_insert_entities( MeshSet::Count& count,
00042                                                     MeshSet::CompactList& clist,
00043                                                     pair_iter_t begin,
00044                                                     pair_iter_t end,
00045                                                     EntityHandle my_handle,
00046                                                     AEntityFactory* adj );
00047 
00048     /** Remove range-based data from range-based MeshSet */
00049     inline static ErrorCode ranged_remove_entities( MeshSet::Count& count,
00050                                                     MeshSet::CompactList& clist,
00051                                                     pair_iter_t begin,
00052                                                     pair_iter_t end,
00053                                                     EntityHandle my_handle,
00054                                                     AEntityFactory* adj );
00055 
00056     /** Insert range-based data into list-based MeshSet */
00057     inline static ErrorCode vector_insert_entities( MeshSet::Count& count,
00058                                                     MeshSet::CompactList& clist,
00059                                                     pair_iter_t begin,
00060                                                     pair_iter_t end,
00061                                                     EntityHandle my_handle,
00062                                                     AEntityFactory* adj );
00063 };
00064 
00065 /** Remove Range of handles fromr vector-based MeshSet */
00066 static ErrorCode vector_remove_range( MeshSet::Count& count,
00067                                       MeshSet::CompactList& clist,
00068                                       const Range& range,
00069                                       EntityHandle my_handle,
00070                                       AEntityFactory* adj );
00071 
00072 /** Remove range-based MeshSet contents from vector-based MeshSet */
00073 static ErrorCode vector_remove_ranges( MeshSet::Count& count,
00074                                        MeshSet::CompactList& clist,
00075                                        const EntityHandle* pair_list,
00076                                        size_t num_pairs,
00077                                        EntityHandle my_handle,
00078                                        AEntityFactory* adj );
00079 
00080 /** Remove unsorted array of handles from vector-based MeshSet */
00081 static ErrorCode vector_remove_vector( MeshSet::Count& count,
00082                                        MeshSet::CompactList& clist,
00083                                        const EntityHandle* vect,
00084                                        size_t vect_size,
00085                                        EntityHandle my_handle,
00086                                        AEntityFactory* adj );
00087 
00088 /** Insert unsorted array of handles into vector-based MeshSet */
00089 static ErrorCode vector_insert_vector( MeshSet::Count& count,
00090                                        MeshSet::CompactList& clist,
00091                                        const EntityHandle* vect,
00092                                        size_t vect_size,
00093                                        EntityHandle my_handle,
00094                                        AEntityFactory* adj );
00095 
00096 /** Convert unsorted array of handles into array of ranged [begin,end] pairs */
00097 static void convert_to_ranges( const EntityHandle* vect_in, size_t vect_in_len, std::vector< EntityHandle >& vect_out );
00098 
00099 /*****************************************************************************************
00100  *                             Parent/Child Operations                                   *
00101  *****************************************************************************************/
00102 
00103 static inline MeshSet::Count insert_in_vector( const MeshSet::Count count,
00104                                                MeshSet::CompactList& list,
00105                                                const EntityHandle h,
00106                                                int& result )
00107 {
00108     switch( count )
00109     {
00110         case MeshSet::ZERO:
00111             list.hnd[0] = h;
00112             result      = true;
00113             return MeshSet::ONE;
00114         case MeshSet::ONE:
00115             if( list.hnd[0] == h )
00116             {
00117                 result = false;
00118                 return MeshSet::ONE;
00119             }
00120             else
00121             {
00122                 result      = true;
00123                 list.hnd[1] = h;
00124                 return MeshSet::TWO;
00125             }
00126         case MeshSet::TWO:
00127             if( list.hnd[0] == h || list.hnd[1] == h )
00128             {
00129                 result = false;
00130                 return MeshSet::TWO;
00131             }
00132             else
00133             {
00134                 EntityHandle* ptr = (EntityHandle*)malloc( 3 * sizeof( EntityHandle ) );
00135                 ptr[0]            = list.hnd[0];
00136                 ptr[1]            = list.hnd[1];
00137                 ptr[2]            = h;
00138                 list.ptr[0]       = ptr;
00139                 list.ptr[1]       = ptr + 3;
00140                 result            = true;
00141                 return MeshSet::MANY;
00142             }
00143         case MeshSet::MANY:
00144             if( std::find( list.ptr[0], list.ptr[1], h ) != list.ptr[1] )
00145             {
00146                 result = false;
00147             }
00148             else
00149             {
00150                 int size          = list.ptr[1] - list.ptr[0];
00151                 list.ptr[0]       = (EntityHandle*)realloc( list.ptr[0], ( size + 1 ) * sizeof( EntityHandle ) );
00152                 list.ptr[0][size] = h;
00153                 list.ptr[1]       = list.ptr[0] + size + 1;
00154                 result            = true;
00155             }
00156             return MeshSet::MANY;
00157     }
00158 
00159     return MeshSet::ZERO;
00160 }
00161 
00162 static inline MeshSet::Count remove_from_vector( const MeshSet::Count count,
00163                                                  MeshSet::CompactList& list,
00164                                                  const EntityHandle h,
00165                                                  int& result )
00166 {
00167     switch( count )
00168     {
00169         case MeshSet::ZERO:
00170             result = false;
00171             return MeshSet::ZERO;
00172         case MeshSet::ONE:
00173             if( h == list.hnd[0] )
00174             {
00175                 result = true;
00176                 return MeshSet::ZERO;
00177             }
00178             else
00179             {
00180                 result = false;
00181                 return MeshSet::ONE;
00182             }
00183         case MeshSet::TWO:
00184             if( h == list.hnd[0] )
00185             {
00186                 list.hnd[0] = list.hnd[1];
00187                 result      = true;
00188                 return MeshSet::ONE;
00189             }
00190             else if( h == list.hnd[1] )
00191             {
00192                 result = true;
00193                 return MeshSet::ONE;
00194             }
00195             else
00196             {
00197                 result = false;
00198                 return MeshSet::TWO;
00199             }
00200         case MeshSet::MANY: {
00201             EntityHandle *i, *j, *p;
00202             i = std::find( list.ptr[0], list.ptr[1], h );
00203             if( i == list.ptr[1] )
00204             {
00205                 result = false;
00206                 return MeshSet::MANY;
00207             }
00208 
00209             result = true;
00210             p      = list.ptr[1] - 1;
00211             while( i != p )
00212             {
00213                 j  = i + 1;
00214                 *i = *j;
00215                 i  = j;
00216             }
00217             int size = p - list.ptr[0];
00218             if( size == 2 )
00219             {
00220                 p           = list.ptr[0];
00221                 list.hnd[0] = p[0];
00222                 list.hnd[1] = p[1];
00223                 free( p );
00224                 return MeshSet::TWO;
00225             }
00226             else
00227             {
00228                 list.ptr[0] = (EntityHandle*)realloc( list.ptr[0], size * sizeof( EntityHandle ) );
00229                 list.ptr[1] = list.ptr[0] + size;
00230                 return MeshSet::MANY;
00231             }
00232         }
00233     }
00234 
00235     return MeshSet::ZERO;
00236 }
00237 
00238 int MeshSet::add_parent( EntityHandle parent )
00239 {
00240     int result   = 0;
00241     mParentCount = insert_in_vector( (Count)mParentCount, parentMeshSets, parent, result );
00242     return result;
00243 }
00244 int MeshSet::add_child( EntityHandle child )
00245 {
00246     int result  = 0;
00247     mChildCount = insert_in_vector( (Count)mChildCount, childMeshSets, child, result );
00248     return result;
00249 }
00250 
00251 int MeshSet::remove_parent( EntityHandle parent )
00252 {
00253     int result   = 0;
00254     mParentCount = remove_from_vector( (Count)mParentCount, parentMeshSets, parent, result );
00255     return result;
00256 }
00257 int MeshSet::remove_child( EntityHandle child )
00258 {
00259     int result  = 0;
00260     mChildCount = remove_from_vector( (Count)mChildCount, childMeshSets, child, result );
00261     return result;
00262 }
00263 
00264 /*****************************************************************************************
00265  *                          Flag Conversion Operations                                   *
00266  *****************************************************************************************/
00267 
00268 ErrorCode MeshSet::convert( unsigned flg, EntityHandle my_handle, AEntityFactory* adj )
00269 {
00270     ErrorCode rval = MB_SUCCESS;
00271     if( ( mFlags & MESHSET_TRACK_OWNER ) && !( flg & MESHSET_TRACK_OWNER ) )
00272         rval = remove_adjacencies( my_handle, adj );
00273     else if( !( mFlags & MESHSET_TRACK_OWNER ) && ( flg & MESHSET_TRACK_OWNER ) )
00274         rval = create_adjacencies( my_handle, adj );
00275     if( MB_SUCCESS != rval ) return rval;
00276 
00277     if( !( mFlags & MESHSET_ORDERED ) && ( flg & MESHSET_ORDERED ) )
00278     {
00279         size_t datalen;
00280         EntityHandle* data = get_contents( datalen );
00281         if( datalen )
00282         {
00283             std::vector< EntityHandle > list( datalen );
00284             memcpy( &list[0], data, datalen * sizeof( EntityHandle ) );
00285             int num_ents  = num_entities();
00286             Count count   = (Count)mContentCount;
00287             data          = resize_compact_list( count, contentList, num_ents );
00288             mContentCount = count;
00289             assert( list.size() % 2 == 0 );
00290             std::vector< EntityHandle >::iterator i = list.begin();
00291             while( i != list.end() )
00292             {
00293                 EntityHandle h = *i;
00294                 ++i;
00295                 EntityHandle e = *i;
00296                 ++i;
00297                 for( ; h <= e; ++h )
00298                 {
00299                     *data = h;
00300                     ++data;
00301                 }
00302             }
00303         }
00304     }
00305     else if( ( mFlags & MESHSET_ORDERED ) && !( flg & MESHSET_ORDERED ) )
00306     {
00307         size_t datalen;
00308         EntityHandle* data = get_contents( datalen );
00309         if( datalen )
00310         {
00311             std::vector< EntityHandle > ranges;
00312             convert_to_ranges( data, datalen, ranges );
00313             Count count   = (Count)mContentCount;
00314             data          = resize_compact_list( count, contentList, ranges.size() );
00315             mContentCount = count;
00316             memcpy( data, &ranges[0], ranges.size() * sizeof( EntityHandle ) );
00317         }
00318     }
00319 
00320     return MB_SUCCESS;
00321 }
00322 
00323 ErrorCode MeshSet::create_adjacencies( EntityHandle my_handle, AEntityFactory* adj )
00324 {
00325     ErrorCode rval = MB_SUCCESS;
00326     ;
00327     size_t count;
00328     const EntityHandle* const ptr = get_contents( count );
00329     const EntityHandle* const end = ptr + count;
00330     if( vector_based() )
00331     {
00332         for( const EntityHandle* i = ptr; i != end; ++i )
00333         {
00334             rval = adj->add_adjacency( *i, my_handle, false );
00335             if( MB_SUCCESS != rval )
00336             {
00337                 for( const EntityHandle* j = ptr; j != i; ++j )
00338                     adj->remove_adjacency( *j, my_handle );
00339                 return rval;
00340             }
00341         }
00342     }
00343     else
00344     {
00345         assert( 0 == count % 2 );
00346         for( const EntityHandle* i = ptr; i != end; i += 2 )
00347         {
00348             for( EntityHandle h = i[0]; h <= i[1]; ++h )
00349             {
00350                 rval = adj->add_adjacency( h, my_handle, false );
00351                 if( MB_SUCCESS != rval )
00352                 {
00353                     for( EntityHandle j = i[0]; j < h; ++j )
00354                         adj->remove_adjacency( j, my_handle );
00355                     for( const EntityHandle* j = ptr; j != i; j += 2 )
00356                         for( EntityHandle k = j[0]; k <= j[1]; ++k )
00357                             adj->remove_adjacency( k, my_handle );
00358                     return rval;
00359                 }
00360             }
00361         }
00362     }
00363     return MB_SUCCESS;
00364 }
00365 
00366 ErrorCode MeshSet::remove_adjacencies( EntityHandle my_handle, AEntityFactory* adj )
00367 {
00368     size_t count;
00369     const EntityHandle* const ptr = get_contents( count );
00370     const EntityHandle* const end = ptr + count;
00371     if( vector_based() )
00372     {
00373         for( const EntityHandle* i = ptr; i != end; ++i )
00374             adj->remove_adjacency( *i, my_handle );
00375     }
00376     else
00377     {
00378         assert( 0 == count % 2 );
00379         for( const EntityHandle* i = ptr; i != end; i += 2 )
00380             for( EntityHandle h = i[0]; h <= i[1]; ++h )
00381                 adj->remove_adjacency( h, my_handle );
00382     }
00383     return MB_SUCCESS;
00384 }
00385 
00386 /*****************************************************************************************
00387  *                          Contents Modifiction Methods                                 *
00388  *****************************************************************************************/
00389 
00390 static EntityHandle* resize_compact_list( MeshSet::Count& count, MeshSet::CompactList& clist, size_t new_list_size )
00391 {
00392     if( count <= 2 )
00393     {
00394         if( new_list_size <= 2 )
00395         {
00396             count = (MeshSet::Count)new_list_size;
00397             return clist.hnd;
00398         }
00399         else
00400         {
00401             EntityHandle* list = (EntityHandle*)malloc( new_list_size * sizeof( EntityHandle ) );
00402             list[0]            = clist.hnd[0];
00403             list[1]            = clist.hnd[1];
00404             clist.ptr[0]       = list;
00405             clist.ptr[1]       = list + new_list_size;
00406             count              = MeshSet::MANY;
00407             return list;
00408         }
00409     }
00410     else if( new_list_size > 2 )
00411     {
00412         if( new_list_size > (size_t)( clist.ptr[1] - clist.ptr[0] ) )
00413             clist.ptr[0] = (EntityHandle*)realloc( clist.ptr[0], new_list_size * sizeof( EntityHandle ) );
00414         clist.ptr[1] = clist.ptr[0] + new_list_size;
00415         count        = MeshSet::MANY;
00416         return clist.ptr[0];
00417     }
00418     else
00419     {
00420         EntityHandle* list = clist.ptr[0];
00421         clist.hnd[0]       = list[0];
00422         clist.hnd[1]       = list[1];
00423         free( list );
00424         count = (MeshSet::Count)new_list_size;
00425         return clist.hnd;
00426     }
00427 }
00428 
00429 typedef std::pair< EntityHandle, EntityHandle > MeshSetRange;
00430 
00431 class MeshSetRComp
00432 {
00433   public:
00434     bool operator()( const MeshSetRange& r, const MeshSetRange& h )
00435     {
00436         return r.second < h.first;
00437     }
00438 };
00439 
00440 template < typename pair_iter_t >
00441 inline ErrorCode range_tool< pair_iter_t >::ranged_insert_entities( MeshSet::Count& count,
00442                                                                     MeshSet::CompactList& clist,
00443                                                                     pair_iter_t begin,
00444                                                                     pair_iter_t end,
00445                                                                     EntityHandle my_handle,
00446                                                                     AEntityFactory* adj )
00447 {
00448     // first pass:
00449     // 1) merge existing ranges
00450     // 2) count number of new ranges that must be inserted
00451     EntityHandle* list_ptr;
00452     size_t list_size;
00453     if( count < MeshSet::MANY )
00454     {
00455         list_ptr  = clist.hnd;
00456         list_size = count;
00457     }
00458     else
00459     {
00460         list_ptr  = clist.ptr[0];
00461         list_size = clist.ptr[1] - clist.ptr[0];
00462     }
00463 
00464     MeshSetRange* list = reinterpret_cast< MeshSetRange* >( list_ptr );
00465     assert( 0 == list_size % 2 );
00466     assert( 2 * sizeof( EntityHandle ) == sizeof( MeshSetRange ) );
00467     list_size /= 2;
00468     MeshSetRange* const list_end = list + list_size;
00469     MeshSetRange *list_read = list, *list_write = list;
00470     pair_iter_t i = begin;
00471 
00472     // count number of range pairs that are straight insertions
00473     // (don't overlap any range pair in the current set) that
00474     // could not be inserted during the first pass.
00475     size_t insert_count = 0;
00476 
00477     // merge lists
00478     while( i != end )
00479     {
00480         // find first range that intersects the current input range
00481 
00482         // do binary search if no holes in current set contents
00483         if( list_read == list_write )
00484         {
00485             // subtract one from i->first because if it is one greater
00486             // then the the last value of some block, then we want that
00487             // block to append to.
00488             MeshSetRange tmp;
00489             tmp.first  = i->first - 1;
00490             tmp.second = i->second;
00491             list_write = std::lower_bound( list_read, list_end, tmp, MeshSetRComp() );
00492             list_read  = list_write;
00493         }
00494         // otherwise shift down until we find where we find a range block
00495         // that intersects
00496         else
00497             while( list_read != list_end && list_read->second + 1 < i->first )
00498             {
00499                 *list_write = *list_read;
00500                 ++list_write;
00501                 ++list_read;
00502             }
00503 
00504         // handle any straight insertions of range blocks
00505         for( ; i != end && ( list_read == list_end || i->second + 1 < list_read->first ); ++i )
00506         {
00507             // If we haven't removed any range pairs, we don't have space to
00508             // insert here.  Defer the insertion until later.
00509             if( list_read == list_write )
00510             {
00511                 ++insert_count;
00512             }
00513             else
00514             {
00515                 if( adj )
00516                     for( EntityHandle j = i->first; j <= i->second; ++j )
00517                         adj->add_adjacency( j, my_handle, false );
00518 
00519                 list_write->first  = i->first;
00520                 list_write->second = i->second;
00521                 ++list_write;
00522             }
00523         }
00524 
00525         // merge all the stuff that gets merged into a single range pair
00526         // from both the input list and the existing set data
00527         if( list_read != list_end )
00528         {
00529             MeshSetRange working = *list_read;  // copy because might be the same as list_write
00530             ++list_read;
00531 
00532             // Check if we need to prepend to the existing block.
00533             // We only need to check this for the first input range because
00534             // after this working.first will always be the first possible handle
00535             // in the merged set of ranges.
00536             if( i != end && i->first < working.first && i->second + 1 >= working.first )
00537             {
00538                 if( adj )
00539                     for( EntityHandle h = i->first; h < working.first; ++h )
00540                         adj->add_adjacency( h, my_handle, false );
00541                 working.first = i->first;
00542             }
00543 
00544             // Now append from the input list and the remaining set contents
00545             // until we've consolidated all overlapping/touching ranges.
00546             bool done = false;
00547             while( !done )
00548             {
00549                 // does next set contents range touch working range?
00550                 bool set_overlap = list_read != list_end && list_read->first <= working.second + 1;
00551                 // does next input range touch working range?
00552                 bool inp_overlap = i != end && i->first <= working.second + 1;
00553 
00554                 // if both ranges touch...
00555                 if( inp_overlap && set_overlap )
00556                 {
00557                     // if next set range is contained in working, skip it
00558                     if( list_read->second <= working.second ) ++list_read;
00559                     // if next input range is contained in working, skip it
00560                     else if( i->second <= working.second )
00561                         ++i;
00562                     // Otherwise set the working end to the smaller of the two
00563                     // ends: either the next set end or the next input end.
00564                     // We want the smaller of the two because the larger might
00565                     // intersect additional ranges in the other list.
00566                     else if( list_read->second <= i->second )
00567                     {
00568                         working.second = list_read->second;
00569                         ++list_read;
00570                     }
00571                     else
00572                     {
00573                         working.second = i->second;
00574                         ++i;
00575                     }
00576                 }
00577                 // If only the input range intersect the current working range...
00578                 else if( inp_overlap )
00579                 {
00580                     // Would it be more efficient to just extent 'working' to
00581                     // the end of the current input range?  We'd end up adding
00582                     // adjacencies for for entities that are already in the tracking
00583                     // set and therefore already have the adjacency.
00584                     EntityHandle last = i->second;
00585                     if( list_read != list_end && list_read->first < last )
00586                         last = list_read->first - 1;
00587                     else
00588                         ++i;
00589 
00590                     if( last > working.second )
00591                     {
00592                         if( adj )
00593                             for( EntityHandle h = working.second + 1; h <= last; ++h )
00594                                 adj->add_adjacency( h, my_handle, false );
00595 
00596                         working.second = last;
00597                     }
00598                 }
00599                 else if( set_overlap )
00600                 {
00601                     if( working.second < list_read->second ) working.second = list_read->second;
00602                     ++list_read;
00603                 }
00604                 else
00605                 {
00606                     done = true;
00607                 }
00608             }
00609 
00610             assert( list_write < list_read );
00611             *list_write = working;
00612             ++list_write;
00613         }
00614     }
00615 
00616     // shuffle down entries to fill holes
00617     if( list_read == list_write )
00618         list_read = list_write = list_end;
00619     else
00620         while( list_read < list_end )
00621         {
00622             *list_write = *list_read;
00623             ++list_read;
00624             ++list_write;
00625         }
00626 
00627     // adjust allocated array size
00628     const size_t occupied_size = list_write - list;
00629     const size_t new_list_size = occupied_size + insert_count;
00630     list_ptr                   = resize_compact_list( count, clist, 2 * new_list_size );
00631     // done?
00632     if( !insert_count ) return MB_SUCCESS;
00633     list = reinterpret_cast< MeshSetRange* >( list_ptr );
00634 
00635     // Second pass: insert non-mergable range pairs
00636     // All range pairs in the input are either completely disjoint from
00637     // the ones in the mesh set and must be inserted or are entirely contained
00638     // within a range pair in the mesh set.
00639     assert( begin != end );  // can't have items to insert if given empty input list
00640     pair_iter_t ri = end;
00641     --ri;
00642     list_write = list + new_list_size - 1;
00643     list_read  = list + occupied_size - 1;
00644     for( ; list_write >= list; --list_write )
00645     {
00646         if( list_read >= list )
00647         {
00648             while( ri->first >= list_read->first && ri->second <= list_read->second )
00649             {
00650                 assert( ri != begin );
00651                 --ri;
00652             }
00653 
00654             if( list_read->first > ri->second )
00655             {
00656                 *list_write = *list_read;
00657                 --list_read;
00658                 continue;
00659             }
00660         }
00661 
00662         assert( insert_count > 0 );
00663         if( adj )
00664             for( EntityHandle h = ri->first; h <= ri->second; ++h )
00665                 adj->add_adjacency( h, my_handle, false );
00666         list_write->first  = ri->first;
00667         list_write->second = ri->second;
00668 
00669         // don't have reverse iterator, so check before decrement
00670         // if insert_count isn't zero, must be more in range
00671         if( 0 == --insert_count )
00672         {
00673             assert( list_read == list_write - 1 );
00674             break;
00675         }
00676         else
00677         {
00678             --ri;
00679         }
00680     }
00681 
00682     assert( !insert_count );
00683     return MB_SUCCESS;
00684 }
00685 
00686 template < typename pair_iter_t >
00687 inline ErrorCode range_tool< pair_iter_t >::ranged_remove_entities( MeshSet::Count& count,
00688                                                                     MeshSet::CompactList& clist,
00689                                                                     pair_iter_t begin,
00690                                                                     pair_iter_t end,
00691                                                                     EntityHandle my_handle,
00692                                                                     AEntityFactory* adj )
00693 {
00694     // first pass:
00695     // 1) remove (from) existing ranges
00696     // 2) count number of ranges that must be split
00697     ptrdiff_t split_count = 0;
00698     EntityHandle* list;
00699     size_t list_size;
00700     if( count < MeshSet::MANY )
00701     {
00702         list      = clist.hnd;
00703         list_size = count;
00704     }
00705     else
00706     {
00707         list      = clist.ptr[0];
00708         list_size = clist.ptr[1] - clist.ptr[0];
00709     }
00710 
00711     EntityHandle* list_write     = list;
00712     EntityHandle *const list_end = list + list_size, *list_read = list;
00713     pair_iter_t i = begin;
00714 
00715     while( list_read != list_end && i != end )
00716     {
00717 
00718         while( i != end && i->second < list_read[0] )
00719             ++i;
00720         if( i == end ) break;
00721 
00722         // if there are holes in the current array, shuffle blocks
00723         // down until we find the next block to remove
00724         if( list_read != list_write )
00725         {
00726             while( list_read != list_end && i->second < list_read[0] )
00727             {
00728                 list_write[0] = list_read[0];
00729                 list_write[1] = list_read[1];
00730                 list_write += 2;
00731                 list_read += 2;
00732             }
00733         }
00734         // otherwise do a binary search
00735         else
00736         {
00737             list_write = std::lower_bound( list_write, list_end, i->first );
00738             // if in middle of range block (odd index), back up to start of block
00739             list_write -= ( list_write - list ) % 2;
00740             list_read = list_write;
00741         }
00742 
00743         // if everything remaning is past end of set contents...
00744         if( list_read == list_end ) break;
00745 
00746         // skip any remove pairs that aren't in the list
00747         if( i->second < list_read[0] )
00748         {
00749             ++i;
00750             continue;
00751         }
00752 
00753         // Begin by assuming that we will keep the entire block
00754         list_write[0] = list_read[0];
00755         list_write[1] = list_read[1];
00756         list_read += 2;
00757 
00758         for( ; i != end && i->first <= list_write[1]; ++i )
00759         {
00760             if( i->first <= list_write[0] )
00761             {
00762                 // remove whole block
00763                 if( i->second >= list_write[1] )
00764                 {
00765                     if( adj )
00766                         for( EntityHandle h = list_write[0]; h <= list_write[1]; ++h )
00767                             adj->remove_adjacency( h, my_handle );
00768                     list_write -= 2;
00769                     break;
00770                 }
00771                 // remove from start of block
00772                 else if( i->second >= list_write[0] )
00773                 {
00774                     if( adj )
00775                         for( EntityHandle h = list_write[0]; h <= i->second; ++h )
00776                             adj->remove_adjacency( h, my_handle );
00777                     list_write[0] = i->second + 1;
00778                 }
00779             }
00780             else if( i->first <= list_write[1] )
00781             {
00782                 // remove from end of block
00783                 if( i->second >= list_write[1] )
00784                 {
00785                     if( adj )
00786                         for( EntityHandle h = i->first; h <= list_write[1]; ++h )
00787                             adj->remove_adjacency( h, my_handle );
00788                     list_write[1] = i->first - 1;
00789                     // list_write += 2;
00790                     break;
00791                 }
00792                 // split block
00793                 else
00794                 {
00795                     if( adj )
00796                         for( EntityHandle h = i->first; h <= i->second; ++h )
00797                             adj->remove_adjacency( h, my_handle );
00798 
00799                     if( list_read - list_write <= 2 )
00800                     {
00801                         ++split_count;
00802                         continue;
00803                     }
00804                     else
00805                     {
00806                         list_write[3] = list_write[1];
00807                         list_write[1] = i->first - 1;
00808                         list_write[2] = i->second + 1;
00809                         list_write += 2;
00810                     }
00811                 }
00812             }
00813         }
00814         list_write += 2;
00815     }
00816 
00817     // shuffle down entries to fill holes
00818     if( list_read == list_write )
00819         list_read = list_write = list_end;
00820     else
00821         while( list_read < list_end )
00822         {
00823             list_write[0] = list_read[0];
00824             list_write[1] = list_read[1];
00825             list_read += 2;
00826             list_write += 2;
00827         }
00828 
00829     // adjust allocated array size
00830     const size_t occupied_size = list_write - list;
00831     const size_t new_list_size = occupied_size + 2 * split_count;
00832     list                       = resize_compact_list( count, clist, new_list_size );
00833     // done?
00834     if( !split_count ) return MB_SUCCESS;
00835 
00836     // Second pass: split range pairs
00837     // All range pairs in the input are either already removed or
00838     // require one of the existing range pairs to be split
00839     assert( begin != end );  // can't have ranges to split if given empty input list
00840     pair_iter_t ri = end;
00841     --ri;
00842     list_write = list + new_list_size - 2;
00843     list_read  = list + occupied_size - 2;
00844     for( ; list_write >= list; list_write -= 2 )
00845     {
00846         if( list_read >= list )
00847         {
00848             while( ri->second > list_read[1] )
00849             {
00850                 assert( ri != begin );
00851                 --ri;
00852             }
00853 
00854             if( list_read[0] > ri->second )
00855             {
00856                 list_write[0] = list_read[0];
00857                 list_write[1] = list_read[1];
00858                 list_read -= 2;
00859                 continue;
00860             }
00861         }
00862 
00863         assert( split_count > 0 );
00864         list_write[0] = ri->second + 1;
00865         list_write[1] = list_read[1];
00866         list_read[1]  = ri->first - 1;
00867 
00868         // don't have reverse iterator, so check before decrement
00869         // if insert_count isn't zero, must be more in range
00870         if( 0 == --split_count )
00871         {
00872             assert( list_read == list_write - 2 );
00873             break;
00874         }
00875         else
00876         {
00877             --ri;
00878         }
00879     }
00880 
00881     assert( !split_count );
00882     return MB_SUCCESS;
00883 }
00884 
00885 template < typename pair_iter_t >
00886 inline ErrorCode range_tool< pair_iter_t >::vector_insert_entities( MeshSet::Count& count,
00887                                                                     MeshSet::CompactList& clist,
00888                                                                     pair_iter_t begin,
00889                                                                     pair_iter_t end,
00890                                                                     EntityHandle my_handle,
00891                                                                     AEntityFactory* adj )
00892 {
00893     const size_t init_size = count < MeshSet::MANY ? (int)count : clist.ptr[1] - clist.ptr[0];
00894     size_t add_size        = 0;
00895     for( pair_iter_t i = begin; i != end; ++i )
00896         add_size += i->second - i->first + 1;
00897     EntityHandle* list = resize_compact_list( count, clist, init_size + add_size );
00898     EntityHandle* li   = list + init_size;
00899 
00900     for( pair_iter_t i = begin; i != end; ++i )
00901     {
00902         for( EntityHandle h = i->first; h <= i->second; ++h )
00903         {
00904             if( adj ) adj->add_adjacency( h, my_handle, false );
00905             *li = h;
00906             ++li;
00907         }
00908     }
00909 
00910     return MB_SUCCESS;
00911 }
00912 
00913 static ErrorCode vector_remove_range( MeshSet::Count& count,
00914                                       MeshSet::CompactList& clist,
00915                                       const Range& range,
00916                                       EntityHandle my_handle,
00917                                       AEntityFactory* adj )
00918 {
00919     EntityHandle* list;
00920     size_t list_size;
00921     if( count < MeshSet::MANY )
00922     {
00923         list      = clist.hnd;
00924         list_size = count;
00925     }
00926     else
00927     {
00928         list      = clist.ptr[0];
00929         list_size = clist.ptr[1] - clist.ptr[0];
00930     }
00931 
00932     const EntityHandle* const list_end = list + list_size;
00933     EntityHandle* list_write           = list;
00934     for( const EntityHandle* list_read = list; list_read != list_end; ++list_read )
00935     {
00936         if( range.find( *list_read ) == range.end() )
00937         {  // keep
00938             *list_write = *list_read;
00939             ++list_write;
00940         }
00941         else if( adj )
00942         {
00943             adj->remove_adjacency( *list_read, my_handle );
00944         }
00945     }
00946 
00947     resize_compact_list( count, clist, list_write - list );
00948     return MB_SUCCESS;
00949 }
00950 
00951 static ErrorCode vector_remove_ranges( MeshSet::Count& count,
00952                                        MeshSet::CompactList& clist,
00953                                        const EntityHandle* pair_list,
00954                                        size_t num_pairs,
00955                                        EntityHandle my_handle,
00956                                        AEntityFactory* adj )
00957 {
00958     EntityHandle* list;
00959     size_t list_size;
00960     if( count < MeshSet::MANY )
00961     {
00962         list      = clist.hnd;
00963         list_size = count;
00964     }
00965     else
00966     {
00967         list      = clist.ptr[0];
00968         list_size = clist.ptr[1] - clist.ptr[0];
00969     }
00970 
00971     const EntityHandle *const list_end = list + list_size, *const input_end = pair_list + 2 * num_pairs;
00972     EntityHandle* list_write = list;
00973     for( const EntityHandle* list_read = list; list_read != list_end; ++list_read )
00974     {
00975         const EntityHandle* ptr = std::lower_bound( pair_list, input_end, *list_read );
00976         if( ( ptr != input_end && ( *ptr == *list_read || ( ptr - pair_list ) % 2 ) ) &&  // if in delete list
00977             std::find( list_read + 1, list_end, *list_read ) == list_end )
00978         {  // and is last occurance in list
00979             // only remove adj if no previous occurance
00980             if( adj && std::find( list, list_write, *list_read ) == list_write )
00981                 adj->remove_adjacency( *list_read, my_handle );
00982         }
00983         else
00984         {
00985             *list_write = *list_read;
00986             ++list_write;
00987         }
00988     }
00989 
00990     resize_compact_list( count, clist, list_write - list );
00991     return MB_SUCCESS;
00992 }
00993 
00994 static ErrorCode vector_remove_vector( MeshSet::Count& count,
00995                                        MeshSet::CompactList& clist,
00996                                        const EntityHandle* vect,
00997                                        size_t vect_size,
00998                                        EntityHandle my_handle,
00999                                        AEntityFactory* adj )
01000 {
01001     EntityHandle* list;
01002     size_t list_size;
01003     if( count < MeshSet::MANY )
01004     {
01005         list      = clist.hnd;
01006         list_size = count;
01007     }
01008     else
01009     {
01010         list      = clist.ptr[0];
01011         list_size = clist.ptr[1] - clist.ptr[0];
01012     }
01013 
01014     const EntityHandle *const list_end = list + list_size, *const input_end = vect + vect_size;
01015     EntityHandle* list_write = list;
01016     for( const EntityHandle* list_read = list; list_read != list_end; ++list_read )
01017     {
01018         if( std::find( vect, input_end, *list_read ) != input_end &&  // if in delete list
01019             std::find( list_read + 1, list_end, *list_read ) == list_end )
01020         {  // and is last occurance in list
01021             // only remove adj if no previous occurance?
01022             if( adj )  // && std::find(list, list_write, *list_read) == list_write)
01023                 adj->remove_adjacency( *list_read, my_handle );
01024         }
01025         else
01026         {
01027             *list_write = *list_read;
01028             ++list_write;
01029         }
01030     }
01031 
01032     resize_compact_list( count, clist, list_write - list );
01033     return MB_SUCCESS;
01034 }
01035 
01036 static ErrorCode vector_insert_vector( MeshSet::Count& count,
01037                                        MeshSet::CompactList& clist,
01038                                        const EntityHandle* vect,
01039                                        size_t vect_size,
01040                                        EntityHandle my_handle,
01041                                        AEntityFactory* adj )
01042 {
01043     const size_t orig_size = count < MeshSet::MANY ? (int)count : clist.ptr[1] - clist.ptr[0];
01044     EntityHandle* list     = resize_compact_list( count, clist, orig_size + vect_size );
01045     if( adj )
01046         for( size_t i = 0; i < vect_size; ++i )
01047             adj->add_adjacency( vect[i], my_handle, false );
01048     memcpy( list + orig_size, vect, sizeof( EntityHandle ) * vect_size );
01049     return MB_SUCCESS;
01050 }
01051 
01052 ErrorCode MeshSet::insert_entity_ranges( const EntityHandle* range_vect,
01053                                          size_t len,
01054                                          EntityHandle my_h,
01055                                          AEntityFactory* adj )
01056 {
01057     typedef const std::pair< EntityHandle, EntityHandle >* pair_vect_t;
01058     pair_vect_t pair_vect = reinterpret_cast< pair_vect_t >( range_vect );
01059     MeshSet::Count count  = static_cast< MeshSet::Count >( mContentCount );
01060     ErrorCode rval;
01061     if( !vector_based() )
01062         rval = range_tool< pair_vect_t >::ranged_insert_entities( count, contentList, pair_vect, pair_vect + len / 2,
01063                                                                   my_h, tracking() ? adj : 0 );
01064     else
01065         rval = range_tool< pair_vect_t >::vector_insert_entities( count, contentList, pair_vect, pair_vect + len / 2,
01066                                                                   my_h, tracking() ? adj : 0 );
01067     mContentCount = count;
01068     return rval;
01069 }
01070 
01071 ErrorCode MeshSet::insert_entity_ranges( const Range& range, EntityHandle my_h, AEntityFactory* adj )
01072 {
01073     ErrorCode rval;
01074     MeshSet::Count count = static_cast< MeshSet::Count >( mContentCount );
01075     if( !vector_based() )
01076         rval = range_tool< Range::const_pair_iterator >::ranged_insert_entities(
01077             count, contentList, range.const_pair_begin(), range.const_pair_end(), my_h, tracking() ? adj : 0 );
01078     else
01079         rval = range_tool< Range::const_pair_iterator >::vector_insert_entities(
01080             count, contentList, range.const_pair_begin(), range.const_pair_end(), my_h, tracking() ? adj : 0 );
01081     mContentCount = count;
01082     return rval;
01083 }
01084 
01085 ErrorCode MeshSet::remove_entity_ranges( const EntityHandle* range_vect,
01086                                          size_t len,
01087                                          EntityHandle my_h,
01088                                          AEntityFactory* adj )
01089 {
01090     ErrorCode rval;
01091     MeshSet::Count count = static_cast< MeshSet::Count >( mContentCount );
01092     if( vector_based() )
01093         rval = vector_remove_ranges( count, contentList, range_vect, len / 2, my_h, tracking() ? adj : 0 );
01094     else
01095     {
01096         typedef const std::pair< EntityHandle, EntityHandle >* pair_vect_t;
01097         pair_vect_t pair_vect = reinterpret_cast< pair_vect_t >( range_vect );
01098         rval = range_tool< pair_vect_t >::ranged_remove_entities( count, contentList, pair_vect, pair_vect + len / 2,
01099                                                                   my_h, tracking() ? adj : 0 );
01100     }
01101     mContentCount = count;
01102     return rval;
01103 }
01104 
01105 ErrorCode MeshSet::remove_entity_ranges( const Range& range, EntityHandle my_h, AEntityFactory* adj )
01106 {
01107     ErrorCode rval;
01108     MeshSet::Count count = static_cast< MeshSet::Count >( mContentCount );
01109     if( vector_based() )
01110         rval = vector_remove_range( count, contentList, range, my_h, tracking() ? adj : 0 );
01111     else
01112         rval = range_tool< Range::const_pair_iterator >::ranged_remove_entities(
01113             count, contentList, range.const_pair_begin(), range.const_pair_end(), my_h, tracking() ? adj : 0 );
01114     mContentCount = count;
01115     return rval;
01116 }
01117 
01118 ErrorCode MeshSet::intersect( const MeshSet* other, EntityHandle my_handle, AEntityFactory* adj )
01119 {
01120     ErrorCode rval;
01121     if( !vector_based() && !other->vector_based() )
01122     {
01123         size_t other_count             = 0;
01124         const EntityHandle* other_vect = other->get_contents( other_count );
01125         if( !other_count ) return clear( my_handle, adj );
01126         assert( 0 == other_count % 2 );
01127 
01128         std::vector< EntityHandle > compliment;
01129         compliment.reserve( other_count + 4 );
01130         if( *other_vect > 0 )
01131         {
01132             compliment.push_back( 0 );
01133             compliment.push_back( *other_vect - 1 );
01134         }
01135         ++other_vect;
01136         const EntityHandle* const other_end = other_vect + other_count - 2;
01137         for( ; other_vect < other_end; other_vect += 2 )
01138         {
01139             compliment.push_back( other_vect[0] + 1 );
01140             compliment.push_back( other_vect[1] - 1 );
01141         }
01142         if( *other_vect < ~(EntityHandle)0 )
01143         {
01144             compliment.push_back( *other_vect + 1 );
01145             compliment.push_back( ~(EntityHandle)0 );
01146         }
01147 
01148         return remove_entity_ranges( &compliment[0], compliment.size(), my_handle, adj );
01149     }
01150     else
01151     {
01152         Range my_ents, other_ents;
01153         rval = get_entities( my_ents );
01154         if( MB_SUCCESS != rval ) return rval;
01155         rval = other->get_entities( other_ents );
01156         return remove_entities( moab::subtract( my_ents, other_ents ), my_handle, adj );
01157     }
01158 }
01159 
01160 static void convert_to_ranges( const EntityHandle* vect_in, size_t vect_in_len, std::vector< EntityHandle >& vect_out )
01161 {
01162     vect_out.reserve( 2 * vect_in_len );
01163     vect_out.resize( vect_in_len );
01164     std::copy( vect_in, vect_in + vect_in_len, vect_out.begin() );
01165     std::sort( vect_out.begin(), vect_out.end() );
01166     vect_out.erase( std::unique( vect_out.begin(), vect_out.end() ), vect_out.end() );
01167 
01168     // duplicate all entries
01169     vect_out.resize( vect_out.size() * 2 );
01170     for( long i = vect_out.size() - 1; i >= 0; --i )
01171         vect_out[i] = vect_out[i / 2];
01172 
01173     // compact adjacent ranges
01174     std::vector< EntityHandle >::iterator r = vect_out.begin(), w = vect_out.begin();
01175     while( r != vect_out.end() )
01176     {
01177         *w = *r;
01178         ++w;
01179         ++r;
01180         *w = *r;
01181         ++r;
01182 
01183         while( r != vect_out.end() && *w + 1 == *r )
01184         {
01185             ++r;
01186             *w = *r;
01187             ++r;
01188         }
01189         ++w;
01190     }
01191 
01192     // remove extra space
01193     vect_out.erase( w, vect_out.end() );
01194 }
01195 
01196 ErrorCode MeshSet::insert_entity_vector( const EntityHandle* vect, size_t len, EntityHandle my_h, AEntityFactory* adj )
01197 {
01198     MeshSet::Count count = static_cast< MeshSet::Count >( mContentCount );
01199     ErrorCode rval;
01200     if( vector_based() )
01201         rval = vector_insert_vector( count, contentList, vect, len, my_h, tracking() ? adj : 0 );
01202     else
01203     {
01204         std::vector< EntityHandle > rangevect;
01205         convert_to_ranges( vect, len, rangevect );
01206         typedef const std::pair< EntityHandle, EntityHandle >* pair_vect_t;
01207         pair_vect_t pair_vect = ( rangevect.empty() ) ? NULL : reinterpret_cast< pair_vect_t >( &rangevect[0] );
01208         rval                  = range_tool< pair_vect_t >::ranged_insert_entities(
01209                              count, contentList, pair_vect, pair_vect + rangevect.size() / 2, my_h, tracking() ? adj : 0 );
01210     }
01211     mContentCount = count;
01212     return rval;
01213 }
01214 
01215 ErrorCode MeshSet::remove_entity_vector( const EntityHandle* vect, size_t len, EntityHandle my_h, AEntityFactory* adj )
01216 {
01217     MeshSet::Count count = static_cast< MeshSet::Count >( mContentCount );
01218     ErrorCode rval;
01219     if( vector_based() )
01220         rval = vector_remove_vector( count, contentList, vect, len, my_h, tracking() ? adj : 0 );
01221     else
01222     {
01223         std::vector< EntityHandle > rangevect;
01224         convert_to_ranges( vect, len, rangevect );
01225         typedef const std::pair< EntityHandle, EntityHandle >* pair_vect_t;
01226         pair_vect_t pair_vect = ( rangevect.empty() ) ? NULL : reinterpret_cast< pair_vect_t >( &rangevect[0] );
01227         rval                  = range_tool< pair_vect_t >::ranged_remove_entities(
01228                              count, contentList, pair_vect, pair_vect + rangevect.size() / 2, my_h, tracking() ? adj : 0 );
01229     }
01230     mContentCount = count;
01231     return rval;
01232 }
01233 
01234 ErrorCode MeshSet::replace_entities( EntityHandle my_handle,
01235                                      const EntityHandle* old_entities,
01236                                      const EntityHandle* new_entities,
01237                                      size_t num_ents,
01238                                      AEntityFactory* adjfact )
01239 {
01240     if( vector_based() )
01241     {
01242         ErrorCode result = MB_SUCCESS;
01243         size_t count;
01244         EntityHandle* vect           = get_contents( count );
01245         EntityHandle* const vect_end = vect + count;
01246         for( size_t i = 0; i < num_ents; ++i )
01247         {
01248             EntityHandle* p = std::find( vect, vect_end, old_entities[i] );
01249             if( p == vect_end )
01250             {
01251                 result = MB_ENTITY_NOT_FOUND;
01252             }
01253             else
01254                 do
01255                 {
01256                     if( tracking() )
01257                     {
01258                         adjfact->remove_adjacency( *p, my_handle );
01259                         adjfact->add_adjacency( new_entities[i], my_handle, false );
01260                     }
01261                     *p = new_entities[i];
01262                     p  = std::find( p + 1, vect_end, old_entities[i] );
01263                 } while( p != vect_end );
01264         }
01265         return result;
01266     }
01267     else
01268     {
01269         ErrorCode r1 = remove_entities( old_entities, num_ents, my_handle, adjfact );
01270         ErrorCode r2 = add_entities( new_entities, num_ents, my_handle, adjfact );
01271         return ( MB_SUCCESS == r2 ) ? r1 : r2;
01272     }
01273 }
01274 
01275 /*****************************************************************************************
01276  *                                  Misc. Methods                                        *
01277  *****************************************************************************************/
01278 
01279 unsigned long MeshSet::get_memory_use() const
01280 {
01281     unsigned long result = 0;
01282     if( mParentCount == MANY ) result += parentMeshSets.ptr[1] - parentMeshSets.ptr[0];
01283     if( mChildCount == MANY ) result += childMeshSets.ptr[1] - childMeshSets.ptr[0];
01284     if( mContentCount == MANY ) result += contentList.ptr[1] - contentList.ptr[0];
01285     return sizeof( EntityHandle ) * result;
01286 }
01287 
01288 }  // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines