Files
easy7zip/CPP/7zip/Common/InMemStream.h
Igor Pavlov 829409452d 9.04 beta
2016-05-28 00:15:59 +01:00

285 lines
5.7 KiB
C++
Executable File

// InMemStream.h
#ifndef __IN_MEM_STREAM_H
#define __IN_MEM_STREAM_H
#include <stdio.h>
#include "../../../C/Alloc.h"
#include "../../Common/MyCom.h"
#include "MemBlocks.h"
class CIntListCheck
{
protected:
int *_data;
public:
CIntListCheck(): _data(0) {}
~CIntListCheck() { FreeList(); }
bool AllocateList(int numItems)
{
FreeList();
if (numItems == 0)
return true;
_data = (int *)::MyAlloc(numItems * sizeof(int));
return (_data != 0);
}
void FreeList()
{
::MyFree(_data);
_data = 0;
}
};
class CResourceList : public CIntListCheck
{
int _headFree;
public:
CResourceList(): _headFree(-1) {}
bool AllocateList(int numItems)
{
FreeList();
if (numItems == 0)
return true;
if (!CIntListCheck::AllocateList(numItems))
return false;
for (int i = 0; i < numItems; i++)
_data[i] = i + 1;
_data[numItems - 1] = -1;
_headFree = 0;
return true;
}
void FreeList()
{
CIntListCheck::FreeList();
_headFree = -1;
}
int AllocateItem()
{
int res = _headFree;
if (res >= 0)
_headFree = _data[res];
return res;
}
void FreeItem(int index)
{
if (index < 0)
return;
_data[index] = _headFree;
_headFree = index;
}
};
class CResourceListMt: public CResourceList
{
NWindows::NSynchronization::CCriticalSection _criticalSection;
public:
NWindows::NSynchronization::CSemaphore Semaphore;
HRes AllocateList(int numItems)
{
if (!CResourceList::AllocateList(numItems))
return E_OUTOFMEMORY;
Semaphore.Close();
return Semaphore.Create(numItems, numItems);
}
int AllocateItem()
{
Semaphore.Lock();
_criticalSection.Enter();
int res = CResourceList::AllocateItem();
_criticalSection.Leave();
return res;
}
void FreeItem(int index)
{
if (index < 0)
return;
_criticalSection.Enter();
CResourceList::FreeItem(index);
_criticalSection.Leave();
Semaphore.Release();
}
};
class CIntQueueMt: public CIntListCheck
{
int _numItems;
int _head;
int _cur;
public:
CIntQueueMt(): _numItems(0), _head(0), _cur(0) {}
NWindows::NSynchronization::CSemaphore Semaphore;
HRes AllocateList(int numItems)
{
FreeList();
if (numItems == 0)
return S_OK;
if (!CIntListCheck::AllocateList(numItems))
return E_OUTOFMEMORY;
_numItems = numItems;
return Semaphore.Create(0, numItems);
}
void FreeList()
{
CIntListCheck::FreeList();
_numItems = 0;
_head = 0;
_cur = 0;
}
void AddItem(int value)
{
_data[_head++] = value;
if (_head == _numItems)
_head = 0;
Semaphore.Release();
// printf("\nRelease prev = %d\n", previousCount);
}
int GetItem()
{
// Semaphore.Lock();
int res = _data[_cur++];
if (_cur == _numItems)
_cur = 0;
return res;
}
};
struct IInMemStreamMtCallback
{
// must be same for all calls
virtual size_t GetBlockSize() = 0;
// Out:
// result != S_OK stops Reading
// if *p = 0, result must be != S_OK;
// Locking is allowed
virtual HRESULT AllocateBlock(void **p) = 0;
virtual void FreeBlock(void *p) = 0;
// It must allow to add at least numSubStreams + 1 ,
// where numSubStreams is value from CInMemStreamMt::Create
// value -1 means End of stream
// Locking is not allowed
virtual void AddStreamIndexToQueue(int index) = 0;
};
struct CStreamInfo
{
CRecordVector<void *> Blocks;
int LastBlockIndex;
size_t LastBlockPos;
bool StreamWasFinished;
int CurBlockIndex;
size_t CurBlockPos;
NWindows::NSynchronization::CCriticalSection *Cs;
NWindows::NSynchronization::CManualResetEvent *CanReadEvent;
HRESULT ExitResult;
CStreamInfo(): Cs(0), CanReadEvent(0), StreamWasFinished(false) { }
~CStreamInfo()
{
delete Cs;
delete CanReadEvent;
// Free();
}
void Create()
{
Cs = new NWindows::NSynchronization::CCriticalSection;
CanReadEvent = new NWindows::NSynchronization::CManualResetEvent;
}
void Free(IInMemStreamMtCallback *callback);
void Init()
{
LastBlockIndex = CurBlockIndex = 0;
CurBlockPos = LastBlockPos = 0;
StreamWasFinished = false;
ExitResult = S_OK;
}
// res must be != S_OK
void Exit(HRESULT res)
{
ExitResult = res;
CanReadEvent->Set();
}
};
class CInMemStreamMt
{
CMyComPtr<ISequentialInStream> _stream;
NWindows::NSynchronization::CCriticalSection CS;
CObjectVector<CStreamInfo> _streams;
int _nextFreeStreamIndex;
int _currentStreamIndex;
UInt64 _subStreamSize;
CResourceListMt _streamIndexAllocator;
// bool _stopReading;
public:
HRESULT Read();
HRESULT ReadResult;
IInMemStreamMtCallback *Callback;
void FreeSubStream(int subStreamIndex);
HRESULT ReadSubStream(int subStreamIndex, void *data, UInt32 size, UInt32 *processedSize, bool keepData);
// numSubStreams: min = 1, good min = numThreads
bool Create(int numSubStreams, UInt64 subStreamSize);
~CInMemStreamMt() { Free(); }
void SetStream(ISequentialInStream *stream) { _stream = stream; }
// to stop reading you must implement
// returning Error in IInMemStreamMtCallback::AllocateBlock
// and then you must free at least one substream
HRes StartReadThread();
void Free();
// you must free at least one substream after that function to unlock waiting.
// void StopReading() { _stopReading = true; }
};
class CInMemStream:
public ISequentialInStream,
public CMyUnknownImp
{
UInt64 _size;
bool _keepData;
public:
int Index;
CInMemStreamMt *mtStream;
void Init(bool keepData = false)
{
_size = 0; _keepData = keepData ;
}
MY_UNKNOWN_IMP
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
UInt64 GetSize() const { return _size; }
};
#endif