108 lines
3.3 KiB
D
108 lines
3.3 KiB
D
module xdiff_mmblocks;
|
||
|
||
import std.exception : enforce;
|
||
import xdiff_init : ensureInit, initMmfile;
|
||
import xdiff;
|
||
|
||
final class MMBlocks
|
||
{
|
||
private:
|
||
mmfile_t _inner;
|
||
bool _owned = true; // владеем ли блоками?
|
||
enum DEFAULT_BSIZE = 8 * 1024;
|
||
|
||
// Глубокая копия: читаем все блоки и записываем в dst
|
||
static void deepCopyAll(mmfile_t* src, MMBlocks dst)
|
||
{
|
||
enforce(xdl_seek_mmfile(src, 0) == 0, "seek(0) failed");
|
||
|
||
long sz = 0;
|
||
auto p = xdl_mmfile_first(src, &sz);
|
||
while (p !is null && sz > 0)
|
||
{
|
||
auto wrote = xdl_write_mmfile(dst.mmfilePtr(), p, sz);
|
||
enforce(wrote == sz, "write failed during deep copy");
|
||
p = xdl_mmfile_next(src, &sz);
|
||
}
|
||
}
|
||
|
||
public:
|
||
this()
|
||
{
|
||
_inner = initMmfile(DEFAULT_BSIZE);
|
||
}
|
||
|
||
static MMBlocks fromBytes(const(ubyte)[] data)
|
||
{
|
||
auto b = new MMBlocks;
|
||
if (data.length > 0)
|
||
{
|
||
auto wrote = xdl_write_mmfile(&b._inner, data.ptr, cast(long)data.length);
|
||
enforce(wrote == cast(long)data.length, "xdl_write_mmfile wrote less than requested");
|
||
}
|
||
return b;
|
||
}
|
||
|
||
~this()
|
||
{
|
||
if (_owned && _inner.head !is null)
|
||
xdl_free_mmfile(&_inner);
|
||
|
||
// обнулим на всякий случай
|
||
_inner.head = null; _inner.tail = null;
|
||
_inner.rcur = null; _inner.wcur = null;
|
||
_inner.fsize = 0; _inner.bsize = 0;
|
||
}
|
||
|
||
// доступ к внутреннему mmfile_t*
|
||
mmfile_t* mmfilePtr() @trusted { return &_inner; }
|
||
|
||
size_t size() { return cast(size_t)xdl_mmfile_size(&_inner); }
|
||
bool isCompact() const { return xdl_mmfile_iscompact(cast(mmfile_t*)&_inner) != 0; }
|
||
|
||
int writeBuf(const(ubyte)[] buf)
|
||
{
|
||
auto wrote = xdl_write_mmfile(&_inner, buf.ptr, cast(long)buf.length);
|
||
return (wrote == cast(long)buf.length) ? 0 : -1;
|
||
}
|
||
|
||
/// Глубокая копия (новое владение)
|
||
MMBlocks clone() const
|
||
{
|
||
auto dst = new MMBlocks;
|
||
// deepCopyAll принимает mmfile_t*, поэтому аккуратно снимаем const с заголовка:
|
||
deepCopyAll(cast(mmfile_t*)&_inner, dst);
|
||
return dst;
|
||
}
|
||
|
||
/// Компактизация через пересборку содержимого
|
||
void toCompact()
|
||
{
|
||
if (isCompact()) return;
|
||
|
||
auto dst = new MMBlocks;
|
||
deepCopyAll(&_inner, dst);
|
||
|
||
// перехватываем владение содержимым dst
|
||
if (_owned && _inner.head !is null)
|
||
xdl_free_mmfile(&_inner);
|
||
|
||
_inner = *dst.mmfilePtr();
|
||
dst._owned = false; // dst больше не владеет
|
||
dst._inner.head = null; // чтобы финалайзер dst ничего не освободил
|
||
dst._inner.tail = null;
|
||
dst._inner.rcur = null;
|
||
dst._inner.wcur = null;
|
||
dst._inner.fsize = 0;
|
||
dst._inner.bsize = 0;
|
||
}
|
||
|
||
/// Снять владение (используется при move в MMFile)
|
||
void disarm()
|
||
{
|
||
_owned = false;
|
||
_inner.head = null; _inner.tail = null;
|
||
_inner.rcur = null; _inner.wcur = null;
|
||
_inner.fsize = 0; _inner.bsize = 0;
|
||
}
|
||
}
|