Leaked source code of windows server 2003
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.
 
 
 
 
 
 

859 lines
25 KiB

//
// RANGE.CPP
//
// 2-20-96: (EricAn)
// Hacked from the Route66 source tree, eliminated stuff we don't use.
// Original copyright below - where did this thing come from?
//
// -*- C -*-
//
// Copyright 1992 Software Innovations, Inc.
//
// $Source: D:\CLASS\SOURCE\range.c-v $
// $Author: martin $
// $Date: 92/07/15 05:09:24 $
// $Revision: 1.1 $
//
//
#include "pch.hxx"
#include "range.h"
#include "rangetst.h"
// QUANTUM defines the number of m_rangeTable cells to be allocated at
// one time. Whenever the m_rangeTable becomes full, it is expanded
// by QUANTUM range cells. m_rangeTable's never shrink.
const int QUANTUM = 64;
inline int inRange(RangeType r, ULONG x) { return ((x>=r.low) && (x<=r.high)); };
CRangeList::CRangeList()
{
m_cRef = 1;
m_numRanges = 0;
m_rangeTableSize = 0;
m_rangeTable = NULL;
}
#if 0
/*
CRangeList::CRangeList(CRangeList& r)
{
m_numRanges = r.m_numRanges;
m_rangeTableSize = r.m_rangeTableSize;
m_rangeTable = new RangeType[m_rangeTableSize];
CopyMemory(m_rangeTable, r.m_rangeTable, m_numRanges * sizeof(RangeType));
}
*/
#endif
CRangeList::~CRangeList()
{
if (m_rangeTable)
MemFree(m_rangeTable);
}
ULONG CRangeList::AddRef(void)
{
return (ULONG)InterlockedIncrement((LPLONG)&m_cRef);
}
ULONG CRangeList::Release(void)
{
ULONG cRefT = (ULONG)InterlockedDecrement((LPLONG)&m_cRef);
if (cRefT == 0)
delete this;
return (cRefT);
}
BOOL CRangeList::IsInRange(const ULONG value) const
{
for (int i=0; i<m_numRanges; i++)
if (inRange(m_rangeTable[i], value))
return TRUE;
return FALSE;
}
ULONG CRangeList::MinOfRange(const ULONG value) const
{
if (RANGE_ERROR == value)
return RANGE_ERROR;
for (register int i=0; i<m_numRanges; i++)
if (inRange(m_rangeTable[i], value))
return m_rangeTable[i].low;
return RANGE_ERROR;
}
ULONG CRangeList::MaxOfRange(const ULONG value) const
{
if (RANGE_ERROR == value)
return RANGE_ERROR;
for (register int i=0; i<m_numRanges; i++)
if (inRange(m_rangeTable[i], value))
return m_rangeTable[i].high;
return RANGE_ERROR;
}
ULONG CRangeList::Max() const
{
if (m_numRanges==0)
return RANGE_ERROR;
return m_rangeTable[m_numRanges-1].high;
}
ULONG CRangeList::Min() const
{
if (m_numRanges==0)
return RANGE_ERROR;
return m_rangeTable[0].low;
}
BOOL CRangeList::Save(LPBYTE *const ppb, ULONG *const pcb) const
{
Assert(ppb);
Assert(pcb);
*pcb = m_numRanges * sizeof(RangeType);
if (*pcb)
{
if (!MemAlloc((LPVOID*)ppb, *pcb))
return FALSE;
CopyMemory(*ppb, m_rangeTable, *pcb);
}
else
*ppb = NULL;
return TRUE;
}
BOOL CRangeList::Load(const LPBYTE pb, const ULONG cb)
{
RangeType *pRangeTable;
Assert(pb != NULL);
Assert(cb > 0);
if (!MemAlloc((void **)&pRangeTable, cb))
return(FALSE);
m_numRanges = m_rangeTableSize = cb / sizeof(RangeType);
if (m_rangeTable)
MemFree(m_rangeTable);
CopyMemory(pRangeTable, pb, cb);
m_rangeTable = pRangeTable;
return TRUE;
}
BOOL CRangeList::NextLowerAntiRange(const ULONG value, RangeType *const rt) const
{
if (RANGE_ERROR == value || m_numRanges < 2 || !rt)
return FALSE;
for (register int i=0; i<m_numRanges; i++)
if (inRange(m_rangeTable[i], value))
{
if (0 == i)
return FALSE;
rt->high = m_rangeTable[i].low-1;
rt->low = m_rangeTable[i-1].high+1;
return TRUE;
}
return FALSE;
}
BOOL CRangeList::NextHigherAntiRange(const ULONG value, RangeType *const rt) const
{
if (RANGE_ERROR == value || m_numRanges < 2 || !rt)
return FALSE;
for (register int i=0; i<m_numRanges; i++)
if (inRange(m_rangeTable[i], value))
{
if (m_numRanges-1 == i)
return FALSE;
rt->low = m_rangeTable[i].high+1;
rt->high = m_rangeTable[i+1].low-1;
return TRUE;
}
return FALSE;
}
BOOL CRangeList::HighestAntiRange(RangeType *const rt) const
{
if (m_numRanges < 2 || !rt)
return FALSE;
rt->high = m_rangeTable[m_numRanges-1].low-1;
rt->low = m_rangeTable[m_numRanges-2].high+1;
return TRUE;
}
BOOL CRangeList::LowestAntiRange(RangeType *const rt) const
{
if (m_numRanges < 2 || !rt)
return FALSE;
rt->high = m_rangeTable[1].low-1;
rt->low = m_rangeTable[0].high+1;
return TRUE;
}
BOOL CRangeList::AddRange(const ULONG value)
{
RangeType r = { value, value };
return AddRange(r);
}
BOOL CRangeList::AddRange(const ULONG low, const ULONG high)
{
RangeType r = { low, high };
return AddRange(r);
}
BOOL CRangeList::AddRange(CRangeList& r)
{
for (int i=0 ; i<r.m_numRanges ; ++i)
if (!AddRange(r.m_rangeTable[i]))
return FALSE;
return TRUE;
}
BOOL CRangeList::AddRange(RangeType *rt, int count)
{
for (int i=0 ; i<count ; ++i)
if (!AddRange(rt[i]))
return FALSE;
return TRUE;
}
BOOL CRangeList::AddRange(const RangeType range)
{
int possibleLoc;
int insertPosition;
if (range.low > range.high)
{
DOUTL(2, "Empty range passed to AddRange()");
return FALSE;
}
if (m_numRanges==0)
{
if (m_rangeTableSize == 0)
if (!Expand())
return FALSE;
m_numRanges = 1;
CopyMemory(&m_rangeTable[0], &range, sizeof(RangeType));
}
else
{
possibleLoc = BinarySearch(range.low);
if (!((possibleLoc > -1) &&
(inRange(m_rangeTable[possibleLoc], range.low)) &&
(inRange(m_rangeTable[possibleLoc], range.high))))
{
insertPosition = possibleLoc + 1;
if (m_numRanges == m_rangeTableSize)
if (!Expand())
return FALSE;
ShiftRight(insertPosition, 1);
CopyMemory(&m_rangeTable[insertPosition], &range, sizeof(RangeType));
if (insertPosition > 0)
SubsumeDown(insertPosition);
if (insertPosition < m_numRanges)
SubsumeUpwards(insertPosition);
}
}
return TRUE;
}
BOOL CRangeList::DeleteRange(const ULONG value)
{
RangeType r = { value, value };
return DeleteRange(r);
}
BOOL CRangeList::DeleteRange(const ULONG low, const ULONG high)
{
RangeType r = { low, high };
return DeleteRange(r);
}
BOOL CRangeList::DeleteRange(CRangeList& r)
{
for (int i=0 ; i<r.m_numRanges ; ++i)
if (!DeleteRange(r.m_rangeTable[i]))
return FALSE;
return TRUE;
}
BOOL CRangeList::DeleteRange(const RangeType range)
{
int lowEndChange;
int highEndChange;
if (range.low > range.high)
{
DOUTL(2, "Empty range passed to DeleteRange()");
return FALSE;
}
lowEndChange = BinarySearch(range.low);
highEndChange = BinarySearch(range.high);
if ((lowEndChange != -1) && (highEndChange == lowEndChange))
{
if (inRange(m_rangeTable[lowEndChange], range.low))
{
if (inRange(m_rangeTable[lowEndChange], range.high))
{
if ((m_rangeTable[lowEndChange].low == range.low) &&
(m_rangeTable[lowEndChange].high == range.high))
{
if (lowEndChange == (m_numRanges-1))
{
m_numRanges--;
}
else
{
ShiftLeft(lowEndChange + 1, 1);
}
}
else
{
if (m_rangeTable[lowEndChange].low == range.low)
{
m_rangeTable[lowEndChange].low = range.high + 1;
}
else
{
if (m_rangeTable[lowEndChange].high == range.high)
{
Assert(range.low > 0);
m_rangeTable[lowEndChange].high = range.low - 1;
}
else
{
// the range to be deleted is properly contained in
// m_rangeTable[lowEndChange]
if (m_numRanges == m_rangeTableSize)
if (!Expand())
return FALSE;
ShiftRight(lowEndChange + 1, 1);
m_rangeTable[lowEndChange + 1].low = range.high + 1;
m_rangeTable[lowEndChange + 1].high = m_rangeTable[lowEndChange].high;
Assert(range.low > 0);
m_rangeTable[lowEndChange].high = range.low - 1;
}
}
}
}
else
{
// range.low is in m_rangeTable[lowEndChange], but range.high
// is not
if (m_rangeTable[lowEndChange].low == range.low)
{
ShiftLeft(lowEndChange + 1, 1);
}
else
{
Assert(range.low > 0);
m_rangeTable[lowEndChange].high = range.low - 1;
}
}
} // of the cases where range.low actually in m_rangeTable[lowEndChange]
}
else
{ // of the cases where highEndChange == lowEndChange
if (lowEndChange != -1)
{
if (inRange(m_rangeTable[lowEndChange], range.low))
{
if (range.low == m_rangeTable[lowEndChange].low)
{
lowEndChange = lowEndChange - 1;
}
else
{
Assert(range.low > 0);
m_rangeTable[lowEndChange].high = range.low - 1;
}
}
}
if (highEndChange != -1)
{
if (inRange(m_rangeTable[highEndChange], range.high))
{
if (range.high == m_rangeTable[highEndChange].high)
{
highEndChange = highEndChange + 1;
}
else
{
m_rangeTable[highEndChange].low = range.high + 1;
}
}
else
{
highEndChange++;
}
}
if (!(lowEndChange > highEndChange))
{
// (0 <= lowEndChange < m_numRanges => m_rangeTable[lowEndChange] has received
// any requisite adjustments and is to be kept)
// and (0 <= highEndChange < m_numRanges => m_rangeTable[highEndChange]
// has received any requistie adjs. and is a keeper)
// and "forall" i [ lowEndChange < i < highEndChange =>
// m_rangeTable[i] is to be overwritten]
if (highEndChange >= m_numRanges)
{
m_numRanges = lowEndChange + 1;
}
else
{
if ((highEndChange - lowEndChange - 1) > 0)
{
ShiftLeft(highEndChange, (highEndChange-lowEndChange-1));
}
}
} // else there's a problem with this code...
}
return TRUE;
}
ULONG CRangeList::Next(const ULONG current) const
{
int loc;
if (m_numRanges == 0)
return RANGE_ERROR;
if ((loc = BinarySearch(current)) == -1)
return m_rangeTable[0].low;
else if (loc == (m_numRanges-1))
{
if (inRange(m_rangeTable[m_numRanges-1], current))
{
if (inRange(m_rangeTable[m_numRanges-1], current + 1))
return current + 1;
else
return RANGE_ERROR;
}
else
return RANGE_ERROR;
}
else // case where loc == m_numRanges-1
{
// 1 <= loc < m_numRanges
if (inRange(m_rangeTable[loc], current))
{
if (inRange(m_rangeTable[loc], current + 1))
return current + 1;
else
return m_rangeTable[loc + 1].low;
}
else
return m_rangeTable[loc + 1].low;
}
}
ULONG CRangeList::Prev(const ULONG current) const
{
int loc;
if (m_numRanges == 0)
return RANGE_ERROR;
if ((loc = BinarySearch(current)) == -1)
{
return RANGE_ERROR;
}
else if (loc == 0)
{
if (inRange(m_rangeTable[0], current))
{
if (current > 0 && inRange(m_rangeTable[0], current - 1))
return current - 1;
else
return RANGE_ERROR;
}
else
return m_rangeTable[0].high;
}
else
{
// 1 < loc <= m_numRanges
if (inRange(m_rangeTable[loc], current))
{
if (current > 0 && inRange(m_rangeTable[loc], current - 1))
return current - 1;
else
return m_rangeTable[loc-1].high;
}
else
return m_rangeTable[loc].high;
}
}
ULONG CRangeList::Cardinality(void) const
{
ULONG card = 0;
for (int i=0 ; i<m_numRanges ; i++)
card += (m_rangeTable[i].high - m_rangeTable[i].low + 1);
return card;
}
int CRangeList::BinarySearch(const ULONG value) const
{
// We are looking for `value' in the m_rangeTable. If value is in the
// set of valid ranges, we return the array subscript of the range
// containing `value'. If `value' is not contained in any of the
// ranges then return `loc' where
// (0 <= loc < m_numRanges =>
// (m_rangeTable[loc].low < rangeNum)
// "and" (m_rangeTable[loc + 1].low > rangeNum))
// "and" (loc = m_numRanges => rangeNum > m_rangeTable[m_numRanges].low)
// "and" (loc = -1 => m_numRanges = 0
// "or" rangeNum < m_rangeTable[0].low) }
long low, high, mid;
int loc=-1;
if (m_numRanges == 0)
return -1;
if (value < m_rangeTable[0].low)
return -1;
low = 0;
high = m_numRanges - 1;
while (low <= high) {
// inv: low < high - 1, and if rngNum is any where in m_rangeTable, it is in
// the range from m_rangeTable[low] to m_rangeTable[high]
mid = (low + high) / 2;
if ((value >= m_rangeTable[mid].low) &&
((mid == (m_numRanges-1)) || (value < m_rangeTable[mid + 1].low)))
{
loc = mid;
high = low - 1;
}
else
{
if (value > m_rangeTable[mid].low)
low = mid + 1;
else
high = mid - 1;
}
}
return loc;
}
// Expand() will grow the m_rangeTable by QUANTUM range cells.
BOOL CRangeList::Expand()
{
RangeType *newRangeTable;
if (!MemAlloc((LPVOID*)&newRangeTable, (m_rangeTableSize + QUANTUM) * sizeof(RangeType)))
return FALSE;
m_rangeTableSize += QUANTUM;
if (m_rangeTable)
{
if (m_numRanges > 0)
CopyMemory(newRangeTable, m_rangeTable, m_numRanges * sizeof(RangeType));
MemFree(m_rangeTable);
}
m_rangeTable = newRangeTable;
return TRUE;
}
void CRangeList::ShiftLeft(int low, int distance)
{
if (m_numRanges - low)
MoveMemory(&m_rangeTable[low-distance], &m_rangeTable[low], (m_numRanges-low)*sizeof(RangeType));
m_numRanges -= distance;
}
void CRangeList::ShiftRight(int low, int distance)
{
if (m_numRanges - low)
MoveMemory(&m_rangeTable[low+distance], &m_rangeTable[low], (m_numRanges-low)*sizeof(RangeType));
m_numRanges += distance;
}
// pre: (m_rangeTable[anchorPosition] has probably just been added to m_rangeTable.)
// 1 <= anchorPosition <= m_numRanges
// and ( anchorPosition = 1
// or (m_rangeTable[anchorPosition].low >
// m_rangeTable[anchorPosition - 1].high) )
// post: No overlapping or contiguous ranges from 1 to m_numRanges. }
void CRangeList::SubsumeUpwards(const int anchor)
{
int posOfLargerLow;
int copyDownDistance;
int copyPos;
posOfLargerLow = anchor + 1;
while ((posOfLargerLow < m_numRanges) &&
(m_rangeTable[posOfLargerLow].low <= m_rangeTable[anchor].high + 1))
posOfLargerLow++;
if (posOfLargerLow == m_numRanges)
{
if (m_rangeTable[m_numRanges-1].high > m_rangeTable[anchor].high)
m_rangeTable[anchor].high = m_rangeTable[m_numRanges-1].high;
m_numRanges = anchor + 1;
}
else
{
// posOfLargerLow now indexes the first element of m_rangeTable, looking from
// m_rangeTable[anchor], with .low > m_rangeTable[anchor].high + 1
if (posOfLargerLow > (anchor + 1))
{
if (m_rangeTable[posOfLargerLow - 1].high > m_rangeTable[anchor].high)
m_rangeTable[anchor].high = m_rangeTable[posOfLargerLow - 1].high;
copyDownDistance = posOfLargerLow - anchor - 1;
copyPos = posOfLargerLow;
while (copyPos < m_numRanges)
{
m_rangeTable[copyPos - copyDownDistance] = m_rangeTable[copyPos];
copyPos = copyPos + 1;
}
m_numRanges -= copyDownDistance;
}
}
}
void CRangeList::SubsumeDown(int& anchor)
{
int posOfSmallerHigh;
int copyDownDistance;
int copyPos;
posOfSmallerHigh = anchor - 1;
while ((posOfSmallerHigh >= 0) &&
(m_rangeTable[posOfSmallerHigh].high + 1 >= m_rangeTable[anchor].low))
{
posOfSmallerHigh--;
}
if (posOfSmallerHigh < 0)
{
if (m_rangeTable[0].low < m_rangeTable[anchor].low)
m_rangeTable[anchor].low = m_rangeTable[0].low;
}
// posOfSmallerHigh either has value 0 or subscripts the first element of
// m_rangeTable, looking down from anchor, with a .high that is
// less than m_rangeTable[anchor].low - 1.
if (m_rangeTable[posOfSmallerHigh + 1].low < m_rangeTable[anchor].low)
m_rangeTable[anchor].low = m_rangeTable[posOfSmallerHigh + 1].low;
copyDownDistance = anchor - posOfSmallerHigh - 1;
if (copyDownDistance > 0)
{
copyPos = anchor;
while (copyPos < m_numRanges)
{
m_rangeTable[copyPos - copyDownDistance] = m_rangeTable[copyPos];
copyPos++;
}
m_numRanges -= copyDownDistance;
anchor -= copyDownDistance;
}
}
#if 0
/*
* We might need these ones again if we decide to import .newsrc files
*
void CRangeList::AddRange(const char *s)
{
char *token, *q;
char *p = new char[strlen(s)+1];
strcpy(p, s);
if ((token = strtok(p, ","))==NULL)
return;
while (token!=NULL) {
if ((q = strchr(token, '-'))==NULL) { // no dash - single value
AddRange(atol(token));
} else {
long low, high;
low = atol(token);
high = atol(q+1);
if (low<=high)
AddRange(low, high);
}
token = strtok(NULL, ",");
}
}
void CRangeList::DeleteRange(const char *s)
{
char *token, *q;
char *p = new char[strlen(s)+1];
strcpy(p, s);
if ((token = strtok(p, ","))==NULL)
return;
while (token!=NULL) {
if ((q = strchr(token, '-'))==NULL) { // no dash - single value
DeleteRange(atol(token));
} else {
long low, high;
low = atol(token);
high = atol(q+1);
if (low<=high)
DeleteRange(low, high);
}
token = strtok(NULL, ",");
}
}
*/
#endif
#ifdef DEBUG
#define WORK_BUFSIZ 256
LPTSTR CRangeList::RangeToString()
{
LPTSTR p, buffer;
TCHAR temp[20];
int buffsize = m_numRanges ? WORK_BUFSIZ : 1;
if (!MemAlloc((LPVOID*)&buffer, buffsize * sizeof(TCHAR)))
return NULL;
*buffer = '\0';
// nothing to do?
if (m_numRanges == 0)
return buffer;
// dump the ranges as a string: "low-high, low-high, singleton, low-high\n"
for (int i=0; i<m_numRanges; i++)
{
if (m_rangeTable[i].low == m_rangeTable[i].high)
wnsprintf(temp, ARRAYSIZE(temp), "%ld", m_rangeTable[i].low);
else
wnsprintf(temp, ARRAYSIZE(temp), "%ld-%ld", m_rangeTable[i].low, m_rangeTable[i].high);
if ((lstrlen(temp) + lstrlen(buffer) + 2) > buffsize)
{
// buffer is about to overflow... double its size
if (!MemAlloc((LPVOID*)&p, 2 * buffsize))
{
MemFree(buffer);
return NULL;
}
buffsize *= 2;
StrCpyN(p, buffer, buffsize);
MemFree(buffer);
buffer = p;
}
StrCatBuff(buffer, temp, buffsize);
if (i < (m_numRanges-1))
StrCatBuff(buffer, ",", buffsize);
}
// save some space, trim the buffer down
buffsize = lstrlen(buffer)+1;
if (MemAlloc((LPVOID*)&p, buffsize * sizeof(TCHAR)))
{
StrCpyN(p, buffer, buffsize);
MemFree(buffer);
buffer = p;
}
return buffer;
}
void CRangeList::DebugOutput(LPTSTR szComment)
{
LPTSTR szRange = RangeToString();
OutputDebugString(szComment);
if (szRange)
{
OutputDebugString(szRange);
MemFree(szRange);
}
OutputDebugString("\r\n");
}
#endif
#ifdef DEBUG
INT_PTR CALLBACK RangeTestDlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
CRangeList *pRL = (CRangeList *)GetWindowLongPtr(hwnd, DWLP_USER);
switch(msg)
{
case WM_INITDIALOG:
{
pRL = new CRangeList();
SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)pRL);
break;
}
case WM_COMMAND:
{
int i1 = GetDlgItemInt(hwnd, idcInput1, NULL, FALSE);
int i2 = GetDlgItemInt(hwnd, idcInput2, NULL, FALSE);
BOOL fRet;
LPTSTR szRange;
switch(GET_WM_COMMAND_ID(wp,lp))
{
case IDOK:
case IDCANCEL:
delete pRL;
SetWindowLongPtr(hwnd, DWLP_USER, 0);
EndDialog(hwnd, TRUE);
return TRUE;
case idcAddRange:
fRet = pRL->AddRange(i1, i2);
szRange = pRL->RangeToString();
SetDlgItemText(hwnd, idcPrint, szRange);
if (szRange)
MemFree(szRange);
SetDlgItemInt(hwnd, idcResult, fRet, FALSE);
return TRUE;
case idcDeleteRange:
fRet = pRL->DeleteRange(i1, i2);
szRange = pRL->RangeToString();
SetDlgItemText(hwnd, idcPrint, szRange);
if (szRange)
MemFree(szRange);
SetDlgItemInt(hwnd, idcResult, fRet, FALSE);
return TRUE;
case idcIsInRange:
SetDlgItemInt(hwnd, idcResult, pRL->IsInRange(i1), FALSE);
return TRUE;
case idcNextInRange:
SetDlgItemInt(hwnd, idcResult, pRL->Next(i1), TRUE);
return TRUE;
case idcPrevInRange:
SetDlgItemInt(hwnd, idcResult, pRL->Prev(i1), TRUE);
return TRUE;
case idcClear:
pRL->Clear();
SetDlgItemText(hwnd, idcPrint, NULL);
SetDlgItemInt(hwnd, idcResult, TRUE, FALSE);
return TRUE;
}
}
break;
}
return FALSE;
}
#endif