HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r) { try { r->OpenResult=0; DataSet *Data=new DataSet; Data->Cmd.DllError=0; Data->OpenMode=r->OpenMode; Data->Cmd.FileArgs->AddString("*"); char an[NM]; if (r->ArcName==NULL && r->ArcNameW!=NULL) { WideToChar(r->ArcNameW,an,NM); r->ArcName=an; } Data->Cmd.AddArcName(r->ArcName,r->ArcNameW); Data->Cmd.Overwrite=OVERWRITE_ALL; Data->Cmd.VersionControl=1; Data->Cmd.Callback=r->Callback; Data->Cmd.UserData=r->UserData; if (!Data->Arc.Open(r->ArcName,r->ArcNameW)) { r->OpenResult=ERAR_EOPEN; delete Data; return(NULL); } if (!Data->Arc.IsArchive(false)) { r->OpenResult=Data->Cmd.DllError!=0 ? Data->Cmd.DllError:ERAR_BAD_ARCHIVE; delete Data; return(NULL); } r->Flags=Data->Arc.NewMhd.Flags; Array<byte> CmtData; if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtData,NULL)) { r->Flags|=2; size_t Size=CmtData.Size()+1; r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1; r->CmtSize=(uint)Min(Size,r->CmtBufSize); memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1); if (Size<=r->CmtBufSize) r->CmtBuf[r->CmtSize-1]=0; } else r->CmtState=r->CmtSize=0; if (Data->Arc.Signed) r->Flags|=0x20; Data->Extract.ExtractArchiveInit(&Data->Cmd,Data->Arc); return((HANDLE)Data); } catch (int ErrCode) { r->OpenResult=RarErrorToDll(ErrCode); return(NULL); } }

/* * Consider replacement of currently selected split with the better one. */ static inline void g_box_consider_split(ConsiderSplitContext *context, int dimNum, double rightLower, int minLeftCount, double leftUpper, int maxLeftCount) { int leftCount, rightCount; float4 ratio, overlap; double range; /* * Calculate entries distribution ratio assuming most uniform distribution * of common entries. */ if (minLeftCount >= (context->entriesCount + 1) / 2) { leftCount = minLeftCount; } else { if (maxLeftCount <= context->entriesCount / 2) leftCount = maxLeftCount; else leftCount = context->entriesCount / 2; } rightCount = context->entriesCount - leftCount; /* * Ratio of split - quotient between size of lesser group and total * entries count. */ ratio = ((float4) Min(leftCount, rightCount)) / ((float4) context->entriesCount); if (ratio > LIMIT_RATIO) { bool selectthis = false; /* * The ratio is acceptable, so compare current split with previously * selected one. Between splits of one dimension we search for minimal * overlap (allowing negative values) and minimal ration (between same * overlaps. We switch dimension if find less overlap (non-negative) * or less range with same overlap. */ if (dimNum == 0) range = context->boundingBox.high.x - context->boundingBox.low.x; else range = context->boundingBox.high.y - context->boundingBox.low.y; overlap = (leftUpper - rightLower) / range; /* If there is no previous selection, select this */ if (context->first) selectthis = true; else if (context->dim == dimNum) { /* * Within the same dimension, choose the new___ split if it has a * smaller overlap, or same overlap but better ratio. */ if (overlap < context->overlap || (overlap == context->overlap && ratio > context->ratio)) selectthis = true; } else { /* * Across dimensions, choose the new___ split if it has a smaller * *non-negative* overlap, or same *non-negative* overlap but * bigger range. This condition differs from the one described in * the article. On the datasets where leaf MBRs don't overlap * themselves, non-overlapping splits (i.e. splits which have zero * *non-negative* overlap) are frequently possible. In this case * splits tends to be along one dimension, because most distant * non-overlapping splits (i.e. having lowest negative overlap) * appears to be in the same dimension as in the previous split. * Therefore MBRs appear to be very prolonged along another * dimension, which leads to bad search performance. Using range * as the second split criteria makes MBRs more quadratic. Using * *non-negative* overlap instead of overlap as the first split * criteria gives to range criteria a chance to matter, because * non-overlapping splits are equivalent in this criteria. */ if (non_negative(overlap) < non_negative(context->overlap) || (range > context->range && non_negative(overlap) <= non_negative(context->overlap))) selectthis = true; } if (selectthis) { /* save information about selected split */ context->first = false; context->ratio = ratio; context->range = range; context->overlap = overlap; context->rightLower = rightLower; context->leftUpper = leftUpper; context->dim = dimNum; } } }

double Min(double x, double y, double z){ return Min(Min(x,y),z); }

/* * compute_tsvector_stats() -- compute statistics for a tsvector column * * This functions computes statistics that are useful for determining @@ * operations' selectivity, along with the fraction of non-null rows and * average width. * * Instead of finding the most common values, as we do for most datatypes, * we're looking for the most common lexemes. This is more useful, because * there most probably won't be any two rows with the same tsvector and thus * the notion of a MCV is a bit bogus with this datatype. With a list of the * most common lexemes we can do a better job at figuring out @@ selectivity. * * For the same reasons we assume that tsvector columns are unique when * determining the number of distinct values. * * The algorithm used is Lossy Counting, as proposed in the paper "Approximate * frequency counts over data streams" by G. S. Manku and R. Motwani, in * Proceedings of the 28th International Conference on Very Large Data Bases, * Hong Kong, China, August 2002, section 4.2. The paper is available at * http://www.vldb.org/conf/2002/S10P03.pdf * * The Lossy Counting (aka LC) algorithm goes like this: * Let s be the threshold frequency for an item (the minimum frequency we * are interested in) and epsilon the error margin for the frequency. Let D * be a set of triples (e, f, delta), where e is an element value, f is that * element's frequency (actually, its current occurrence count) and delta is * the maximum error in f. We start with D empty and process the elements in * batches of size w. (The batch size is also known as "bucket size" and is * equal to 1/epsilon.) Let the current batch number be b_current, starting * with 1. For each element e we either increment its f count, if it's * already in D, or insert a new triple into D with values (e, 1, b_current * - 1). After processing each batch we prune D, by removing from it all * elements with f + delta <= b_current. After the algorithm finishes we * suppress all elements from D that do not satisfy f >= (s - epsilon) * N, * where N is the total number of elements in the input. We emit the * remaining elements with estimated frequency f/N. The LC paper proves * that this algorithm finds all elements with true frequency at least s, * and that no frequency is overestimated or is underestimated by more than * epsilon. Furthermore, given reasonable assumptions about the input * distribution, the required table size is no more than about 7 times w. * * We set s to be the estimated frequency of the K'th word in a natural * language's frequency table, where K is the target number of entries in * the MCELEM array plus an arbitrary constant, meant to reflect the fact * that the most common words in any language would usually be stopwords * so we will not actually see them in the input. We assume that the * distribution of word frequencies (including the stopwords) follows Zipf's * law with an exponent of 1. * * Assuming Zipfian distribution, the frequency of the K'th word is equal * to 1/(K * H(W)) where H(n) is 1/2 + 1/3 + ... + 1/n and W is the number of * words in the language. Putting W as one million, we get roughly 0.07/K. * Assuming top 10 words are stopwords gives s = 0.07/(K + 10). We set * epsilon = s/10, which gives bucket width w = (K + 10)/0.007 and * maximum expected hashtable size of about 1000 * (K + 10). * * Note: in the above discussion, s, epsilon, and f/N are in terms of a * lexeme's frequency as a fraction of all lexemes seen in the input. * However, what we actually want to store in the finished pg_statistic * entry is each lexeme's frequency as a fraction of all rows that it occurs * in. Assuming that the input tsvectors are correctly constructed, no * lexeme occurs more than once per tsvector, so the final count f is a * correct estimate of the number of input tsvectors it occurs in, and we * need only change the divisor from N to nonnull_cnt to get the number we * want. */ static void compute_tsvector_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows) { int num_mcelem; int null_cnt = 0; double total_width = 0; /* This is D from the LC algorithm. */ HTAB *lexemes_tab; HASHCTL hash_ctl; HASH_SEQ_STATUS scan_status; /* This is the current bucket number from the LC algorithm */ int b_current; /* This is 'w' from the LC algorithm */ int bucket_width; int vector_no, lexeme_no; LexemeHashKey hash_key; TrackItem *item; /* * We want statistics_target * 10 lexemes in the MCELEM array. This * multiplier is pretty arbitrary, but is meant to reflect the fact that * the number of individual lexeme values tracked in pg_statistic ought to * be more than the number of values for a simple scalar column. */ num_mcelem = stats->attr->attstattarget * 10; /* * We set bucket width equal to (num_mcelem + 10) / 0.007 as per the * comment above. */ bucket_width = (num_mcelem + 10) * 1000 / 7; /* * Create the hashtable. It will be in local memory, so we don't need to * worry about overflowing the initial size. Also we don't need to pay any * attention to locking and memory management. */ MemSet(&hash_ctl, 0, sizeof(hash_ctl)); hash_ctl.keysize = sizeof(LexemeHashKey); hash_ctl.entrysize = sizeof(TrackItem); hash_ctl.hash = lexeme_hash; hash_ctl.match = lexeme_match; hash_ctl.hcxt = CurrentMemoryContext; lexemes_tab = hash_create("Analyzed lexemes table", bucket_width * 7, &hash_ctl, HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT); /* Initialize counters. */ b_current = 1; lexeme_no = 0; /* Loop over the tsvectors. */ for (vector_no = 0; vector_no < samplerows; vector_no++) { Datum value; bool isnull; TSVector vector; WordEntry *curentryptr; char *lexemesptr; int j; vacuum_delay_point(); value = fetchfunc(stats, vector_no, &isnull); /* * Check for null/nonnull. */ if (isnull) { null_cnt++; continue; } /* * Add up widths for average-width calculation. Since it's a * tsvector, we know it's varlena. As in the regular * compute_minimal_stats function, we use the toasted width for this * calculation. */ total_width += VARSIZE_ANY(DatumGetPointer(value)); /* * Now detoast the tsvector if needed. */ vector = DatumGetTSVector(value); /* * We loop through the lexemes in the tsvector and add them to our * tracking hashtable. Note: the hashtable entries will point into * the (detoasted) tsvector value, therefore we cannot free that * storage until we're done. */ lexemesptr = STRPTR(vector); curentryptr = ARRPTR(vector); for (j = 0; j < vector->size; j++) { bool found; /* Construct a hash key */ hash_key.lexeme = lexemesptr + curentryptr->pos; hash_key.length = curentryptr->len; /* Lookup current lexeme in hashtable, adding it if new */ item = (TrackItem *) hash_search(lexemes_tab, (const void *) &hash_key, HASH_ENTER, &found); if (found) { /* The lexeme is already on the tracking list */ item->frequency++; } else { /* Initialize new tracking list element */ item->frequency = 1; item->delta = b_current - 1; } /* lexeme_no is the number of elements processed (ie N) */ lexeme_no++; /* We prune the D structure after processing each bucket */ if (lexeme_no % bucket_width == 0) { prune_lexemes_hashtable(lexemes_tab, b_current); b_current++; } /* Advance to the next WordEntry in the tsvector */ curentryptr++; } } /* We can only compute real stats if we found some non-null values. */ if (null_cnt < samplerows) { int nonnull_cnt = samplerows - null_cnt; int i; TrackItem **sort_table; int track_len; int cutoff_freq; int minfreq, maxfreq; stats->stats_valid = true; /* Do the simple null-frac and average width stats */ stats->stanullfrac = (double) null_cnt / (double) samplerows; stats->stawidth = total_width / (double) nonnull_cnt; /* Assume it's a unique column (see notes above) */ stats->stadistinct = -1.0; /* * Construct an array of the interesting hashtable items, that is, * those meeting the cutoff frequency (s - epsilon)*N. Also identify * the minimum and maximum frequencies among these items. * * Since epsilon = s/10 and bucket_width = 1/epsilon, the cutoff * frequency is 9*N / bucket_width. */ cutoff_freq = 9 * lexeme_no / bucket_width; i = hash_get_num_entries(lexemes_tab); /* surely enough space */ sort_table = (TrackItem **) palloc(sizeof(TrackItem *) * i); hash_seq_init(&scan_status, lexemes_tab); track_len = 0; minfreq = lexeme_no; maxfreq = 0; while ((item = (TrackItem *) hash_seq_search(&scan_status)) != NULL) { if (item->frequency > cutoff_freq) { sort_table[track_len++] = item; minfreq = Min(minfreq, item->frequency); maxfreq = Max(maxfreq, item->frequency); } } Assert(track_len <= i); /* emit some statistics for debug purposes */ elog(DEBUG3, "tsvector_stats: target # mces = %d, bucket width = %d, " "# lexemes = %d, hashtable size = %d, usable entries = %d", num_mcelem, bucket_width, lexeme_no, i, track_len); /* * If we obtained more lexemes than we really want, get rid of those * with least frequencies. The easiest way is to qsort the array into * descending frequency order and truncate the array. */ if (num_mcelem < track_len) { qsort(sort_table, track_len, sizeof(TrackItem *), trackitem_compare_frequencies_desc); /* reset minfreq to the smallest frequency we're keeping */ minfreq = sort_table[num_mcelem - 1]->frequency; } else num_mcelem = track_len; /* Generate MCELEM slot entry */ if (num_mcelem > 0) { MemoryContext old_context; Datum *mcelem_values; float4 *mcelem_freqs; /* * We want to store statistics sorted on the lexeme value using * first length, then byte-for-byte comparison. The reason for * doing length comparison first is that we don't care about the * ordering so long as it's consistent, and comparing lengths * first gives us a chance to avoid a strncmp() call. * * This is different from what we do with scalar statistics -- * they get sorted on frequencies. The rationale is that we * usually search through most common elements looking for a * specific value, so we can grab its frequency. When values are * presorted we can employ binary search for that. See * ts_selfuncs.c for a real usage scenario. */ qsort(sort_table, num_mcelem, sizeof(TrackItem *), trackitem_compare_lexemes); /* Must copy the target values into anl_context */ old_context = MemoryContextSwitchTo(stats->anl_context); /* * We sorted statistics on the lexeme value, but we want to be * able to find out the minimal and maximal frequency without * going through all the values. We keep those two extra * frequencies in two extra cells in mcelem_freqs. */ mcelem_values = (Datum *) palloc(num_mcelem * sizeof(Datum)); mcelem_freqs = (float4 *) palloc((num_mcelem + 2) * sizeof(float4)); /* * See comments above about use of nonnull_cnt as the divisor for * the final frequency estimates. */ for (i = 0; i < num_mcelem; i++) { TrackItem *item = sort_table[i]; mcelem_values[i] = PointerGetDatum(cstring_to_text_with_len(item->key.lexeme, item->key.length)); mcelem_freqs[i] = (double) item->frequency / (double) nonnull_cnt; } mcelem_freqs[i++] = (double) minfreq / (double) nonnull_cnt; mcelem_freqs[i] = (double) maxfreq / (double) nonnull_cnt; MemoryContextSwitchTo(old_context); stats->stakind[0] = STATISTIC_KIND_MCELEM; stats->staop[0] = TextEqualOperator; stats->stanumbers[0] = mcelem_freqs; /* See above comment about two extra frequency fields */ stats->numnumbers[0] = num_mcelem + 2; stats->stavalues[0] = mcelem_values; stats->numvalues[0] = num_mcelem; /* We are storing text values */ stats->statypid[0] = TEXTOID; stats->statyplen[0] = -1; /* typlen, -1 for varlena */ stats->statypbyval[0] = false; stats->statypalign[0] = 'i'; } } else { /* We found only nulls; assume the column is entirely null */ stats->stats_valid = true; stats->stanullfrac = 1.0; stats->stawidth = 0; /* "unknown" */ stats->stadistinct = 0.0; /* "unknown" */ } /* * We don't need to bother cleaning up any of our temporary palloc's. The * hashtable should also go away, as it used a child memory context. */ }

