//
// srecord - manipulate eprom load files
// Copyright (C) 1998-2000, 2002, 2004-2007 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
using namespace std;
//
// NAME
// interval_create_empty - create an empty interval
//
// SYNOPSIS
// interval_ty *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;
// assert(valid());
}
static inline interval::data64_t
promote(interval::data_t datum, size_t pos)
{
if (datum == 0 && (pos & 1))
return ((interval::data64_t)1 << 32);
return datum;
}
//
// NAME
// interval_create_range - create a single range interval
//
// SYNOPSIS
// interval_ty *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 first, data_t last)
{
length = 2;
size = 8;
data = new data_t[size + 1];
scan_index = 0;
scan_next_datum = 0;
if (first <= promote(last, 1))
{
data[0] = first;
data[1] = last;
}
else
{
data[0] = last;
data[1] = first;
}
data[2] = 2;
// assert(valid());
}
interval::interval(data_t first)
{
length = 2;
size = 8;
data = new data_t[size + 1];
scan_index = 0;
scan_next_datum = 0;
data[0] = first;
data[1] = first + 1;
data[2] = 2;
// assert(valid());
}
interval::interval(const interval &arg)
{
// assert(arg.valid());
length = arg.length;
size = length;
scan_index = 0;
scan_next_datum = 0;
if (size)
{
data = new data_t[size + 1];
for (size_t j = 0; j <= length; ++j)
data[j] = arg.data[j];
}
else
data = 0;
// assert(valid());
}
interval &
interval::operator=(const interval &arg)
{
if (this != &arg)
{
if (data)
{
delete [] data;
data = 0;
}
// assert(arg.valid());
length = arg.length;
size = length;
scan_index = 0;
scan_next_datum = 0;
if (size)
{
data = new data_t[size + 1];
for (size_t j = 0; j <= length; ++j)
data[j] = arg.data[j];
}
else
data = 0;
// assert(valid());
}
return *this;
}
//
// NAME
// interval_free - release interval memory
//
// SYNOPSIS
// void interval_free(interval_ty *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()
{
// assert(valid());
if (data)
{
delete [] data;
data = 0;
}
}
//
// NAME
// interval_valid - internal consistency check
//
// SYNOPSIS
// int interval_valid(interval_ty *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.
//
bool
interval::valid()
const
{
if (length > size)
return false;
if (length & 1)
return false;
if ((size == 0) != (data == 0))
return false;
if (length == 0)
return true;
if (data[length] != length)
return false;
//
// As a special case, an upper bound of zero means
// positive infinity. It has to be the last one.
//
size_t max = length;
if (data[max - 1] == 0)
--max;
for (size_t j = 1; j < max; ++j)
if (data[j - 1] >= data[j])
return false;
return true;
}
//
// NAME
// append - append datum to interval data
//
// SYNOPSIS
// void append(interval_ty **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
//
// assert(length < 1 || promote(datum, length) >=
// promote(data[length - 1], length - 1));
//
// make it larger if necessary
//
if (length >= size)
{
size = size * 2 + 8;
data_t *tmp = new data_t[size + 1];
if (data)
{
for (size_t k = 0; k < length; ++k)
tmp[k] = data[k];
delete [] data;
}
data = tmp;
}
//
// remeber the datum
//
data[length++] = datum;
//
// elide empty sequences
//
// See the comment for the "data" instance variable; it is a
// series of [lo, hi) pairs.
//
// There are two cases here
// length is odd: [a, b) [b, ???) --> [a, ???)
// length is even: [a, a) --> {}
// Either way, discard the last two elements.
//
if (length >= 2 && data[length - 1] == data[length - 2])
length -= 2;
}
//
// NAME
// interval_union - union of two intervals
//
// SYNOPSIS
// interval_ty *interval_union(interval_ty *left, interval_ty *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::union_(const interval &left, const interval &right)
{
// assert(left.valid());
// assert(right.valid());
interval result;
size_t left_pos = 0;
size_t right_pos = 0;
int count = 0;
for (;;)
{
int old_count = count;
data_t place;
if (left_pos < left.length)
{
if (right_pos < right.length)
{
data64_t left_val = promote(left.data[left_pos], left_pos);
data64_t right_val = promote(right.data[right_pos], right_pos);
if (left_val < right_val)
{
count += (left_pos & 1 ? -1 : 1);
place = left.data[left_pos++];
}
else
{
count += (right_pos & 1 ? -1 : 1);
place = right.data[right_pos++];
}
}
else
{
count += (left_pos & 1 ? -1 : 1);
place = left.data[left_pos++];
}
}
else
{
if (right_pos < right.length)
{
count += (right_pos & 1 ? -1 : 1);
place = right.data[right_pos++];
}
else
break;
}
if ((count >= 1) != (old_count >= 1))
result.append(place);
}
if (result.length)
result.data[result.length] = result.length;
// assert(result.valid());
return result;
}
//
// NAME
// interval_intersection - intersection of two intervals
//
// SYNOPSIS
// interval_ty *interval_intersection(interval_ty *left,
// interval_ty *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::intersection(const interval &left, const interval &right)
{
// assert(left.valid());
// assert(right.valid());
interval result;
size_t left_pos = 0;
size_t right_pos = 0;
int count = 0;
for (;;)
{
int old_count = count;
data_t place;
if (left_pos < left.length)
{
if (right_pos < right.length)
{
data64_t left_val = promote(left.data[left_pos], left_pos);
data64_t right_val = promote(right.data[right_pos], right_pos);
if (left_val < right_val)
{
count += (left_pos & 1 ? -1 : 1);
place = left.data[left_pos++];
}
else
{
count += (right_pos & 1 ? -1 : 1);
place = right.data[right_pos++];
}
}
else
{
count += (left_pos & 1 ? -1 : 1);
place = left.data[left_pos++];
}
}
else
{
if (right_pos < right.length)
{
count += (right_pos & 1 ? -1 : 1);
place = right.data[right_pos++];
}
else
break;
}
if ((count >= 2) != (old_count >= 2))
result.append(place);
}
if (result.length)
result.data[result.length] = result.length;
// assert(result.valid());
return result;
}
//
// NAME
// interval_difference - difference of two intervals
//
// SYNOPSIS
// interval_ty *interval_difference(interval_ty *left, interval_ty *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::difference(const interval &left, const interval &right)
{
// assert(left.valid());
// assert(right.valid());
interval result;
size_t left_pos = 0;
size_t right_pos = 0;
int count = 0;
for (;;)
{
int old_count = count;
data_t place;
if (left_pos < left.length)
{
if (right_pos < right.length)
{
data64_t left_val = promote(left.data[left_pos], left_pos);
data64_t right_val = promote(right.data[right_pos], right_pos);
if (left_val < right_val)
{
count += (left_pos & 1 ? -1 : 1);
place = left.data[left_pos++];
}
else
{
count -= (right_pos & 1 ? -1 : 1);
place = right.data[right_pos++];
}
}
else
{
count += (left_pos & 1 ? -1 : 1);
place = left.data[left_pos++];
}
}
else
{
if (right_pos < right.length)
{
count -= (right_pos & 1 ? -1 : 1);
place = right.data[right_pos++];
}
else
break;
}
if ((count >= 1) != (old_count >= 1))
result.append(place);
}
if (result.length)
result.data[result.length] = result.length;
// assert(result.valid());
return result;
}
//
// NAME
// interval_member - test for membership
//
// SYNOPSIS
// int interval_member(interval_ty *, 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
{
if (length == 0)
return false;
// assert(valid());
long min = 0;
long max = length - 2;
while (min <= max)
{
long mid = ((min + max) / 2) & ~1;
data_t lo = data[mid];
data64_t hi = promote(data[mid + 1], mid + 1);
if (lo <= datum && datum < hi)
return true;
if (lo < datum)
min = mid + 2;
else
max = mid - 2;
}
return false;
}
//
// NAME
// interval_scan_begin
//
// SYNOPSIS
// void interval_scan_begin(interval_ty *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()
{
// 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_ty *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 >= promote(data[scan_index], 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_ty *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()
{
// assert(valid());
// assert(scan_index & 1);
scan_index = 0;
scan_next_datum = 0;
}
void
interval::first_interval_only()
{
// assert(valid());
if (length > 2)
{
length = 2;
data[length] = length;
}
}
bool
interval::empty()
const
{
return (length == 0);
}
bool
interval::equal(const interval &lhs, const interval &rhs)
{
if (lhs.length != rhs.length)
return false;
for (size_t j = 0; j < lhs.length; ++j)
if (lhs.data[j] != rhs.data[j])
return false;
return true;
}
interval::data_t
interval::get_lowest()
const
{
// assert(valid());
return (length > 0 ? data[0] : 0);
}
interval::data_t
interval::get_highest()
const
{
// assert(valid());
return (length > 0 ? data[length - 1] : 0);
}
void
interval::print(ostream &os)
const
{
if (length != 2)
os << "(";
for (size_t j = 0; j < length; j += 2)
{
if (j)
os << ", ";
os << data[j];
if (data[j] + 2 == data[j + 1])
os << ", " << data[j] + 1;
else if (data[j] + 1 != data[j + 1])
os << " - " << (data[j + 1] - 1);
}
if (length != 2)
os << ")";
}
static string
to_string(interval::data_t x)
{
int width = 4;
if (x >= 0x10000)
width += 2;
if (x >= 0x1000000)
width += 2;
char buffer[20];
snprintf(buffer, sizeof(buffer), "0x%0*lX", width, (unsigned long)x);
return buffer;
}
string
interval::representation()
const
{
string result;
result += '(';
for (size_t j = 0; j < length; j += 2)
{
if (j)
result += ", ";
result += to_string(data[j]);
if (data[j] + 2 == data[j + 1])
{
result += ", ";
result += to_string(data[j] + 1);
}
else if (data[j] + 1 != data[j + 1])
{
result += " - ";
result += to_string(data[j + 1] - 1);
}
}
result += ')';
return result;
}
interval
interval::pad(int mult)
const
{
if (mult < 2)
return *this;
interval result;
for (size_t j = 0; j < length; j += 2)
{
data_t lo = data[j];
lo = (lo / mult) * mult;
data_t hi = data[j + 1];
hi = ((hi + mult - 1) / mult) * mult;
result += interval(lo, hi);
}
return result;
}