]> granicus.if.org Git - re2c/commitdiff
Restricted 'Tagpool' lifetime to DFA construction phase.
authorUlya Trofimovich <skvadrik@gmail.com>
Mon, 31 Oct 2016 15:59:57 +0000 (15:59 +0000)
committerUlya Trofimovich <skvadrik@gmail.com>
Mon, 31 Oct 2016 16:05:16 +0000 (16:05 +0000)
20 files changed:
re2c/Makefile.am
re2c/src/codegen/emit_action.cc
re2c/src/ir/adfa/adfa.cc
re2c/src/ir/adfa/adfa.h
re2c/src/ir/dfa/determinization.cc
re2c/src/ir/dfa/dfa.h
re2c/src/ir/dfa/fallback_tags.cc
re2c/src/ir/dfa/tag_liveness.cc
re2c/src/ir/dfa/tag_optimize.cc
re2c/src/ir/dfa/tag_optimize.h
re2c/src/ir/dfa/tag_renaming.cc
re2c/src/ir/dfa/tagpool.cc [new file with mode: 0644]
re2c/src/ir/dfa/tagpool.h [new file with mode: 0644]
re2c/src/ir/nfa/init_rules.cc
re2c/src/ir/nfa/nfa.cc
re2c/src/ir/nfa/nfa.h
re2c/src/ir/rule.h
re2c/src/ir/skeleton/skeleton.cc
re2c/src/ir/tag.cc
re2c/src/ir/tag.h

index 7bbc82f04cbbb6ed2b15a9d4583d1ab7c9b3f16f..778cc478740b9e6847cbceaa436f1ea83586791d 100644 (file)
@@ -26,6 +26,7 @@ SRC_HDR = \
        src/ir/dfa/dfa.h \
        src/ir/dfa/find_state.h \
        src/ir/dfa/tag_optimize.h \
+       src/ir/dfa/tagpool.h \
        src/ir/nfa/nfa.h \
        src/ir/regexp/encoding/case.h \
        src/ir/regexp/encoding/enc.h \
@@ -105,6 +106,7 @@ SRC = \
        src/ir/dfa/tag_liveness.cc \
        src/ir/dfa/tag_optimize.cc \
        src/ir/dfa/tag_renaming.cc \
+       src/ir/dfa/tagpool.cc \
        src/ir/regexp/encoding/enc.cc \
        src/ir/regexp/encoding/range_suffix.cc \
        src/ir/regexp/encoding/utf8/utf8_regexp.cc \