void sim_update(Simulator* sim, Tilemap* map, real dt) { Sim_Body *a, *b; for(isize times = 0; times < Sim_Iter_i; ++times) { //#if 0 if(sim->sort_axis == 0) { body_sort_on_x(sim->bodies, sim->bodies_count); } else if(sim->sort_axis == 1) { body_sort_on_y(sim->bodies, sim->bodies_count); } //#endif Vec2 center_sum1 = v2(0, 0); Vec2 center_sum2 = v2(0, 0); Vec2 variance = v2(0, 0); for(isize i = 0; i < sim->bodies_count; ++i) { a = sim->bodies + i; //sweep and prune stuff center_sum1 += a->shape.center; for(isize q = 0; q < 2; ++q) { center_sum2.e[q] += a->shape.center.e[q] * a->shape.center.e[q]; } //if(a->is_static) continue; for(isize j = i + 1; j < sim->bodies_count; ++j) { b = sim->bodies + j; uint64 a_is_static = Has_Flag(a->flags, Body_Flag_Static); uint64 b_is_static = Has_Flag(b->flags, Body_Flag_Static); if(a_is_static && b_is_static) continue; //#if 0 if(sim->sort_axis == 0) { if(AABB_x1(b->shape) > AABB_x2(a->shape)) { break; } } else if(sim->sort_axis == 1) { if(AABB_y1(b->shape) > AABB_y2(a->shape)) { break; } } //#endif if(aabb_intersect(&a->shape, &b->shape)) { Vec2 overlap; aabb_overlap(&a->shape, &b->shape, &overlap); real ovl_mag = sqrtf(v2_dot(overlap, overlap)); if (ovl_mag < 0.0001f) continue; Vec2 normal = overlap * (1.0f / ovl_mag); if(a->id == 0 || b->id == 0) { aabb_intersect(&a->shape, &b->shape); } #define _collision_slop (0.8f) if(a_is_static && !b_is_static) { b->shape.center += overlap; Vec2 relative_velocity = b->velocity; real velocity_on_normal = v2_dot(relative_velocity, normal); if(velocity_on_normal > 0) continue; real e = Min(a->restitution, b->restitution); real mag = -1.0f * (1.0f + e) * velocity_on_normal; mag /= b->inv_mass; Vec2 impulse = mag * normal; b->collision_vel += b->inv_mass * impulse; } else if(!a_is_static && b_is_static) { a->shape.center -= overlap; Vec2 relative_velocity = -a->velocity; real velocity_on_normal = v2_dot(relative_velocity, normal); if(velocity_on_normal > 0) continue; real e = Min(a->restitution, b->restitution); real mag = -1.0f * (1.0f + e) * velocity_on_normal; mag /= a->inv_mass + 0; Vec2 impulse = mag * normal; a->collision_vel -= a->inv_mass * impulse; } else { Vec2 separation = Max(ovl_mag - _collision_slop, 0) * (1.0f / (a->inv_mass + b->inv_mass)) * 0.5f * normal; a->shape.center -= a->inv_mass * separation; b->shape.center += b->inv_mass * separation; Vec2 relative_velocity = b->velocity - a->velocity; real velocity_on_normal = v2_dot(relative_velocity, normal); if(velocity_on_normal > 0) continue; real e = Min(a->restitution, b->restitution); real mag = -1.0f * (1.0f + e) * velocity_on_normal; mag /= a->inv_mass + b->inv_mass; Vec2 impulse = mag * normal; a->collision_vel -= a->inv_mass * impulse; b->collision_vel += b->inv_mass * impulse; } } } } for(isize i = 0; i < 2; ++i) { variance.e[i] = center_sum2.e[i] - center_sum1.e[i] * center_sum1.e[i] / sim->bodies_count; } if(variance.x > variance.y) { sim->sort_axis = 0; } else { sim->sort_axis = 1; } for(isize i = 0; i < sim->bodies_count; ++i) { a = sim->bodies + i; if(Has_Flag(a->flags, Body_Flag_Static)) continue; Vec2 iter_acl = (a->force * a->inv_mass) / Sim_Iter; Vec2 new_vel = a->velocity + (dt * iter_acl); Vec2 dpos = (a->velocity + new_vel) * 0.5f; dpos *= 1.0f / Sim_Iter; a->shape.center += dpos * dt; a->shape.center += a->collision_vel / Sim_Iter * dt; a->velocity = new_vel; Tile_Info* tile = map->info + tilemap_get_at(map, a->shape.center); real damping = 1.0f; if(Has_Flag(a->flags, Body_Flag_No_Friction)) { damping = a->damping; } else { damping = sqrtf(a->damping * a->damping + tile->friction * tile->friction) * Math_InvSqrt2; } a->velocity *= powf(damping, Sim_Iter); a->velocity += a->collision_vel; a->collision_vel = v2(0, 0); } } body_sort_on_id(sim->bodies, sim->bodies_count); }

void CastRelation() { char ignoreT[objMax]; int i, saveRev; real ratio, t1, t2, t; real ppowerT[oNormOpt+1]; /* Cast the first chart. */ ciMain = ciCore; if (us.fRelocation && us.nRel == rcComposite) { OO=us.lonDef; AA=us.latDef ; NN=us.altDef; } t1 = CastChart(fTrue); cp1 = cp0; saveRev = hRevers; if (us.nRel == rcTransit || us.nRel == rcProgress) for (i = 1; i <= cObjOpt; i++) { cp1.dir[i] = 0.0; if (i > oNormOpt) continue; cp1.altdir[i] = 0.0; } #ifdef GRAPH /* Struct GS is defined with graphics. */ if (!gs.nAnim) { #endif if (!FCreateGrid(fFalse)) return; PlanetPPower(); #ifdef GRAPH } #endif /* Cast the second chart. */ ciCore = ciTwin; if (us.nRel == rcTransit) { for (i = 0; i <= cObjOpt; i++) { ignoreT[i] = ignore[i]; if (us.fSector || us.fAstroGraph) ignore[i] = ignore[i] && ignore2[i]; else ignore[i] = ignore2[i]; } } else if (us.nRel == rcProgress) { us.fProgress = fTrue; is.JDp = MdytszToJulian(MM, DD, YY, TT, SS, ZZ)-rRound; ciCore = ciMain; for (i = 0; i <= cObjOpt; i++) { ignoreT[i] = ignore[i]; if (us.fSector || us.fAstroGraph) ignore[i] = ignore[i] && ignore3[i]; else ignore[i] = ignore3[i]; } } if (us.fRelocation && us.nRel == rcComposite) { OO=us.lonDef; AA=us.latDef ; NN=us.altDef; } t2 = CastChart(fTrue); if (us.nRel == rcTransit) { for (i = 0; i <= cObjOpt; i++) { ignore2[i] = ignore[i]; ignore[i] = ignoreT[i]; } } else if (us.nRel == rcProgress) { us.fProgress = fFalse; for (i = 0; i <= cObjOpt; i++) { ignore3[i] = ignore[i]; ignore[i] = ignoreT[i]; } } cp2 = cp0; if (us.nRel == rcDual) { if (!FCreateGrid(fFalse)) return; for (i = 0; i <= oNormOpt; i++) ppowerT[i] = ppower1[i]; PlanetPPower(); for (i = 0; i <= oNormOpt; i++) { ppower2[i] = ppower1[i]; ppower1[i] = ppowerT[i]; } } hRevers = saveRev; ciCore = ciMain; /* Now combine the two charts based on what relation we are doing. */ /* For the standard -r synastry chart, use the house cusps of chart1 */ /* and the planets positions of chart2. */ ratio = (real)us.nRatio1 / ((real)(us.nRatio1 + us.nRatio2)); if (us.nRel <= rcSynastry) { for (i = 1; i <= cSign; i++) chouse[i] = cp1.cusp[i]; /* For the -rc composite chart, take the midpoints of the planets/houses. */ } else if (us.nRel == rcComposite) { if (fProgressRatio) { ratio=(MdytszToJulian(ciThre.mon,ciThre.day,ciThre.yea,ciThre.tim,ciThre.dst,ciThre.zon)- Min(MdytszToJulian(Mon, Day, Yea, Tim, Dst, Zon), MdytszToJulian(ciTwin.mon,ciTwin.day,ciTwin.yea,ciTwin.tim,ciTwin.dst,ciTwin.zon)))/ RAbs(MdytszToJulian(Mon, Day, Yea, Tim, Dst, Zon)- MdytszToJulian(ciTwin.mon,ciTwin.day,ciTwin.yea,ciTwin.tim,ciTwin.dst,ciTwin.zon)); } for (i = 0; i <= cObjOpt; i++) { planet[i] = Ratio(cp1.obj[i], cp2.obj[i], ratio); if (RAbs(cp2.obj[i] - cp1.obj[i]) > rDegHalf) planet[i] = Mod(planet[i] + rDegMax*ratio); planetalt[i] = Ratio(cp1.alt[i], cp2.alt[i], ratio); ret[i] = Ratio(cp1.dir[i], cp2.dir[i], ratio); altret[i] = Ratio(cp1.altdir[i], cp2.altdir[i], ratio); planetdis[i] = Ratio(cp1.dis[i], cp2.dis[i], ratio); disret[i] = Ratio(cp1.disdir[i], cp2.disdir[i], ratio); } for (i = 1; i <= cSign; i++) { chouse[i] = Ratio(cp1.cusp[i], cp2.cusp[i], ratio); if (RAbs(cp2.cusp[i] - cp1.cusp[i]) > rDegHalf) chouse[i] = Mod(chouse[i] + rDegMax*ratio); } /* Make sure we don't have any 180 degree errors in house cusp */ /* complement pairs, which may happen if the cusps are far apart. */ for (i = 1; i <= cSign; i++) if (MinDistance(chouse[sCap], Mod(chouse[i]-ZFromS(i+3))) > rDegQuad) chouse[i] = Mod(chouse[i]+rDegHalf); for (i = 1; i <= cSign; i++) if (RAbs(MinDistance(chouse[i], planet[oAsc - 1 + i])) > rDegQuad) planet[oAsc - 1 + i] = Mod(planet[oAsc - 1 + i]+rDegHalf); ciMain.loc=""; if (!us.fGraphics) ciMain.nam=strdup(strcat(strcat(ciMain.nam," and "),ciTwin.nam)); /* For the -rm time space midpoint chart, calculate the midpoint time and */ /* place between the two charts and then recast for the new chart info. */ } else if (us.nRel == rcMidpoint) { if (!is.fDavison) { is.T = Ratio(t1, t2, ratio); t = (is.T*36525.0)+rRound; is.JD = RFloor(t)+2415020.0; TT = RFract(t)*24.0; /* ZZ = Ratio(DecToDeg(Zon), DecToDeg(ciTwin.zon), ratio); SS = Ratio(DecToDeg(Dst), DecToDeg(ciTwin.dst), ratio); TT -= ZZ - SS; if (TT < 0.0) { TT += 24.0; is.JD -= 1.0; } if (TT >= 24.0) { TT -= 24.0; is.JD += 1.0; }*/ JulianToMdy(is.JD, &MM, &DD, &YY); OO = Ratio(DecToDeg(Lon), DecToDeg(ciTwin.lon), ratio); if (RAbs(ciTwin.lon-Lon) > rDegHalf) OO = Mod(OO+rDegMax*ratio); AA = Ratio(DecToDeg(Lat), DecToDeg(ciTwin.lat), ratio); NN = Ratio(DecToDeg(Alt), DecToDeg(ciTwin.alt), ratio); TT = DegToDec(TT); SS=ZZ=0.0; /*SS = DegToDec(SS); ZZ = DegToDec(ZZ);*/ OO = DegToDec(OO); AA = DegToDec(AA); ciCore.loc=""; if (!us.fGraphics) ciCore.nam=strdup(strcat(strcat(ciMain.nam," and "),ciTwin.nam)); ciMain = ciCore; } else is.T=t1; CastChart(fFalse); is.fDavison=fTrue; /* There are a couple of non-astrological charts, which only require the */ /* number of days that have passed between the two charts to be done. */ } else is.JD = RAbs(t2-t1)*36525.0; ComputeInHouses(); }

Vec2 Min( const Vec2 &A, const Vec2 &B ) { return Vec2( Min( A.X(), B.X() ), Min( A.Y(), B.Y() ) ); }

/* ======================== idSnapShot::ReadDeltaForJob ======================== */ bool idSnapShot::ReadDeltaForJob( const char* deltaMem, int deltaSize, int visIndex, idSnapShot* templateStates ) { bool report = net_verboseSnapshotReport.GetBool(); net_verboseSnapshotReport.SetBool( false ); lzwCompressionData_t lzwData; idZeroRunLengthCompressor rleCompressor; idLZWCompressor lzwCompressor( &lzwData ); int bytesRead = 0; // how many uncompressed bytes we read in. Used to figure out compression ratio lzwCompressor.Start( ( uint8* )deltaMem, deltaSize ); // Skip past sequence and baseSequence int sequence = 0; int baseSequence = 0; lzwCompressor.ReadAgnostic( sequence ); lzwCompressor.ReadAgnostic( baseSequence ); lzwCompressor.ReadAgnostic( time ); bytesRead += sizeof( int ) * 3; int objectNum = 0; uint16 delta = 0; while( lzwCompressor.ReadAgnostic( delta, true ) == sizeof( delta ) ) { bytesRead += sizeof( delta ); objectNum += delta; if( objectNum >= 0xFFFF ) { // full delta if( net_verboseSnapshotCompression.GetBool() ) { float compRatio = static_cast<float>( deltaSize ) / static_cast<float>( bytesRead ); idLib::Printf( "Snapshot (%d/%d). ReadSize: %d DeltaSize: %d Ratio: %.3f\n", sequence, baseSequence, bytesRead, deltaSize, compRatio ); } return true; } objectState_t& state = FindOrCreateObjectByID( objectNum ); objectSize_t newsize = 0; lzwCompressor.ReadAgnostic( newsize ); bytesRead += sizeof( newsize ); if( newsize == SIZE_STALE ) { NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d goes stale\n", objectNum ); // sanity bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0; if( !oldVisible ) { NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected already stale\n" ); } state.visMask &= ~( 1 << visIndex ); state.stale = true; // We need to make sure we haven't freed stale objects. assert( state.buffer.Size() > 0 ); // no more data continue; } else if( newsize == SIZE_NOT_STALE ) { NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d no longer stale\n", objectNum ); // sanity bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0; if( oldVisible ) { NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected not stale\n" ); } state.visMask |= ( 1 << visIndex ); state.stale = false; // the latest state is packed in, get the new size and continue reading the new state lzwCompressor.ReadAgnostic( newsize ); bytesRead += sizeof( newsize ); } objectState_t* objTemplateState = templateStates->FindObjectByID( objectNum ); if( newsize == 0 ) { // object deleted: reset state now so next one to use it doesn't have old data state.deleted = false; state.stale = false; state.changedCount = 0; state.expectedSequence = 0; state.visMask = 0; state.buffer._Release(); state.createdFromTemplate = false; if( objTemplateState != NULL && objTemplateState->buffer.Size() && objTemplateState->expectedSequence < baseSequence ) { idLib::PrintfIf( net_ssTemplateDebug.GetBool(), "Clearing old template state[%d] [%d<%d]\n", objectNum, objTemplateState->expectedSequence, baseSequence ); objTemplateState->deleted = false; objTemplateState->stale = false; objTemplateState->changedCount = 0; objTemplateState->expectedSequence = 0; objTemplateState->visMask = 0; objTemplateState->buffer._Release(); } } else { // new state? bool debug = false; if( state.buffer.Size() == 0 ) { state.createdFromTemplate = true; // Brand new state if( objTemplateState != NULL && objTemplateState->buffer.Size() > 0 && sequence >= objTemplateState->expectedSequence ) { idLib::PrintfIf( net_ssTemplateDebug.GetBool(), "\nAdding basestate for new object %d (for SS %d/%d. obj base created in ss %d) deltaSize: %d\n", objectNum, sequence, baseSequence, objTemplateState->expectedSequence, deltaSize ); state.buffer = objTemplateState->buffer; if( net_ssTemplateDebug.GetBool() ) { state.Print( "SPAWN STATE" ); debug = true; PrintAlign( "DELTA STATE" ); } } else if( net_ssTemplateDebug.GetBool() ) { idLib::Printf( "\nNew snapobject[%d] in snapshot %d/%d but no basestate found locally so creating new\n", objectNum, sequence, baseSequence ); } } else { state.createdFromTemplate = false; } // the buffer shrank or stayed the same objectBuffer_t newbuffer( newsize ); rleCompressor.Start( NULL, &lzwCompressor, newsize ); objectSize_t compareSize = Min( state.buffer.Size(), newsize ); for( objectSize_t i = 0; i < compareSize; i++ ) { byte b = rleCompressor.ReadByte(); newbuffer[i] = state.buffer[i] + b; if( debug && InDebugRange( i ) ) { idLib::Printf( "%02X", b ); } } // Catch leftover if( newsize > compareSize ) { rleCompressor.ReadBytes( newbuffer.Ptr() + compareSize, newsize - compareSize ); if( debug ) { for( objectSize_t i = compareSize; i < newsize; i++ ) { if( InDebugRange( i ) ) { idLib::Printf( "%02X", newbuffer[i] ); } } } } state.buffer = newbuffer; state.changedCount = sequence; bytesRead += sizeof( byte ) * newsize; if( debug ) { idLib::Printf( "\n" ); state.Print( "NEW STATE" ); } if( report ) { idLib::Printf( " Obj %d Compressed: Size %d \n", objectNum, rleCompressor.CompressedSize() ); } } #ifdef SNAPSHOT_CHECKSUMS extern uint32 SnapObjChecksum( const uint8 * data, int length ); if( state.buffer.Size() > 0 ) { uint32 checksum = 0; lzwCompressor.ReadAgnostic( checksum ); bytesRead += sizeof( checksum ); if( !verify( checksum == SnapObjChecksum( state.buffer.Ptr(), state.buffer.Size() ) ) ) { idLib::Error( " Invalid snapshot checksum" ); } } #endif } // partial delta return false; }

/* ======================== idSnapShot::ReadDelta ======================== */ bool idSnapShot::ReadDelta( idFile* file, int visIndex ) { file->ReadBig( time ); int objectNum = 0; uint16 delta = 0; while( file->ReadBig( delta ) == sizeof( delta ) ) { objectNum += delta; if( objectNum >= 0xFFFF ) { // full delta return true; } objectState_t& state = FindOrCreateObjectByID( objectNum ); objectSize_t newsize = 0; file->ReadBig( newsize ); if( newsize == SIZE_STALE ) { NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d goes stale\n", objectNum ); // sanity bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0; if( !oldVisible ) { NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected already stale\n" ); } state.visMask &= ~( 1 << visIndex ); state.stale = true; // We need to make sure we haven't freed stale objects. assert( state.buffer.Size() > 0 ); // no more data continue; } else if( newsize == SIZE_NOT_STALE ) { NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d no longer stale\n", objectNum ); // sanity bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0; if( oldVisible ) { NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected not stale\n" ); } state.visMask |= ( 1 << visIndex ); state.stale = false; // the latest state is packed in, get the new size and continue reading the new state file->ReadBig( newsize ); } if( newsize == 0 ) { // object deleted state.buffer._Release(); } else { objectBuffer_t newbuffer( newsize ); objectSize_t compareSize = Min( newsize, state.buffer.Size() ); for( objectSize_t i = 0; i < compareSize; i++ ) { uint8 delta = 0; file->ReadBig<byte>( delta ); newbuffer[i] = state.buffer[i] + delta; } if( newsize > compareSize ) { file->Read( newbuffer.Ptr() + compareSize, newsize - compareSize ); } state.buffer = newbuffer; state.changedCount++; } #ifdef SNAPSHOT_CHECKSUMS if( state.buffer.Size() > 0 ) { unsigned int checksum = 0; file->ReadBig( checksum ); assert( checksum == MD5_BlockChecksum( state.buffer.Ptr(), state.buffer.Size() ) ); } #endif } // partial delta return false; }

///////////////////////////////////////////////////////////////////////////// // Change lane value to reach a given radius ///////////////////////////////////////////////////////////////////////////// void K1999::AdjustRadius(int prev, int i, int next, double TargetRInverse, double Security) { double OldLane = tLane[i]; double Width = Mag((txLeft[i]-txRight[i]),(tyLeft[i]-tyRight[i])); // // Start by aligning points for a reasonable initial lane // tLane[i] = (-(ty[next] - ty[prev]) * (txLeft[i] - tx[prev]) + (tx[next] - tx[prev]) * (tyLeft[i] - ty[prev])) / ( (ty[next] - ty[prev]) * (txRight[i] - txLeft[i]) - (tx[next] - tx[prev]) * (tyRight[i] - tyLeft[i])); // the original algorithm allows going outside the track /* if (tLane[i] < -0.2) tLane[i] = -0.2; else if (tLane[i] > 1.2) tLane[i] = 1.2;*/ if (tLane[i] < 0.0) tLane[i] = 0.0; else if (tLane[i] > 1.0) tLane[i] = 1.0; UpdateTxTy(i); // // Newton-like resolution method // const double dLane = 0.0001; double dx = dLane * (txRight[i] - txLeft[i]); double dy = dLane * (tyRight[i] - tyLeft[i]); double dRInverse = GetRInverse(prev, tx[i] + dx, ty[i] + dy, next); if (dRInverse > 0.000000001) { tLane[i] += (dLane / dRInverse) * TargetRInverse; double ExtLane = (SideDistExt + Security) / Width; double IntLane = (SideDistInt + Security) / Width; if (ExtLane > 0.5) ExtLane = 0.5; if (IntLane > 0.5) IntLane = 0.5; if (TargetRInverse >= 0.0) { if (tLane[i] < IntLane) tLane[i] = IntLane; if (1 - tLane[i] < ExtLane) { if (1 - OldLane < ExtLane) tLane[i] = Min(OldLane, tLane[i]); else tLane[i] = 1 - ExtLane; } } else { if (tLane[i] < ExtLane) { if (OldLane < ExtLane) tLane[i] = Max(OldLane, tLane[i]); else tLane[i] = ExtLane; } if (1 - tLane[i] < IntLane) tLane[i] = 1 - IntLane; } } UpdateTxTy(i); }

inline T Clamp(const T x, const T xMin, const T xMax) { return Max(xMin, Min(x, xMax)); }

// Returns file path including the trailing path separator symbol. void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength) { size_t PathLength=Min(MaxLength-1,PointToName(FullName)-FullName); strncpyw(Path,FullName,PathLength); Path[PathLength]=0; }

void CExtension::CreateIcon (int cxWidth, int cyHeight, CG32bitImage **retpIcon) const // CreateIcon // // Creates a cover icon for the adventure. The caller is responsible for // freeing the result. { // Load the image CG32bitImage *pBackground = GetCoverImage(); if (pBackground == NULL || pBackground->GetWidth() == 0 || pBackground->GetHeight() == 0) { int cxSize = Min(cxWidth, cyHeight); *retpIcon = new CG32bitImage; (*retpIcon)->Create(cxSize, cxSize); return; } // Figure out the dimensions of the icon based on the image size and the // desired output. // // If the background is larger than the icon size then we need to scale it. CG32bitImage *pIcon; if (pBackground->GetWidth() > cxWidth || pBackground->GetHeight() > cyHeight) { int xSrc, ySrc, cxSrc, cySrc; Metric rScale; // If we have a widescreen cover image and we want a portrait or // square icon, then we zoom in on the key part of the cover. if (pBackground->GetWidth() > 2 * pBackground->GetHeight()) { rScale = (Metric)cyHeight / pBackground->GetHeight(); cxSrc = (int)(cxWidth / rScale); xSrc = Min(pBackground->GetWidth() - cxSrc, pBackground->GetWidth() - (RIGHT_COVER_OFFSET + (cxSrc / 2))); ySrc = 0; cySrc = pBackground->GetHeight(); } else { rScale = (Metric)cxWidth / pBackground->GetWidth(); if (rScale * pBackground->GetHeight() > (Metric)cyHeight) rScale = (Metric)cyHeight / pBackground->GetHeight(); xSrc = 0; ySrc = 0; cxSrc = pBackground->GetWidth(); cySrc = pBackground->GetHeight(); } // Create the icon pIcon = new CG32bitImage; pIcon->CreateFromImageTransformed(*pBackground, xSrc, ySrc, cxSrc, cySrc, rScale, rScale, 0.0); } // Otherwise we center the image on the icon else { // Create the icon pIcon = new CG32bitImage; pIcon->Create(cxWidth, cyHeight); // Blt pIcon->Blt(0, 0, pBackground->GetWidth(), pBackground->GetHeight(), *pBackground, (cxWidth - pBackground->GetWidth()) / 2, (cyHeight - pBackground->GetHeight()) / 2); } // Done *retpIcon = pIcon; }

int32 refc_find_ref_coors_convex(FMField *ref_coors, int32 *cells, int32 n_cells, int32 *status, int32 n_status, FMField *coors, Mesh *mesh, FMField *centroids, FMField *normals0, FMField *normals1, int32 *ics, int32 n_ics, FMField *eref_coors, int32 *nodes, int32 n_nodes, int32 n_nodes_col, FMField *mtx_i, int32 allow_extrapolation, float64 close_limit, float64 qp_eps, int32 i_max, float64 newton_eps) { int32 ip, ic, icell, icell_max = 0, ii, imin, ik, ok, ret = RET_OK; int32 xi_ok, hexa_reverse; int32 D = mesh->topology->max_dim; int32 dim = D - 1; int32 nc = mesh->geometry->dim; uint32 tri0[] = {0, 1, 3}; uint32 tri1[] = {2, 3, 1}; uint32 cell, cell0, cell00, facet; uint32 *noffs, *foffs, aux[2]; uint32 *cell_types = mesh->topology->cell_types; float64 vmin, vmax, d_min, tmin, tt, dist; float64 *mesh_coors = mesh->geometry->coors; float64 buf3[3]; float64 buf9[9]; float64 buf_ec_max[8 * 3]; // Max. n_ep * dim. FMField point[1], centroid[1], _normals0[1], _normals1[1], e_coors[1], xi[1]; FMField bc[1]; Indices cell_vertices[1]; MeshEntity cell_ent[1]; MeshConnectivity *cD0 = 0; // D -> 0 MeshConnectivity *c0D = 0; // 0 -> D MeshConnectivity *cDd = 0; // cell -> facet MeshConnectivity *cdD = 0; // facet -> cell MeshConnectivity *loc = 0; MeshConnectivity **locs = 0; mesh_setup_connectivity(mesh, D, 0); cD0 = mesh->topology->conn[IJ(D, D, 0)]; mesh_setup_connectivity(mesh, 0, D); c0D = mesh->topology->conn[IJ(D, 0, D)]; mesh_setup_connectivity(mesh, D, dim); cDd = mesh->topology->conn[IJ(D, D, dim)]; noffs = cDd->offsets; mesh_setup_connectivity(mesh, dim, D); cdD = mesh->topology->conn[IJ(D, dim, D)]; // Local entities - reference cell edges or faces. locs = (dim == 1) ? mesh->entities->edges : mesh->entities->faces; fmf_pretend_nc(point, coors->nRow, 1, 1, nc, coors->val); fmf_pretend_nc(centroid, centroids->nRow, 1, 1, nc, centroids->val); fmf_pretend_nc(xi, 1, 1, 1, nc, buf3); fmf_fillC(xi, 0.0); vmin = eref_coors->val[0]; vmax = eref_coors->val[nc]; for (ip = 0; ip < coors->nRow; ip++) { ic = ics[ip]; /* output("***** %d %d\n", ip, ic); */ FMF_SetCell(point, ip); /* fmf_print(point, stdout, 0); */ cell = cell0 = cell00 = c0D->indices[c0D->offsets[ic]]; ok = icell = hexa_reverse = imin = 0; d_min = 1e10; while (1) { /* output("*** %d %d %d\n", icell, cell, hexa_reverse); */ FMF_SetCell(centroid, cell); /* fmf_print(centroid, stdout, 0); */ cell_ent->ii = cell; me_get_incident2(cell_ent, cell_vertices, cD0); loc = locs[cell_types[cell]]; foffs = loc->offsets; if (cell_types[cell] != 4) { // No hexahedron -> planar facet. fmf_pretend_nc(_normals0, noffs[cell+1] - noffs[cell], 1, 1, nc, normals0->val + nc * noffs[cell]); tmin = 1e10; for (ii = 0; ii < loc->num; ii++) { FMF_SetCell(_normals0, ii); ik = loc->indices[foffs[ii]]; _intersect_line_plane(&tt, centroid->val, point->val, mesh_coors + nc * cell_vertices->indices[ik], _normals0->val, nc); if ((tt >= -qp_eps) && (tt < (tmin + qp_eps))) { imin = ii; tmin = tt; } } if (tmin >= (1.0 - qp_eps)) { _get_cell_coors(e_coors, cell_vertices, mesh_coors, nc, buf_ec_max); /* fmf_print(e_coors, stdout, 0); */ xi_ok = _get_xi_dist(&dist, xi, cell_vertices->num, nc, D, point, e_coors, eref_coors, bc, nodes, n_nodes_col, mtx_i, vmin, vmax, i_max, newton_eps); d_min = Min(dist, d_min); if (xi_ok && (dist < qp_eps)) { ok = 1; } break; } } else { // Hexahedron -> non-planar facet in general. fmf_pretend_nc(_normals0, noffs[cell+1] - noffs[cell], 1, 1, nc, normals0->val + nc * noffs[cell]); fmf_pretend_nc(_normals1, noffs[cell+1] - noffs[cell], 1, 1, nc, normals1->val + nc * noffs[cell]); for (ii = 0; ii < loc->num; ii++) { FMF_SetCell(_normals0, ii); _get_tri_coors(buf9, loc->indices, foffs[ii], tri0, mesh_coors, cell_vertices->indices); _intersect_line_triangle(&tt, centroid->val, point->val, buf9, _normals0->val); if ((tt >= -qp_eps) && (tt < 1e10)) { ok = 2; imin = ii; if ((tt >= (1.0 - qp_eps)) || hexa_reverse) { _get_cell_coors(e_coors, cell_vertices, mesh_coors, nc, buf_ec_max); xi_ok = _get_xi_dist(&dist, xi, cell_vertices->num, nc, D, point, e_coors, eref_coors, bc, nodes, n_nodes_col, mtx_i, vmin, vmax, i_max, newton_eps); d_min = Min(dist, d_min); if (xi_ok && (dist < qp_eps)) { ok = 1; } else { hexa_reverse = 1; } } break; } FMF_SetCell(_normals1, ii); _get_tri_coors(buf9, loc->indices, foffs[ii], tri1, mesh_coors, cell_vertices->indices); _intersect_line_triangle(&tt, centroid->val, point->val, buf9, _normals1->val); if ((tt >= -qp_eps) && (tt < 1e10)) { ok = 2; imin = ii; if ((tt >= (1.0 - qp_eps)) || hexa_reverse) { _get_cell_coors(e_coors, cell_vertices, mesh_coors, nc, buf_ec_max); xi_ok = _get_xi_dist(&dist, xi, cell_vertices->num, nc, D, point, e_coors, eref_coors, bc, nodes, n_nodes_col, mtx_i, vmin, vmax, i_max, newton_eps); d_min = Min(dist, d_min); if (xi_ok && (dist < qp_eps)) { ok = 1; } else { hexa_reverse = 1; } } break; } } if (ok == 1) { break; } if (ok == 0) { errput("cannot intersect bilinear faces!\n"); ERR_CheckGo(ret); } } facet = cDd->indices[cDd->offsets[cell] + imin]; if ((cdD->offsets[facet+1] - cdD->offsets[facet]) == 2) { aux[0] = cdD->indices[cdD->offsets[facet]]; aux[1] = cdD->indices[cdD->offsets[facet]+1]; cell00 = cell0; cell0 = cell; cell = (aux[0] == cell) ? aux[1] : aux[0]; if (cell == cell00) { // Ping-pong between two cells. hexa_reverse = 1; } } else { // Boundary facet. cell_ent->ii = cell; me_get_incident2(cell_ent, cell_vertices, cD0); _get_cell_coors(e_coors, cell_vertices, mesh_coors, nc, buf_ec_max); xi_ok = _get_xi_dist(&dist, xi, cell_vertices->num, nc, D, point, e_coors, eref_coors, bc, nodes, n_nodes_col, mtx_i, vmin, vmax, i_max, newton_eps); d_min = Min(dist, d_min); if (xi_ok && (dist < qp_eps)) { ok = 1; } else { ok = 0; } break; } icell++; icell_max = Max(icell, icell_max); if (icell > 10000) { errput("cannot find containing cell!\n"); ERR_CheckGo(ret); } } /* fmf_print(xi, stdout, 0); */ /* output("-> %d %d %d %.3e\n", cell, xi_ok, ok, d_min); */ cells[ip] = cell; if (ok != 1) { if (!xi_ok) { status[ip] = 4; } else if (allow_extrapolation) { // Try using minimum distance xi. if (sqrt(d_min) < close_limit) { status[ip] = 1; } else { status[ip] = 2; } } else { status[ip] = 3; } } else { status[ip] = 0; } for (ii = 0; ii < nc; ii++) { ref_coors->val[nc*ip+ii] = xi->val[ii]; } } /* output("%d\n", icell_max); */ end_label: return(ret); }

/* * Verify mbstr to make sure that it has a valid character sequence. * mbstr is not necessarily NULL terminated; length of mbstr is * specified by len. * * If OK, return TRUE. If a problem is found, return FALSE when noError is * true; when noError is false, ereport() a descriptive message. */ bool pg_verifymbstr(const char *mbstr, int len, bool noError) { int l; int i; int encoding; /* we do not need any check in single-byte encodings */ if (pg_database_encoding_max_length() <= 1) return true; encoding = GetDatabaseEncoding(); while (len > 0 && *mbstr) { l = pg_mblen(mbstr); /* special UTF-8 check */ if (encoding == PG_UTF8) { if (!pg_utf8_islegal((const unsigned char *) mbstr, l)) { if (noError) return false; ereport(ERROR, (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), errmsg("invalid UTF-8 byte sequence detected near byte 0x%02x", (unsigned char) *mbstr))); } } else { for (i = 1; i < l; i++) { /* * we expect that every multibyte char consists of bytes * having the 8th bit set */ if (i >= len || (mbstr[i] & 0x80) == 0) { char buf[8 * 2 + 1]; char *p = buf; int j, jlimit; if (noError) return false; jlimit = Min(l, len); jlimit = Min(jlimit, 8); /* prevent buffer overrun */ for (j = 0; j < jlimit; j++) p += sprintf(p, "%02x", (unsigned char) mbstr[j]); ereport(ERROR, (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), errmsg("invalid byte sequence for encoding \"%s\": 0x%s", GetDatabaseEncodingName(), buf))); } } } len -= l; mbstr += l; } return true; }

/* ======================== idSnapShot::WriteObject ======================== */ void idSnapShot::WriteObject( idFile* file, int visIndex, objectState_t* newState, objectState_t* oldState, int& lastobjectNum ) { assert( newState != NULL || oldState != NULL ); bool visChange = false; // visibility changes will be signified with a 0xffff state size bool visSendState = false; // the state is sent when an entity is no longer stale // Compute visibility changes // (we need to do this before writing out object id, because we may not need to write out the id if we early out) // (when we don't write out the id, we assume this is an "ack" when we deserialize the objects) if( newState != NULL && oldState != NULL ) { // Check visibility assert( newState->objectNum == oldState->objectNum ); if( visIndex > 0 ) { bool oldVisible = ( oldState->visMask & ( 1 << visIndex ) ) != 0; bool newVisible = ( newState->visMask & ( 1 << visIndex ) ) != 0; // Force visible if we need to either create or destroy this object newVisible |= ( newState->buffer.Size() == 0 ) != ( oldState->buffer.Size() == 0 ); if( !oldVisible && !newVisible ) { // object is stale and ack'ed for this client, write nothing (see 'same object' below) return; } else if( oldVisible && !newVisible ) { NET_VERBOSESNAPSHOT_PRINT( "object %d to client %d goes stale\n", newState->objectNum, visIndex ); visChange = true; visSendState = false; } else if( !oldVisible && newVisible ) { NET_VERBOSESNAPSHOT_PRINT( "object %d to client %d no longer stale\n", newState->objectNum, visIndex ); visChange = true; visSendState = true; } } // Same object, write a delta (never early out during vis changes) if( !visChange && newState->buffer.Size() == oldState->buffer.Size() && ( ( newState->buffer.Ptr() == oldState->buffer.Ptr() ) || memcmp( newState->buffer.Ptr(), oldState->buffer.Ptr(), newState->buffer.Size() ) == 0 ) ) { // same state, write nothing return; } } // Get the id of the object we are writing out uint16 objectNum; if( newState != NULL ) { objectNum = newState->objectNum; } else if( oldState != NULL ) { objectNum = oldState->objectNum; } else { objectNum = 0; } assert( objectNum == 0 || objectNum > lastobjectNum ); // Write out object id (using delta) uint16 objectDelta = objectNum - lastobjectNum; file->WriteBig( objectDelta ); lastobjectNum = objectNum; if( newState == NULL ) { // Deleted, write 0 size assert( oldState != NULL ); file->WriteBig<objectSize_t>( 0 ); } else if( oldState == NULL ) { // New object, write out full state assert( newState != NULL ); // delta against an empty snap file->WriteBig( newState->buffer.Size() ); file->Write( newState->buffer.Ptr(), newState->buffer.Size() ); } else { // Compare to last object assert( newState != NULL && oldState != NULL ); assert( newState->objectNum == oldState->objectNum ); if( visChange ) { // fake size indicates vis state change // NOTE: we may still send a real size and a state below, for 'no longer stale' transitions // TMP: send 0xFFFF for going stale and 0xFFFF - 1 for no longer stale file->WriteBig<objectSize_t>( visSendState ? SIZE_NOT_STALE : SIZE_STALE ); } if( !visChange || visSendState ) { objectSize_t compareSize = Min( newState->buffer.Size(), oldState->buffer.Size() ); // Get the number of bytes that overlap file->WriteBig( newState->buffer.Size() ); // Write new size // Compare bytes that overlap for( objectSize_t b = 0; b < compareSize; b++ ) { file->WriteBig<byte>( ( 0xFF + 1 + newState->buffer[b] - oldState->buffer[b] ) & 0xFF ); } // Write leftover if( newState->buffer.Size() > compareSize ) { file->Write( newState->buffer.Ptr() + oldState->buffer.Size(), newState->buffer.Size() - compareSize ); } } } #ifdef SNAPSHOT_CHECKSUMS if( ( !visChange || visSendState ) && newState != NULL ) { assert( newState->buffer.Size() > 0 ); unsigned int checksum = MD5_BlockChecksum( newState->buffer.Ptr(), newState->buffer.Size() ); file->WriteBig( checksum ); } #endif }

/* * Find the gtm port and try a connection */ static bool test_gtm_connection() { GTM_Conn *conn; bool success = false; int i; char portstr[32]; char *p; char *q; char connstr[128]; /* Should be way more than enough! */ *portstr = '\0'; /* * Look in gtm_opts for a -p switch. * * This parsing code is not amazingly bright; it could for instance * get fooled if ' -p' occurs within a quoted argument value. Given * that few people pass complicated settings in gtm_opts, it's * probably good enough. */ for (p = gtm_opts; *p;) { /* advance past whitespace */ while (isspace((unsigned char) *p)) p++; if (strncmp(p, "-p", 2) == 0) { p += 2; /* advance past any whitespace/quoting */ while (isspace((unsigned char) *p) || *p == '\'' || *p == '"') p++; /* find end of value (not including any ending quote!) */ q = p; while (*q && !(isspace((unsigned char) *q) || *q == '\'' || *q == '"')) q++; /* and save the argument value */ strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr))); /* keep looking, maybe there is another -p */ p = q; } /* Advance to next whitespace */ while (*p && !isspace((unsigned char) *p)) p++; } /* * Search config file for a 'port' option. * * This parsing code isn't amazingly bright either, but it should be okay * for valid port settings. */ if (!*portstr) { char **optlines; optlines = readfile(conf_file); if (optlines != NULL) { for (; *optlines != NULL; optlines++) { p = *optlines; while (isspace((unsigned char) *p)) p++; if (strncmp(p, "port", 4) != 0) continue; p += 4; while (isspace((unsigned char) *p)) p++; if (*p != '=') continue; p++; /* advance past any whitespace/quoting */ while (isspace((unsigned char) *p) || *p == '\'' || *p == '"') p++; /* find end of value (not including any ending quote/comment!) */ q = p; while (*q && !(isspace((unsigned char) *q) || *q == '\'' || *q == '"' || *q == '#')) q++; /* and save the argument value */ strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr))); /* keep looking, maybe there is another */ } } } /* Still not found? Use compiled-in default */ #define GTM_DEFAULT_PORT 6666 if (!*portstr) snprintf(portstr, sizeof(portstr), "%d", GTM_DEFAULT_PORT); /* * We need to set a connect timeout otherwise on Windows the SCM will * probably timeout first * a PGXC node ID has to be set for GTM connection protocol, * so its value doesn't really matter here. */ snprintf(connstr, sizeof(connstr), "host=localhost port=%s connect_timeout=5 node_name=one", portstr); for (i = 0; i < wait_seconds; i++) { if ((conn = PQconnectGTM(connstr)) != NULL && (GTMPQstatus(conn) == CONNECTION_OK)) { GTMPQfinish(conn); success = true; break; } else { GTMPQfinish(conn); print_msg("."); sleep(1); /* 1 sec */ } } return success; }

BOOL vncDesktop:: CalculateSWrect(RECT &rect) { if (!m_Single_hWnd) { m_server->SingleWindow(false); m_SWtoDesktop=TRUE; rect.top=0; rect.left=0; rect.right=m_scrinfo.framebufferWidth; rect.bottom=m_scrinfo.framebufferHeight; return FALSE; } if (IsIconic(m_Single_hWnd)) { m_server->SingleWindow(false); m_Single_hWnd=NULL; m_SWtoDesktop=TRUE; rect.top=0; rect.left=0; rect.right=m_scrinfo.framebufferWidth; rect.bottom=m_scrinfo.framebufferHeight; return FALSE; } if ( IsWindowVisible(m_Single_hWnd) && GetWindowRect(m_Single_hWnd,&rect)) { RECT taskbar; rect.top=Max(rect.top,0); rect.left=Max(rect.left,0); rect.right=Min(rect.right,m_scrinfo.framebufferWidth); rect.bottom=Min(rect.bottom,m_scrinfo.framebufferHeight); APPBARDATA pabd; pabd.cbSize=sizeof(APPBARDATA); SHAppBarMessage(ABM_GETTASKBARPOS, &pabd); taskbar.top=Max(pabd.rc.top,0); taskbar.left=Max(pabd.rc.left,0); taskbar.right=Min(pabd.rc.right,m_scrinfo.framebufferWidth); taskbar.bottom=Min(pabd.rc.bottom,m_scrinfo.framebufferHeight); ///desktop if (rect.top==0 && rect.left== 0&& rect.right==m_scrinfo.framebufferWidth && rect.bottom==m_scrinfo.framebufferHeight) { m_server->SingleWindow(false); m_Single_hWnd=NULL; rect.top=0; rect.left=0; rect.right=m_scrinfo.framebufferWidth; rect.bottom=m_scrinfo.framebufferHeight; return TRUE; } //taskbar if (rect.top>=taskbar.top && rect.left== taskbar.left&& rect.right==taskbar.right && rect.bottom==taskbar.bottom) { rect.top=taskbar.top; rect.left=taskbar.left; rect.right=taskbar.right; rect.bottom=taskbar.bottom; if ((m_SWHeight!=(rect.bottom-rect.top)) || (m_SWWidth!=(rect.right-rect.left))) m_SWSizeChanged=TRUE; m_SWHeight=rect.bottom-rect.top; m_SWWidth=rect.right-rect.left; return TRUE; } //eliminate other little windows if ((m_SWHeight!=(rect.bottom-rect.top)) || (m_SWWidth!=(rect.right-rect.left))) m_SWSizeChanged=TRUE; //vnclog.Print(LL_INTINFO, VNCLOG("screen format %d %d %d %d\n"), // rect.top, // rect.bottom,rect.right,rect.left); if ((rect.bottom-rect.top)<64||(rect.right-rect.left)<128 || rect.bottom<0 ||rect.top<0 || rect.right<0 || rect.left<0 || rect.bottom>m_scrinfo.framebufferHeight||rect.top>m_scrinfo.framebufferHeight|| rect.right>m_scrinfo.framebufferWidth||rect.left>m_scrinfo.framebufferWidth) { m_server->SingleWindow(false); m_Single_hWnd=NULL; m_SWtoDesktop=TRUE; rect.top=0; rect.left=0; rect.right=m_scrinfo.framebufferWidth; rect.bottom=m_scrinfo.framebufferHeight; m_SWSizeChanged=FALSE; return FALSE; } m_SWHeight=rect.bottom-rect.top; m_SWWidth=rect.right-rect.left; return TRUE; } m_server->SingleWindow(false); m_Single_hWnd=NULL; m_SWtoDesktop=TRUE; rect.top=0; rect.left=0; rect.right=m_scrinfo.framebufferWidth; rect.bottom=m_scrinfo.framebufferHeight; return FALSE; }

byte CSurface3DFrame::FitPanel()//Rectangle() { byte eTryDiv=C3D_DivNxN; if (m_p3D->m_pBoundary) { CSurface3DBoundary &B=*m_p3D->m_pBoundary; if (m_dXMin>=B.m_XMin && m_dXMax<=B.m_XMax && m_dYMin>=B.m_YMin && m_dYMax<=B.m_YMax) { double BYxmn=B.m_FnYx(m_dXMin); double BYxmx=B.m_FnYx(m_dXMax); double BXymn=B.m_FnXy(m_dYMin); double BXymx=B.m_FnXy(m_dYMax); byte LCross=(m_dYMin<BYxmn && BYxmn<m_dYMax) ? 1 : 0; byte RCross=(m_dYMin<BYxmx && BYxmx<m_dYMax) ? 2 : 0; byte BCross=(m_dXMin<BXymn && BXymn<m_dXMax) ? 4 : 0; byte TCross=(m_dXMin<BXymx && BXymx<m_dXMax) ? 8 : 0; eTryDiv=PanelLayout[LCross+RCross+TCross+BCross].Divs; double Val1=dNAN; double Val2=dNAN; switch (eTryDiv) { case C3D_Div2V: { Val1=BCross ? BXymn : BXymx; CSurface3DFrame Frames[2]; Frames[0].Initialise(m_p3D, m_iLevel+1, m_dXMin, Val1, 1, m_dYMin, m_dYMax, 1); Frames[1].Initialise(m_p3D, m_iLevel+1, Val1, m_dXMax, 1, m_dYMin, m_dYMax, 1); if (!FitAndTestPanels(2,1, Frames)) eTryDiv=C3D_DivNxN; } break; case C3D_Div3V: { Val1=Min(BXymn, BXymx); Val2=Max(BXymn, BXymx); CSurface3DFrame Frames[3]; Frames[0].Initialise(m_p3D, m_iLevel+1, m_dXMin, Val1, 1, m_dYMin, m_dYMax, 1); Frames[1].Initialise(m_p3D, m_iLevel+1, Val1, Val2, 1, m_dYMin, m_dYMax, 1); Frames[2].Initialise(m_p3D, m_iLevel+1, Val2, m_dXMax, 1, m_dYMin, m_dYMax, 1); if (!FitAndTestPanels(3,1, Frames)) eTryDiv=C3D_DivNxN; } break; case C3D_Div2H: { Val1=LCross ? BYxmn : BYxmx; CSurface3DFrame Frames[2]; Frames[0].Initialise(m_p3D, m_iLevel+1, m_dXMin, m_dXMax, 1, m_dYMin, Val1, 1); Frames[1].Initialise(m_p3D, m_iLevel+1, m_dXMin, m_dXMax, 1, Val1, m_dYMax, 1); if (!FitAndTestPanels(1,2, Frames)) eTryDiv=C3D_DivNxN; } break; case C3D_Div3H: { Val1=Min(BYxmn, BYxmx); Val2=Max(BYxmn, BYxmx); CSurface3DFrame Frames[3]; Frames[0].Initialise(m_p3D, m_iLevel+1, m_dXMin, m_dXMax, 1, m_dYMin, Val1, 1); Frames[1].Initialise(m_p3D, m_iLevel+1, m_dXMin, m_dXMax, 1, Val1, Val2, 1); Frames[2].Initialise(m_p3D, m_iLevel+1, m_dXMin, m_dXMax, 1, Val2, m_dYMax, 1); if (!FitAndTestPanels(1,3, Frames)) eTryDiv=C3D_DivNxN; } break; case C3D_Div2x2: { Val1=BCross ? BXymn : BXymx; Val2=LCross ? BYxmn : BYxmx; CSurface3DFrame Frames[4]; Frames[0].Initialise(m_p3D, m_iLevel+1, m_dXMin, Val1, 1, m_dYMin, Val2, 1); Frames[1].Initialise(m_p3D, m_iLevel+1, Val1, m_dXMax, 1, m_dYMin, Val2, 1); Frames[2].Initialise(m_p3D, m_iLevel+1, m_dXMin, Val1, 1, Val2, m_dYMax, 1); Frames[3].Initialise(m_p3D, m_iLevel+1, Val1, m_dXMax, 1, Val2, m_dYMax, 1); if (!FitAndTestPanels(2,2, Frames)) eTryDiv=C3D_DivNxN; } break; case C3D_DivNxN: if (m_nDivsX*m_nDivsY<2) DoBreak(); break; case C3D_Bad: DoBreak(); } } else eTryDiv=C3D_Div1x1; } else eTryDiv=C3D_Div1x1; if (eTryDiv==C3D_Div1x1) { CSurface3DPanel * pPanel=BuildPanel(); if (m_iLevel>=8) DoBreak(); if (pPanel->CheckFit(this)) { m_eDivision=eTryDiv; m_pPanel=pPanel; #if dbgSurfaces if (dbg3DTrack()) dbgpln("Add new Panel %-20s %-5s %08x [%2i] %14.8f %14.8f", m_p3D->Name(), s_sDivText[m_eDivision], m_pPanel, m_iLevel, 0.5*(m_dXMin+m_dXMax), 0.5*(m_dYMin+m_dYMax)); #endif } else { delete pPanel; eTryDiv= C3D_DivNxN; #if dbgSurfaces if (dbg3DTrack()) dbgpln("Drill Down %-20s %-5s %8s [%2i] %14.8f %14.8f", m_p3D->Name(), s_sDivText[eTryDiv], "", m_iLevel, 0.5*(m_dXMin+m_dXMax), 0.5*(m_dYMin+m_dYMax)); #endif } } if (eTryDiv==C3D_DivNxN) { if (m_nDivsX*m_nDivsY<2) DoBreak(); ASSERT(m_Frames==NULL); long nElements=m_nDivsX*m_nDivsY; m_Frames=new LPCSurface3DFrame[nElements]; for (int i=0; i<nElements; i++) m_Frames[i]= NULL; } m_eDivision=eTryDiv; return eTryDiv; }

/* * Form a tuple for entry tree. * * If the tuple would be too big to be stored, function throws a suitable * error if errorTooBig is TRUE, or returns NULL if errorTooBig is FALSE. * * On leaf pages, Index tuple has non-traditional layout. Tuple may contain * posting list or root blocknumber of posting tree. * Macros: GinIsPostingTree(itup) / GinSetPostingTree(itup, blkno) * 1) Posting list * - itup->t_info & INDEX_SIZE_MASK contains total size of tuple as usual * - ItemPointerGetBlockNumber(&itup->t_tid) contains original * size of tuple (without posting list). * Macros: GinGetOrigSizePosting(itup) / GinSetOrigSizePosting(itup,n) * - ItemPointerGetOffsetNumber(&itup->t_tid) contains number * of elements in posting list (number of heap itempointers) * Macros: GinGetNPosting(itup) / GinSetNPosting(itup,n) * - After standard part of tuple there is a posting list, ie, array * of heap itempointers * Macros: GinGetPosting(itup) * 2) Posting tree * - itup->t_info & INDEX_SIZE_MASK contains size of tuple as usual * - ItemPointerGetBlockNumber(&itup->t_tid) contains block number of * root of posting tree * - ItemPointerGetOffsetNumber(&itup->t_tid) contains magic number * GIN_TREE_POSTING, which distinguishes this from posting-list case * * Attributes of an index tuple are different for single and multicolumn index. * For single-column case, index tuple stores only value to be indexed. * For multicolumn case, it stores two attributes: column number of value * and value. */ IndexTuple GinFormTuple(Relation index, GinState *ginstate, OffsetNumber attnum, Datum key, ItemPointerData *ipd, uint32 nipd, bool errorTooBig) { bool isnull[2] = {FALSE, FALSE}; IndexTuple itup; uint32 newsize; if (ginstate->oneCol) itup = index_form_tuple(ginstate->origTupdesc, &key, isnull); else { Datum datums[2]; datums[0] = UInt16GetDatum(attnum); datums[1] = key; itup = index_form_tuple(ginstate->tupdesc[attnum - 1], datums, isnull); } GinSetOrigSizePosting(itup, IndexTupleSize(itup)); if (nipd > 0) { newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData) * nipd); if (newsize > Min(INDEX_SIZE_MASK, GinMaxItemSize)) { if (errorTooBig) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("index row size %lu exceeds maximum %lu for index \"%s\"", (unsigned long) newsize, (unsigned long) Min(INDEX_SIZE_MASK, GinMaxItemSize), RelationGetRelationName(index)))); return NULL; } itup = repalloc(itup, newsize); /* set new size */ itup->t_info &= ~INDEX_SIZE_MASK; itup->t_info |= newsize; if (ipd) memcpy(GinGetPosting(itup), ipd, sizeof(ItemPointerData) * nipd); GinSetNPosting(itup, nipd); } else { /* * Gin tuple without any ItemPointers should be large enough to keep * one ItemPointer, to prevent inconsistency between * ginHeapTupleFastCollect and ginEntryInsert called by * ginHeapTupleInsert. ginHeapTupleFastCollect forms tuple without * extra pointer to heap, but ginEntryInsert (called for pending list * cleanup during vacuum) will form the same tuple with one * ItemPointer. */ newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData)); if (newsize > Min(INDEX_SIZE_MASK, GinMaxItemSize)) { if (errorTooBig) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("index row size %lu exceeds maximum %lu for index \"%s\"", (unsigned long) newsize, (unsigned long) Min(INDEX_SIZE_MASK, GinMaxItemSize), RelationGetRelationName(index)))); return NULL; } GinSetNPosting(itup, 0); } return itup; }

