// ---------------------------------------------------------------------------
// - Lexicon.cpp -
// - afnix:txt module - lexicon object 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 "Vector.hpp"
#include "Boolean.hpp"
#include "Integer.hpp"
#include "Lexicon.hpp"
#include "Runnable.hpp"
#include "QuarkZone.hpp"
#include "Exception.hpp"
namespace afnix {
// -------------------------------------------------------------------------
// - private section -
// -------------------------------------------------------------------------
// the trie structure - all methods operate by looking at the next
// link - this approach permits to operate with an empty root tree
struct s_eirt {
// the character reference
t_quad d_cref;
// the terminal flag
bool d_term;
// the horizontal link
s_eirt* p_hlnk;
// the vertical link
s_eirt* p_vlnk;
// create a default trie element
s_eirt (void) {
d_cref = nilq;
d_term = false;
p_hlnk = nilp;
p_vlnk = nilp;
}
// create a trie element by value
s_eirt (const t_quad c) {
d_cref = c;
d_term = false;
p_hlnk = nilp;
p_vlnk = nilp;
}
// destroy this trie element
~s_eirt (void) {
delete p_vlnk;
delete p_hlnk;
}
// find the next trie element
s_eirt* find (const t_quad c) const {
// initialize with the v-link
s_eirt* elem = p_vlnk;
// iterate with the h-links
while (elem != nilp) {
if (elem->d_cref == c) return elem;
elem = elem->p_hlnk;
}
return nilp;
}
// add the next element
s_eirt* add (const t_quad c) {
// check the v-link
if (p_vlnk == nilp) {
p_vlnk = new s_eirt (c);
return p_vlnk;
}
// check for first entry
if (c < p_vlnk->d_cref) {
s_eirt* elem = new s_eirt (c);
elem->p_hlnk = p_vlnk;
p_vlnk = elem;
return elem;
}
// look horizontaly
s_eirt* elem = p_vlnk;
while (elem != nilp){
if (elem->d_cref == c) return elem;
if (elem->p_hlnk == nilp) {
elem->p_hlnk = new s_eirt (c);
return elem->p_hlnk;
} else {
if (c < elem->p_hlnk->d_cref) {
s_eirt* helm = new s_eirt (c);
helm->p_hlnk = elem->p_hlnk;
elem->p_hlnk = helm;
return helm;
}
}
elem = elem->p_hlnk;
}
throw Exception ("internal-error", "end of trie list reached in add");
}
};
// -------------------------------------------------------------------------
// - class section -
// -------------------------------------------------------------------------
// create a default lexicon
Lexicon::Lexicon (void) {
d_llen = 0;
p_eirt = new s_eirt;
}
// destroy this lexicon
Lexicon::~Lexicon (void) {
delete p_eirt;
}
// return the class name
String Lexicon::repr (void) const {
return "Lexicon";
}
// reset this lexicon
void Lexicon::reset (void) {
wrlock ();
delete p_eirt;
d_llen = 0;
p_eirt = new s_eirt;
unlock ();
}
// return true if the lexicon is empty
bool Lexicon::empty (void) const {
rdlock ();
bool result = (d_llen == 0);
unlock ();
return result;
}
// return the number of elements
long Lexicon::length (void) const {
rdlock ();
long result = d_llen;
unlock ();
return result;
}
// return true if a name exists
bool Lexicon::exists (const String& name) const {
// do nothing with a nil name
if (name.isnil () == true) return false;
// lock and check
rdlock ();
try {
// get the trie tree
s_eirt* elem = p_eirt;
// loop in the name
long nlen = name.length ();
for (long i = nlen-1; 0 <= i; i--) {
t_quad c = name[i];
elem = elem->find (c);
if (elem == nilp) break;
}
bool result = (elem == nilp) ? false : elem->d_term;
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// add a name in the lexicon
void Lexicon::add (const String& name) {
// do nothing with a nil name
if (name.isnil () == true) return;
// lock and bind
wrlock ();
try {
// get the trie tree
s_eirt* elem = p_eirt;
// loop in the name
long nlen = name.length ();
for (long i = nlen-1; 0 <= i; i--) {
t_quad c = name[i];
elem = elem->add (c);
}
// mark the trie element
if (elem->d_term == false) {
d_llen++;
elem->d_term = true;
}
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// -------------------------------------------------------------------------
// - object section -
// -------------------------------------------------------------------------
// the quark zone
static const long QUARK_ZONE_LENGTH = 5;
static QuarkZone zone (QUARK_ZONE_LENGTH);
// the object supported quarks
static const long QUARK_ADD = zone.intern ("add");
static const long QUARK_RESET = zone.intern ("reset");
static const long QUARK_EMPTY = zone.intern ("empty-p");
static const long QUARK_LENGTH = zone.intern ("length");
static const long QUARK_EXISTS = zone.intern ("exists-p");
// create a new object in a generic way
Object* Lexicon::mknew (Vector* argv) {
long argc = (argv == nilp) ? 0 : argv->length ();
// check for 0 argument
if (argc == 0) return new Lexicon;
throw Exception ("argument-error", "too many arguments with lexicon");
}
// return true if the given quark is defined
bool Lexicon::isquark (const long quark, const bool hflg) const {
rdlock ();
if (zone.exists (quark) == true) {
unlock ();
return true;
}
bool result = hflg ? Object::isquark (quark, hflg) : false;
unlock ();
return result;
}
// apply this object with a set of arguments and a quark
Object* Lexicon::apply (Runnable* robj, Nameset* nset, const long quark,
Vector* argv) {
// get the number of arguments
long argc = (argv == nilp) ? 0 : argv->length ();
// dispatch 0 argument
if (argc == 0) {
if (quark == QUARK_EMPTY) return new Boolean (empty ());
if (quark == QUARK_LENGTH) return new Integer (length ());
if (quark == QUARK_RESET) {
reset ();
return nilp;
}
}
// dispatch 1 argument
if (argc == 1) {
if (quark == QUARK_ADD) {
String name = argv->getstring (0);
add (name);
return nilp;
}
if (quark == QUARK_EXISTS) {
String name = argv->getstring (0);
return new Boolean (exists (name));
}
}
// call the object method
return Object::apply (robj, nset, quark, argv);
}
}
syntax highlighted by Code2HTML, v. 0.9.1