//
// aegis - project change supervisor
// Copyright (C) 1991-2014 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include
#include
#include
#include
//
// NAME
// interval_valid - internal consistency check
//
// SYNOPSIS
// int interval_valid(interval *ip);
//
// DESCRIPTION
// The interval_valid function is used to check the internal
// consistency of an interval.
//
// ARGUMENTS
// ip - pointer to interval to check
//
// RETURNS
// int 1 if interval is valid
// 0 if interval is not valid
//
// CAVEAT
// This function is only available if DEBUG is defined,
// and is intended for use in assert() statements.
//
#ifdef DEBUG
bool
interval::valid(void)
const
{
if (length > size)
return false;
if (length & 1)
return false;
if (size == 0 && data == 0)
return (length == 0);
if ((size_t)data[length] != length)
return false;
for (size_t j = 1; j < length; ++j)
if (data[j - 1] >= data[j])
return false;
return true;
}
#endif
//
// NAME
// interval_create_empty - create an empty interval
//
// SYNOPSIS
// interval *interval_create_empty(void);
//
// DESCRIPTION
// The interval_create_empty function is used to create
// an empty interval.
//
// RETURNS
// a pointer to the new interval in dynamic memory
//
// CAVEAT
// It is the responsibility of the caller to release the
// interval to dynamic memory when no longer required.
// Use the interval_free function for this purpose.
//
interval::interval() :
length(0),
size(0),
scan_index(0),
scan_next_datum(0),
data(0)
{
trace(("interval()\n"));
assert(valid());
}
//
// NAME
// interval_free - release interval memory
//
// SYNOPSIS
// void interval_free(interval *ip);
//
// DESCRIPTION
// The interval_free function is used to release the dynamic
// memory used by an interval back to the dynamic memory pool.
//
// ARGUMENTS
// ip - the interval to release
//
interval::~interval()
{
trace(("~interval()\n"));
clear();
}
void
interval::clear(void)
{
assert(valid());
delete [] data;
length = 0;
size = 0;
scan_index = 0;
scan_next_datum = 0;
data = 0;
assert(valid());
}
//
// NAME
// interval_create_range - create a single range interval
//
// SYNOPSIS
// interval *interval_create_range(interval_data_ty first,
// interval_data_ty last);
//
// DESCRIPTION
// The interval_create_range function is used to create an interval
// consisting of a single range, from first to last inclusive.
//
// ARGUMENTS
// first - the start of the range
// last - the end of the range (inclusive)
//
// RETURNS
// a pointer to the new interval in dynamic memory
//
// CAVEAT
// It is the responsibility of the caller to release the
// interval to dynamic memory when no longer required.
// Use the interval_free function for this purpose.
//
interval::interval(data_t a_first, data_t a_last) :
length(2),
size(2),
scan_index(0),
scan_next_datum(0),
data(new data_t[3])
{
trace(("interval(%ld, %ld)\n", a_first, a_last));
data[0] = a_first;
data[1] = a_last + 1;
data[2] = 2;
assert(valid());
}
interval::interval(data_t n) :
length(2),
size(2),
scan_index(0),
scan_next_datum(0),
data(new data_t[3])
{
trace(("interval(%ld)\n", n));
data[0] = n;
data[1] = n + 1;
data[2] = 2;
assert(valid());
}
interval::interval(const interval &rhs) :
length(0),
size(0),
scan_index(0),
scan_next_datum(0),
data(0)
{
trace(("interval()\n"));
if (!rhs.empty())
{
for (;;)
{
size = size * 2 + 8;
if (rhs.length <= size)
break;
}
data = new data_t [size + 1];
length = rhs.length;
for (size_t j = 0; j < length; ++j)
data[j] = rhs.data[j];
data[length] = length;
}
assert(valid());
}
interval &
interval::operator=(const interval &rhs)
{
if (this != &rhs)
{
if (rhs.empty())
clear();
else
{
if (rhs.length > size)
{
for (;;)
{
size = size * 2 + 8;
if (rhs.length <= size)
break;
}
delete [] data;
data = new data_t [size + 1];
}
length = rhs.length;
for (size_t j = 0; j < length; ++j)
data[j] = rhs.data[j];
data[length] = length;
}
}
return *this;
}
//
// NAME
// append - append datum to interval data
//
// SYNOPSIS
// void append(interval **ipp, interval_data_ty datum);
//
// DESCRIPTION
// The append function is used to append a datum to
// the end of an interval under construction.
//
// ARGUMENTS
// ipp - pointer to inerval pointer.
// datum - value to append.
//
// CAVEAT
// The interval may move in dynamic memory, with is why ** is used.
// The interval will need to be normalized before you
// next use interval_valid.
//
void
interval::append(data_t datum)
{
//
// should always be increasing
//
trace(("interval::append()\n{\n"));
assert(length < 1 || datum >= data[length - 1]);
//
// make it larger if necessary
//
if (length >= size)
{
size = size * 2 + 8;
data_t *new_data = new data_t [size + 1];
for (size_t j = 0; j < length; ++j)
new_data[j] = data[j];
delete [] data;
data = new_data;
}
//
// remeber the datum
//
data[length++] = datum;
//
// elide empty sequences
//
if (length >= 2 && data[length - 1] == data[length - 2])
length -= 2;
// NOTE: this may produce an invalid interval. This method shall
// always be balled an even number of times.
trace(("}\n"));
}
//
// NAME
// normalize - clean up after append
//
// SYNOPSIS
// void normalize(interval **);
//
// DESCRIPTION
// The normalize function is used to clean up after
// the append function.
//
// ARGUMENTS
// ipp - pointer to interval to normalize
//
// CAVEAT
// The interval may move in dynamic memory, with is why ** is used.
//
void
interval::normalize(void)
{
trace(("interval::normalize()\n{\n"));
if (length == 0)
{
assert(!size == !data);
if (data)
{
delete [] data;
size = 0;
}
}
else
{
data[length] = length;
}
assert(valid());
trace(("}\n"));
}
//
// NAME
// interval_union - union of two intervals
//
// SYNOPSIS
// interval *interval_union(interval *left, interval *right);
//
// DESCRIPTION
// The interval_union function is used to form the
// union of two intervals.
//
// ARGUMENTS
// left - interval to be unioned with
// right - another interval
//
// RETURNS
// a pointer to the new interval in dynamic memory
//
// CAVEAT
// It is the responsibility of the caller to release the
// interval to dynamic memory when no longer required.
// Use the interval_free function for this purpose.
//
interval
interval::operator+(const interval &rhs)
const
{
trace(("interval::operator+()\n{\n"));
data_t place;
assert(valid());
assert(rhs.valid());
interval result;
size_t left_pos = 0;
size_t right_pos = 0;
int count = 0;
for (;;)
{
int old_count = count;
if (left_pos < length)
{
if (right_pos < rhs.length)
{
if (data[left_pos] < rhs.data[right_pos])
{
count += ((left_pos & 1) ? -1 : 1);
place = data[left_pos++];
}
else
{
count += (right_pos & 1 ? -1 : 1);
place = rhs.data[right_pos++];
}
}
else
{
count += ((left_pos & 1) ? -1 : 1);
place = data[left_pos++];
}
}
else
{
if (right_pos < rhs.length)
{
count += ((right_pos & 1) ? -1 : 1);
place = rhs.data[right_pos++];
}
else
break;
}
if ((count >= 1) != (old_count >= 1))
result.append(place);
}
result.normalize();
trace(("}\n"));
return result;
}
void
interval::operator+=(const interval &rhs)
{
interval i = *this + rhs;
*this = i;
}
//
// NAME
// interval_intersection - intersection of two intervals
//
// SYNOPSIS
// interval *interval_intersection(interval *left,
// interval *right);
//
// DESCRIPTION
// The interval_intersection function is used to form the
// intersection of two intervals.
//
// ARGUMENTS
// left - interval to be intersected with
// right - another interval
//
// RETURNS
// a pointer to the new interval in dynamic memory
//
// CAVEAT
// It is the responsibility of the caller to release the
// interval to dynamic memory when no longer required.
// Use the interval_free function for this purpose.
//
interval
interval::operator*(const interval &rhs)
const
{
trace(("interval::operator*()\n{\n"));
assert(valid());
assert(rhs.valid());
interval result;
size_t left_pos = 0;
size_t right_pos = 0;
int count = 0;
for (;;)
{
data_t place;
int old_count = count;
if (left_pos < length)
{
if (right_pos < rhs.length)
{
if (data[left_pos] < rhs.data[right_pos])
{
count += ((left_pos & 1) ? -1 : 1);
place = data[left_pos++];
}
else
{
count += ((right_pos & 1) ? -1 : 1);
place = rhs.data[right_pos++];
}
}
else
{
count += ((left_pos & 1) ? -1 : 1);
place = data[left_pos++];
}
}
else
{
if (right_pos < rhs.length)
{
count += ((right_pos & 1) ? -1 : 1);
place = rhs.data[right_pos++];
}
else
break;
}
if ((count >= 2) != (old_count >= 2))
result.append(place);
}
result.normalize();
assert(result.valid());
trace(("}\n"));
return result;
}
void
interval::operator*=(const interval &rhs)
{
interval i = *this * rhs;
*this = i;
}
//
// NAME
// interval_difference - difference of two intervals
//
// SYNOPSIS
// interval *interval_difference(interval *left, interval *right);
//
// DESCRIPTION
// The interval_difference function is used to form the
// difference of two intervals.
//
// ARGUMENTS
// left - interval to take things out of
// right - things to take out of it
//
// RETURNS
// a pointer to the new interval in dynamic memory
//
// CAVEAT
// It is the responsibility of the caller to release the
// interval to dynamic memory when no longer required.
// Use the interval_free function for this purpose.
//
interval
interval::operator-(const interval &rhs)
const
{
trace(("interval::operator-()\n{\n"));
assert(valid());
assert(rhs.valid());
interval result;
size_t left_pos = 0;
size_t right_pos = 0;
int count = 0;
for (;;)
{
data_t place;
int old_count = count;
if (left_pos < length)
{
if (right_pos < rhs.length)
{
if (data[left_pos] < rhs.data[right_pos])
{
count += ((left_pos & 1) ? -1 : 1);
place = data[left_pos++];
}
else
{
count -= ((right_pos & 1) ? -1 : 1);
place = rhs.data[right_pos++];
}
}
else
{
count += ((left_pos & 1) ? -1 : 1);
place = data[left_pos++];
}
}
else
{
if (right_pos < rhs.length)
{
count -= ((right_pos & 1) ? -1 : 1);
place = rhs.data[right_pos++];
}
else
break;
}
if ((count >= 1) != (old_count >= 1))
result.append(place);
}
result.normalize();
trace(("}\n"));
return result;
}
void
interval::operator-=(const interval &rhs)
{
interval i = *this - rhs;
*this = i;
}
//
// NAME
// interval_member - test for membership
//
// SYNOPSIS
// int interval_member(interval *, interval_data_ty datum);
//
// DESCRIPTION
// The interval_member function is used to test if a particular
// datum is included in an interval.
//
// ARGUMENTS
// ip - interval to test
// datum - value to test for
//
// RETURNS
// int 1 if is a member
// 0 if is not a member
//
bool
interval::member(data_t datum)
const
{
trace(("interval::member(this = %p, datum = %ld)\n{\n",
this, (long)datum));
assert(valid());
size_t min = 0;
size_t max = length - 2;
while (min <= max)
{
size_t mid = ((min + max) / 2) & ~1;
if (data[mid] <= datum && datum < data[mid + 1])
{
trace(("return true;\n"));
trace(("}\n"));
return true;
}
if (data[mid] < datum)
min = mid + 2;
else
max = mid - 2;
}
trace(("return false;\n"));
trace(("}\n"));
return false;
}
//
// NAME
// interval_scan_begin
//
// SYNOPSIS
// void interval_scan_begin(interval *ip);
//
// DESCRIPTION
// The interval_scan_begin function is used to
// start traversing every datum in the interval.
//
// ARGUMENTS
// ip - interval to scan
//
void
interval::scan_begin(void)
{
assert(valid());
assert(!scan_index);
scan_index = 1;
if (length)
scan_next_datum = data[0];
else
scan_next_datum = 0;
}
//
// NAME
// interval_scan_next
//
// SYNOPSIS
// int interval_scan_next(interval *ip, interval_data_ty *datum);
//
// DESCRIPTION
// The interval_scan_next function is used to
// traverse every datum in the interval.
//
// ARGUMENTS
// ip - interval to scan
// datum - pointer to where to place datum
//
// RETURNS
// int 1 if datum available
// 0 if reached end of interval
//
bool
interval::scan_next(data_t &datum)
{
assert(valid());
assert(scan_index & 1);
if (scan_index >= length)
return false;
if (scan_next_datum >= data[scan_index])
{
scan_index += 2;
if (scan_index >= length)
return false;
scan_next_datum = data[scan_index - 1];
}
datum = scan_next_datum++;
return true;
}
//
// NAME
// interval_scan_end
//
// SYNOPSIS
// void interval_scan_end(interval *ip);
//
// DESCRIPTION
// The interval_scan_end function is used to
// finish traversing every datum in the interval.
//
// ARGUMENTS
// ip - interval to scan
//
void
interval::scan_end(void)
{
assert(valid());
assert(scan_index & 1);
scan_index = 0;
scan_next_datum = 0;
}
interval::data_t
interval::first(void)
const
{
assert(valid());
assert(!empty());
return data[0];
}
interval::data_t
interval::last(void)
const
{
assert(valid());
assert(!empty());
return (data[length - 1] - 1);
}
interval::data_t
interval::second_last(void)
const
{
assert(valid());
assert(!empty());
return data[length - 2];
}
// vim: set ts=8 sw=4 et :