Beispiel #1
0
 // Free memory associated with a 'stepcompress' object
 public void Dispose()
 {
     Stepcompress.free(queue);
 }
Beispiel #2
0
        // Find a 'step_move' that covers a series of step times
        step_move compress_bisect_add()
        {
            uint *qlast = queue_next;

            if (qlast > queue_pos + 65535)
            {
                qlast = queue_pos + 65535;
            }
            points point = minmax_point(queue_pos);
            int    outer_mininterval = point.minp, outer_maxinterval = point.maxp;
            int    add = 0, minadd = -0x8000, maxadd = 0x7fff;
            int    bestinterval = 0, bestcount = 1, bestadd = 1, bestreach = int.MinValue;
            int    zerointerval = 0, zerocount = 0;

            int count, addfactor, nextaddfactor, c;

            while (true)
            {
                // Find longest valid sequence with the given 'add'
                points nextpoint;
                int    nextmininterval = outer_mininterval;
                int    nextmaxinterval = outer_maxinterval, interval = nextmaxinterval;
                int    nextcount = 1;
                for (; ;)
                {
                    nextcount++;
                    if (&queue_pos[nextcount - 1] >= qlast)
                    {
                        count = nextcount - 1;
                        return(new step_move((uint)interval, (ushort)count, (short)add));
                    }
                    nextpoint     = minmax_point(queue_pos + nextcount - 1);
                    nextaddfactor = nextcount * (nextcount - 1) / 2;
                    c             = add * nextaddfactor;
                    if (nextmininterval * nextcount < nextpoint.minp - c)
                    {
                        nextmininterval = Stepcompress.DIV_ROUND_UP(nextpoint.minp - c, nextcount);
                    }
                    if (nextmaxinterval * nextcount > nextpoint.maxp - c)
                    {
                        nextmaxinterval = (nextpoint.maxp - c) / nextcount;
                    }
                    if (nextmininterval > nextmaxinterval)
                    {
                        break;
                    }
                    interval = nextmaxinterval;
                }

                // Check if this is the best sequence found so far
                count     = nextcount - 1;
                addfactor = count * (count - 1) / 2;
                int reach = add * addfactor + interval * count;
                if (reach > bestreach ||
                    (reach == bestreach && interval > bestinterval))
                {
                    bestinterval = interval;
                    bestcount    = count;
                    bestadd      = add;
                    bestreach    = reach;
                    if (add == 0)
                    {
                        zerointerval = interval;
                        zerocount    = count;
                    }
                    if (count > 0x200)
                    {
                        // No 'add' will improve sequence; avoid integer overflow
                        break;
                    }
                }

                // Check if a greater or lesser add could extend the sequence
                nextaddfactor = nextcount * (nextcount - 1) / 2;
                int nextreach = add * nextaddfactor + interval * nextcount;
                if (nextreach < nextpoint.minp)
                {
                    minadd            = add + 1;
                    outer_maxinterval = nextmaxinterval;
                }
                else
                {
                    maxadd            = add - 1;
                    outer_mininterval = nextmininterval;
                }

                // The maximum valid deviation between two quadratic sequences
                // can be calculated and used to further limit the add range.
                if (count > 1)
                {
                    int errdelta = (int)max_error * Stepcompress.QUADRATIC_DEV / (count * count);
                    if (minadd < add - errdelta)
                    {
                        minadd = add - errdelta;
                    }
                    if (maxadd > add + errdelta)
                    {
                        maxadd = add + errdelta;
                    }
                }

                // See if next point would further limit the add range
                c = outer_maxinterval * nextcount;
                if (minadd * nextaddfactor < nextpoint.minp - c)
                {
                    minadd = Stepcompress.idiv_up(nextpoint.minp - c, nextaddfactor);
                }
                c = outer_mininterval * nextcount;
                if (maxadd * nextaddfactor > nextpoint.maxp - c)
                {
                    maxadd = Stepcompress.idiv_down(nextpoint.maxp - c, nextaddfactor);
                }

                // Bisect valid add range and try again with new 'add'
                if (minadd > maxadd)
                {
                    break;
                }
                add = maxadd - (maxadd - minadd) / 4;
            }
            if (zerocount + zerocount / 16 >= bestcount)
            {
                // Prefer add=0 if it's similar to the best found sequence
                return(new step_move((uint)zerointerval, (ushort)zerocount, 0));
            }
            return(new step_move((uint)bestinterval, (ushort)bestcount, (short)bestadd));
        }
Beispiel #3
0
        // Slow path for queue_append()
        public int queue_append_slow(double rel_sc)
        {
            ulong abs_step_clock = (ulong)(rel_sc + last_step_clock);

            if (abs_step_clock >= last_step_clock + Stepcompress.CLOCK_DIFF_MAX)
            {
                // Avoid integer overflow on steps far in the future
                int ret = flush(abs_step_clock - Stepcompress.CLOCK_DIFF_MAX + 1);
                if (ret != 0)
                {
                    return(ret);
                }

                if (abs_step_clock >= last_step_clock + Stepcompress.CLOCK_DIFF_MAX)
                {
                    return(flush_far(abs_step_clock));
                }
            }

            if (queue_next - queue_pos > 65535 + 2000)
            {
                // No point in keeping more than 64K steps in memory
                uint flush = *(queue_next - 65535) - (uint)last_step_clock;
                int  ret   = this.flush(last_step_clock + flush);
                if (ret != 0)
                {
                    return(ret);
                }
            }

            if (queue_next >= queue_end)
            {
                // Make room in the queue
                long in_use = queue_next - queue_pos;
                if (queue_pos > queue)
                {
                    // Shuffle the internal queue to avoid having to allocate more ram
                    Stepcompress.memmove(queue, queue_pos, in_use * sizeof(uint));
                }
                else
                {
                    // Expand the internal queue of step times
                    long alloc = queue_end - queue;
                    if (alloc == 0)
                    {
                        alloc = Stepcompress.QUEUE_START_SIZE;
                    }
                    while (in_use >= alloc)
                    {
                        alloc *= 2;
                    }
                    queue     = (uint *)Stepcompress.realloc(queue, alloc * sizeof(uint));
                    queue_end = queue + alloc;
                }
                queue_pos  = queue;
                queue_next = queue + in_use;
            }

            *queue_next++ = (uint)abs_step_clock;
            return(0);
        }