mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1076 lines
20 KiB
1076 lines
20 KiB
#include <pch.cxx>
|
|
|
|
#define _NTAPI_ULIB_
|
|
#define _IFSUTIL_MEMBER_
|
|
|
|
#include "ulib.hxx"
|
|
#include "ifsutil.hxx"
|
|
|
|
#include "numset.hxx"
|
|
#include "iterator.hxx"
|
|
|
|
DEFINE_EXPORTED_CONSTRUCTOR( NUMBER_SET, OBJECT, IFSUTIL_EXPORT );
|
|
|
|
DEFINE_CONSTRUCTOR( NUMBER_EXTENT, OBJECT );
|
|
|
|
VOID
|
|
NUMBER_SET::Construct (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor for NUMBER_SET.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
_card = 0;
|
|
_iterator = NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
NUMBER_SET::Destroy(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the NUMBER_SET to its initial state.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
_list.DeleteAllMembers();
|
|
_card = 0;
|
|
DELETE(_iterator);
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
NUMBER_SET::~NUMBER_SET(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor for NUMBER_SET.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::Initialize(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the stack for new input.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
Destroy();
|
|
|
|
if (!_list.Initialize() ||
|
|
!(_iterator = _list.QueryIterator())) {
|
|
|
|
Destroy();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::Add(
|
|
IN BIG_INT Number
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds 'Number' to the set.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number to add to the set.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
PNUMBER_EXTENT p, pn;
|
|
PNUMBER_EXTENT new_extent;
|
|
BIG_INT next;
|
|
|
|
DebugAssert(_iterator);
|
|
|
|
_iterator->Reset();
|
|
while (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
|
|
if (p->Start <= Number) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (p) {
|
|
|
|
next = p->Start + p->Length;
|
|
|
|
if (Number < next) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (Number == next) {
|
|
|
|
p->Length += 1;
|
|
_card += 1;
|
|
|
|
if (pn = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
|
|
if (pn->Start == Number + 1) {
|
|
|
|
p->Length += pn->Length;
|
|
pn = (PNUMBER_EXTENT) _list.Remove(_iterator);
|
|
DELETE(pn);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
|
|
if (Number + 1 == p->Start) {
|
|
|
|
p->Start = Number;
|
|
p->Length += 1;
|
|
_card += 1;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (!(new_extent = NEW NUMBER_EXTENT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
new_extent->Start = Number;
|
|
new_extent->Length = 1;
|
|
|
|
if (!_list.Insert(new_extent, _iterator)) {
|
|
DELETE(new_extent);
|
|
return FALSE;
|
|
}
|
|
|
|
_card += 1;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::AddStart(
|
|
IN BIG_INT Number
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds 'Number' to the set. Call this routine once before calling
|
|
AddNext.
|
|
|
|
NOTE: Do not insert other calls of this class in between AddStart and AddNext.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number to add to the set.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
PNUMBER_EXTENT p, pn;
|
|
PNUMBER_EXTENT new_extent;
|
|
BIG_INT next;
|
|
|
|
DebugAssert(_iterator);
|
|
|
|
_iterator->Reset();
|
|
p = (PNUMBER_EXTENT) _iterator->GetPrevious();
|
|
|
|
while (p != NULL) {
|
|
if (p->Start <= Number) {
|
|
next = p->Start + p->Length;
|
|
|
|
// if within range, then done
|
|
if (Number < next)
|
|
return TRUE;
|
|
|
|
// if passed the range by 1, try to expand the range to include it
|
|
if (Number == next) {
|
|
p->Length += 1;
|
|
_card += 1;
|
|
// see if the next range can be merged with the expanded range
|
|
if (pn = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
if (pn->Start == Number + 1) {
|
|
p->Length += pn->Length;
|
|
pn = (PNUMBER_EXTENT) _list.Remove(_iterator);
|
|
DELETE(pn);
|
|
}
|
|
}
|
|
p = (PNUMBER_EXTENT)_iterator->GetPrevious();
|
|
return TRUE;
|
|
}
|
|
|
|
// if less than the next range by 1, try to expand the range to
|
|
// include it. There won't be a merge as there must be more than
|
|
// one hole in between the two ranges
|
|
if (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
if (p->Start <= Number)
|
|
continue;
|
|
if ((Number+1) == p->Start) {
|
|
p->Start = Number;
|
|
p->Length += 1;
|
|
_card += 1;
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
} else {
|
|
// search backwards
|
|
p = (PNUMBER_EXTENT) _iterator->GetPrevious();
|
|
if (p == NULL) {
|
|
p = (PNUMBER_EXTENT) _iterator->GetNext();
|
|
DebugAssert(p);
|
|
if (p && ((Number+1) == p->Start)) {
|
|
p->Start = Number;
|
|
p->Length += 1;
|
|
_card += 1;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(new_extent = NEW NUMBER_EXTENT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
new_extent->Start = Number;
|
|
new_extent->Length = 1;
|
|
|
|
if (!_list.Insert(new_extent, _iterator)) {
|
|
DELETE(new_extent);
|
|
return FALSE;
|
|
}
|
|
|
|
_card += 1;
|
|
|
|
p = (PNUMBER_EXTENT) _iterator->GetPrevious();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::AddNext(
|
|
IN BIG_INT Number
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds 'Number' to the set. Call this routine after calling
|
|
AddStart once. This routine differs from Add ni the sense that it searches
|
|
through each of the subset from where it last added instead of starting
|
|
backwards like Add does.
|
|
|
|
NOTE: Do not insert any other call of this class in between two AddNext calls.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number to add to the set.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
PNUMBER_EXTENT p, pn;
|
|
PNUMBER_EXTENT new_extent;
|
|
BIG_INT next;
|
|
|
|
DebugAssert(_iterator);
|
|
|
|
if (!(p = (PNUMBER_EXTENT) _iterator->GetCurrent())) {
|
|
_iterator->Reset();
|
|
p = (PNUMBER_EXTENT) _iterator->GetPrevious();
|
|
}
|
|
|
|
while (p != NULL) {
|
|
if (p->Start <= Number) {
|
|
next = p->Start + p->Length;
|
|
|
|
// if within range, then done
|
|
if (Number < next)
|
|
return TRUE;
|
|
|
|
// if passed the range by 1, try to expand the range to include it
|
|
if (Number == next) {
|
|
p->Length += 1;
|
|
_card += 1;
|
|
// see if the next range can be merged with the expanded range
|
|
if (pn = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
if (pn->Start == Number + 1) {
|
|
p->Length += pn->Length;
|
|
pn = (PNUMBER_EXTENT) _list.Remove(_iterator);
|
|
DELETE(pn);
|
|
}
|
|
}
|
|
p = (PNUMBER_EXTENT)_iterator->GetPrevious();
|
|
return TRUE;
|
|
}
|
|
|
|
// if less than the next range by 1, try to expand the range to
|
|
// include it. There won't be a merge as there must be more than
|
|
// one hole in between the two ranges
|
|
if (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
if (p->Start <= Number)
|
|
continue;
|
|
if ((Number+1) == p->Start) {
|
|
p->Start = Number;
|
|
p->Length += 1;
|
|
_card += 1;
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
} else {
|
|
// search backwards
|
|
p = (PNUMBER_EXTENT) _iterator->GetPrevious();
|
|
if (p == NULL) {
|
|
p = (PNUMBER_EXTENT) _iterator->GetNext();
|
|
DebugAssert(p);
|
|
if (p && ((Number+1) == p->Start)) {
|
|
p->Start = Number;
|
|
p->Length += 1;
|
|
_card += 1;
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(new_extent = NEW NUMBER_EXTENT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
new_extent->Start = Number;
|
|
new_extent->Length = 1;
|
|
|
|
if (!_list.Insert(new_extent, _iterator)) {
|
|
DELETE(new_extent);
|
|
return FALSE;
|
|
}
|
|
|
|
_card += 1;
|
|
|
|
p = (PNUMBER_EXTENT) _iterator->GetPrevious();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::Add(
|
|
IN BIG_INT Start,
|
|
IN BIG_INT Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds the range of numbers to the set.
|
|
|
|
Arguments:
|
|
|
|
Start - Supplies the first number to add to the set.
|
|
Length - Supplies the length of the run to add.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
BIG_INT i, sup;
|
|
BOOLEAN r;
|
|
|
|
sup = Start + Length;
|
|
|
|
r = TRUE;
|
|
for (i = Start; i < sup; i += 1) {
|
|
r = Add(i) && r;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::Add(
|
|
IN PCNUMBER_SET NumberSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds all of the elements in the given number set to
|
|
this one.
|
|
|
|
Arguments:
|
|
|
|
NumberSet - Supplies the numbers to add.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
ULONG i, n;
|
|
BIG_INT s, l;
|
|
|
|
n = NumberSet->QueryNumDisjointRanges();
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
NumberSet->QueryDisjointRange(i, &s, &l);
|
|
|
|
if (!Add(s, l)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::CheckAndAdd(
|
|
IN BIG_INT Number,
|
|
OUT PBOOLEAN Duplicate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds 'Number' to the set.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number to add to the set.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
PNUMBER_EXTENT p, pn;
|
|
PNUMBER_EXTENT new_extent;
|
|
BIG_INT next;
|
|
|
|
DebugAssert(_iterator);
|
|
DebugAssert(Duplicate);
|
|
|
|
*Duplicate = FALSE;
|
|
|
|
_iterator->Reset();
|
|
while (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
|
|
if (p->Start <= Number) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (p) {
|
|
|
|
next = p->Start + p->Length;
|
|
|
|
if (Number < next) {
|
|
*Duplicate = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
if (Number == next) {
|
|
|
|
p->Length += 1;
|
|
_card += 1;
|
|
|
|
if (pn = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
|
|
if (pn->Start == Number + 1) {
|
|
|
|
p->Length += pn->Length;
|
|
pn = (PNUMBER_EXTENT) _list.Remove(_iterator);
|
|
DELETE(pn);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
|
|
if (Number + 1 == p->Start) {
|
|
|
|
p->Start = Number;
|
|
p->Length += 1;
|
|
_card += 1;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (!(new_extent = NEW NUMBER_EXTENT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
new_extent->Start = Number;
|
|
new_extent->Length = 1;
|
|
|
|
if (!_list.Insert(new_extent, _iterator)) {
|
|
DELETE(new_extent);
|
|
return FALSE;
|
|
}
|
|
|
|
_card += 1;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::Remove(
|
|
IN BIG_INT Number
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes a number from the number set.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number to remove.
|
|
|
|
Routine Description:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
PNUMBER_EXTENT p;
|
|
PNUMBER_EXTENT new_extent;
|
|
BIG_INT next, new_length;
|
|
|
|
DebugAssert(_iterator);
|
|
|
|
_iterator->Reset();
|
|
while (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
if (p->Start > Number) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
|
|
|
|
next = p->Start + p->Length;
|
|
|
|
if (p->Start == Number) {
|
|
p->Start += 1;
|
|
p->Length -= 1;
|
|
_card -= 1;
|
|
|
|
if (p->Length == 0) {
|
|
p = (PNUMBER_EXTENT) _list.Remove(_iterator);
|
|
DELETE(p);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (Number + 1 == next) {
|
|
p->Length -= 1;
|
|
_card -= 1;
|
|
return TRUE;
|
|
}
|
|
|
|
if (Number < next) {
|
|
|
|
if (!(new_extent = NEW NUMBER_EXTENT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
_iterator->GetNext();
|
|
|
|
if (!_list.Insert(new_extent, _iterator)) {
|
|
DELETE(new_extent);
|
|
return FALSE;
|
|
}
|
|
|
|
new_length = Number - p->Start;
|
|
|
|
new_extent->Start = Number + 1;
|
|
new_extent->Length = p->Length - 1 - new_length;
|
|
|
|
p->Length = new_length;
|
|
|
|
_card -= 1;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::RemoveAll(
|
|
)
|
|
{
|
|
PNUMBER_EXTENT p;
|
|
|
|
DebugAssert(_iterator);
|
|
|
|
_iterator->Reset();
|
|
if ((p = (PNUMBER_EXTENT) _iterator->GetNext()))
|
|
do {
|
|
p = (PNUMBER_EXTENT) _list.Remove(_iterator);
|
|
DELETE(p);
|
|
} while ((p=(PNUMBER_EXTENT)_iterator->GetCurrent()));
|
|
_card = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::CheckAndRemove(
|
|
IN BIG_INT Number,
|
|
OUT PBOOLEAN DoesExists
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes a number from the number set.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number to remove.
|
|
DoesExists - TRUE if Number was found in the set
|
|
|
|
Routine Description:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
PNUMBER_EXTENT p;
|
|
PNUMBER_EXTENT new_extent;
|
|
BIG_INT next, new_length;
|
|
|
|
DebugAssert(_iterator);
|
|
DebugAssert(DoesExists);
|
|
|
|
*DoesExists = FALSE;
|
|
|
|
_iterator->Reset();
|
|
while (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
if (p->Start > Number) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
|
|
|
|
next = p->Start + p->Length;
|
|
|
|
if (p->Start == Number) {
|
|
p->Start += 1;
|
|
p->Length -= 1;
|
|
_card -= 1;
|
|
*DoesExists = TRUE;
|
|
|
|
if (p->Length == 0) {
|
|
p = (PNUMBER_EXTENT) _list.Remove(_iterator);
|
|
DELETE(p);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (Number + 1 == next) {
|
|
p->Length -= 1;
|
|
_card -= 1;
|
|
*DoesExists = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
if (Number < next) {
|
|
|
|
if (!(new_extent = NEW NUMBER_EXTENT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
_iterator->GetNext();
|
|
|
|
if (!_list.Insert(new_extent, _iterator)) {
|
|
DELETE(new_extent);
|
|
return FALSE;
|
|
}
|
|
|
|
new_length = Number - p->Start;
|
|
|
|
new_extent->Start = Number + 1;
|
|
new_extent->Length = p->Length - 1 - new_length;
|
|
|
|
p->Length = new_length;
|
|
|
|
_card -= 1;
|
|
*DoesExists = TRUE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::Remove(
|
|
IN BIG_INT Start,
|
|
IN BIG_INT Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes the given range from the number set.
|
|
|
|
Arguments:
|
|
|
|
Start - Supplies the beginning of the range.
|
|
Length - Supplies the length of the range.
|
|
|
|
Routine Description:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
BIG_INT i, sup;
|
|
BOOLEAN r;
|
|
|
|
sup = Start + Length;
|
|
|
|
r = TRUE;
|
|
for (i = Start; i < sup; i += 1) {
|
|
r = Remove(i) && r;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::Remove(
|
|
IN PCNUMBER_SET NumberSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes all of the elements in the given number set from
|
|
this one.
|
|
|
|
Arguments:
|
|
|
|
NumberSet - Supplies the numbers to remove.
|
|
|
|
Return Value:
|
|
|
|
FALSE - Failure.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
ULONG i, n;
|
|
BIG_INT s, l;
|
|
|
|
n = NumberSet->QueryNumDisjointRanges();
|
|
for (i = 0; i < n; i++) {
|
|
|
|
NumberSet->QueryDisjointRange(i, &s, &l);
|
|
|
|
if (!Remove(s, l)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
BIG_INT
|
|
NUMBER_SET::QueryNumber(
|
|
IN BIG_INT Index
|
|
) CONST
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the Nth number contained in this set.
|
|
|
|
Arguments:
|
|
|
|
Index - Supplies a zero-based index into the ordered set.
|
|
|
|
Return Value:
|
|
|
|
The Nth number in this set.
|
|
|
|
--*/
|
|
{
|
|
PNUMBER_EXTENT p;
|
|
BIG_INT r;
|
|
BIG_INT count;
|
|
|
|
DebugAssert(Index < _card);
|
|
|
|
_iterator->Reset();
|
|
count = 0;
|
|
while (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
|
|
count += p->Length;
|
|
|
|
if (count > Index) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
DebugAssert(p);
|
|
|
|
return p->Start + Index - (count - p->Length);
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::DoesIntersectSet(
|
|
IN BIG_INT Start,
|
|
IN BIG_INT Length
|
|
) CONST
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine computes whether or not the range specified intersects
|
|
the current number set. This routine will return FALSE if the
|
|
intersection is empty, TRUE otherwise.
|
|
|
|
Arguments:
|
|
|
|
Start - Supplies the start of the range.
|
|
Length - Supplies the length of the range.
|
|
|
|
Return Value:
|
|
|
|
FALSE - The specified range does not intersect the number set.
|
|
TRUE - The specified range makes a non-empty intersection with
|
|
the number set.
|
|
|
|
--*/
|
|
{
|
|
PNUMBER_EXTENT p;
|
|
BIG_INT pnext, next;
|
|
|
|
DebugAssert(_iterator);
|
|
|
|
if (Length == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
next = Start + Length;
|
|
|
|
_iterator->Reset();
|
|
while (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
|
|
|
|
pnext = p->Start + p->Length;
|
|
|
|
if (Start >= p->Start) {
|
|
|
|
if (Start < pnext) {
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
|
|
if (next > p->Start) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
VOID
|
|
NUMBER_SET::QueryDisjointRange(
|
|
IN ULONG Index,
|
|
OUT PBIG_INT Start,
|
|
OUT PBIG_INT Length
|
|
) CONST
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the 'Index'th disjoint range. (This is zero
|
|
based).
|
|
|
|
Arguments:
|
|
|
|
Index - Supplies the index of the disjoint range.
|
|
Start - Returns the start of the disjoint range.
|
|
Length - Returns the length of the disjoint range.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
PNUMBER_EXTENT p;
|
|
|
|
DebugAssert(_iterator);
|
|
|
|
_iterator->Reset();
|
|
for (i = 0; i <= Index; i++) {
|
|
p = (PNUMBER_EXTENT) _iterator->GetNext();
|
|
}
|
|
|
|
DebugAssert(p);
|
|
DebugAssert(Start);
|
|
DebugAssert(Length);
|
|
|
|
*Start = p->Start;
|
|
*Length = p->Length;
|
|
}
|
|
|
|
|
|
IFSUTIL_EXPORT
|
|
BOOLEAN
|
|
NUMBER_SET::QueryContainingRange(
|
|
IN BIG_INT Number,
|
|
OUT PBIG_INT Start,
|
|
OUT PBIG_INT Length
|
|
) CONST
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the range that contains the given number.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number.
|
|
Start - Returns the start of the range.
|
|
Length - Returns the length of the range.
|
|
|
|
Return Value:
|
|
|
|
FALSE - The given number was not in the set.
|
|
TRUE - Success.
|
|
|
|
--*/
|
|
{
|
|
PNUMBER_EXTENT p;
|
|
|
|
DebugAssert(_iterator);
|
|
|
|
_iterator->Reset();
|
|
while (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
|
|
if (p->Start <= Number) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!p || Number >= p->Start + p->Length) {
|
|
return FALSE;
|
|
}
|
|
|
|
*Start = p->Start;
|
|
*Length = p->Length;
|
|
|
|
return TRUE;
|
|
}
|