/* * tuplestore_trim - remove all no-longer-needed tuples * * Calling this function authorizes the tuplestore to delete all tuples * before the oldest read pointer, if no read pointer is marked as requiring * REWIND capability. * * Note: this is obviously safe if no pointer has BACKWARD capability either. * If a pointer is marked as BACKWARD but not REWIND capable, it means that * the pointer can be moved backward but not before the oldest other read * pointer. */ void tuplestore_trim(Tuplestorestate *state) { int oldest; int nremove; int i; /* * Truncation is disallowed if any read pointer requires rewind * capability. */ if (state->eflags & EXEC_FLAG_REWIND) return; /* * We don't bother trimming temp files since it usually would mean more * work than just letting them sit in kernel buffers until they age out. */ if (state->status != TSS_INMEM) return; /* Find the oldest read pointer */ oldest = state->memtupcount; for (i = 0; i < state->readptrcount; i++) { if (!state->readptrs[i].eof_reached) oldest = Min(oldest, state->readptrs[i].current); } /* * Note: you might think we could remove all the tuples before the oldest * "current", since that one is the next to be returned. However, since * tuplestore_gettuple returns a direct pointer to our internal copy of * the tuple, it's likely that the caller has still got the tuple just * before "current" referenced in a slot. So we keep one extra tuple * before the oldest "current". (Strictly speaking, we could require such * callers to use the "copy" flag to tuplestore_gettupleslot, but for * efficiency we allow this one case to not use "copy".) */ nremove = oldest - 1; if (nremove <= 0) return; /* nothing to do */ Assert(nremove <= state->memtupcount); /* Release no-longer-needed tuples */ for (i = 0; i < nremove; i++) { FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i])); pfree(state->memtuples[i]); } /* * Slide the array down and readjust pointers. This may look pretty * stupid, but we expect that there will usually not be very many * tuple-pointers to move, so this isn't that expensive; and it keeps a * lot of other logic simple. * * In fact, in the current usage for merge joins, it's demonstrable that * there will always be exactly one non-removed tuple; so optimize that * case. */ if (nremove + 1 == state->memtupcount) state->memtuples[0] = state->memtuples[nremove]; else memmove(state->memtuples, state->memtuples + nremove, (state->memtupcount - nremove) * sizeof(void *)); state->memtupcount -= nremove; for (i = 0; i < state->readptrcount; i++) { if (!state->readptrs[i].eof_reached) state->readptrs[i].current -= nremove; } /* mark tuplestore as truncated (used for Assert crosschecks only) */ state->truncated = true; }

