aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/goto.cpp29
-rw-r--r--src/goto.h39
-rw-r--r--src/help.cpp14
-rw-r--r--src/help.h16
-rw-r--r--src/qregisters.cpp2
-rw-r--r--src/qregisters.h44
-rw-r--r--src/rbtree.cpp6
-rw-r--r--src/rbtree.h138
8 files changed, 167 insertions, 121 deletions
diff --git a/src/goto.cpp b/src/goto.cpp
index c5fda9a..01cf0a9 100644
--- a/src/goto.cpp
+++ b/src/goto.cpp
@@ -42,16 +42,15 @@ namespace Goto {
}
gint
-GotoTable::remove(gchar *name)
+GotoTable::remove(const gchar *name)
{
gint existing_pc = -1;
- Label label(name);
- Label *existing = (Label *)RBTree::find(&label);
+ Label *existing = (Label *)RBTreeString::find(name);
if (existing) {
existing_pc = existing->pc;
- RBTree::remove(existing);
+ RBTreeString::remove(existing);
delete existing;
}
@@ -59,35 +58,29 @@ GotoTable::remove(gchar *name)
}
gint
-GotoTable::find(gchar *name)
+GotoTable::find(const gchar *name)
{
- Label label(name);
- Label *existing = (Label *)RBTree::find(&label);
+ Label *existing = (Label *)RBTreeString::find(name);
return existing ? existing->pc : -1;
}
gint
-GotoTable::set(gchar *name, gint pc)
+GotoTable::set(const gchar *name, gint pc)
{
if (pc < 0)
return remove(name);
- Label *label = new Label(name, pc);
- Label *existing;
gint existing_pc = -1;
+ Label *existing = (Label *)RBTreeString::find(name);
- existing = (Label *)RBTree::find(label);
if (existing) {
existing_pc = existing->pc;
g_free(existing->name);
- existing->name = label->name;
- existing->pc = label->pc;
-
- label->name = NULL;
- delete label;
+ existing->name = g_strdup(name);
+ existing->pc = pc;
} else {
- RBTree::insert(label);
+ RBTree::insert(new Label(name, pc));
}
#ifdef DEBUG
@@ -101,7 +94,7 @@ GotoTable::set(gchar *name, gint pc)
void
GotoTable::dump(void)
{
- for (Label *cur = (Label *)RBTree::min();
+ for (Label *cur = (Label *)min();
cur != NULL;
cur = (Label *)cur->next())
g_printf("table[\"%s\"] = %d\n", cur->name, cur->pc);
diff --git a/src/goto.h b/src/goto.h
index 1621acd..4fa5766 100644
--- a/src/goto.h
+++ b/src/goto.h
@@ -30,7 +30,7 @@
namespace SciTECO {
-class GotoTable : public RBTree {
+class GotoTable : private RBTreeString {
class UndoTokenSet : public UndoToken {
GotoTable *table;
@@ -38,7 +38,7 @@ class GotoTable : public RBTree {
gint pc;
public:
- UndoTokenSet(GotoTable *_table, gchar *_name, gint _pc = -1)
+ UndoTokenSet(GotoTable *_table, const gchar *_name, gint _pc = -1)
: table(_table), name(g_strdup(_name)), pc(_pc) {}
~UndoTokenSet()
{
@@ -61,23 +61,12 @@ class GotoTable : public RBTree {
}
};
- class Label : public RBTree::RBEntry {
+ class Label : public RBEntryOwnString {
public:
- gchar *name;
- gint pc;
-
- Label(gchar *_name, gint _pc = -1)
- : name(g_strdup(_name)), pc(_pc) {}
- ~Label()
- {
- g_free(name);
- }
+ gint pc;
- int
- operator <(RBEntry &l2)
- {
- return g_strcmp0(name, ((Label &)l2).name);
- }
+ Label(const gchar *name, gint _pc = -1)
+ : RBEntryOwnString(name), pc(_pc) {}
};
/*
@@ -86,19 +75,25 @@ class GotoTable : public RBTree {
bool must_undo;
public:
- GotoTable(bool _undo = true) : RBTree(), must_undo(_undo) {}
+ GotoTable(bool _undo = true) : must_undo(_undo) {}
- gint remove(gchar *name);
- gint find(gchar *name);
+ gint remove(const gchar *name);
+ gint find(const gchar *name);
- gint set(gchar *name, gint pc);
+ gint set(const gchar *name, gint pc);
inline void
- undo_set(gchar *name, gint pc = -1)
+ undo_set(const gchar *name, gint pc = -1)
{
if (must_undo)
undo.push<UndoTokenSet>(this, name, pc);
}
+ inline void
+ clear(void)
+ {
+ RBTreeString::clear();
+ }
+
#ifdef DEBUG
void dump(void);
#endif
diff --git a/src/help.cpp b/src/help.cpp
index 0205cf1..542a11f 100644
--- a/src/help.cpp
+++ b/src/help.cpp
@@ -51,6 +51,10 @@ HelpIndex::load(void)
GDir *women_dir;
const gchar *basename;
+ if (G_UNLIKELY(min() != NULL))
+ /* already loaded */
+ return;
+
lib_path = QRegisters::globals["$SCITECOPATH"]->get_string();
women_path = g_build_filename(lib_path, "women", NIL);
g_free(lib_path);
@@ -157,10 +161,9 @@ HelpIndex::find(const gchar *name)
*/
gchar *term = String::canonicalize_ctl(name);
- Topic topic(term);
- ret = (Topic *)RBTree::find(&topic);
- g_free(term);
+ ret = (Topic *)RBTreeStringCase::find(term);
+ g_free(term);
return ret;
}
@@ -170,7 +173,7 @@ HelpIndex::set(const gchar *name, const gchar *filename, tecoInt pos)
Topic *topic = new Topic(name, filename, pos);
Topic *existing;
- existing = (Topic *)RBTree::find(topic);
+ existing = (Topic *)RBTree<RBEntryString>::find(topic);
if (existing) {
gchar *basename;
@@ -279,8 +282,7 @@ StateGetHelp::initial(void)
* not depend on the availability of the standard
* library.
*/
- if (G_UNLIKELY(!help_index.min()))
- help_index.load();
+ help_index.load();
}
State *
diff --git a/src/help.h b/src/help.h
index db78979..7ce7ea2 100644
--- a/src/help.h
+++ b/src/help.h
@@ -30,29 +30,21 @@
namespace SciTECO {
-class HelpIndex : public RBTree {
+class HelpIndex : private RBTreeStringCase {
public:
- class Topic : public RBTree::RBEntry {
+ class Topic : public RBEntryOwnString {
public:
- gchar *name;
gchar *filename;
tecoInt pos;
- Topic(const gchar *_name, const gchar *_filename = NULL, tecoInt _pos = 0)
- : name(g_strdup(_name)),
+ Topic(const gchar *name, const gchar *_filename = NULL, tecoInt _pos = 0)
+ : RBEntryOwnString(name),
filename(_filename ? g_strdup(_filename) : NULL),
pos(_pos) {}
~Topic()
{
- g_free(name);
g_free(filename);
}
-
- int
- operator <(RBEntry &l2)
- {
- return g_ascii_strcasecmp(name, ((Topic &)l2).name);
- }
};
void load(void);
diff --git a/src/qregisters.cpp b/src/qregisters.cpp
index c4c164f..6ca7990 100644
--- a/src/qregisters.cpp
+++ b/src/qregisters.cpp
@@ -696,7 +696,7 @@ QRegisterClipboard::undo_exchange_string(QRegisterData &reg)
reg.undo_set_string();
}
-QRegisterTable::QRegisterTable(bool _undo) : RBTree(), must_undo(_undo)
+QRegisterTable::QRegisterTable(bool _undo) : must_undo(_undo)
{
/* general purpose registers */
for (gchar q = 'A'; q <= 'Z'; q++)
diff --git a/src/qregisters.h b/src/qregisters.h
index 22fa93d..1ea47ee 100644
--- a/src/qregisters.h
+++ b/src/qregisters.h
@@ -134,30 +134,17 @@ public:
friend class QRegisterStack;
};
-class QRegister : public RBTree::RBEntry, public QRegisterData {
+class QRegister : public RBTreeString::RBEntryOwnString, public QRegisterData {
protected:
/**
* The default constructor for subclasses.
* This leaves the name uninitialized.
*/
- QRegister(void) : name(NULL) {}
+ QRegister() {}
public:
- gchar *name;
-
- QRegister(const gchar *_name)
- : name(g_strdup(_name)) {}
- virtual
- ~QRegister()
- {
- g_free(name);
- }
-
- int
- operator <(RBEntry &entry)
- {
- return g_strcmp0(name, ((QRegister &)entry).name);
- }
+ QRegister(const gchar *name)
+ : RBTreeString::RBEntryOwnString(name) {}
virtual void edit(void);
virtual void undo_edit(void);
@@ -300,7 +287,7 @@ public:
void undo_exchange_string(QRegisterData &reg);
};
-class QRegisterTable : private RBTree {
+class QRegisterTable : private RBTreeString {
class UndoTokenRemove : public UndoTokenWithSize<UndoTokenRemove> {
QRegisterTable *table;
QRegister *reg;
@@ -332,11 +319,7 @@ public:
insert(QRegister *reg)
{
reg->must_undo = must_undo;
- /* FIXME: Returns already existing regs with the same name.
- This could be used to optimize commands that initialize
- a register if it does not yet exist (saves one table
- lookup): */
- RBTree::insert(reg);
+ RBTreeString::insert(reg);
return reg;
}
inline QRegister *
@@ -352,30 +335,33 @@ public:
}
inline QRegister *
+ find(const gchar *name)
+ {
+ return (QRegister *)RBTreeString::find(name);
+ }
+ inline QRegister *
operator [](const gchar *name)
{
- QRegister reg(name);
- return (QRegister *)find(&reg);
+ return find(name);
}
inline QRegister *
operator [](gchar chr)
{
gchar buf[] = {chr, '\0'};
- return operator [](buf);
+ return find(buf);
}
inline QRegister *
nfind(const gchar *name)
{
- QRegister reg(name);
- return (QRegister *)RBTree::nfind(&reg);
+ return (QRegister *)RBTreeString::nfind(name);
}
void edit(QRegister *reg);
inline QRegister *
edit(const gchar *name)
{
- QRegister *reg = operator [](name);
+ QRegister *reg = find(name);
if (!reg)
return NULL;
diff --git a/src/rbtree.cpp b/src/rbtree.cpp
index e64de96..f1d870d 100644
--- a/src/rbtree.cpp
+++ b/src/rbtree.cpp
@@ -19,12 +19,14 @@
#include "config.h"
#endif
-#include <bsd/sys/tree.h>
+#include <glib.h>
+#include <glib/gprintf.h>
#include "rbtree.h"
namespace SciTECO {
-RB_GENERATE(RBTree::Tree, RBTree::RBEntry, nodes, RBTree::compare_entries);
+template class RBTreeStringT<strcmp, strncmp>;
+template class RBTreeStringT<g_ascii_strcasecmp, g_ascii_strncasecmp>;
} /* namespace SciTECO */
diff --git a/src/rbtree.h b/src/rbtree.h
index bc836bd..4a4bbdb 100644
--- a/src/rbtree.h
+++ b/src/rbtree.h
@@ -18,30 +18,22 @@
#ifndef __RBTREE_H
#define __RBTREE_H
+#include <string.h>
+
#include <bsd/sys/tree.h>
#include <glib.h>
-
-#include "undo.h"
+#include <glib/gprintf.h>
namespace SciTECO {
+template <class RBEntryType>
class RBTree {
public:
- class RBEntry;
-
-private:
- RB_HEAD(Tree, RBEntry) head;
-
- RB_PROTOTYPE_INTERNAL(Tree, RBEntry, nodes, /* unused */, static);
-
-public:
class RBEntry {
public:
RB_ENTRY(RBEntry) nodes;
- virtual ~RBEntry() {}
-
inline RBEntry *
next(void)
{
@@ -52,17 +44,23 @@ public:
{
return RBTree::Tree_RB_PREV(this);
}
-
- virtual int operator <(RBEntry &entry) = 0;
};
private:
+ RB_HEAD(Tree, RBEntry) head;
+
static inline int
compare_entries(RBEntry *e1, RBEntry *e2)
{
- return *e1 < *e2;
+ return ((RBEntryType *)e1)->compare(*(RBEntryType *)e2);
}
+ /*
+ * All generated functions are plain-C, so they can be
+ * static methods.
+ */
+ RB_GENERATE_INTERNAL(Tree, RBEntry, nodes, compare_entries, static);
+
public:
RBTree()
{
@@ -74,42 +72,47 @@ public:
clear();
}
- inline RBEntry *
- insert(RBEntry *entry)
+ inline RBEntryType *
+ insert(RBEntryType *entry)
{
RB_INSERT(Tree, &head, entry);
return entry;
}
- inline RBEntry *
- remove(RBEntry *entry)
+ inline RBEntryType *
+ remove(RBEntryType *entry)
+ {
+ return (RBEntryType *)RB_REMOVE(Tree, &head, entry);
+ }
+ inline RBEntryType *
+ find(RBEntryType *entry)
{
- return RB_REMOVE(Tree, &head, entry);
+ return (RBEntryType *)RB_FIND(Tree, &head, entry);
}
- inline RBEntry *
- find(RBEntry *entry)
+ inline RBEntryType *
+ operator [](RBEntryType *entry)
{
- return RB_FIND(Tree, &head, entry);
+ return find(entry);
}
- inline RBEntry *
- nfind(RBEntry *entry)
+ inline RBEntryType *
+ nfind(RBEntryType *entry)
{
- return RB_NFIND(Tree, &head, entry);
+ return (RBEntryType *)RB_NFIND(Tree, &head, entry);
}
- inline RBEntry *
+ inline RBEntryType *
min(void)
{
- return RB_MIN(Tree, &head);
+ return (RBEntryType *)RB_MIN(Tree, &head);
}
- inline RBEntry *
+ inline RBEntryType *
max(void)
{
- return RB_MAX(Tree, &head);
+ return (RBEntryType *)RB_MAX(Tree, &head);
}
inline void
clear(void)
{
- RBEntry *cur;
+ RBEntryType *cur;
while ((cur = min())) {
remove(cur);
@@ -118,6 +121,79 @@ public:
}
};
+typedef gint (*StringCmpFunc)(const gchar *str1, const gchar *str2);
+typedef gint (*StringNCmpFunc)(const gchar *str1, const gchar *str2, gsize n);
+
+template <StringCmpFunc StringCmp>
+class RBEntryStringT : public RBTree<RBEntryStringT<StringCmp>>::RBEntry {
+public:
+ /*
+ * It is convenient to be able to access the string
+ * key with various attribute names.
+ */
+ union {
+ gchar *key;
+ gchar *name;
+ };
+
+ RBEntryStringT(gchar *_key) : key(_key) {}
+
+ virtual ~RBEntryStringT() {}
+
+ inline gint
+ compare(RBEntryStringT &other)
+ {
+ return StringCmp(key, other.key);
+ }
+};
+
+template <StringCmpFunc StringCmp, StringNCmpFunc StringNCmp>
+class RBTreeStringT : public RBTree<RBEntryStringT<StringCmp>> {
+public:
+ typedef RBEntryStringT<StringCmp> RBEntryString;
+
+ class RBEntryOwnString : public RBEntryString {
+ public:
+ RBEntryOwnString(const gchar *key = NULL)
+ : RBEntryString(key ? g_strdup(key) : NULL) {}
+
+ ~RBEntryOwnString()
+ {
+ g_free(RBEntryString::key);
+ }
+ };
+
+ inline RBEntryString *
+ find(const gchar *str)
+ {
+ RBEntryString entry((gchar *)str);
+ return RBTree<RBEntryString>::find(&entry);
+ }
+ inline RBEntryString *
+ operator [](const gchar *name)
+ {
+ return find(name);
+ }
+
+ inline RBEntryString *
+ nfind(const gchar *str)
+ {
+ RBEntryString entry((gchar *)str);
+ return RBTree<RBEntryString>::nfind(&entry);
+ }
+};
+
+typedef RBTreeStringT<strcmp, strncmp> RBTreeString;
+typedef RBTreeStringT<g_ascii_strcasecmp, g_ascii_strncasecmp> RBTreeStringCase;
+
+/*
+ * Only these two instantiations of RBTreeStringT are ever used,
+ * so it is more efficient to explicitly instantiate them.
+ * NOTE: The insane rules of C++ prevent using the typedefs here...
+ */
+extern template class RBTreeStringT<strcmp, strncmp>;
+extern template class RBTreeStringT<g_ascii_strcasecmp, g_ascii_strncasecmp>;
+
} /* namespace SciTECO */
#endif