1
0
Fork 0

Template Magic

Removed need to allocate a fake meta block by using templates to provide a version
of the code that does not use metas. Also changed the function to a template
argument to make sure that the compilier is able to inline it.
This commit is contained in:
Tycho 2014-04-28 10:31:07 -07:00
parent 744e00c904
commit a42480cf82
4 changed files with 183 additions and 173 deletions

View File

@ -13,18 +13,20 @@
// This wild construct allows us to pass a function argument and still have it inlined by the compiler :)
/// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function
template<typename Combinator> void InternalMergeBlocks(
typedef void (CombinatorFunc)(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta);
template<bool MetasValid, CombinatorFunc Combinator>
void InternalMergeBlocks(
BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes,
NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas,
int a_SizeX, int a_SizeY, int a_SizeZ,
int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ,
int a_DstOffX, int a_DstOffY, int a_DstOffZ,
int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ,
int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ,
Combinator a_Combinator
int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ
)
{
UNUSED(a_SrcSizeY);
@ -41,7 +43,15 @@ template<typename Combinator> void InternalMergeBlocks(
int DstIdx = DstBaseZ + a_DstOffX;
for (int x = 0; x < a_SizeX; x++)
{
a_Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]);
if (MetasValid)
{
Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]);
}
else
{
BLOCKTYPE FakeDestMeta = 0;
Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], FakeDestMeta, (NIBBLETYPE)0);
}
++DstIdx;
++SrcIdx;
} // for x
@ -51,13 +61,12 @@ template<typename Combinator> void InternalMergeBlocks(
/// Combinator used for cBlockArea::msOverwrite merging
template<bool MetaValid>
static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
if (MetaValid) a_DstMeta = a_SrcMeta;
}
@ -65,12 +74,13 @@ static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_S
/// Combinator used for cBlockArea::msFillAir merging
template<bool MetaValid>
static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if (a_DstType == E_BLOCK_AIR)
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
if (MetaValid) a_DstMeta = a_SrcMeta;
}
// "else" is the default, already in place
}
@ -80,12 +90,13 @@ static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_Src
/// Combinator used for cBlockArea::msImprint merging
template<bool MetaValid>
static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if (a_SrcType != E_BLOCK_AIR)
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
if (MetaValid) a_DstMeta = a_SrcMeta;
}
// "else" is the default, already in place
}
@ -95,6 +106,7 @@ static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_Src
/// Combinator used for cBlockArea::msLake merging
template<bool MetaValid>
static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
// Sponge is the NOP block
@ -107,7 +119,7 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
if (a_SrcType == E_BLOCK_AIR)
{
a_DstType = E_BLOCK_AIR;
a_DstMeta = 0;
if (MetaValid) a_DstMeta = 0;
return;
}
@ -132,7 +144,7 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
case E_BLOCK_STATIONARY_LAVA:
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
if (MetaValid) a_DstMeta = a_SrcMeta;
return;
}
}
@ -146,7 +158,7 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
case E_BLOCK_MYCELIUM:
{
a_DstType = E_BLOCK_STONE;
a_DstMeta = 0;
if (MetaValid) a_DstMeta = 0;
return;
}
}
@ -159,13 +171,14 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
/** Combinator used for cBlockArea::msSpongePrint merging */
template<bool MetaValid>
static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
// Sponge overwrites nothing, everything else overwrites anything
if (a_SrcType != E_BLOCK_SPONGE)
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
if (MetaValid) a_DstMeta = a_SrcMeta;
}
}
@ -174,17 +187,18 @@ static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a
/** Combinator used for cBlockArea::msDifference merging */
template<bool MetaValid>
static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
if ((a_DstType == a_SrcType) && (a_DstMeta == a_SrcMeta))
if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta)))
{
a_DstType = E_BLOCK_AIR;
a_DstMeta = 0;
if (MetaValid) a_DstMeta = 0;
}
else
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
if (MetaValid) a_DstMeta = a_SrcMeta;
}
}
@ -193,13 +207,14 @@ static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_
/** Combinator used for cBlockArea::msMask merging */
template<bool MetaValid>
static inline void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
{
// If the blocks are the same, keep the dest; otherwise replace with air
if ((a_SrcType != a_DstType) || (a_SrcMeta != a_DstMeta))
if ((a_SrcType != a_DstType) || !MetaValid || (a_SrcMeta != a_DstMeta))
{
a_DstType = E_BLOCK_AIR;
a_DstMeta = 0;
if (MetaValid) a_DstMeta = 0;
}
}
@ -484,7 +499,7 @@ void cBlockArea::CopyTo(cBlockArea & a_Into) const
a_Into.Clear();
a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
a_Into.m_Origin = m_Origin;
int BlockCount = GetBlockCount();
size_t BlockCount = GetBlockCount();
if (HasBlockTypes())
{
memcpy(a_Into.m_BlockTypes, m_BlockTypes, BlockCount * sizeof(BLOCKTYPE));
@ -532,7 +547,7 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
f.Write(&SizeZ, 4);
unsigned char DataTypes = (unsigned char)GetDataTypes();
f.Write(&DataTypes, 1);
int NumBlocks = GetBlockCount();
size_t NumBlocks = GetBlockCount();
if (HasBlockTypes())
{
f.Write(m_BlockTypes, NumBlocks * sizeof(BLOCKTYPE));
@ -637,160 +652,19 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa
void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy)
{
// Block types are compulsory, block metas are voluntary
if (!HasBlockTypes() || !a_Src.HasBlockTypes())
{
LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
return;
}
// Dst is *this, Src is a_Src
int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading
int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing
int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy
int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading
int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing
int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy
int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading
int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing
int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy
const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas();
NIBBLETYPE * DstMetas = m_BlockMetas;
bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL));
if (IsDummyMetas)
{
size_t SrcCount = a_Src.GetBlockCount();
size_t DestCount = GetBlockCount();
NIBBLETYPE * tempSrcMetas = new NIBBLETYPE[SrcCount];
memset(tempSrcMetas, 0, SrcCount);
SrcMetas = tempSrcMetas;
DstMetas = new NIBBLETYPE[DestCount];
memset(DstMetas, 0, DestCount);
MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
}
switch (a_Strategy)
else
{
case msOverwrite:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorOverwrite
);
break;
} // case msOverwrite
case msFillAir:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorFillAir
);
break;
} // case msFillAir
case msImprint:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorImprint
);
break;
} // case msImprint
case msLake:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorLake
);
break;
} // case msLake
case msSpongePrint:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorSpongePrint
);
break;
} // case msSpongePrint
case msDifference:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorDifference
);
break;
} // case msDifference
case msMask:
{
InternalMergeBlocks(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorMask
);
break;
} // case msMask
default:
{
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
ASSERT(!"Unknown block area merge strategy");
break;
}
} // switch (a_Strategy)
if (IsDummyMetas)
{
delete[] SrcMetas;
delete[] DstMetas;
MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
}
}
@ -2084,7 +1958,7 @@ void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, i
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
size_t BlockCount = (size_t)NewSizeX * NewSizeY * NewSizeZ;
BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount];
memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE));
int OldIndex = 0;
@ -2114,7 +1988,7 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
size_t BlockCount = (size_t)NewSizeX * NewSizeY * NewSizeZ;
NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount];
memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE));
int OldIndex = 0;
@ -2166,4 +2040,137 @@ void cBlockArea::RelSetData(
template<bool MetasValid>
void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas)
{
// Block types are compulsory, block metas are voluntary
if (!HasBlockTypes() || !a_Src.HasBlockTypes())
{
LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
return;
}
// Dst is *this, Src is a_Src
int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading
int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing
int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy
int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading
int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing
int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy
int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading
int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing
int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy
switch (a_Strategy)
{
case cBlockArea::msOverwrite:
{
InternalMergeBlocks<MetasValid, MergeCombinatorOverwrite<MetasValid> >(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z
);
break;
} // case msOverwrite
case cBlockArea::msFillAir:
{
InternalMergeBlocks<MetasValid, MergeCombinatorFillAir<MetasValid> >(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z
);
break;
} // case msFillAir
case cBlockArea::msImprint:
{
InternalMergeBlocks<MetasValid, MergeCombinatorImprint<MetasValid> >(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z
);
break;
} // case msImprint
case cBlockArea::msLake:
{
InternalMergeBlocks<MetasValid, MergeCombinatorLake<MetasValid> >(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z
);
break;
} // case msLake
case cBlockArea::msSpongePrint:
{
InternalMergeBlocks<MetasValid, MergeCombinatorSpongePrint<MetasValid> >(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z
);
break;
} // case msSpongePrint
case cBlockArea::msDifference:
{
InternalMergeBlocks<MetasValid, MergeCombinatorDifference<MetasValid> >(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z
);
break;
} // case msDifference
case cBlockArea::msMask:
{
InternalMergeBlocks<MetasValid, MergeCombinatorMask<MetasValid> >(
m_BlockTypes, a_Src.GetBlockTypes(),
DstMetas, SrcMetas,
SizeX, SizeY, SizeZ,
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
m_Size.x, m_Size.y, m_Size.z
);
break;
} // case msMask
default:
{
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
ASSERT(!"Unknown block area merge strategy");
break;
}
} // switch (a_Strategy)
}

View File

@ -294,7 +294,7 @@ public:
NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block!
NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block!
NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block!
int GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; }
size_t GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; }
int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const;
protected:
@ -363,6 +363,9 @@ protected:
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
);
template<bool MetasValid>
void MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas);
// tolua_begin
} ;
// tolua_end

View File

@ -143,7 +143,7 @@ bool cFile::IsEOF(void) const
int cFile::Read (void * iBuffer, int iNumBytes)
int cFile::Read (void * iBuffer, size_t iNumBytes)
{
ASSERT(IsOpen());
@ -159,7 +159,7 @@ int cFile::Read (void * iBuffer, int iNumBytes)
int cFile::Write(const void * iBuffer, int iNumBytes)
int cFile::Write(const void * iBuffer, size_t iNumBytes)
{
ASSERT(IsOpen());

View File

@ -80,10 +80,10 @@ public:
bool IsEOF(void) const;
/** Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open */
int Read (void * iBuffer, int iNumBytes);
int Read (void * iBuffer, size_t iNumBytes);
/** Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */
int Write(const void * iBuffer, int iNumBytes);
int Write(const void * iBuffer, size_t iNumBytes);
/** Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open */
int Seek (int iPosition);