Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _MDB_
# include "mdb.h"
#endif
#ifndef _MORK_
# include "mork.h"
#endif
#ifndef _MORKBLOB_
# include "morkBlob.h"
#endif
#ifndef _MORKATOM_
# include "morkAtom.h"
#endif
#ifndef _MORKENV_
# include "morkEnv.h"
#endif
#ifndef _MORKATOMSPACE_
# include "morkAtomSpace.h"
#endif
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
/* static */
mork_bool morkAtom::GetYarn(const morkAtom* atom, mdbYarn* outYarn) {
const void* source = 0;
mdb_fill fill = 0;
mdb_cscode form = 0;
outYarn->mYarn_More = 0;
if (atom) {
if (atom->IsWeeBook()) {
morkWeeBookAtom* weeBook = (morkWeeBookAtom*)atom;
source = weeBook->mWeeBookAtom_Body;
fill = weeBook->mAtom_Size;
} else if (atom->IsBigBook()) {
morkBigBookAtom* bigBook = (morkBigBookAtom*)atom;
source = bigBook->mBigBookAtom_Body;
fill = bigBook->mBigBookAtom_Size;
form = bigBook->mBigBookAtom_Form;
} else if (atom->IsWeeAnon()) {
morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*)atom;
source = weeAnon->mWeeAnonAtom_Body;
fill = weeAnon->mAtom_Size;
} else if (atom->IsBigAnon()) {
morkBigAnonAtom* bigAnon = (morkBigAnonAtom*)atom;
source = bigAnon->mBigAnonAtom_Body;
fill = bigAnon->mBigAnonAtom_Size;
form = bigAnon->mBigAnonAtom_Form;
}
}
if (source && fill) // have an atom with nonempty content?
{
// if we have too many bytes, and yarn seems growable:
if (fill > outYarn->mYarn_Size && outYarn->mYarn_Grow) // try grow?
(*outYarn->mYarn_Grow)(outYarn, (mdb_size)fill); // request bigger
mdb_size size = outYarn->mYarn_Size; // max dest size
if (fill > size) // too much atom content?
{
outYarn->mYarn_More = fill - size; // extra atom bytes omitted
fill = size; // copy no more bytes than size of yarn buffer
}
void* dest = outYarn->mYarn_Buf; // where bytes are going
if (!dest) // nil destination address buffer?
fill = 0; // we can't write any content at all
if (fill) // anything to copy?
MORK_MEMCPY(dest, source, fill); // copy fill bytes to yarn
outYarn->mYarn_Fill = fill; // tell yarn size of copied content
} else // no content to put into the yarn
{
outYarn->mYarn_Fill = 0; // tell yarn that atom has no bytes
}
outYarn->mYarn_Form = form; // always update the form slot
return (source != 0);
}
/* static */
mork_bool morkAtom::AliasYarn(const morkAtom* atom, mdbYarn* outYarn) {
outYarn->mYarn_More = 0;
outYarn->mYarn_Form = 0;
if (atom) {
if (atom->IsWeeBook()) {
morkWeeBookAtom* weeBook = (morkWeeBookAtom*)atom;
outYarn->mYarn_Buf = weeBook->mWeeBookAtom_Body;
outYarn->mYarn_Fill = weeBook->mAtom_Size;
outYarn->mYarn_Size = weeBook->mAtom_Size;
} else if (atom->IsBigBook()) {
morkBigBookAtom* bigBook = (morkBigBookAtom*)atom;
outYarn->mYarn_Buf = bigBook->mBigBookAtom_Body;
outYarn->mYarn_Fill = bigBook->mBigBookAtom_Size;
outYarn->mYarn_Size = bigBook->mBigBookAtom_Size;
outYarn->mYarn_Form = bigBook->mBigBookAtom_Form;
} else if (atom->IsWeeAnon()) {
morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*)atom;
outYarn->mYarn_Buf = weeAnon->mWeeAnonAtom_Body;
outYarn->mYarn_Fill = weeAnon->mAtom_Size;
outYarn->mYarn_Size = weeAnon->mAtom_Size;
} else if (atom->IsBigAnon()) {
morkBigAnonAtom* bigAnon = (morkBigAnonAtom*)atom;
outYarn->mYarn_Buf = bigAnon->mBigAnonAtom_Body;
outYarn->mYarn_Fill = bigAnon->mBigAnonAtom_Size;
outYarn->mYarn_Size = bigAnon->mBigAnonAtom_Size;
outYarn->mYarn_Form = bigAnon->mBigAnonAtom_Form;
} else
atom = 0; // show desire to put empty content in yarn
}
if (!atom) // empty content for yarn?
{
outYarn->mYarn_Buf = 0;
outYarn->mYarn_Fill = 0;
outYarn->mYarn_Size = 0;
// outYarn->mYarn_Grow = 0; // please don't modify the Grow slot
}
return (atom != 0);
}
mork_aid morkAtom::GetBookAtomAid() const // zero or book atom's ID
{
return (this->IsBook()) ? ((morkBookAtom*)this)->mBookAtom_Id : 0;
}
mork_scope morkAtom::GetBookAtomSpaceScope(
morkEnv* ev) const // zero or book's space's scope
{
mork_scope outScope = 0;
if (this->IsBook()) {
const morkBookAtom* bookAtom = (const morkBookAtom*)this;
morkAtomSpace* space = bookAtom->mBookAtom_Space;
if (space->IsAtomSpace())
outScope = space->SpaceScope();
else
space->NonAtomSpaceTypeError(ev);
}
return outScope;
}
void morkAtom::MakeCellUseForever(morkEnv* ev) {
MORK_USED_1(ev);
mAtom_CellUses = morkAtom_kForeverCellUses;
}
mork_u1 morkAtom::AddCellUse(morkEnv* ev) {
MORK_USED_1(ev);
if (mAtom_CellUses < morkAtom_kMaxCellUses) // not already maxed out?
++mAtom_CellUses;
return mAtom_CellUses;
}
mork_u1 morkAtom::CutCellUse(morkEnv* ev) {
if (mAtom_CellUses) // any outstanding uses to cut?
{
if (mAtom_CellUses < morkAtom_kMaxCellUses) // not frozen at max?
--mAtom_CellUses;
} else
this->CellUsesUnderflowWarning(ev);
return mAtom_CellUses;
}
/*static*/ void morkAtom::CellUsesUnderflowWarning(morkEnv* ev) {
ev->NewWarning("mAtom_CellUses underflow");
}
/*static*/ void morkAtom::BadAtomKindError(morkEnv* ev) {
ev->NewError("bad mAtom_Kind");
}
/*static*/ void morkAtom::ZeroAidError(morkEnv* ev) {
ev->NewError("zero atom ID");
}
/*static*/ void morkAtom::AtomSizeOverflowError(morkEnv* ev) {
ev->NewError("atom mAtom_Size overflow");
}
void morkOidAtom::InitRowOidAtom(morkEnv* ev, const mdbOid& inOid) {
MORK_USED_1(ev);
mAtom_CellUses = 0;
mAtom_Kind = morkAtom_kKindRowOid;
mAtom_Change = morkChange_kNil;
mAtom_Size = 0;
mOidAtom_Oid = inOid; // bitwise copy
}
void morkOidAtom::InitTableOidAtom(morkEnv* ev, const mdbOid& inOid) {
MORK_USED_1(ev);
mAtom_CellUses = 0;
mAtom_Kind = morkAtom_kKindTableOid;
mAtom_Change = morkChange_kNil;
mAtom_Size = 0;
mOidAtom_Oid = inOid; // bitwise copy
}
void morkWeeAnonAtom::InitWeeAnonAtom(morkEnv* ev, const morkBuf& inBuf) {
mAtom_Kind = 0;
mAtom_Change = morkChange_kNil;
if (inBuf.mBuf_Fill <= morkAtom_kMaxByteSize) {
mAtom_CellUses = 0;
mAtom_Kind = morkAtom_kKindWeeAnon;
mork_size size = inBuf.mBuf_Fill;
mAtom_Size = (mork_u1)size;
if (size && inBuf.mBuf_Body)
MORK_MEMCPY(mWeeAnonAtom_Body, inBuf.mBuf_Body, size);
mWeeAnonAtom_Body[size] = 0;
} else
this->AtomSizeOverflowError(ev);
}
void morkBigAnonAtom::InitBigAnonAtom(morkEnv* ev, const morkBuf& inBuf,
mork_cscode inForm) {
MORK_USED_1(ev);
mAtom_CellUses = 0;
mAtom_Kind = morkAtom_kKindBigAnon;
mAtom_Change = morkChange_kNil;
mAtom_Size = 0;
mBigAnonAtom_Form = inForm;
mork_size size = inBuf.mBuf_Fill;
mBigAnonAtom_Size = size;
if (size && inBuf.mBuf_Body)
MORK_MEMCPY(mBigAnonAtom_Body, inBuf.mBuf_Body, size);
mBigAnonAtom_Body[size] = 0;
}
/*static*/ void morkBookAtom::NonBookAtomTypeError(morkEnv* ev) {
ev->NewError("non morkBookAtom");
}
mork_u4 morkBookAtom::HashFormAndBody(morkEnv* ev) const {
// This hash is obviously a variation of the dragon book string hash.
// (I won't bother to explain or rationalize this usage for you.)
mork_u4 outHash = 0; // hash value returned
unsigned char c; // next character
const mork_u1* body; // body of bytes to hash
mork_size size = 0; // the number of bytes to hash
if (this->IsWeeBook()) {
size = mAtom_Size;
body = ((const morkWeeBookAtom*)this)->mWeeBookAtom_Body;
} else if (this->IsBigBook()) {
size = ((const morkBigBookAtom*)this)->mBigBookAtom_Size;
body = ((const morkBigBookAtom*)this)->mBigBookAtom_Body;
} else if (this->IsFarBook()) {
size = ((const morkFarBookAtom*)this)->mFarBookAtom_Size;
body = ((const morkFarBookAtom*)this)->mFarBookAtom_Body;
} else {
this->NonBookAtomTypeError(ev);
return 0;
}
const mork_u1* end = body + size;
while (body < end) {
c = *body++;
outHash <<= 4;
outHash += c;
mork_u4 top = outHash & 0xF0000000L; // top four bits
if (top) // any of high four bits equal to one?
{
outHash ^= (top >> 24); // fold down high bits
outHash ^= top; // zero top four bits
}
}
return outHash;
}
mork_bool morkBookAtom::EqualFormAndBody(morkEnv* ev,
const morkBookAtom* inAtom) const {
mork_bool outEqual = morkBool_kFalse;
const mork_u1* body = 0; // body of inAtom bytes to compare
mork_size size; // the number of inAtom bytes to compare
mork_cscode form; // nominal charset for ioAtom
if (inAtom->IsWeeBook()) {
size = inAtom->mAtom_Size;
body = ((const morkWeeBookAtom*)inAtom)->mWeeBookAtom_Body;
form = 0;
} else if (inAtom->IsBigBook()) {
size = ((const morkBigBookAtom*)inAtom)->mBigBookAtom_Size;
body = ((const morkBigBookAtom*)inAtom)->mBigBookAtom_Body;
form = ((const morkBigBookAtom*)inAtom)->mBigBookAtom_Form;
} else if (inAtom->IsFarBook()) {
size = ((const morkFarBookAtom*)inAtom)->mFarBookAtom_Size;
body = ((const morkFarBookAtom*)inAtom)->mFarBookAtom_Body;
form = ((const morkFarBookAtom*)inAtom)->mFarBookAtom_Form;
} else {
inAtom->NonBookAtomTypeError(ev);
return morkBool_kFalse;
}
const mork_u1* thisBody = 0; // body of bytes in this to compare
mork_size thisSize; // the number of bytes in this to compare
mork_cscode thisForm; // nominal charset for this atom
if (this->IsWeeBook()) {
thisSize = mAtom_Size;
thisBody = ((const morkWeeBookAtom*)this)->mWeeBookAtom_Body;
thisForm = 0;
} else if (this->IsBigBook()) {
thisSize = ((const morkBigBookAtom*)this)->mBigBookAtom_Size;
thisBody = ((const morkBigBookAtom*)this)->mBigBookAtom_Body;
thisForm = ((const morkBigBookAtom*)this)->mBigBookAtom_Form;
} else if (this->IsFarBook()) {
thisSize = ((const morkFarBookAtom*)this)->mFarBookAtom_Size;
thisBody = ((const morkFarBookAtom*)this)->mFarBookAtom_Body;
thisForm = ((const morkFarBookAtom*)this)->mFarBookAtom_Form;
} else {
this->NonBookAtomTypeError(ev);
return morkBool_kFalse;
}
// if atoms are empty, form is irrelevant
if (body && thisBody && size == thisSize && (!size || form == thisForm))
outEqual = (MORK_MEMCMP(body, thisBody, size) == 0);
return outEqual;
}
void morkBookAtom::CutBookAtomFromSpace(morkEnv* ev) {
morkAtomSpace* space = mBookAtom_Space;
if (space) {
mBookAtom_Space = 0;
space->mAtomSpace_AtomBodies.CutAtom(ev, this);
space->mAtomSpace_AtomAids.CutAtom(ev, this);
} else
ev->NilPointerError();
}
morkWeeBookAtom::morkWeeBookAtom(mork_aid inAid) {
mAtom_Kind = morkAtom_kKindWeeBook;
mAtom_CellUses = 0;
mAtom_Change = morkChange_kNil;
mAtom_Size = 0;
mBookAtom_Space = 0;
mBookAtom_Id = inAid;
mWeeBookAtom_Body[0] = 0;
}
void morkWeeBookAtom::InitWeeBookAtom(morkEnv* ev, const morkBuf& inBuf,
morkAtomSpace* ioSpace, mork_aid inAid) {
mAtom_Kind = 0;
mAtom_Change = morkChange_kNil;
if (ioSpace) {
if (inAid) {
if (inBuf.mBuf_Fill <= morkAtom_kMaxByteSize) {
mAtom_CellUses = 0;
mAtom_Kind = morkAtom_kKindWeeBook;
mBookAtom_Space = ioSpace;
mBookAtom_Id = inAid;
mork_size size = inBuf.mBuf_Fill;
mAtom_Size = (mork_u1)size;
if (size && inBuf.mBuf_Body)
MORK_MEMCPY(mWeeBookAtom_Body, inBuf.mBuf_Body, size);
mWeeBookAtom_Body[size] = 0;
} else
this->AtomSizeOverflowError(ev);
} else
this->ZeroAidError(ev);
} else
ev->NilPointerError();
}
void morkBigBookAtom::InitBigBookAtom(morkEnv* ev, const morkBuf& inBuf,
mork_cscode inForm,
morkAtomSpace* ioSpace, mork_aid inAid) {
mAtom_Kind = 0;
mAtom_Change = morkChange_kNil;
if (ioSpace) {
if (inAid) {
mAtom_CellUses = 0;
mAtom_Kind = morkAtom_kKindBigBook;
mAtom_Size = 0;
mBookAtom_Space = ioSpace;
mBookAtom_Id = inAid;
mBigBookAtom_Form = inForm;
mork_size size = inBuf.mBuf_Fill;
mBigBookAtom_Size = size;
if (size && inBuf.mBuf_Body)
MORK_MEMCPY(mBigBookAtom_Body, inBuf.mBuf_Body, size);
mBigBookAtom_Body[size] = 0;
} else
this->ZeroAidError(ev);
} else
ev->NilPointerError();
}
void morkFarBookAtom::InitFarBookAtom(morkEnv* ev, const morkBuf& inBuf,
mork_cscode inForm,
morkAtomSpace* ioSpace, mork_aid inAid) {
mAtom_Kind = 0;
mAtom_Change = morkChange_kNil;
if (ioSpace) {
if (inAid) {
mAtom_CellUses = 0;
mAtom_Kind = morkAtom_kKindFarBook;
mAtom_Size = 0;
mBookAtom_Space = ioSpace;
mBookAtom_Id = inAid;
mFarBookAtom_Form = inForm;
mFarBookAtom_Size = inBuf.mBuf_Fill;
mFarBookAtom_Body = (mork_u1*)inBuf.mBuf_Body;
} else
this->ZeroAidError(ev);
} else
ev->NilPointerError();
}
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789