void CoolingTower::EvalProducts(CNodeEvalIndex & NEI) { switch (SolveMethod()) { case SM_Direct: { const int wi = H2OLiq(); const int si = H2OVap(); const int ioLiq = IOWithId_Self(ioid_Liq); const int ioVap = IOWithId_Self(ioid_Vap); const int ioLoss = IOWithId_Self(ioid_LiqLoss); const int ioDrift = IOWithId_Self(ioid_DriftLoss); SpConduit & Ql=*IOConduit(ioLiq); SpConduit & Qv=*IOConduit(ioVap); StkSpConduit QMix("Mix", chLINEID(), this); iCycles = Max(2L, iCycles); dLGRatio = Range(0.01, dLGRatio, 10.0); ClrCI(3); ClrCI(4); ClrCI(5); ClrCI(6); dDuty = 0.0; SigmaQInPMin(QMix(), som_ALL, Id_2_Mask(ioid_Feed)); Ql.QCopy(QMix()); Qv.QCopy(QMix()); const double QmWaterLiqIn = QMix().VMass[wi]; const double QmWaterVapIn = QMix().VMass[si]; const double QmVapIn = QMix().QMass(som_Gas); dQmIn = QMix().QMass(som_ALL); const flag HasFlw = (dQmIn>UsableMass); dTempKFeed = QMix().Temp(); const double TotHfAtFeedT_Before = QMix().totHf(som_ALL, dTempKFeed, QMix().Press()); //RB.EvalProducts(QMix); //EHX.EvalProducts(QMix); //double POut = AtmosPress(); //force outlet to Atmos P double POut = Std_P; //force outlet to Std_P //double AvgCellAgeY=AvgCellAge/(365.25*24.0*60.0*60.0); //double TimeSinceDescaleM=TimeSinceDescale/(365.25*24.0*60.0*60.0/12.0); //double RqdLiqTemp = AirWetBulbT + Approach + AvgCellAgeY*1.1 + TimeSinceDescaleM/12.0*4.0; double RqdLiqTemp = dAirWetBulbT + dApproachT; double T1 = QMix().Temp(); double T2 = RqdLiqTemp; dLossQm = 0.0; bool ValidData; switch (iMethod) { case CTM_Simple: ValidData = (RqdLiqTemp<T1); break; case CTM_Merkel: ValidData = (iMerkelCalcType==MCT_TOut ? (dAirWetBulbT<T1) : (RqdLiqTemp<T1)); break; } if (!HasFlw) ValidData = false; double RqdLiqTempUsed; if (ValidData) { m_VLE.SetHfInAtZero(QMix()); if (iMethod==CTM_Simple) { //const double h1 = QMix().totHf(); RqdLiqTempUsed = RqdLiqTemp; EvapFnd EF(QMix(), RqdLiqTempUsed, POut, m_VLE);//QMix().Press()); EF.SetTarget(QMix().totHf()); if (Valid(dEvapFrac)) { EF.SetEstimate(dEvapFrac, 1.0); //dEvapFrac = dNAN; } flag Ok = false; dMaxEvapFrac = Range(0.01, dMaxEvapFrac, 1.0); int iRet=EF.Start(0.0, dMaxEvapFrac); if (iRet==RF_EstimateOK) //estimate is good, solve not required { Ok = true; } else { if (iRet==RF_BadEstimate) iRet = EF.Start(0.0, dMaxEvapFrac); // Restart if (iRet==RF_OK) if (EF.Solve_Brent()==RF_OK) Ok = true; } dEvapFrac = EF.Result(); //use result regardless if (!Ok) { SigmaQInPMin(QMix(), som_ALL, Id_2_Mask(ioid_Feed)); m_VLE.SetSatPVapFrac(QMix(), dEvapFrac, 0); QMix().SetPress(POut); RqdLiqTempUsed = QMix().Temp(); } //const double h2 = QMix().totHf(); //dDuty = h1-h2; this gives 0 (as expected) //dDuty is zero because there is no heattransfer with the air } else { dAirCp = Max(0.000001, dAirCp); dAirWetBulbT = Range(MerkelTMn, dAirWetBulbT, MerkelTMx-10.0); if (T1<MerkelTMn || T1>MerkelTMx) { SetCI(6, true); T1 = Range(MerkelTMn, T1, MerkelTMx); } MerkelTempFnd Fnd(QMix(), *this, T1); if (iMerkelCalcType==MCT_KaVL) { if (T2<MerkelTMn || T2>MerkelTMx) { SetCI(5, true); T2 = Range(MerkelTMn, T2, MerkelTMx); RqdLiqTemp = T2; } dKaVL = Fnd.Function(T2); } else { Fnd.SetTarget(dKaVL); //Note that for high LG_Ratio (eg>1.0) then ApproachT is higher. double Mn = dAirWetBulbT+(T1-dAirWetBulbT)*0.005; const double Mx = dAirWetBulbT+(T1-dAirWetBulbT)*0.999;//T1-0.001; if (Valid(RqdLiqTemp) && RqdLiqTemp>Mn && RqdLiqTemp<Mx) { Fnd.SetEstimate(RqdLiqTemp, 1.0); //RqdLiqTemp = dNAN; } flag Ok = false; int iRet=Fnd.Start(Mn, Mx); if (iRet==RF_EstimateOK) //estimate is good, solve not required { Ok = true; } else { double KaVL_MnTest = Fnd.Function(Mn); if (KaVL_MnTest<0.0) { //Crude fix to find min temp that doesn't cause KaV/L to be negative... double fr = 0.01; while (KaVL_MnTest<0.0 && fr<0.9) { Mn = dAirWetBulbT+(T1-dAirWetBulbT)*fr; KaVL_MnTest = Fnd.Function(Mn); fr += 0.01; } iRet = Fnd.Start(Mn, Mx); // Restart } if (iRet==RF_OK) if (Fnd.Solve_Brent()==RF_OK) Ok = true; } RqdLiqTemp = Fnd.Result(); //use result regardless T2 = RqdLiqTemp; if (!Ok) { const double KaVL_Calc = Fnd.Function(T2); SetCI(3, fabs(KaVL_Calc-dKaVL)>1.0e-6); } dApproachT = RqdLiqTemp - dAirWetBulbT; } dEvapFactor = Min(dEvapFactor, 0.1); //prevent user from puting a silly large number for this dEvapLossQm = dQmIn * dEvapFactor * (C2F(T1)-C2F(T2));//Evaporation Loss: WLe = Wc * EvapFactor * dT dEvapLossQm = Min(dEvapLossQm, QmWaterLiqIn); //limit the amount that can be evaporated RqdLiqTempUsed = RqdLiqTemp; dEvapFrac = Min(dMaxEvapFrac, (dEvapLossQm+QmWaterVapIn)/GTZ(QmWaterLiqIn+QmWaterVapIn)); const double h1 = QMix().totHf(); m_VLE.SetSatPVapFrac(QMix(), dEvapFrac, 0); QMix().SetPress(POut); QMix().SetTemp(RqdLiqTempUsed); const double h2 = QMix().totHf(); dDuty = h1-h2; //dAirEnthOut = AirEnth(T2); dAirEnthOut = Fnd.h2 / 0.430210432; //convert from Btu/lb to kJ/kg dAirQmIn = dQmIn/dLGRatio; dAirTRise = dDuty/GTZ(dAirQmIn)/dAirCp; dAirTOut = dAirDryBulbT + dAirTRise; dAirMixQm = dAirQmIn + dEvapLossQm; const double EvapLossCp = Qv.msCp(); dAirMixCp = dAirQmIn/GTZ(dAirMixQm)*dAirCp + dEvapLossQm/GTZ(dAirMixQm)*EvapLossCp; dAirMixT = dAirQmIn/GTZ(dAirMixQm)*dAirTOut + dEvapLossQm/GTZ(dAirMixQm)*T2; } double QmWaterVapOut = QMix().VMass[si]; dQmWaterEvap = Max(0.0, QmWaterVapOut - QmWaterVapIn); if (iMethod==CTM_Simple) dEvapLossQm=dQmWaterEvap; switch (iLossMethod) { case WLM_None: dDriftLossQm = 0.0; dBlowdownLossQm = 0.0; dLossQm = 0.0; break; case WLM_Frac: dRqdDriftLossFrac = Range(0.0, dRqdDriftLossFrac, 1.0); dRqdLossFrac = Range(0.0, dRqdLossFrac, 0.9); dLossQm = dQmIn * dRqdLossFrac; dDriftLossQm = dLossQm * dRqdDriftLossFrac; dBlowdownLossQm = dLossQm - dDriftLossQm; break; case WLM_Qm: dRqdDriftLossFrac = Range(0.0, dRqdDriftLossFrac, 1.0); dLossQm = dRqdLossQm; dDriftLossQm = dLossQm * dRqdDriftLossFrac; dBlowdownLossQm = dLossQm - dDriftLossQm; break; case WLM_DriftBlowdown: dDriftLossQm = dQmIn * dDriftLossFrac;//Drift Loss: WLd = % of water flow dBlowdownLossQm = dEvapLossQm/(iCycles-1);//Blowdown Loss: WLb = WLe / (cycles - 1) dLossQm = dDriftLossQm+dBlowdownLossQm; break; } if (dLossQm>dQmIn-dEvapLossQm-QmVapIn) { SetCI(4, true); dLossQm = dQmIn-dEvapLossQm-QmVapIn; } m_VLE.AddHfOutAtZero(QMix()); } else { RqdLiqTempUsed = T1; dEvapFrac = 0.0; dLossQm = 0.0; dDriftLossQm = 0.0; dBlowdownLossQm = 0.0; dEvapLossQm = 0.0; dQmWaterEvap = 0.0; //if (iMethod==CTM_Merkel) { dAirEnthOut = TotHfAtFeedT_Before / 0.430210432; //convert from Btu/lb to kJ/kg dAirQmIn = 0.0; dAirTRise = 0.0; dAirTOut = dTempKFeed; dAirMixQm = 0.0; dAirMixCp = 0.0; dAirMixT = dTempKFeed; } } //QMix.ChangeModel(&SMSteamClass); const double TotHfAtFeedT_After = QMix().totHf(som_ALL, dTempKFeed, QMix().Press()); Qv.QSetF(QMix(), som_Gas, 1.0); Qv.SetPress(POut); Qv.SetTemp(RqdLiqTempUsed); const double Qsl = QMix().QMass(som_SL); if (ioLoss<0) { if (ioDrift<0) { Ql.QSetF(QMix(), som_SL, 1.0); Ql.SetPress(POut); Ql.SetTemp(RqdLiqTempUsed); } else { SpConduit & Qdrift=*IOConduit(ioDrift); const double f = dDriftLossQm/GTZ(Qsl); Ql.QSetF(QMix(), som_SL, 1.0-f); Ql.SetPress(POut); Ql.SetTemp(RqdLiqTempUsed); Qdrift.QCopy(QMix()); Qdrift.QSetF(QMix(), som_SL, f); Qdrift.SetPress(POut); Qdrift.SetTemp(RqdLiqTempUsed); } } else { SpConduit & Qloss=*IOConduit(ioLoss); const double f = dLossQm/GTZ(Qsl); Ql.QSetF(QMix(), som_SL, 1.0-f); Ql.SetPress(POut); Ql.SetTemp(RqdLiqTempUsed); if (ioDrift<0) { Qloss.QCopy(QMix()); Qloss.QSetF(QMix(), som_SL, f); Qloss.SetPress(POut); Qloss.SetTemp(RqdLiqTempUsed); } else { const double fd = dDriftLossQm/GTZ(Qsl); const double fl = f - fd; SpConduit & Qdrift=*IOConduit(ioDrift); Qdrift.QCopy(QMix()); Qdrift.QSetF(QMix(), som_SL, fd); Qdrift.SetPress(POut); Qdrift.SetTemp(RqdLiqTempUsed); Qloss.QCopy(QMix()); Qloss.QSetF(QMix(), som_SL, fl); Qloss.SetPress(POut); Qloss.SetTemp(RqdLiqTempUsed); } } //results... dTotalLossQm = dLossQm+dEvapLossQm; dHeatFlow = TotHfAtFeedT_After - TotHfAtFeedT_Before; //what exactly is this??? dFinalP = Ql.Press(); dFinalT = Ql.Temp(); dTempDrop = T1 - dFinalT; SetCI(1, HasFlw && RqdLiqTemp>T1); SetCI(2, HasFlw && RqdLiqTempUsed>RqdLiqTemp); break; } default: MN_Surge::EvalProducts(NEI); } }

GeometryService::InOut TiltedCylinderIF::InsideOutside(const RealVect& lo, const RealVect& hi) const { // Fast Sphere-Box intersection from "Graphics Gems" pp 335-338, 1990 Real dmin = 0; //distance from cylinder axis to nearest point in box (squared) Real dmax = 0; //distance from cylinder axis to farthest point in box (squared) Real ai, bi, a, b; Tuple<int,CH_SPACEDIM-1> tanDirs = PolyGeom::computeTanDirs(m_coordDir); for (int i=0; i<CH_SPACEDIM-1; ++i) { ai = m_point[tanDirs[i]] - lo[tanDirs[i]]; bi = m_point[tanDirs[i]] - hi[tanDirs[i]]; a = ai * ai; b = bi * bi; dmax = dmax + Max(a,b); if (m_point[tanDirs[i]] < lo[tanDirs[i]] || m_point[tanDirs[i]] > hi[tanDirs[i]]) dmin = dmin + Min(a,b); } if (m_inside) { if (dmin >= m_radius2) return GeometryService::Covered; if (dmax < m_radius2) return GeometryService::Regular; } else { if (dmin > m_radius2) return GeometryService::Regular; if (dmax <= m_radius2) return GeometryService::Covered; } return GeometryService::Irregular; }

/* cube_union_v0 */ NDBOX * cube_union_v0(NDBOX *a, NDBOX *b) { int i; NDBOX *result; int dim; int size; /* trivial case */ if (a == b) return a; /* swap the arguments if needed, so that 'a' is always larger than 'b' */ if (DIM(a) < DIM(b)) { NDBOX *tmp = b; b = a; a = tmp; } dim = DIM(a); size = CUBE_SIZE(dim); result = palloc0(size); SET_VARSIZE(result, size); SET_DIM(result, dim); /* First compute the union of the dimensions present in both args */ for (i = 0; i < DIM(b); i++) { result->x[i] = Min( Min(LL_COORD(a, i), UR_COORD(a, i)), Min(LL_COORD(b, i), UR_COORD(b, i)) ); result->x[i + DIM(a)] = Max( Max(LL_COORD(a, i), UR_COORD(a, i)), Max(LL_COORD(b, i), UR_COORD(b, i)) ); } /* continue on the higher dimensions only present in 'a' */ for (; i < DIM(a); i++) { result->x[i] = Min(0, Min(LL_COORD(a, i), UR_COORD(a, i)) ); result->x[i + dim] = Max(0, Max(LL_COORD(a, i), UR_COORD(a, i)) ); } /* * Check if the result was in fact a point, and set the flag in the datum * accordingly. (we don't bother to repalloc it smaller) */ if (cube_is_point_internal(result)) { size = POINT_SIZE(dim); SET_VARSIZE(result, size); SET_POINT_BIT(result); } return (result); }

#include ELEM_SCALE_INC #include ELEM_GERU_INC namespace elem { namespace lu { // Local LU _without_ partial pivoting template<typename F> inline void UnbFLAME( Matrix<F>& A ) { DEBUG_ONLY(CallStackEntry cse("lu::UnbFLAME")) const Int m = A.Height(); const Int n = A.Width(); const Int minDim = Min(m,n); for( Int k=0; k<minDim; ++k ) { auto alpha11 = ViewRange( A, k, k, k+1, k+1 ); auto a12 = ViewRange( A, k, k+1, k+1, n ); auto a21 = ViewRange( A, k+1, k, m, k+1 ); auto A22 = ViewRange( A, k+1, k+1, m, n ); F alpha = alpha11.Get(0,0); if( alpha == F(0) ) throw SingularMatrixException(); Scale( 1/alpha, a21 ); Geru( F(-1), a21, a12, A22 ); } }

/* cube_inter */ Datum cube_inter(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0); NDBOX *b = PG_GETARG_NDBOX(1); NDBOX *result; bool swapped = false; int i; int dim; int size; /* swap the arguments if needed, so that 'a' is always larger than 'b' */ if (DIM(a) < DIM(b)) { NDBOX *tmp = b; b = a; a = tmp; swapped = true; } dim = DIM(a); size = CUBE_SIZE(dim); result = (NDBOX *) palloc0(size); SET_VARSIZE(result, size); SET_DIM(result, dim); /* First compute intersection of the dimensions present in both args */ for (i = 0; i < DIM(b); i++) { result->x[i] = Max( Min(LL_COORD(a, i), UR_COORD(a, i)), Min(LL_COORD(b, i), UR_COORD(b, i)) ); result->x[i + DIM(a)] = Min( Max(LL_COORD(a, i), UR_COORD(a, i)), Max(LL_COORD(b, i), UR_COORD(b, i)) ); } /* continue on the higher dimensions only present in 'a' */ for (; i < DIM(a); i++) { result->x[i] = Max(0, Min(LL_COORD(a, i), UR_COORD(a, i)) ); result->x[i + DIM(a)] = Min(0, Max(LL_COORD(a, i), UR_COORD(a, i)) ); } /* * Check if the result was in fact a point, and set the flag in the datum * accordingly. (we don't bother to repalloc it smaller) */ if (cube_is_point_internal(result)) { size = POINT_SIZE(dim); result = repalloc(result, size); SET_VARSIZE(result, size); SET_POINT_BIT(result); } if (swapped) { PG_FREE_IF_COPY(b, 0); PG_FREE_IF_COPY(a, 1); } else { PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); } /* * Is it OK to return a non-null intersection for non-overlapping boxes? */ PG_RETURN_NDBOX(result); }

/* * -------------------------------------------------------------------------- * Double sorting split algorithm. This is used for both boxes and points. * * The algorithm finds split of boxes by considering splits along each axis. * Each entry is first projected as an interval on the X-axis, and different * ways to split the intervals into two groups are considered, trying to * minimize the overlap of the groups. Then the same is repeated for the * Y-axis, and the overall best split is chosen. The quality of a split is * determined by overlap along that axis and some other criteria (see * g_box_consider_split). * * After that, all the entries are divided into three groups: * * 1) Entries which should be placed to the left group * 2) Entries which should be placed to the right group * 3) "Common entries" which can be placed to any of groups without affecting * of overlap along selected axis. * * The common entries are distributed by minimizing penalty. * * For details see: * "A new___ double sorting-based node splitting algorithm for R-tree", A. Korotkov * http://syrcose.ispras.ru/2011/files/SYRCoSE2011_Proceedings.pdf#page=36 * -------------------------------------------------------------------------- */ Datum gist_box_picksplit(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); OffsetNumber i, maxoff; ConsiderSplitContext context; BOX *box, *leftBox, *rightBox; int dim, commonEntriesCount; SplitInterval *intervalsLower, *intervalsUpper; CommonEntry *commonEntries; int nentries; memset(&context, 0, sizeof(ConsiderSplitContext)); maxoff = entryvec->n - 1; nentries = context.entriesCount = maxoff - FirstOffsetNumber + 1; /* Allocate arrays for intervals along axes */ intervalsLower = (SplitInterval *) palloc(nentries * sizeof(SplitInterval)); intervalsUpper = (SplitInterval *) palloc(nentries * sizeof(SplitInterval)); /* * Calculate the overall minimum bounding box over all the entries. */ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { box = DatumGetBoxP(entryvec->vector[i].key); if (i == FirstOffsetNumber) context.boundingBox = *box; else adjustBox(&context.boundingBox, box); } /* * Iterate over axes for optimal split searching. */ context.first = true; /* nothing selected yet */ for (dim = 0; dim < 2; dim++) { double leftUpper, rightLower; int i1, i2; /* Project each entry as an interval on the selected axis. */ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { box = DatumGetBoxP(entryvec->vector[i].key); if (dim == 0) { intervalsLower[i - FirstOffsetNumber].lower = box->low.x; intervalsLower[i - FirstOffsetNumber].upper = box->high.x; } else { intervalsLower[i - FirstOffsetNumber].lower = box->low.y; intervalsLower[i - FirstOffsetNumber].upper = box->high.y; } } /* * Make two arrays of intervals: one sorted by lower bound and another * sorted by upper bound. */ memcpy(intervalsUpper, intervalsLower, sizeof(SplitInterval) * nentries); qsort(intervalsLower, nentries, sizeof(SplitInterval), interval_cmp_lower); qsort(intervalsUpper, nentries, sizeof(SplitInterval), interval_cmp_upper); /*---- * The goal is to form a left and right interval, so that every entry * interval is contained by either left or right interval (or both). * * For example, with the intervals (0,1), (1,3), (2,3), (2,4): * * 0 1 2 3 4 * +-+ * +---+ * +-+ * +---+ * * The left and right intervals are of the form (0,a) and (b,4). * We first consider splits where b is the lower bound of an entry. * We iterate through all entries, and for each b, calculate the * smallest possible a. Then we consider splits where a is the * uppper bound of an entry, and for each a, calculate the greatest * possible b. * * In the above example, the first loop would consider splits: * b=0: (0,1)-(0,4) * b=1: (0,1)-(1,4) * b=2: (0,3)-(2,4) * * And the second loop: * a=1: (0,1)-(1,4) * a=3: (0,3)-(2,4) * a=4: (0,4)-(2,4) */ /* * Iterate over lower bound of right group, finding smallest possible * upper bound of left group. */ i1 = 0; i2 = 0; rightLower = intervalsLower[i1].lower; leftUpper = intervalsUpper[i2].lower; while (true) { /* * Find next lower bound of right group. */ while (i1 < nentries && rightLower == intervalsLower[i1].lower) { leftUpper = Max(leftUpper, intervalsLower[i1].upper); i1++; } if (i1 >= nentries) break; rightLower = intervalsLower[i1].lower; /* * Find count of intervals which anyway should be placed to the * left group. */ while (i2 < nentries && intervalsUpper[i2].upper <= leftUpper) i2++; /* * Consider found split. */ g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2); } /* * Iterate over upper bound of left group finding greates possible * lower bound of right group. */ i1 = nentries - 1; i2 = nentries - 1; rightLower = intervalsLower[i1].upper; leftUpper = intervalsUpper[i2].upper; while (true) { /* * Find next upper bound of left group. */ while (i2 >= 0 && leftUpper == intervalsUpper[i2].upper) { rightLower = Min(rightLower, intervalsUpper[i2].lower); i2--; } if (i2 < 0) break; leftUpper = intervalsUpper[i2].upper; /* * Find count of intervals which anyway should be placed to the * right group. */ while (i1 >= 0 && intervalsLower[i1].lower >= rightLower) i1--; /* * Consider found split. */ g_box_consider_split(&context, dim, rightLower, i1 + 1, leftUpper, i2 + 1); } } /* * If we failed to find any acceptable splits, use trivial split. */ if (context.first) { fallbackSplit(entryvec, v); PG_RETURN_POINTER(v); } /* * Ok, we have now selected the split across one axis. * * While considering the splits, we already determined that there will be * enough entries in both groups to reach the desired ratio, but we did * not memorize which entries go to which group. So determine that now. */ /* Allocate vectors for results */ v->spl_left = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber)); v->spl_right = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber)); v->spl_nleft = 0; v->spl_nright = 0; /* Allocate bounding boxes of left and right groups */ leftBox = static_cast<BOX *>(palloc0(sizeof(BOX))); rightBox = static_cast<BOX *>(palloc0(sizeof(BOX))); /* * Allocate an array for "common entries" - entries which can be placed to * either group without affecting overlap along selected axis. */ commonEntriesCount = 0; commonEntries = (CommonEntry *) palloc(nentries * sizeof(CommonEntry)); /* Helper macros to place an entry in the left or right group */ #define PLACE_LEFT(box, off) \ do { \ if (v->spl_nleft > 0) \ adjustBox(leftBox, box); \ else \ *leftBox = *(box); \ v->spl_left[v->spl_nleft++] = off; \ } while(0) #define PLACE_RIGHT(box, off) \ do { \ if (v->spl_nright > 0) \ adjustBox(rightBox, box); \ else \ *rightBox = *(box); \ v->spl_right[v->spl_nright++] = off; \ } while(0) /* * Distribute entries which can be distributed unambiguously, and collect * common entries. */ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { double lower, upper; /* * Get upper and lower bounds along selected axis. */ box = DatumGetBoxP(entryvec->vector[i].key); if (context.dim == 0) { lower = box->low.x; upper = box->high.x; } else { lower = box->low.y; upper = box->high.y; } if (upper <= context.leftUpper) { /* Fits to the left group */ if (lower >= context.rightLower) { /* Fits also to the right group, so "common entry" */ commonEntries[commonEntriesCount++].index = i; } else { /* Doesn't fit to the right group, so join to the left group */ PLACE_LEFT(box, i); } } else { /* * Each entry should fit on either left or right group. Since this * entry didn't fit on the left group, it better fit in the right * group. */ Assert(lower >= context.rightLower); /* Doesn't fit to the left group, so join to the right group */ PLACE_RIGHT(box, i); } } /* * Distribute "common entries", if any. */ if (commonEntriesCount > 0) { /* * Calculate minimum number of entries that must be placed in both * groups, to reach LIMIT_RATIO. */ int m = ceil(LIMIT_RATIO * (double) nentries); /* * Calculate delta between penalties of join "common entries" to * different groups. */ for (i = 0; i < commonEntriesCount; i++) { box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key); commonEntries[i].delta = Abs(box_penalty(leftBox, box) - box_penalty(rightBox, box)); } /* * Sort "common entries" by calculated deltas in order to distribute * the most ambiguous entries first. */ qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp); /* * Distribute "common entries" between groups. */ for (i = 0; i < commonEntriesCount; i++) { box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key); /* * Check if we have to place this entry in either group to achieve * LIMIT_RATIO. */ if (v->spl_nleft + (commonEntriesCount - i) <= m) PLACE_LEFT(box, commonEntries[i].index); else if (v->spl_nright + (commonEntriesCount - i) <= m) PLACE_RIGHT(box, commonEntries[i].index); else { /* Otherwise select the group by minimal penalty */ if (box_penalty(leftBox, box) < box_penalty(rightBox, box)) PLACE_LEFT(box, commonEntries[i].index); else PLACE_RIGHT(box, commonEntries[i].index); } } } v->spl_ldatum = PointerGetDatum(leftBox); v->spl_rdatum = PointerGetDatum(rightBox); PG_RETURN_POINTER(v); }

