bool VersionVector::operator<=( const VersionVector& other ) const { // build a set of all keys in both vectors set_t keys; keyUnion(keys,other); for( auto& key : keys ) { int64_t v1 = (*this)[key]; int64_t v2 = other[key]; if( v1 > v2 ) return false; } return true; }
bool VersionVector::operator<( const VersionVector& other ) const { // build a set of all keys in both vectors set_t keys; keyUnion(keys,other); bool atLeastOneLess = false; for( auto& key : keys ) { int64_t v1 = (*this)[key]; int64_t v2 = other[key]; if( v1 > v2 ) return false; else if( v1 < v2 ) atLeastOneLess = true; } return atLeastOneLess; }
void partitionEntries( IndexEntry *I, /* input entry list to partition */ Int fan, /* fan or order of index */ IndexEntry **A, /* 1st group partitioned entries */ IndexEntry **B ) /* 2nd group partitioned entries */ { /* beginning of partitionEntries() */ IndexEntry *entry1; /* looping entry to find first entry of groups */ IndexEntry *entry2; /* looping entry to find first entry of groups */ IndexEntry *currentEntry; /* looping entry for input list */ IndexEntry *previousEntry; /* looping entry for input list */ IndexEntry *tempA; /* temp entry to find first entry of group A */ IndexEntry *tempB; /* temp entry to find first entry of group B */ IndexKey unionAB; /* union of first entries of group A and B */ Float volumeAB; /* volume of first entries of group A and B */ Int sizeOfGroupA; /* current size of group A */ Int sizeOfGroupB; /* current size of group B */ static Char name[] = "partitionEntries"; assert( I && I->next ); /* need at least two entries to partition */ assert( MINIMUM_FAN_SIZE > 1 ); assert( fan >= MINIMUM_FAN_SIZE ); /* * Find "worst" combination of all entries in I. The worst combination is * the one which produces the largest bounding index key, i.e., the * largest hyper-cube volume. The two entries which form the worst combo * will be the first entries into the two groups, A and B. The method * used to find the worst combo is straight forward enumeration of all * possible combinations. Note that only forward combinations are * necessary since the volume( union( A, B ) ) is the same as the * volume( union( B, A ) ). The first candidate pair for the worst case * are chosen as the first and second entries of the input list, I. */ *A = I; *B = I->next; keyUnion( &(*A)->key, &(*B)->key, &unionAB ); volumeAB = volume( unionAB ); /* * A double loop through the input list, I, is used to find all * combinations. */ for ( entry1 = I; entry1 != NULL; entry1 = entry1->next ) { for ( entry2 = entry1->next; entry2 != NULL; entry2 = entry2->next ) { IndexKey tempKey; Float tempVolume; /* * If this combination produces a worse penalty, then replace old * candidates with new pair. */ keyUnion( &entry1->key, &entry2->key, &tempKey ); tempVolume = volume( tempKey ); if ( tempVolume > volumeAB ) { *A = entry1; *B = entry2; unionAB = tempKey; volumeAB = tempVolume; } /* end of if ( tempVolume > volumeAB ) */ } /* end of loop for entry2 */ } /* end of loop for entry1 */ /* * The entry pointers, A and B, now point to the first entries of the * two groups which are forming during the partition. Remove them from the * input list, I. Set the size of each group to one for the initial * entries. The entries of I which correspond to A and B are * found by comparing pointer values. */ currentEntry = I; /* current entry (starts at beginning of I) */ previousEntry = NULL; /* previous entry (NULL for first entry) */ while ( currentEntry != NULL ) { if ( currentEntry == *A || currentEntry == *B ) { /* * Found A or B in list as currentEntry. Remove current entry from * list, checking for special case where current entry is the head * of list, i.e., no previous entry. */ if ( previousEntry == NULL ) { /* * No previous pointer means that the current entry is the * head of the list. Removing the entry means updating I and * reseting the values for currentEntry and previousEntry. */ I = currentEntry->next; currentEntry = I; previousEntry = NULL; } /* end of if ( previousEntry == NULL ) */ else { /* * Remove current entry by setting previous entry's pointer to * skip the current. */ previousEntry->next = currentEntry->next; /* * Setup entries for next loop. Since an entry was removed * from the list, the previous entry, previousEntry, does not * change. */ currentEntry = previousEntry->next; } /* end of else */ } /* end of if ( currentEntry == A || currentEntry == B ) */ else { /* * Did not find either A or B, so just set up for next loop */ previousEntry = currentEntry; currentEntry = currentEntry->next; } /* end of else */ } /* end of loop for currentEntry */ /* * Finish up by fixing the next pointers for both A and B to NULL since * their the first and only entries in the lists, and setting the size of * each group to one. */ (*A)->next = NULL; (*B)->next = NULL; sizeOfGroupA = 1; sizeOfGroupB = 1; /* * The first entries of groups A and B are now assigned and removed from * the input list, I. The "volume" for A and B is the "worst" possible * for all combinations of the entries of I. * * Assign all remaining entries of I to each group based on penalty. The * current implementation finds the penalty of the entry with the first * entries into the group, i.e., A or B. Other methods are possible, * including using the penalty of the current group rather than the first * entry into that group. */ tempA = *A; tempB = *B; while ( I != NULL ) { /* * If neither group is full, add according to penalty */ if ( sizeOfGroupA < fan && sizeOfGroupB < fan ) { if ( penalty( **A, *I ) < penalty( **B, *I ) ) { /* * Place current entry into group A, incrementing counter */ tempA->next = I; /* add current entry to group A */ I = I->next; /* increment current entry */ tempA = tempA->next; /* increment group A ptr */ tempA->next = NULL; /* remove new entry from group I */ sizeOfGroupA++; } /* end of if ( penalty( I, A ) < penalty( I, B ) ) */ else { /* * Place current entry into group B, incrementing counter */ tempB->next = I; /* add current entry to group B */ I = I->next; /* increment current entry */ tempB = tempB->next; /* increment group B ptr */ tempB->next = NULL; /* remove new entry from group I */ sizeOfGroupB++; } /* end of else */ } /* end of if ( sizeOfGroupA < fan && sizeOfGroupB < fan ) */ /* * If group A is full and there is room on group B, then add entry to * group B */ else if ( sizeOfGroupA >= fan && sizeOfGroupB < fan ) { /* * Place entry into group B, incrementing counter */ tempB->next = I; /* add current entry to group B */ I = I->next; /* increment current entry */ tempB = tempB->next; /* increment group B ptr */ tempB->next = NULL; /* remove new entry from group I */ sizeOfGroupB++; } /* end of if ( sizeOfGroupA >= fan ) */ /* * If group B is full and there is room on group A, then add entry to * group A */ else if ( sizeOfGroupB >= fan && sizeOfGroupA < fan ) { /* * Place current entry into group A, incrementing counter */ tempA->next = I; /* add current entry to group A */ I = I->next; /* increment current entry */ tempA = tempA->next; /* increment group A ptr */ tempA->next = NULL; /* remove new entry from group I */ sizeOfGroupA++; } /* end of if ( sizeOfGroupB >= fan ) */ else { /* * Special(error) case when both groups are full and no where to * place entry. Simply ignore entry and try to continue. */ I = I->next; errorMessage( "too many entries to partition", REPLACE ); errorMessage( name, PREPEND ); } } /* end of loop for currentEntry */ return; } /* end paritionEntries() */