// ---------------------------------------------------------------------------
// - Sheet.cpp -
// - afnix:sps module - sheet class implementation -
// ---------------------------------------------------------------------------
// - This program is free software; you can redistribute it and/or modify -
// - it provided that this copyright notice is kept intact. -
// - -
// - This program is distributed in the hope that it will be useful, but -
// - without any warranty; without even the implied warranty of -
// - merchantability or fitness for a particular purpose. In no event shall -
// - the copyright holder be liable for any direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software. -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2007 amaury darsch -
// ---------------------------------------------------------------------------
#include "Sheet.hpp"
#include "Input.hpp"
#include "Spssid.hxx"
#include "Boolean.hpp"
#include "Integer.hpp"
#include "Importer.hpp"
#include "Runnable.hpp"
#include "QuarkZone.hpp"
#include "Exception.hpp"
namespace afnix {
// -------------------------------------------------------------------------
// - private section -
// -------------------------------------------------------------------------
class SheetSorter {
private:
// the column index
long d_col;
// the sorting mode
bool d_mode;
// compare two objects for ascending order
bool cmplth (Object* ref, Object* slv) const {
// check that we have a object records
Record* rref = dynamic_cast <Record*> (ref);
Record* rslv = dynamic_cast <Record*> (slv);
// map the cell to their object
Object* robj = nilp;
try {
robj = (rref == nilp) ? nilp : rref->map (d_col);
} catch (...) {
robj = nilp;
}
Object* sobj = nilp;
try {
sobj = (rslv == nilp) ? nilp : rslv->map (d_col);
} catch (...) {
sobj = nilp;
}
// compare with operator
if (robj == nilp) return true;
Object* obj = robj->oper (Object::LTH, sobj);
Boolean* bobj = dynamic_cast <Boolean*> (obj);
bool result = (bobj == nilp) ? false : bobj->toboolean ();
Object::cref (obj);
return result;
}
// compare two objects for descending order
bool cmpgth (Object* ref, Object* slv) const {
// check that we have a object records
Record* rref = dynamic_cast <Record*> (ref);
Record* rslv = dynamic_cast <Record*> (slv);
// map the cell to their object
Object* robj = nilp;
try {
robj = (rref == nilp) ? nilp : rref->map (d_col);
} catch (...) {
robj = nilp;
}
Object* sobj = nilp;
try {
sobj = (rslv == nilp) ? nilp : rslv->map (d_col);
} catch (...) {
sobj = nilp;
}
// compare with operator
if ((robj == nilp) && (sobj == nilp)) return true;
if ((robj == nilp) && (sobj != nilp)) return false;
Object* obj = robj->oper (Object::GTH, sobj);
Boolean* bobj = dynamic_cast <Boolean*> (obj);
bool result = (bobj == nilp) ? false : bobj->toboolean ();
Object::cref (obj);
return result;
}
// partition the vector and returns the pivot index
long partition (Vector& argv, const long first, const long last) const {
// initialize the pivot index, last index and next (unknown) index
long pidx = first;
long lidx = first;
long uidx = lidx + 1;
// get the pivot object - and protect it
Object* pvt = Object::iref (argv.get (pidx));
// swap until we have reached the last element
while (uidx <= last) {
Object* ref = Object::iref (argv.get (uidx));
bool cflg = d_mode ? cmplth (ref, pvt) : cmpgth (ref, pvt);
if (cflg == true) {
lidx++;
argv.set (uidx, argv.get (lidx));
argv.set (lidx, ref);
}
Object::tref (ref);
// the intel is in the other region
uidx++;
}
// place the pivot in proper position
argv.set (first, argv.get (lidx));
argv.set (lidx, pvt);
Object::tref (pvt);
// the pivot index is now the last index
return lidx;
}
// this function performs a recursive quick sort
void quicksort (Vector& argv, const long first, const long last) const {
if (first >= last) return;
long pidx = partition (argv, first, last);
quicksort (argv, first, pidx - 1);
quicksort (argv, pidx + 1, last);
}
public:
// create a default sheet sorter
SheetSorter (void) {
d_col = 0;
d_mode = false;
}
// create a sorting object by index
SheetSorter (const long col, const bool mode) {
d_col = col;
d_mode = mode;
}
// sort a vector
void qsort (Vector& argv) const {
// sort the vector in place
argv.wrlock ();
try {
long argc = argv.length ();
quicksort (argv, 0, argc - 1);
argv.unlock ();
} catch (...) {
argv.unlock ();
throw;
}
}
};
// this function computes the maximum between two numbers
static inline long max (const long x, const long y) {
return (x < y) ? y : x;
}
// this procedure returns a new sheet object for deserialization
static Serial* mksob (void) {
return new Sheet;
}
// register this cell serial id
static const t_byte SERIAL_ID = Serial::setsid (SERIAL_SHTT_ID, mksob);
// -------------------------------------------------------------------------
// - class section -
// -------------------------------------------------------------------------
// create a nil sheet
Sheet::Sheet (void) {
reset ();
}
// create a new sheet by name
Sheet::Sheet (const String& name) {
d_name = name;
reset ();
}
// create a new sheet by name and info
Sheet::Sheet (const String& name, const String& info) {
d_name = name;
d_info = info;
reset ();
}
// copy construct this sheet
Sheet::Sheet (const Sheet& that) {
that.rdlock ();
try {
d_name = that.d_name;
d_info = that.d_info;
d_tags = that.d_tags;
d_mark = that.d_mark;
d_sign = that.d_sign;
d_head = that.d_head;
d_foot = that.d_foot;
long slen = that.length ();
for (long i = 0; i < slen; i++) {
Record* rcd = that.get (i);
add (new Record (*rcd));
}
that.unlock ();
} catch (...) {
that.unlock ();
throw;
}
}
// return the object name
String Sheet::repr (void) const {
return "Sheet";
}
// return a clone of this object
Object* Sheet::clone (void) const {
return new Sheet (*this);
}
// return the sheet serial id
t_byte Sheet::serialid (void) const {
return SERIAL_SHTT_ID;
}
// serialize a sheet
void Sheet::wrstream (Output& os) const {
rdlock ();
// save the sheet name
d_name.wrstream (os);
// save the sheet info
d_info.wrstream (os);
/// save the tags
d_tags.wrstream (os);
// save the markers
d_mark.wrstream (os);
// save the signature
d_sign.wrstream (os);
// save the header
d_head.wrstream (os);
// save the footer
d_foot.wrstream (os);
// save the vector
d_body.wrstream (os);
unlock ();
}
// deserialize this sheet
void Sheet::rdstream (Input& is) {
wrlock ();
// get the sheet name
d_name.rdstream (is);
// get the sheet info
d_info.rdstream (is);
// get the tags
d_tags.rdstream (is);
// get the markers
d_mark.rdstream (is);
// get the signature
d_sign.rdstream (is);
// get the header
d_head.rdstream (is);
// get the footer
d_foot.rdstream (is);
// get the vector
d_body.rdstream (is);
unlock ();
}
// reset the sheet
void Sheet::reset (void) {
wrlock ();
try {
d_head.reset ();
d_foot.reset ();
d_body.reset ();
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// return the sheet name
String Sheet::getname (void) const {
rdlock ();
String result = d_name;
unlock ();
return result;
}
// set the sheet name
void Sheet::setname (const String& name) {
wrlock ();
d_name = name;
unlock ();
}
// return the sheet info
String Sheet::getinfo (void) const {
rdlock ();
String result = d_info;
unlock ();
return result;
}
// set the sheet info
void Sheet::setinfo (const String& info) {
wrlock ();
d_info = info;
unlock ();
}
// add a sheet tag
void Sheet::addtag (const String& tag) {
wrlock ();
try {
if (d_tags.exists (tag) == false) d_tags.add (tag);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// add a vector of literals in the tags descriptor
void Sheet::addtag (const Vector* argv) {
long argc = (argv == nilp) ? 0 : argv->length ();
if (argc == 0) return;
wrlock ();
try {
for (long i = 0; i < argc; i++) {
Object* obj = argv->get (i);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error",
"non literal object with sheet add-tag",
Object::repr (obj));
}
d_tags.add (lobj->tostring ());
}
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// return the tag descriptor length
long Sheet::tagslen (void) const {
rdlock ();
try {
long result = d_tags.length ();
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// check if a tag exists
bool Sheet::istag (const String& tag) const {
rdlock ();
try {
bool result = d_tags.exists (tag);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// get a tag by index
String Sheet::gettag (const long index) const {
wrlock ();
try {
String result = d_tags.get (index);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// set the sheet tag by index
void Sheet::settag (const long index, Literal* lobj) {
wrlock ();
try {
String value = (lobj == nilp) ? "" : lobj->tostring ();
d_tags.set (index, value);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// find a tag index by tag
long Sheet::findtag (const String& tag) const {
rdlock ();
try {
long result = d_tags.lookup (tag);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// add a literal in the markers descriptor
void Sheet::addmark (const String& mark) {
wrlock ();
try {
d_mark.add (mark);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// add a vector of objects in the marker record
void Sheet::addmark (const Vector* argv) {
long argc = (argv == nilp) ? 0 : argv->length ();
if (argc == 0) return;
wrlock ();
try {
for (long i = 0; i < argc; i++) {
Object* obj = argv->get (i);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error",
"non literal object with sheet add-mark",
Object::repr (obj));
}
d_mark.add (lobj->tostring ());
}
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// return the marker length
long Sheet::marklen (void) const {
rdlock ();
try {
long result = d_mark.length ();
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// check if a marker exists exists
bool Sheet::ismark (const String& mark) const {
rdlock ();
try {
bool result = d_mark.exists (mark);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// get a sheet marker by index
String Sheet::getmark (const long index) const {
wrlock ();
try {
String result = d_mark.get (index);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// set the sheet marker by index
void Sheet::setmark (const long index, Literal* lobj) {
wrlock ();
try {
String value = (lobj == nilp) ? "" : lobj->tostring ();
d_mark.set (index, value);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// find a marker index by mark
long Sheet::findmark (const String& mark) const {
rdlock ();
try {
long result = d_mark.lookup (mark);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// add a literal in the signature descriptor
void Sheet::addsign (const String& sign) {
wrlock ();
try {
d_sign.add (sign);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// add a vector of objects in the signature record
void Sheet::addsign (const Vector* argv) {
long argc = (argv == nilp) ? 0 : argv->length ();
if (argc == 0) return;
wrlock ();
try {
for (long i = 0; i < argc; i++) {
Object* obj = argv->get (i);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error",
"non literal object with sheet add-sign",
Object::repr (obj));
}
d_sign.add (lobj->tostring ());
}
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// return the signer length
long Sheet::signlen (void) const {
rdlock ();
try {
long result = d_sign.length ();
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// check if a signer exists exists
bool Sheet::issign (const String& sign) const {
rdlock ();
try {
bool result = d_sign.exists (sign);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// get a sheet signer by index
String Sheet::getsign (const long index) const {
wrlock ();
try {
String result = d_sign.get (index);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// set the sheet signer by index
void Sheet::setsign (const long index, Literal* lobj) {
wrlock ();
try {
String value = (lobj == nilp) ? "" : lobj->tostring ();
d_sign.set (index, value);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// find a signer index by sign
long Sheet::findsign (const String& sign) const {
rdlock ();
try {
long result = d_sign.lookup (sign);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// add an object in the header record
void Sheet::addhead (Object* object) {
wrlock ();
try {
d_head.add (object);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// add a vector of objects in the header record
void Sheet::addhead (const Vector* argv) {
long argc = (argv == nilp) ? 0 : argv->length ();
if (argc == 0) return;
wrlock ();
try {
for (long i = 0; i < argc; i++) d_head.add (argv->get (i));
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// get a header cell by index
Cell* Sheet::gethead (const long index) const {
rdlock ();
try {
Cell* result = dynamic_cast <Cell*> (d_head.get (index));
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// evaluate a header cell by index
Literal* Sheet::maphead (const long index) const {
rdlock ();
try {
Cell* cell = gethead (index);
Literal* result = (cell == nilp) ? nilp : cell->get ();
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// set a record header by index and literal
void Sheet::sethead (const long index, Literal* lobj) {
wrlock ();
try {
Cell* cell = dynamic_cast <Cell*> (d_head.get (index));
if (cell != nilp) cell->set (lobj);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// add an object in the footer record
void Sheet::addfoot (Object* object) {
wrlock ();
try {
d_foot.add (object);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// add a vector of objects in the footer record
void Sheet::addfoot (const Vector* argv) {
long argc = (argv == nilp) ? 0 : argv->length ();
if (argc == 0) return;
wrlock ();
try {
for (long i = 0; i < argc; i++) d_foot.add (argv->get (i));
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// get a footer cell by index
Cell* Sheet::getfoot (const long index) const {
rdlock ();
try {
Cell* result = dynamic_cast <Cell*> (d_foot.get (index));
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// evaluate a footer cell by index
Literal* Sheet::mapfoot (const long index) const {
rdlock ();
try {
Cell* cell = getfoot (index);
Literal* result = (cell == nilp) ? nilp : cell->get ();
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// set a record footer by index and literal
void Sheet::setfoot (const long index, Literal* lobj) {
wrlock ();
try {
Cell* cell = dynamic_cast <Cell*> (d_foot.get (index));
if (cell != nilp) cell->set (lobj);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// add a record in this sheet
void Sheet::add (Record* rcd) {
if (rcd == nilp) return;
wrlock ();
try {
d_body.append (rcd);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// get a record by index
Record* Sheet::get (const long index) const {
rdlock ();
try {
Record* result = dynamic_cast <Record*> (d_body.get (index));
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// get a cell by row and column
Cell* Sheet::get (const long row, const long col) const {
rdlock ();
try {
// get the record
Record* rcd = get (row);
if (rcd == nilp) {
unlock ();
return nilp;
}
// get the cell
Cell* cell = rcd->get (col);
unlock ();
return cell;
} catch (...) {
unlock ();
throw;
}
}
// map a cell literal by ow and column
Literal* Sheet::map (const long row, const long col) const {
rdlock ();
try {
Cell* cell = get (row, col);
Literal* lobj = (cell == nilp) ? nilp : cell->get ();
unlock ();
return lobj;
} catch (...) {
unlock ();
throw;
}
}
// set a record in this sheet by index
void Sheet::set (const long index, Record* rcd) {
wrlock ();
try {
d_body.set (index, rcd);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// set an object in this sheet by row and column
void Sheet::set (const long row, const long col, Object* object) {
wrlock ();
try {
// check if we have enough record
long slen = length ();
if (row >= slen) {
long delta = row - slen + 1;
for (long i = 0; i < delta; i++) add (new Record);
}
// get the record
Record* rcd = get (row);
if (rcd == nilp) {
unlock ();
return;
}
// set the cell
rcd->set (col, object);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// add a vector of literal as a record
void Sheet::adddata (const Vector* argv) {
long argc = (argv == nilp) ? 0 : argv->length ();
if (argc == 0) return;
wrlock ();
Record* rcd = new Record;
try {
for (long i = 0; i < argc; i++) rcd->add (argv->get (i));
d_body.append (rcd);
unlock ();
} catch (...) {
Object::cref (rcd);
unlock ();
throw;
}
}
// return the length of the sheet list
long Sheet::length (void) const {
rdlock ();
try {
long result = d_body.length ();
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// return the number of columns
long Sheet::getcols (void) const {
rdlock ();
try {
// get the sheet length
long tlen = length ();
// compute the maximum columns
long result = 0;
for (long i = 0; i < tlen; i++) {
Record* rcd = get (i);
if (rcd == nilp) continue;
result = max (result, rcd->length ());
}
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// import data in this sheet
void Sheet::import (Input* is) {
// do nothing if nil
if (is == nilp) return;
// protect us during the importation
wrlock ();
Object::iref (this);
// create a new importer
try {
Sheeting si (this);
si.import (is);
Object::tref (this);
unlock ();
} catch (...) {
Object::tref (this);
unlock ();
throw;
}
}
// convert this sheet into a print sheet
PrintTable* Sheet::convert (long max, long start, bool flag) const {
rdlock ();
// get the number of rows
long rows = length ();
// check for start index
if ((rows != 0) && ((start < 0) || (start >= rows))) {
unlock ();
throw Exception ("sheet-error", "start index out of range for convert");
}
// check for max index
long tlen = start + ((max == 0) ? rows : max);
if (tlen > rows) {
unlock ();
throw Exception ("sheet-error", "max index is out of range for convert");
}
// format result
long cols = getcols ();
PrintTable* result = new PrintTable (cols);
try {
// iterate through the record
for (long i = start; i < tlen; i++) {
Record* rcd = get (i);
if (rcd == nilp) continue;
long row = result->add ();
// get the record length
long rlen = rcd->length ();
for (long j = 0; j < rlen; j++) {
Literal* lobj = rcd->map (j);
if (lobj == nilp) {
result->set (row, j, "nil");
} else {
String data = flag ? lobj->tostring () : lobj->toliteral ();
result->set (row, j, data);
}
}
// fill the rest of the sheet
for (long j = rlen; j < cols; j++) result->set (row, j, "nil");
}
unlock ();
return result;
} catch (...) {
delete result;
unlock ();
throw;
}
}
// sort this sheet by column index and mode
void Sheet::sort (const long col, const bool mode) {
wrlock ();
try {
// build the sorter object
SheetSorter sorter (col, mode);
// sort the vector
sorter.qsort (d_body);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// link a sheet column into this sheet
void Sheet::lkcol (const Sheet* sheet, const long col) {
// check for a sheet and lock
if ((sheet == nilp) || (sheet == this)) return;
sheet->rdlock ();
wrlock ();
try {
// get the insert column
long cidx = getcols ();
// get the column size
long size = sheet->length ();
// copy the column
for (long i = 0; i < size; i++) {
Cell* cell = sheet->get (i, col);
set (i, cidx, cell);
}
} catch (...) {
unlock ();
sheet->unlock ();
throw;
}
}
// -------------------------------------------------------------------------
// - object section -
// -------------------------------------------------------------------------
// the quark zone
static const long QUARK_ZONE_LENGTH = 42;
static QuarkZone zone (QUARK_ZONE_LENGTH);
// the sheet supported quarks
static const long QUARK_ADD = zone.intern ("add");
static const long QUARK_GET = zone.intern ("get");
static const long QUARK_MAP = zone.intern ("map");
static const long QUARK_SET = zone.intern ("set");
static const long QUARK_SORT = zone.intern ("sort");
static const long QUARK_RESET = zone.intern ("reset");
static const long QUARK_IMPORT = zone.intern ("import");
static const long QUARK_LENGTH = zone.intern ("length");
static const long QUARK_COLLEN = zone.intern ("column-length");
static const long QUARK_ADDTAG = zone.intern ("add-tag");
static const long QUARK_TAGLEN = zone.intern ("tag-length");
static const long QUARK_ISTAGP = zone.intern ("tag-p");
static const long QUARK_GETTAG = zone.intern ("get-tag");
static const long QUARK_SETTAG = zone.intern ("set-tag");
static const long QUARK_FINDTAG = zone.intern ("find-tag");
static const long QUARK_CONVERT = zone.intern ("convert");
static const long QUARK_GETNAME = zone.intern ("get-name");
static const long QUARK_SETNAME = zone.intern ("set-name");
static const long QUARK_GETINFO = zone.intern ("get-info");
static const long QUARK_SETINFO = zone.intern ("set-info");
static const long QUARK_ADDMARK = zone.intern ("add-marker");
static const long QUARK_MARKLEN = zone.intern ("marker-length");
static const long QUARK_ISMARKP = zone.intern ("marker-p");
static const long QUARK_GETMARK = zone.intern ("get-marker");
static const long QUARK_SETMARK = zone.intern ("set-marker");
static const long QUARK_FINDMRK = zone.intern ("find-marker");
static const long QUARK_ADDSIGN = zone.intern ("add-sign");
static const long QUARK_SIGNLEN = zone.intern ("signature-length");
static const long QUARK_ISSIGNP = zone.intern ("sign-p");
static const long QUARK_GETSIGN = zone.intern ("get-sign");
static const long QUARK_SETSIGN = zone.intern ("set-sign");
static const long QUARK_FINDSGN = zone.intern ("find-sign");
static const long QUARK_ADDHEAD = zone.intern ("add-header");
static const long QUARK_GETHEAD = zone.intern ("get-header");
static const long QUARK_MAPHEAD = zone.intern ("map-header");
static const long QUARK_SETHEAD = zone.intern ("set-header");
static const long QUARK_ADDFOOT = zone.intern ("add-footer");
static const long QUARK_GETFOOT = zone.intern ("get-footer");
static const long QUARK_MAPFOOT = zone.intern ("map-footer");
static const long QUARK_SETFOOT = zone.intern ("set-footer");
static const long QUARK_ADDDATA = zone.intern ("add-data");
static const long QUARK_LINKCOL = zone.intern ("link-column");
// create a new object in a generic way
Object* Sheet::mknew (Vector* argv) {
// get number of arguments
long argc = (argv == nilp) ? 0 : argv->length ();
// check for 0 argument
if (argc == 0) return new Sheet;
// check for 1 argument
if (argc == 1) {
String name = argv->getstring (0);
return new Sheet (name);
}
// check for 2 arguments
if (argc == 2) {
String name = argv->getstring (0);
String info = argv->getstring (1);
return new Sheet (name, info);
}
throw Exception ("argument-error", "too many argument with sheet");
}
// return true if the given quark is defined
bool Sheet::isquark (const long quark, const bool hflg) const {
rdlock ();
if (zone.exists (quark) == true) {
unlock ();
return true;
}
bool result = hflg ? Persist::isquark (quark, hflg) : false;
unlock ();
return result;
}
// apply this object with a set of arguments and a quark
Object* Sheet::apply (Runnable* robj, Nameset* nset, const long quark,
Vector* argv) {
// check for generic quark
if (quark == QUARK_ADDDATA) {
adddata (argv);
return nilp;
}
if (quark == QUARK_ADDTAG) {
addtag (argv);
return nilp;
}
if (quark == QUARK_ADDMARK) {
addmark (argv);
return nilp;
}
if (quark == QUARK_ADDSIGN) {
addsign (argv);
return nilp;
}
if (quark == QUARK_ADDHEAD) {
addhead (argv);
return nilp;
}
if (quark == QUARK_ADDFOOT) {
addfoot (argv);
return nilp;
}
// get the number of arguments
long argc = (argv == nilp) ? 0 : argv->length ();
// dispatch 0 argument
if (argc == 0) {
if (quark == QUARK_LENGTH ) return new Integer (length ());
if (quark == QUARK_COLLEN ) return new Integer (getcols ());
if (quark == QUARK_TAGLEN ) return new Integer (tagslen ());
if (quark == QUARK_MARKLEN) return new Integer (marklen ());
if (quark == QUARK_SIGNLEN) return new Integer (signlen ());
if (quark == QUARK_GETNAME) return new String (getname ());
if (quark == QUARK_GETINFO) return new String (getinfo ());
if (quark == QUARK_CONVERT) return convert (0, 0, true);
if (quark == QUARK_RESET) {
reset ();
return nilp;
}
if (quark == QUARK_SORT) {
sort (0, true);
return nilp;
}
}
// dispatch 1 argument
if (argc == 1) {
if (quark == QUARK_SETNAME) {
String name = argv->getstring (0);
setname (name);
return nilp;
}
if (quark == QUARK_SETINFO) {
String info = argv->getstring (0);
setinfo (info);
return nilp;
}
if (quark == QUARK_ISTAGP) {
Object* obj = argv->get (0);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error", "non literal object with tag-p",
Object::repr (obj));
}
String tag = lobj->tostring ();
return new Boolean (istag (tag));
}
if (quark == QUARK_GETTAG) {
long index = argv->getint (0);
return new String (gettag (index));
}
if (quark == QUARK_ISMARKP) {
Object* obj = argv->get (0);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error", "non literal object with marker-p",
Object::repr (obj));
}
String mark = lobj->tostring ();
return new Boolean (ismark (mark));
}
if (quark == QUARK_ISSIGNP) {
Object* obj = argv->get (0);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error", "non literal object with sign-p",
Object::repr (obj));
}
String sign = lobj->tostring ();
return new Boolean (issign (sign));
}
if (quark == QUARK_GETMARK) {
long index = argv->getint (0);
return new String (getmark (index));
}
if (quark == QUARK_GETSIGN) {
long index = argv->getint (0);
return new String (getsign (index));
}
if (quark == QUARK_FINDTAG) {
Object* obj = argv->get (0);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error", "non literal object with find-tag",
Object::repr (obj));
}
String tag = lobj->tostring ();
return new Integer (findtag (tag));
}
if (quark == QUARK_FINDMRK) {
Object* obj = argv->get (0);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error", "non literal object with find-marker",
Object::repr (obj));
}
String mark = lobj->tostring ();
return new Integer (findmark (mark));
}
if (quark == QUARK_FINDSGN) {
Object* obj = argv->get (0);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error", "non literal object with find-sign",
Object::repr (obj));
}
String sign = lobj->tostring ();
return new Integer (findsign (sign));
}
if (quark == QUARK_GET) {
long idx = argv->getint (0);
rdlock ();
try {
Object* result = get (idx);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_ADD) {
Object* obj = argv->get (0);
Record* rcd = dynamic_cast <Record*> (obj);
if (rcd != nilp) {
add (rcd);
return nilp;
}
throw Exception ("type-error", "invalid object to add in sheet",
Object::repr (obj));
}
if (quark == QUARK_GETHEAD) {
long index = argv->getint (0);
rdlock ();
try {
Object* result = gethead (index);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_MAPHEAD) {
long index = argv->getint (0);
rdlock ();
try {
Object* result = maphead (index);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_GETFOOT) {
long index = argv->getint (0);
rdlock ();
try {
Object* result = getfoot (index);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_MAPFOOT) {
long index = argv->getint (0);
rdlock ();
try {
Object* result = mapfoot (index);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_IMPORT) {
Object* obj = argv->get (0);
Input* is = dynamic_cast <Input*> (obj);
if (is != nilp) {
import (is);
return nilp;
}
throw Exception ("type-error", "invalid object for sheet importation",
Object::repr (obj));
}
if (quark == QUARK_CONVERT) {
long max = argv->getint (0);
return convert (max, 0, true);
}
if (quark == QUARK_SORT) {
Object* obj = argv->get (0);
// check for integer
Integer* col = dynamic_cast <Integer*> (obj);
if (col != nilp) {
sort (col->tointeger (), true);
return nilp;
}
// check for boolean
Boolean* mode = dynamic_cast <Boolean*> (obj);
if (mode != nilp) {
sort (0, mode->toboolean ());
return nilp;
}
// invalid arguments
throw Exception ("type-error", "invalid object for sorting ",
Object::repr (obj));
}
}
// dispatch 2 argument
if (argc == 2) {
if (quark == QUARK_SETTAG) {
long idx = argv->getint (0);
Object* obj = argv->get (1);
Literal* lobj = dynamic_cast <Literal*> (obj);
if ((obj != nilp) && (lobj == nilp))
throw Exception ("type-error", "invalid object to set in tags",
Object::repr (obj));
settag (idx, lobj);
return nilp;
}
if (quark == QUARK_SETMARK) {
long idx = argv->getint (0);
Object* obj = argv->get (1);
Literal* lobj = dynamic_cast <Literal*> (obj);
if ((obj != nilp) && (lobj == nilp))
throw Exception ("type-error", "invalid object to set in marker",
Object::repr (obj));
setmark (idx, lobj);
return nilp;
}
if (quark == QUARK_SETSIGN) {
long idx = argv->getint (0);
Object* obj = argv->get (1);
Literal* lobj = dynamic_cast <Literal*> (obj);
if ((obj != nilp) && (lobj == nilp))
throw Exception ("type-error", "invalid object to set in signature",
Object::repr (obj));
setsign (idx, lobj);
return nilp;
}
if (quark == QUARK_SETHEAD) {
long idx = argv->getint (0);
Object* obj = argv->get (1);
Literal* lobj = dynamic_cast <Literal*> (obj);
if ((obj != nilp) && (lobj == nilp))
throw Exception ("type-error", "invalid object to set in header",
Object::repr (obj));
sethead (idx, lobj);
return nilp;
}
if (quark == QUARK_SETFOOT) {
long idx = argv->getint (0);
Object* obj = argv->get (1);
Literal* lobj = dynamic_cast <Literal*> (obj);
if ((obj != nilp) && (lobj == nilp))
throw Exception ("type-error", "invalid object to set in footer",
Object::repr (obj));
setfoot (idx, lobj);
return nilp;
}
if (quark == QUARK_GET) {
long row = argv->getint (0);
long col = argv->getint (1);
rdlock ();
try {
Object* result = get (row, col);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_MAP) {
long row = argv->getint (0);
long col = argv->getint (1);
rdlock ();
try {
Object* result = map (row, col);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_SET) {
long idx = argv->getint (0);
Object* obj = argv->get (1);
Record* rcd = dynamic_cast <Record*> (obj);
if ((obj != nilp) && (rcd == nilp))
throw Exception ("type-error", "invalid object to set in sheet",
Object::repr (obj));
set (idx, rcd);
return nilp;
}
if (quark == QUARK_CONVERT) {
long max = argv->getint (0);
long start = argv->getint (1);
return convert (max, start, true);
}
if (quark == QUARK_SORT) {
long col = argv->getint (0);
bool mode = argv->getbool (1);
sort (col, mode);
return nilp;
}
if (quark == QUARK_LINKCOL) {
Object* obj = argv->get (0);
Sheet* sht = dynamic_cast <Sheet*> (obj);
if (sht == nilp) {
throw Exception ("type-error", "invalid object with link-column",
Object::repr (obj));
}
long col = argv->getint (1);
lkcol (sht, col);
return nilp;
}
}
// dispatch 3 arguments
if (argc == 3) {
if (quark == QUARK_CONVERT) {
long max = argv->getint (0);
long start = argv->getint (1);
bool flag = argv->getbool (2);
return convert (max, start, flag);
}
if (quark == QUARK_SET) {
long row = argv->getint (0);
long col = argv->getint (1);
Object* obj = argv->get (2);
set (row, col, obj);
return nilp;
}
}
// call the persist method
return Persist::apply (robj, nset, quark, argv);
}
}
syntax highlighted by Code2HTML, v. 0.9.1