diff options
author | Rodrigo Arias Mallo <rodarima@gmail.com> | 2024-12-10 22:30:12 +0100 |
---|---|---|
committer | Rodrigo Arias Mallo <rodarima@gmail.com> | 2024-12-10 22:30:12 +0100 |
commit | 429d5f88b94ff28416cbfc6420b6389fa284df97 (patch) | |
tree | fb6fdaf7731de1ef396f98b748c56f3149801c84 /common/tools.cc |
Import RTFL 0.1.1v0.1.1
Diffstat (limited to 'common/tools.cc')
-rw-r--r-- | common/tools.cc | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/common/tools.cc b/common/tools.cc new file mode 100644 index 0000000..7dfb412 --- /dev/null +++ b/common/tools.cc @@ -0,0 +1,264 @@ +/* + * RTFL + * + * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version; with the following exception: + * + * The copyright holders of RTFL give you permission to link this file + * statically or dynamically against all versions of the graphviz + * library, which are published by AT&T Corp. under one of the following + * licenses: + * + * - Common Public License version 1.0 as published by International + * Business Machines Corporation (IBM), or + * - Eclipse Public License version 1.0 as published by the Eclipse + * Foundation. + * + * 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "tools.hh" + +#include <stdio.h> +#include <errno.h> + +using namespace lout::object; +using namespace lout::container::untyped; + +namespace rtfl { + +namespace tools { + +const char *numSuffix (int n) +{ + if (n % 10 == 1 && n != 11) + return "st"; + else if (n % 10 == 2 && n != 12) + return "nd"; + else if (n % 10 == 3 && n != 13) + return "rd"; + else + return "th"; +} + +static const char + *const roman_I0[] = { "","I","II","III","IV","V","VI","VII","VIII","IX" }, + *const roman_I1[] = { "","X","XX","XXX","XL","L","LX","LXX","LXXX","XC" }, + *const roman_I2[] = { "","C","CC","CCC","CD","D","DC","DCC","DCCC","CM" }, + *const roman_I3[] = { "","M","MM","MMM","MMMM" }; + +void numToRoman (int num, char *buf, int buflen) +{ + int i3, i2, i1, i0; + + if (buflen <= 0) + return; + + i0 = num; + i1 = i0/10; i2 = i1/10; i3 = i2/10; + i0 %= 10; i1 %= 10; i2 %= 10; + if (num < 0 || i3 > 4) /* more than 4999 elements ? */ + snprintf(buf, buflen, "****"); + else + snprintf(buf, buflen, "%s%s%s%s", roman_I3[i3], roman_I2[i2], + roman_I1[i1], roman_I0[i0]); +} + +void syserr (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + vfprintf (stderr, fmt, args); + fprintf (stderr, ": %s\n", strerror (errno)); + exit (1); +} + +// ---------------------------------------------------------------------- + +EquivalenceRelation::RefTarget::RefTarget (Object *object, bool ownerOfObject) +{ + this->object = object; + this->ownerOfObject = ownerOfObject; + refCount = 1; + allKeys = new HashSet (false); +} + +EquivalenceRelation::RefTarget::~RefTarget () +{ + if (ownerOfObject) + delete object; + delete allKeys; +} + +// ---------------------------------------------------------------------- + +EquivalenceRelation::RefSource::RefSource (Object *key, RefTarget *target) +{ + this->target = target; + this->key = key; + refTarget (); +} + +EquivalenceRelation::RefSource::~RefSource () +{ + unrefTarget (); +} + +void EquivalenceRelation::RefSource::refTarget () +{ + if (target) { + target->ref (); + target->putKey (key); + } +} + +void EquivalenceRelation::RefSource::unrefTarget () +{ + if (target) { + target->removeKey (key); + target->unref (); + target = NULL; + } +} + +void EquivalenceRelation::RefSource::setTarget (RefTarget *target) +{ + if (target != this->target) { + unrefTarget (); + this->target = target; + refTarget (); + } +} + +// ---------------------------------------------------------------------- + +EquivalenceRelation::EquivalenceRelation (bool ownerOfKeys, bool ownerOfValues) +{ + this->ownerOfKeys = ownerOfKeys; + this->ownerOfValues = ownerOfValues; + sources = new HashTable (ownerOfKeys, true); +} + +EquivalenceRelation::~EquivalenceRelation () +{ + delete sources; +} + +void EquivalenceRelation::put (Object *key, Object *value) +{ + assert (!contains(key)); + + RefTarget *target = new RefTarget (value, ownerOfValues); + RefSource *source = new RefSource (key, target); + target->unref (); + sources->put (key, source); +} + +Object *EquivalenceRelation::get (Object *key) const +{ + RefSource *source = (RefSource*) sources->get(key); + if (source) { + Object *object = source->getTarget()->getObject (); + return object; + } else + return NULL; +} + +bool EquivalenceRelation::contains (Object *key) const +{ + return sources->contains (key); +} + +Iterator EquivalenceRelation::iterator () +{ + return sources->iterator (); +} + +Iterator EquivalenceRelation::relatedIterator (Object *key) +{ + assert (contains (key)); + + RefSource *source = (RefSource*) sources->get (key); + RefTarget *target = source->getTarget (); + return target->getAllKeys()->iterator (); +} + +void EquivalenceRelation::relate (Object *key1, Object *key2) +{ + assert (contains(key1) && contains(key2)); + + RefSource *source1 = (RefSource*) sources->get (key1); + RefSource *source2 = (RefSource*) sources->get (key2); + if (source1->getTarget () != source2->getTarget ()) { + // The first value is kept, the second destroyed. The caller has + // to care about the order. + + // Consider all keys already related to `key2`; this is possible by + // iterating over `RefTarget::allKeys`. To avoid accessing freed memory, + // copy all keys to a new temporary set. + + HashSet target2Keys (false); + for (Iterator it = source2->getTarget()->getAllKeys()->iterator (); + it.hasNext (); ) + target2Keys.put (it.getNext ()); + + for (Iterator it = target2Keys.iterator (); it.hasNext (); ) { + RefSource *otherSource = (RefSource*) sources->get (it.getNext ()); + otherSource->setTarget (source1->getTarget ()); + } + } +} + +void EquivalenceRelation::putRelated (Object *oldKey, Object *newKey) +{ + assert (contains(oldKey) && !contains(newKey)); + + RefSource *oldSource = (RefSource*) sources->get (oldKey); + RefSource *newSource = new RefSource (newKey, oldSource->getTarget ()); + sources->put (newKey, newSource); +} + +void EquivalenceRelation::removeSimple (lout::object::Object *key) +{ + // The order is important: a simple "sources->remove (key)" will + // cause an access to freed memory. + + RefSource *source = (RefSource*) sources->get (key); + source->setTarget (NULL); // Will unref() the target. + sources->remove (key); +} + +void EquivalenceRelation::remove (Object *key) +{ + assert (contains (key)); + + RefSource *source = (RefSource*) sources->get (key); + RefTarget *target = source->getTarget (); + target->ref (); + + for (Iterator it = target->getAllKeys()->iterator (); it.hasNext (); ) { + Object *otherKey = it.getNext (); + + // The order is important: see removeSimple(). + RefSource *otherSource = (RefSource*) sources->get (otherKey); + otherSource->setTarget (NULL); // Will unref() the target. + sources->remove (otherKey); + } + + target->unref (); +} + + +} // namespace tools + +} // namespace dw |