312 lines
6.4 KiB
C++
312 lines
6.4 KiB
C++
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Microsoft Windows
|
|||
|
//
|
|||
|
// Copyright (C) Microsoft Corporation, 1992 - 1999
|
|||
|
//
|
|||
|
// File: queue.cxx
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <precomp.hxx>
|
|||
|
#include <queue.hxx>
|
|||
|
|
|||
|
|
|||
|
QUEUE::QUEUE (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We will construct an empty queue.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ALLOCATE_THIS(QUEUE);
|
|||
|
|
|||
|
QueueSlots = InitialQueueSlots;
|
|||
|
NumberOfQueueSlots = INITIALQUEUESLOTS;
|
|||
|
EndOfQueue = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
QUEUE::~QUEUE (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Desciption:
|
|||
|
|
|||
|
We need to free up the queue slots if they have expanded beyond
|
|||
|
the initial ones.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (QueueSlots != InitialQueueSlots)
|
|||
|
delete QueueSlots;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
QUEUE::PutOnQueue (
|
|||
|
IN void * Item,
|
|||
|
IN unsigned int Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The item will be placed on the tail of the queue.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Item - Supplies the item to be placed on the queue.
|
|||
|
|
|||
|
Length - Supplies the length of the item.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Zero will be returned if everything completes successfully; otherwise,
|
|||
|
non-zero will be returned indicating an out of memory error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
QUEUE_ITEM * NewQueueSlots;
|
|||
|
int Count;
|
|||
|
|
|||
|
if (EndOfQueue == NumberOfQueueSlots)
|
|||
|
{
|
|||
|
NewQueueSlots = (QUEUE_ITEM *) new char[
|
|||
|
sizeof(QUEUE_ITEM) * NumberOfQueueSlots * 2];
|
|||
|
if (NewQueueSlots == 0)
|
|||
|
return(1);
|
|||
|
memcpy(NewQueueSlots, QueueSlots,
|
|||
|
sizeof(QUEUE_ITEM) * NumberOfQueueSlots);
|
|||
|
if (QueueSlots != InitialQueueSlots)
|
|||
|
delete QueueSlots;
|
|||
|
QueueSlots = NewQueueSlots;
|
|||
|
NumberOfQueueSlots *= 2;
|
|||
|
}
|
|||
|
|
|||
|
for (Count = EndOfQueue; Count > 0; Count--)
|
|||
|
{
|
|||
|
ASSERT(QueueSlots[Count-1].Buffer != Item);
|
|||
|
QueueSlots[Count] = QueueSlots[Count - 1];
|
|||
|
}
|
|||
|
|
|||
|
EndOfQueue += 1;
|
|||
|
QueueSlots[0].Buffer = Item;
|
|||
|
QueueSlots[0].BufferLength = Length;
|
|||
|
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
QUEUE::PutOnFrontOfQueue (
|
|||
|
IN void * Item,
|
|||
|
IN unsigned int Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The item will be placed on the front of the queue.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Item - Supplies the item to be placed on the queue.
|
|||
|
|
|||
|
Length - Supplies the length of the item.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Zero will be returned if everything completes successfully; otherwise,
|
|||
|
non-zero will be returned indicating an out of memory error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
QUEUE_ITEM * NewQueueSlots;
|
|||
|
int Count;
|
|||
|
|
|||
|
if (EndOfQueue == NumberOfQueueSlots)
|
|||
|
{
|
|||
|
NewQueueSlots = (QUEUE_ITEM *) new char[
|
|||
|
sizeof(QUEUE_ITEM) * NumberOfQueueSlots * 2];
|
|||
|
if (NewQueueSlots == 0)
|
|||
|
return(1);
|
|||
|
memcpy(NewQueueSlots, QueueSlots,
|
|||
|
sizeof(QUEUE_ITEM) * NumberOfQueueSlots);
|
|||
|
if (QueueSlots != InitialQueueSlots)
|
|||
|
delete QueueSlots;
|
|||
|
QueueSlots = NewQueueSlots;
|
|||
|
NumberOfQueueSlots *= 2;
|
|||
|
}
|
|||
|
|
|||
|
QueueSlots[EndOfQueue].Buffer = Item;
|
|||
|
QueueSlots[EndOfQueue].BufferLength = Length;
|
|||
|
EndOfQueue += 1;
|
|||
|
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void *
|
|||
|
QUEUE::TakeOffQueue (
|
|||
|
OUT unsigned int * Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will remove an item from the front of the queue and
|
|||
|
return it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Length - Returns the length of the item in the queue.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the queue is not empty, the last item in the queue will be
|
|||
|
returned; otherwise, zero will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (EndOfQueue == 0)
|
|||
|
return(0);
|
|||
|
EndOfQueue -= 1;
|
|||
|
*Length = QueueSlots[EndOfQueue].BufferLength;
|
|||
|
return(QueueSlots[EndOfQueue].Buffer);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void *
|
|||
|
QUEUE::TakeOffEndOfQueue (
|
|||
|
OUT unsigned int * Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will remove an item from the tail of the queue and
|
|||
|
return it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Length - Returns the length of the item in the queue.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the queue is not empty, the last item in the queue will be
|
|||
|
returned; otherwise, zero will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
void *Buffer;
|
|||
|
int Count;
|
|||
|
|
|||
|
if (EndOfQueue == 0)
|
|||
|
return(0);
|
|||
|
|
|||
|
*Length = QueueSlots[0].BufferLength;
|
|||
|
Buffer = QueueSlots[0].Buffer;
|
|||
|
|
|||
|
EndOfQueue -= 1;
|
|||
|
|
|||
|
for (Count = 0; Count < EndOfQueue; Count++)
|
|||
|
{
|
|||
|
QueueSlots[Count] = QueueSlots[Count + 1];
|
|||
|
}
|
|||
|
|
|||
|
return(Buffer);
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
QUEUE::MergeWithQueue (
|
|||
|
IN QUEUE *pQueue
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Takes the contents of the second queue and merges it into the first queue. Does not check for
|
|||
|
duplicates. Does not implement transactional semantics - i.e. if merging fails halfway due to lack
|
|||
|
of memory, the operation is aborted, and the amount of elements that were transferred remain in
|
|||
|
the this queue. Appropriate synchronization must be taken care for by the caller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pQueue - the queue that we want to merge from.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
0 - success
|
|||
|
!0 - failure - out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
unsigned int nLength;
|
|||
|
void *pQueueElement;
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
pQueueElement = pQueue->TakeOffQueue(&nLength);
|
|||
|
if (pQueueElement == 0)
|
|||
|
break;
|
|||
|
|
|||
|
if (PutOnQueue(pQueueElement, nLength) != 0)
|
|||
|
{
|
|||
|
// guaranteed to succeed since we never decrease buffers
|
|||
|
pQueue->PutOnFrontOfQueue(pQueueElement, nLength);
|
|||
|
return 1;
|
|||
|
}
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
QUEUE::MergeWithQueueInFront (
|
|||
|
IN QUEUE *SourceQueue
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Takes the contents of the second queue and merges it into the front of first queue. Does not check for
|
|||
|
duplicates. Does not implement transactional semantics - i.e. if merging fails halfway due to lack
|
|||
|
of memory, the operation is aborted, and the amount of elements that were transferred remain in
|
|||
|
the this queue. Appropriate synchronization must be taken care for by the caller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SourceQueue - the queue that we want to merge from.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
0 - success
|
|||
|
!0 - failure - out of memory
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
unsigned int nLength;
|
|||
|
void *pQueueElement;
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
pQueueElement = SourceQueue->TakeOffEndOfQueue(&nLength);
|
|||
|
if (pQueueElement == 0)
|
|||
|
break;
|
|||
|
|
|||
|
if (PutOnFrontOfQueue(pQueueElement, nLength) != 0)
|
|||
|
{
|
|||
|
// guaranteed to succeed since we never decrease buffers
|
|||
|
SourceQueue->PutOnFrontOfQueue(pQueueElement, nLength);
|
|||
|
return 1;
|
|||
|
}
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|