/* make up a metric in which one box will be 'lower' than the other -- this can be useful for sorting and to determine uniqueness */ int32 cube_cmp_v0(NDBOX *a, NDBOX *b) { int i; int dim; dim = Min(DIM(a), DIM(b)); /* compare the common dimensions */ for (i = 0; i < dim; i++) { if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Min(LL_COORD(b, i), UR_COORD(b, i))) return 1; if (Min(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i))) return -1; } for (i = 0; i < dim; i++) { if (Max(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i))) return 1; if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Max(LL_COORD(b, i), UR_COORD(b, i))) return -1; } /* compare extra dimensions to zero */ if (DIM(a) > DIM(b)) { for (i = dim; i < DIM(a); i++) { if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0) return 1; if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0) return -1; } for (i = dim; i < DIM(a); i++) { if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0) return 1; if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0) return -1; } /* * if all common dimensions are equal, the cube with more dimensions * wins */ return 1; } if (DIM(a) < DIM(b)) { for (i = dim; i < DIM(b); i++) { if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0) return -1; if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0) return 1; } for (i = dim; i < DIM(b); i++) { if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0) return -1; if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0) return 1; } /* * if all common dimensions are equal, the cube with more dimensions * wins */ return -1; } /* They're really equal */ return 0; }

int main(int argc, char * argv[]) { try { libmaus2::util::ArgInfo const arginfo(argc,argv); std::string const isain = arginfo.getUnparsedRestArg(0); std::string const isaout = arginfo.getUnparsedRestArg(1); std::string const tmpdir = arginfo.getUnparsedValue("tmpdir",arginfo.getCurDir()); std::string const tmpout = tmpdir + "/" + arginfo.getDefaultTmpFileName() + "_sort_isa.tmp"; libmaus2::util::TempFileRemovalContainer::addTempFile(tmpout); // std::string const tmpout = isaout + ".tmp"; uint64_t const sortbufsize = arginfo.getValueUnsignedNumeric<uint64_t>("sortbufsize",16*1024*1024); uint64_t const inbufsize = arginfo.getValueUnsignedNumeric<uint64_t>("inbufsize",8*1024); bool const verbose = arginfo.getValue<int>("verbose",1); libmaus2::aio::OutputStream::unique_ptr_type Ptmp(libmaus2::aio::OutputStreamFactoryContainer::constructUnique(tmpout)); libmaus2::aio::SortingBufferedOutput< std::pair<uint64_t,uint64_t> >::unique_ptr_type Psortout( new libmaus2::aio::SortingBufferedOutput< std::pair<uint64_t,uint64_t> >(*Ptmp,sortbufsize)); libmaus2::aio::InputStream::unique_ptr_type Pin(libmaus2::aio::InputStreamFactoryContainer::constructUnique(isain)); libmaus2::aio::SynchronousGenericInput<uint64_t> Sin(*Pin,inbufsize); uint64_t v0 = 0, v1 = 0; uint64_t c_in = 0; while ( Sin.peekNext(v0) ) { bool const ok0 = Sin.getNext(v0); assert ( ok0 ); bool const ok1 = Sin.getNext(v1); if ( ! ok1 ) { libmaus2::exception::LibMausException lme; lme.getStream() << "Uneven number of words in input file." << std::endl; lme.finish(); throw lme; } Psortout->put(std::pair<uint64_t,uint64_t>(v1,v0)); c_in += 1; if ( verbose && (c_in & (1024*1024-1)) == 0 ) std::cerr << "[V] in " << c_in/(1024*1024) << std::endl; } Psortout->flush(); std::vector<uint64_t> const blocksizes = Psortout->getBlockSizes(); Psortout.reset(); Ptmp->flush(); Ptmp.reset(); // libmaus2::aio::InputStream::unique_ptr_type Ptmpin(libmaus2::aio::InputStreamFactoryContainer::constructUnique(tmpout)); libmaus2::sorting::MergingReadBack< std::pair<uint64_t,uint64_t> >::unique_ptr_type Min( new libmaus2::sorting::MergingReadBack< std::pair<uint64_t,uint64_t> >(tmpout,blocksizes) ); std::pair<uint64_t,uint64_t> P; libmaus2::aio::OutputStream::unique_ptr_type Pout(libmaus2::aio::OutputStreamFactoryContainer::constructUnique(isaout)); uint64_t c_out = 0; bool gotfirst = false; bool gotfirstdif = false; bool difconsistent = true; uint64_t firstpos = std::numeric_limits<uint64_t>::max(); uint64_t prevpos = std::numeric_limits<uint64_t>::max(); uint64_t firstdif = std::numeric_limits<uint64_t>::max(); libmaus2::util::Histogram hist; while ( Min->getNext(P) ) { libmaus2::util::NumberSerialisation::serialiseNumber(*Pout,P.first); libmaus2::util::NumberSerialisation::serialiseNumber(*Pout,P.second); c_out += 1; if ( verbose && (c_out & (1024*1024-1)) == 0 ) std::cerr << "[V] out " << static_cast<double>(c_out) / c_in << " first pos " << firstpos << " first dif " << firstdif << " consistent " << difconsistent << std::endl; if ( ! gotfirst ) { gotfirst = true; firstpos = P.first; } else { assert ( prevpos != std::numeric_limits<uint64_t>::max() ); assert ( P.first > prevpos ); uint64_t const dif = P.first - prevpos; hist(dif); if ( ! gotfirstdif ) { gotfirstdif = true; firstdif = dif; } else { if ( dif != firstdif ) difconsistent = false; } } prevpos = P.first; } if ( verbose ) std::cerr << "[V] out " << static_cast<double>(c_out) / c_in << " first pos " << firstpos << " first dif " << firstdif << " consistent " << difconsistent << std::endl; Min.reset(); Pout->flush(); Pout.reset(); hist.print(std::cerr); } catch(std::exception const & ex) { std::cerr << ex.what() << std::endl; } }

/* * bms_subset_compare - compare A and B for equality/subset relationships * * This is more efficient than testing bms_is_subset in both directions. */ BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b) { BMS_Comparison result; int shortlen; int longlen; int i; /* Handle cases where either input is NULL */ if (a == NULL) { if (b == NULL) return BMS_EQUAL; return bms_is_empty(b) ? BMS_EQUAL : BMS_SUBSET1; } if (b == NULL) return bms_is_empty(a) ? BMS_EQUAL : BMS_SUBSET2; /* Check common words */ result = BMS_EQUAL; /* status so far */ shortlen = Min(a->nwords, b->nwords); for (i = 0; i < shortlen; i++) { bitmapword aword = a->words[i]; bitmapword bword = b->words[i]; if ((aword & ~bword) != 0) { /* a is not a subset of b */ if (result == BMS_SUBSET1) return BMS_DIFFERENT; result = BMS_SUBSET2; } if ((bword & ~aword) != 0) { /* b is not a subset of a */ if (result == BMS_SUBSET2) return BMS_DIFFERENT; result = BMS_SUBSET1; } } /* Check extra words */ if (a->nwords > b->nwords) { longlen = a->nwords; for (; i < longlen; i++) { if (a->words[i] != 0) { /* a is not a subset of b */ if (result == BMS_SUBSET1) return BMS_DIFFERENT; result = BMS_SUBSET2; } } } else if (a->nwords < b->nwords) { longlen = b->nwords; for (; i < longlen; i++) { if (b->words[i] != 0) { /* b is not a subset of a */ if (result == BMS_SUBSET2) return BMS_DIFFERENT; result = BMS_SUBSET1; } } } return result; }