index 6295b92ea09531a3ac97c0f52d038efc5524ea94..9c153621e17f1af30a3b7ae4782f237abc253739 100644 (file)
@@ -427,7 +427,7 @@ void gen_fintags(OutputFile &o, uint32_t ind, const DFA &dfa, const Rule &rule)
 {
        const bool generic = opts->input_api.type() == InputAPI::CUSTOM;
        const std::valarray<Tag> &tags = dfa.tags;
-       const tagver_t *vers = dfa.tagpool[rule.tags];
+       const tagver_t *vers = rule.tags;
 
        // trailing context
        if (rule.trail != Tag::NONE) {
index 226c5bdf939f22c6f5f1fa749cf627d4b61e4385..63fcd1d727ead09a49e1b3ffdde3bda81de4008f 100644 (file)
@@ -35,7 +35,6 @@ DFA::DFA
        , head(NULL)
        , rules(dfa.rules)
        , tags(dfa.tags)
-       , tagpool(dfa.tagpool)
        , max_fill (0)
        , need_backup (false)
        , need_accept (false)
@@ -97,7 +96,6 @@ DFA::~DFA()
        delete skeleton;
        delete &rules;
        delete &tags;
-       delete &tagpool;
 }
 
 /* note [reordering DFA states]
index fb0d8f7fcfdc492e161b3b57dc0a8ac8f64a56b7..b7354bb38a6a36464034f94fb59f9e37a3445a79 100644 (file)
@@ -68,7 +68,6 @@ struct DFA
        State * head;
        std::valarray<Rule> &rules;
        std::valarray<Tag> &tags;
-       Tagpool &tagpool;
        size_t max_fill;
        bool need_backup;
        bool need_accept;
index 3a93da4acc1210c4e5972e3652260d410e860acf..c16f39a47262d5c62c58496ad9d2e785cdaac513 100644 (file)
@@ -55,10 +55,10 @@ dfa_t::dfa_t(const nfa_t &nfa,
        , nchars(charset.size() - 1) // (n + 1) bounds for n ranges
        , rules(nfa.rules)
        , tags(*nfa.tags)
-       , tagpool(*nfa.tagpool)
        , maxtagver(0)
 {
        const size_t ntag = tags.size();
+       Tagpool tagpool(ntag);
        clospool_t clospool;
        closure_t clos1, clos2;
        bool *badtags = new bool[ntag]();
index 7fa5eb244ca6b859c30f48659c4783e64704aaf0..b2df17f7ddc162d661cfe77c4f0ef99599eaee15 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/ir/regexp/regexp.h"
 #include "src/ir/rule.h"
 #include "src/ir/tag.h"
+#include "src/ir/dfa/tagpool.h"
 #include "src/util/forbid_copy.h"
 
 namespace re2c
@@ -50,7 +51,6 @@ struct dfa_t
        const size_t nchars;
        std::valarray<Rule> &rules;
        std::valarray<Tag> &tags;
-       Tagpool &tagpool;
        tagver_t maxtagver;
 
        dfa_t(const nfa_t &nfa, const charset_t &charset,
index e850e54807426cd790a7261ce2d5261ab89f7cc5..0956df2efec6ca040780dd33c7a0b9afab6c75f8 100644 (file)
@@ -78,7 +78,7 @@ void insert_fallback_tags(dfa_t &dfa)
                std::fill(owrt, owrt + nver, false);
                find_overwritten_tags(dfa, i, been, owrt);
 
-               const tagver_t *fin = dfa.tagpool[dfa.rules[s->rule].tags];
+               const tagver_t *fin = dfa.rules[s->rule].tags;
                for (const tagsave_t *p = s->rule_tags.save; p; p = p->next) {
                        owrt[p->ver] = false;
                }
index 2df92cf926e2ec36ce30900fa7d28db99849de26..739b9c14e5acd9a76c8218094460c0d79f23518f 100644 (file)
@@ -7,11 +7,10 @@ namespace re2c
 
 void tag_liveness(const cfg_t &cfg, bool *live)
 {
-       const Tagpool &tagpool = cfg.dfa.tagpool;
        const size_t
                nbb = cfg.nbblock,
                nver = static_cast<size_t>(cfg.dfa.maxtagver) + 1,
-               ntag = tagpool.ntags;
+               ntag = cfg.dfa.tags.size();
        bool *buf1 = new bool[nver];
        bool *buf2 = new bool[nver];
 
@@ -32,11 +31,10 @@ void tag_liveness(const cfg_t &cfg, bool *live)
                        const cfg_bb_t *b = cfg.bblocks + i;
 
                        memset(buf1, 0, nver * sizeof(bool));
-                       if (b->use != TAGVER_ZERO) {
+                       if (b->use) {
                                // final bblock, no successors
-                               const tagver_t *use = tagpool[b->use];
                                for (size_t t = 0; t < ntag; ++t) {
-                                       const tagver_t u = use[t];
+                                       const tagver_t u = b->use[t];
                                        if (u != TAGVER_ZERO) {
                                                buf1[u] = true;
                                        }
@@ -83,12 +81,11 @@ void tag_liveness(const cfg_t &cfg, bool *live)
        for (cfg_ix_t i = 0; i < nbb; ++i) {
                const cfg_bb_t *b = cfg.bblocks + i;
 
-               if (b->use == TAGVER_ZERO) continue;
+               if (!b->use) continue;
 
-               const tagver_t *use = tagpool[b->use];
                memset(buf1, 0, nver * sizeof(bool));
                for (size_t t = 0; t < ntag; ++t) {
-                       const tagver_t u = use[t];
+                       const tagver_t u = b->use[t];
                        if (u != TAGVER_ZERO) {
                                buf1[u] = true;
                        }
index 305c2c724b9e1203ce10789f4d8b384fc064c196..8a208deafebddc68e680e6e54deaaf2236233335 100644 (file)
@@ -8,7 +8,7 @@ namespace re2c
 
 static cfg_ix_t map_arcs_to_bblocks(const dfa_t &dfa, cfg_ix_t *arc2bb);
 static cfg_bb_t *create_bblocks(const dfa_t &dfa, const cfg_ix_t *arc2bb, cfg_ix_t nbblock);
-static void basic_block(cfg_bb_t *bb, const cfg_ix_t *succb, const cfg_ix_t *succe, const tagcmd_t *cmd, size_t use);
+static void basic_block(cfg_bb_t *bb, const cfg_ix_t *succb, const cfg_ix_t *succe, const tagcmd_t *cmd, tagver_t *use);
 static void successors(const dfa_t &dfa, const cfg_ix_t *arc2bb, bool *been, cfg_ix_t *&succ, size_t x);
 static void fallback(const dfa_t &dfa, const cfg_ix_t *arc2bb, bool *been, cfg_ix_t *&succ, size_t x);
 
@@ -122,7 +122,7 @@ cfg_bb_t *create_bblocks(const dfa_t &dfa, const cfg_ix_t *arc2bb, cfg_ix_t nbbl
 }
 
 void basic_block(cfg_bb_t *bb, const cfg_ix_t *succb,
-       const cfg_ix_t *succe, const tagcmd_t *cmd, size_t use)
+       const cfg_ix_t *succe, const tagcmd_t *cmd, tagver_t *use)
 {
        const size_t n = static_cast<size_t>(succe - succb);
        cfg_ix_t *s = new cfg_ix_t[n];
index 4bb0bac306c3ff6d5f97a2e57e004bffd3bc189f..5252621a86e55b1d48c8fffccdcd8b9ccf696d2c 100644 (file)
@@ -13,7 +13,7 @@ struct cfg_bb_t
        cfg_ix_t *succb;
        cfg_ix_t *succe;
        tagcmd_t *cmd;
-       size_t use;
+       tagver_t *use;
 };
 
 // control flow graph
index 1582910dad962ea69439f484934070b54615b968..4e954b87fe47325deae6b771a0ab351636624323 100644 (file)
@@ -3,66 +3,41 @@
 namespace re2c
 {
 
-static void rename_rule(Tagpool &tagpool, size_t &tags, const tagver_t *ver2new);
-static void rename_save(tagsave_t **psave, const tagver_t *ver2new);
-static void rename_copy(tagcopy_t **pcopy, const tagver_t *ver2new);
-
 void tag_renaming(cfg_t &cfg, const tagver_t *ver2new, tagver_t maxver)
 {
        tagver_t &oldmax = cfg.dfa.maxtagver;
-       if (maxver >= oldmax) {
-               assert(maxver == oldmax);
-               return;
-       }
+       if (oldmax == maxver) return;
        oldmax = maxver;
 
        cfg_bb_t *b = cfg.bblocks, *e = b + cfg.nbblock;
        for (; b < e; ++b) {
-               rename_save(&b->cmd->save, ver2new);
-               rename_copy(&b->cmd->copy, ver2new);
-       }
-
-       std::valarray<Rule> &rules = cfg.dfa.rules;
-       Tagpool &tagpool = cfg.dfa.tagpool;
-       for (size_t i = 0; i < rules.size(); ++i) {
-               rename_rule(tagpool, rules[i].tags, ver2new);
-       }
-}
-
-void rename_rule(Tagpool &tagpool, size_t &tags, const tagver_t *ver2new)
-{
-       if (tags == ZERO_TAGS) return;
-
-       const tagver_t *oldver = tagpool[tags];
-       tagver_t *newver = tagpool.buffer1;
-       const size_t ntag = tagpool.ntags;
 
-       for (size_t t = 0; t < ntag; ++t) {
-               const tagver_t v = oldver[t];
-               newver[t] = v != TAGVER_ZERO
-                       ? ver2new[v]
-                       : v;
-       }
-
-       tags = tagpool.insert(newver);
-}
+               // tag versions in save commands
+               for (tagsave_t *p = b->cmd->save; p; p = p->next) {
+                       p->ver = ver2new[p->ver];
+               }
 
-void rename_save(tagsave_t **psave, const tagver_t *ver2new)
-{
-       for (tagsave_t *p = *psave; p; p = p->next) {
-               p->ver = ver2new[p->ver];
+               // tag versions in copy commands
+               for (tagcopy_t *c, **pc = &b->cmd->copy; (c = *pc);) {
+                       c->lhs = ver2new[c->lhs];
+                       c->rhs = ver2new[c->rhs];
+                       if (c->lhs == c->rhs) {
+                               *pc = c->next;
+                       } else {
+                               pc = &c->next;
+                       }
+               }
        }
-}
 
-void rename_copy(tagcopy_t **pcopy, const tagver_t *ver2new)
-{
-       for (tagcopy_t *c, **pc = pcopy; (c = *pc);) {
-               c->lhs = ver2new[c->lhs];
-               c->rhs = ver2new[c->rhs];
-               if (c->lhs == c->rhs) {
-                       *pc = c->next;
-               } else {
-                       pc = &c->next;
+       // final tag versions in rules
+       std::valarray<Rule> &rules = cfg.dfa.rules;
+       for (size_t r = 0, t = 0; r < rules.size(); ++r) {
+               Rule &rule = rules[r];
+               for (; t < rule.htag; ++t) {
+                       tagver_t &v = rule.tags[t];
+                       if (v != TAGVER_ZERO) {
+                               v = ver2new[v];
+                       }
                }
        }
 }
diff --git a/re2c/src/ir/dfa/tagpool.cc b/re2c/src/ir/dfa/tagpool.cc
new file mode 100644 (file)
index 0000000..1311f06
--- /dev/null
@@ -0,0 +1,63 @@
+#include <assert.h>
+#include <stdlib.h> // malloc
+#include <string.h> // memcpy, memcmp
+
+#include "src/ir/dfa/tagpool.h"
+#include "src/util/hash32.h"
+
+namespace re2c
+{
+
+struct eqtag_t
+{
+       size_t ntags;
+
+       explicit eqtag_t(size_t n): ntags(n) {}
+       inline tagver_t operator()(const tagver_t *x, const tagver_t *y) const
+       {
+               return memcmp(x, y, ntags * sizeof(tagver_t)) == 0;
+       }
+};
+
+Tagpool::Tagpool(size_t n)
+       : lookup()
+       , buffer(new tagver_t[n * 3])
+       , ntags(n)
+       , buffer1(&buffer[n * 1])
+       , buffer2(&buffer[n * 2])
+{
+       // all-zero tag configuration must have static number zero
+       std::fill(buffer, buffer + ntags, TAGVER_ZERO);
+       assert(ZERO_TAGS == insert(buffer));
+}
+
+Tagpool::~Tagpool()
+{
+       delete[] buffer;
+       const size_t n = lookup.size();
+       for (size_t i = 0; i < n; ++i) {
+               free(const_cast<tagver_t*>(lookup[i]));
+       }
+}
+
+size_t Tagpool::insert(const tagver_t *tags)
+{
+       const size_t size = ntags * sizeof(tagver_t);
+       const uint32_t hash = hash32(0, tags, size);
+
+       const size_t idx = lookup.find_with(hash, tags, eqtag_t(ntags));
+       if (idx != taglookup_t::NIL) {
+               return idx;
+       }
+
+       tagver_t *copy = static_cast<tagver_t*>(malloc(size));
+       memcpy(copy, tags, size);
+       return lookup.push(hash, copy);
+}
+
+const tagver_t *Tagpool::operator[](size_t idx) const
+{
+       return lookup[idx];
+}
+
+} // namespace re2c
diff --git a/re2c/src/ir/dfa/tagpool.h b/re2c/src/ir/dfa/tagpool.h
new file mode 100644 (file)
index 0000000..f7dddfb
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _RE2C_IR_DFA_TAGPOOL_
+#define _RE2C_IR_DFA_TAGPOOL_
+
+#include "src/ir/tag.h"
+#include "src/util/lookup.h"
+#include "src/util/forbid_copy.h"
+
+namespace re2c
+{
+
+static const size_t ZERO_TAGS = 0;
+
+struct Tagpool
+{
+private:
+       typedef lookup_t<const tagver_t*> taglookup_t;
+       taglookup_t lookup;
+       tagver_t *buffer;
+
+public:
+       const size_t ntags;
+       tagver_t *buffer1;
+       tagver_t *buffer2;
+
+       explicit Tagpool(size_t n);
+       ~Tagpool();
+       size_t insert(const tagver_t *tags);
+       const tagver_t *operator[](size_t idx) const;
+       FORBID_COPY(Tagpool);
+};
+
+} // namespace re2c
+
+#endif // _RE2C_IR_DFA_TAGPOOL_
index d884cb17dbefb0044486d5709ab8216499179f7f..b48022e2acb6034ae98e9f44ea9f96d4035c5b7d 100644 (file)
@@ -35,8 +35,7 @@ static void assert_tags_used_once(const Rule &rule,
 
 void init_rules(const std::vector<const RegExpRule*> &regexps,
        std::valarray<Rule> &rules,
-       const std::valarray<Tag> &tags,
-       Tagpool &tagpool)
+       const std::valarray<Tag> &tags)
 {
        const size_t nr = rules.size();
        const size_t nt = tags.size();
@@ -50,14 +49,14 @@ void init_rules(const std::vector<const RegExpRule*> &regexps,
                rule.htag = t;
 
                // mark *all* variable tags, including trailing context
-               tagver_t *vers = tagpool.buffer1;
+               tagver_t *vers = new tagver_t[nt];
                std::fill(vers, vers + nt, TAGVER_ZERO);
                for (size_t i = rule.ltag; i < rule.htag; ++i) {
                        if (tags[i].type == Tag::VAR) {
                                vers[i] = static_cast<tagver_t>(i + 1);
                        }
                }
-               rule.tags = tagpool.insert(vers);
+               rule.tags = vers;
 
                // tags in trailing context are forbidden (they make no sense),
                // and since tags are constructed in reversed order, this implies
index dc92245861f2c1a184ddfa2c5e435a14e7ebcb59..b2dc638aea4160a3a9aaa49d1cc10093c8f0dc11 100644 (file)
@@ -8,20 +8,18 @@ nfa_t::nfa_t(const std::vector<const RegExpRule*> &regexps)
        , states(NULL)
        , rules(*new std::valarray<Rule>(regexps.size()))
        , tags(NULL)
-       , tagpool(NULL)
        , root(NULL)
 {
        size_t ntags = 0;
        max_size = counters(regexps, ntags);
 
-       tagpool = new Tagpool(ntags);
        tags = new std::valarray<Tag>(ntags);
        make_tags(regexps, *tags);
 
        states = new nfa_state_t[max_size];
        regexps2nfa(regexps, *this);
 
-       init_rules(regexps, rules, *tags, *tagpool);
+       init_rules(regexps, rules, *tags);
 }
 
 nfa_t::~nfa_t()
index be376179c536726770976eaee61bcba86e599a19..11fdc89d52aa377fab81ac06a6d3dc76c8e499a0 100644 (file)
@@ -77,7 +77,6 @@ struct nfa_t
        nfa_state_t *states;
        std::valarray<Rule> &rules;
        std::valarray<Tag> *tags;
-       Tagpool *tagpool;
        nfa_state_t *root;
 
        nfa_t(const std::vector<const RegExpRule*> &rs);
@@ -90,10 +89,7 @@ size_t counters(const std::vector<const RegExpRule*> &regexps, size_t &ntags);
 void make_tags(const std::vector<const RegExpRule*> &regexps, std::valarray<Tag> &tags);
 void regexps2nfa(const std::vector<const RegExpRule*> &regexps, nfa_t &nfa);
 bool nullable_rule(const RegExpRule *rule);
-void init_rules(const std::vector<const RegExpRule*> &regexps,
-       std::valarray<Rule> &rules,
-       const std::valarray<Tag> &tags,
-       Tagpool &tagpool);
+void init_rules(const std::vector<const RegExpRule*> &regexps, std::valarray<Rule> &rules, const std::valarray<Tag> &tags);
 
 } // namespace re2c
 
index b1dd91d60fd3e648400d3c8cc39002b7d0790f00..9d7437fa5e85869fcd43cacd36aeb20e61edac0a 100644 (file)
@@ -38,7 +38,7 @@ struct Rule
        size_t ltag;
        size_t htag;
        size_t trail;
-       size_t tags;
+       tagver_t *tags;
        std::set<uint32_t> shadow;
 
        Rule()
@@ -46,9 +46,13 @@ struct Rule
                , ltag(0)
                , htag(0)
                , trail(Tag::NONE)
-               , tags(ZERO_TAGS)
+               , tags(NULL)
                , shadow()
        {}
+       ~Rule()
+       {
+               delete[] tags;
+       }
 
        FORBID_COPY(Rule);
 };
index 562fa49d6aeb7aa2fc2868e4c969888f2521bd81..2cf84078e107608e3d77b0d086c2e171195fe210 100644 (file)
@@ -112,7 +112,7 @@ Skeleton::Skeleton(
                if (s->rule != Rule::NONE) {
                        trail = dfa.rules[s->rule].trail;
                        if (trail != Tag::NONE) {
-                               trver = dfa.tagpool[dfa.rules[s->rule].tags][trail];
+                               trver = dfa.rules[s->rule].tags[trail];
                        }
                }
 
index 391761ed5761b2e31c59a0a89751ed7f18acbc27..44b0eb3c303b1ab4a179ee12641ef0150e42f7b6 100644 (file)
@@ -1,26 +1,11 @@
-#include <assert.h>
 #include <limits>
-#include <stdlib.h> // malloc
-#include <string.h> // memcpy, memcmp
 
 #include "src/ir/rule.h"
 #include "src/ir/tag.h"
-#include "src/util/hash32.h"
 
 namespace re2c
 {
 
-struct eqtag_t
-{
-       size_t ntags;
-
-       explicit eqtag_t(size_t n): ntags(n) {}
-       inline tagver_t operator()(const tagver_t *x, const tagver_t *y) const
-       {
-               return memcmp(x, y, ntags * sizeof(tagver_t)) == 0;
-       }
-};
-
 const size_t Tag::NONE = std::numeric_limits<size_t>::max();
 
 Tag::Tag()
@@ -46,47 +31,6 @@ void init_fix_tag(Tag &tag, size_t r, const std::string *n, size_t b, size_t d)
        tag.fix.dist = d;
 }
 
-Tagpool::Tagpool(size_t n)
-       : lookup()
-       , buffer(new tagver_t[n * 3])
-       , ntags(n)
-       , buffer1(&buffer[n * 1])
-       , buffer2(&buffer[n * 2])
-{
-       // all-zero tag configuration must have static number zero
-       std::fill(buffer, buffer + ntags, TAGVER_ZERO);
-       assert(ZERO_TAGS == insert(buffer));
-}
-
-Tagpool::~Tagpool()
-{
-       delete[] buffer;
-       const size_t n = lookup.size();
-       for (size_t i = 0; i < n; ++i) {
-               free(const_cast<tagver_t*>(lookup[i]));
-       }
-}
-
-size_t Tagpool::insert(const tagver_t *tags)
-{
-       const size_t size = ntags * sizeof(tagver_t);
-       const uint32_t hash = hash32(0, tags, size);
-
-       const size_t idx = lookup.find_with(hash, tags, eqtag_t(ntags));
-       if (idx != taglookup_t::NIL) {
-               return idx;
-       }
-
-       tagver_t *copy = static_cast<tagver_t*>(malloc(size));
-       memcpy(copy, tags, size);
-       return lookup.push(hash, copy);
-}
-
-const tagver_t *Tagpool::operator[](size_t idx) const
-{
-       return lookup[idx];
-}
-
 free_list<tagsave_t*> tagsave_t::freelist;
 
 tagsave_t::tagsave_t(tagsave_t *n, tagver_t v)
index 541ea228b738da91d8afd16feb6896a91fb92e56..91557baad0fe857e818da87fc6cf2cd460756faa 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <string>
 
-#include "src/util/lookup.h"
+#include "src/util/c99_stdint.h"
 #include "src/util/forbid_copy.h"
 #include "src/util/free_list.h"
 
@@ -34,27 +34,6 @@ struct Tag
 void init_var_tag(Tag &tag, size_t r, const std::string *n);
 void init_fix_tag(Tag &tag, size_t r, const std::string *n, size_t b, size_t d);
 
-static const size_t ZERO_TAGS = 0;
-
-struct Tagpool
-{
-private:
-       typedef lookup_t<const tagver_t*> taglookup_t;
-       taglookup_t lookup;
-       tagver_t *buffer;
-
-public:
-       const size_t ntags;
-       tagver_t *buffer1;
-       tagver_t *buffer2;
-
-       explicit Tagpool(size_t n);
-       ~Tagpool();
-       size_t insert(const tagver_t *tags);
-       const tagver_t *operator[](size_t idx) const;
-       FORBID_COPY(Tagpool);
-};
-
 struct tagsave_t
 {
        static free_list<tagsave_t*> freelist;