Permalink
Browse files

TS-720: remove dependencies in STL, add new templated containers.

git-svn-id: https://svn.apache.org/repos/asf/trafficserver/traffic/trunk@1086420 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information...
1 parent 013f601 commit c324be764903a36db7875072550ee3d9b85e912e John Bradley Plevyak committed Mar 28, 2011
View
27 LICENSE
@@ -359,6 +359,33 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
~~~
+Copyright (c) 1994-2011 John Bradley Plevyak, All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+~~~
+
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
View
118 lib/ts/List.h
@@ -61,6 +61,7 @@
#include "ink_queue.h"
#include "ink_resource.h"
#include "Compatability.h"
+#include "defalloc.h"
//
// Link cell for singly-linked list of objects of type C.
@@ -346,8 +347,123 @@ template<class C, class L = typename C::Link_link> struct SortableQueue: public
};
#define SortableQue(_c, _l) SortableQueue<_c, _c::Link##_##_f>
+//
+// Adds counting to the Queue
+//
+
+template <class C, class L = typename C::Link_link> struct CountQueue : public Queue<C,L> {
+ int size;
+ inline CountQueue(void) : size(0) {}
+ inline void push(C *e);
+ inline C *pop();
+ inline void enqueue(C *e);
+ inline C *dequeue();
+ inline void remove(C *e);
+ inline void insert(C *e, C *after);
+ inline void append(CountQueue<C,L> &q);
+ inline void append_clear(CountQueue<C,L> &q);
+};
+#define CountQue(_c, _f) CountQueue<_c, _c::Link##_##_f>
+#define CountQueM(_c, _m, _mf, _f) CountQueue<_c, _c::Link##_##_mf##_##_f>
+
+template <class C, class L> inline void
+CountQueue<C,L>::push(C *e) {
+ Queue<C,L>::push(e);
+ size++;
+}
+
+template <class C, class L> inline C *
+CountQueue<C,L>::pop() {
+ C *ret = Queue<C,L>::pop();
+ if (ret)
+ size--;
+ return ret;
+}
+
+template <class C, class L> inline void
+CountQueue<C,L>::remove(C *e) {
+ Queue<C,L>::remove(e);
+ size--;
+}
+
+template <class C, class L> inline void
+CountQueue<C,L>::enqueue(C *e) {
+ Queue<C,L>::enqueue(e);
+ size++;
+}
+
+template <class C, class L> inline C *
+CountQueue<C,L>::dequeue() {
+ return pop();
+}
-// atomic lists
+template <class C, class L> inline void
+CountQueue<C,L>::insert(C *e, C *after) {
+ Queue<C,L>::insert(e, after);
+ size++;
+}
+
+template <class C, class L> inline void
+CountQueue<C,L>::append(CountQueue<C,L> &q) {
+ Queue<C,L>::append(q);
+ size += q.size;
+};
+
+template <class C, class L> inline void
+CountQueue<C,L>::append_clear(CountQueue<C,L> &q) {
+ append(q);
+ q.head = q.tail = 0;
+ q.size = 0;
+}
+
+//
+// List using cons cells
+//
+
+template <class C, class A = DefaultAlloc>
+struct ConsCell {
+ C car;
+ ConsCell *cdr;
+ ConsCell(C acar, ConsCell *acdr) : car(acar), cdr(acdr) {}
+ ConsCell(C acar) : car(acar), cdr(NULL) {}
+ ConsCell(ConsCell *acdr) : cdr(acdr) {}
+ static void *operator new(size_t size) { return A::alloc(size); }
+ static void operator delete(void *p, size_t size) { A::free(p); }
+};
+
+template <class C, class A = DefaultAlloc>
+struct List {
+ ConsCell<C,A> *head;
+ C first() { if (head) return head->car; else return 0; }
+ C car() { return first(); }
+ ConsCell<C,A> *rest() { if (head) return head->cdr; else return 0; }
+ ConsCell<C,A> *cdr() { return rest(); }
+ void push(C a) { head = new ConsCell<C,A>(a, head); }
+ void push() { head = new ConsCell<C,A>(head); }
+ C pop() { C a = car(); head = cdr(); return a; }
+ void clear() { head = NULL; }
+ void reverse();
+ List(C acar) : head(new ConsCell<C,A>(acar)) {}
+ List(C a, C b) : head(new ConsCell<C,A>(a, new ConsCell<C,A>(b))) {}
+ List(C a, C b, C c) : head(new ConsCell<C,A>(a, new ConsCell<C,A>(b, new ConsCell<C,A>(c)))) {}
+ List() : head(0) {}
+};
+#define forc_List(_c, _p, _l) if ((_l).head) for (_c *_p = (_l).head; _p; _p = _p->cdr)
+
+template <class C,class A> void
+List<C,A>::reverse() {
+ ConsCell<C,A> *n, *t;
+ for (ConsCell<C,A> *p = head; p; p = n) {
+ n = p->cdr;
+ p->cdr = t;
+ t = p;
+ }
+ head = t;
+}
+
+//
+// Atomic lists
+//
template<class C, class L = typename C::Link_link> struct AtomicSLL
{
View
10 lib/ts/Makefile.am
@@ -17,7 +17,7 @@
# limitations under the License.
noinst_PROGRAMS = mkdfa CompileParseRules
-check_PROGRAMS = test_atomic test_freelist test_arena test_List
+check_PROGRAMS = test_atomic test_freelist test_arena test_List test_Map test_Vec
TESTS = $(check_PROGRAMS)
lib_LTLIBRARIES = libtsutil.la
@@ -39,6 +39,7 @@ libtsutil_la_SOURCES = \
DynArray.h \
HostLookup.cc \
HostLookup.h \
+ defalloc.h \
ink_aiocb.h \
ink_align.h \
ink_apidefs.h \
@@ -143,6 +144,9 @@ libtsutil_la_SOURCES = \
TextBuffer.h \
Tokenizer.cc \
Tokenizer.h \
+ Vec.h \
+ Vec.cc \
+ Map.h \
Version.cc
# Special hacks to generate the parser rules
@@ -166,6 +170,10 @@ test_arena_LDADD = libtsutil.la @LIBTHREAD@ @LIBTCL@ @LIBICONV@ @LIBEXECINFO@
test_arena_LDFLAGS = @EXTRA_CXX_LDFLAGS@
test_List_SOURCES = test_List.cc
+test_Map_SOURCES = test_Map.cc
+test_Map_LDADD = libtsutil.la
+test_Vec_SOURCES = test_Vec.cc
+test_Vec_LDADD = libtsutil.la
CompileParseRules_SOURCES = CompileParseRules.cc
View
937 lib/ts/Map.h
@@ -0,0 +1,937 @@
+/** @file
+
+ A set of Map templates.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef _map_H_
+#define _map_H_
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "List.h"
+#include "Vec.h"
+
+#define MAP_INTEGRAL_SIZE (1 << (2))
+#define MAP_INITIAL_SHIFT ((2)+1)
+#define MAP_INITIAL_SIZE (1 << MAP_INITIAL_SHIFT)
+
+typedef const char cchar;
+
+template<class A>
+static inline char *
+_dupstr(cchar *s, cchar *e = 0) {
+ int l = e ? e-s : strlen(s);
+ char *ss = (char*)A::alloc(l+1);
+ memcpy(ss, s, l);
+ ss[l] = 0;
+ return ss;
+}
+
+// Simple direct mapped Map (pointer hash table) and Environment
+
+template <class K, class C> class MapElem {
+ public:
+ K key;
+ C value;
+ bool operator==(MapElem &e) { return e.key == key; }
+ operator uintptr_t(void) { return (uintptr_t)(uintptr_t)key; }
+ MapElem(uintptr_t x) { assert(!x); key = 0; }
+ MapElem(K akey, C avalue) : key(akey), value(avalue) {}
+ MapElem(MapElem &e) : key(e.key), value(e.value) {}
+ MapElem() : key(0) {}
+};
+
+template <class K, class C, class A = DefaultAlloc> class Map : public Vec<MapElem<K,C>, A> {
+ public:
+ typedef MapElem<K,C> ME;
+ typedef Vec<ME,A> PType;
+ using PType::n;
+ using PType::i;
+ using PType::v;
+ ME *put(K akey, C avalue);
+ ME *put(K akey);
+ C get(K akey);
+ C *getp(K akey);
+ void get_keys(Vec<K> &keys);
+ void get_keys_set(Vec<K> &keys);
+ void get_values(Vec<C> &values);
+ void map_union(Map<K,C> &m);
+ int some_disjunction(Map<K,C> &m);
+};
+
+template <class C> class HashFns {
+ public:
+ static uintptr_t hash(C a);
+ static int equal(C a, C b);
+};
+
+template <class K, class C> class HashSetFns {
+ public:
+ static uintptr_t hash(C a);
+ static uintptr_t hash(K a);
+ static int equal(C a, C b);
+ static int equal(K a, C b);
+};
+
+template <class K, class AHashFns, class C, class A = DefaultAlloc> class HashMap : public Map<K,C,A> {
+ public:
+ using Map<K,C,A>::n;
+ using Map<K,C,A>::i;
+ using Map<K,C,A>::v;
+ using Map<K,C,A>::e;
+ MapElem<K,C> *get_internal(K akey);
+ C get(K akey);
+ MapElem<K,C> *put(K akey, C avalue);
+ void get_keys(Vec<K> &keys);
+ void get_values(Vec<C> &values);
+};
+
+#define form_Map(_c, _p, _v) if ((_v).n) for (_c *qq__##_p = (_c*)0, *_p = &(_v).v[0]; \
+ ((intptr_t)(qq__##_p) < (_v).n) && ((_p = &(_v).v[(intptr_t)qq__##_p]) || 1); \
+ qq__##_p = (_c*)(((intptr_t)qq__##_p) + 1)) \
+ if ((_p)->key)
+
+
+template <class K, class AHashFns, class C, class A = DefaultAlloc> class HashSet : public Vec<C,A> {
+ public:
+ typedef Vec<C,A> V;
+ using V::n;
+ using V::i;
+ using V::v;
+ using V::e;
+ C get(K akey);
+ C *put( C avalue);
+};
+
+class StringHashFns {
+ public:
+ static uintptr_t hash(cchar *s) {
+ uintptr_t h = 0;
+ // 31 changed to 27, to avoid prime2 in vec.cpp
+ while (*s) h = h * 27 + (unsigned char)*s++;
+ return h;
+ }
+ static int equal(cchar *a, cchar *b) { return !strcmp(a, b); }
+};
+
+class CaseStringHashFns {
+ public:
+ static uintptr_t hash(cchar *s) {
+ uintptr_t h = 0;
+ // 31 changed to 27, to avoid prime2 in vec.cpp
+ while (*s) h = h * 27 + (unsigned char)toupper(*s++);
+ return h;
+ }
+ static int equal(cchar *a, cchar *b) { return !strcasecmp(a, b); }
+};
+
+class PointerHashFns {
+ public:
+ static uintptr_t hash(void *s) { return (uintptr_t)(uintptr_t)s; }
+ static int equal(void *a, void *b) { return a == b; }
+};
+
+template <class C, class AHashFns, class A = DefaultAlloc> class ChainHash : public Map<uintptr_t, List<C,A>,A> {
+ public:
+ using Map<uintptr_t, List<C,A>,A>::n;
+ using Map<uintptr_t, List<C,A>,A>::v;
+ typedef ConsCell<C, A> ChainCons;
+ C put(C c);
+ C get(C c);
+ C put_bag(C c);
+ int get_bag(C c,Vec<C> &v);
+ int del(C avalue);
+ void get_elements(Vec<C> &elements);
+};
+
+template <class K, class AHashFns, class C, class A = DefaultAlloc> class ChainHashMap :
+ public Map<uintptr_t, List<MapElem<K,C>,A>,A> {
+ public:
+ using Map<uintptr_t, List<MapElem<K,C>,A>,A>::n;
+ using Map<uintptr_t, List<MapElem<K,C>,A>,A>::v;
+ MapElem<K,C> *put(K akey, C avalue);
+ C get(K akey);
+ int del(K akey);
+ MapElem<K,C> *put_bag(K akey, C c);
+ int get_bag(K akey, Vec<C> &v);
+ void get_keys(Vec<K> &keys);
+ void get_values(Vec<C> &values);
+};
+
+template<class F = StringHashFns, class A = DefaultAlloc>
+class StringChainHash : public ChainHash<cchar *, F, A> {
+ public:
+ cchar *canonicalize(cchar *s, cchar *e);
+ cchar *canonicalize(cchar *s) { return canonicalize(s, s + strlen(s)); }
+};
+
+template <class C, class AHashFns, int N, class A = DefaultAlloc> class NBlockHash {
+ public:
+ int n;
+ int i;
+ C *v;
+ C e[N];
+
+ C* end() { return last(); }
+ int length() { return N * n; }
+ C *first();
+ C *last();
+ C put(C c);
+ C get(C c);
+ C* assoc_put(C *c);
+ C* assoc_get(C *c);
+ int del(C c);
+ void clear();
+ void reset();
+ int count();
+ void size(int p2);
+ void copy(const NBlockHash<C,AHashFns,N,A> &hh);
+ void move(NBlockHash<C,AHashFns,N,A> &hh);
+ NBlockHash();
+ NBlockHash(NBlockHash<C,AHashFns,N,A> &hh) { v = e; copy(hh); }
+};
+
+/* use forv_Vec on BlockHashes */
+
+#define DEFAULT_BLOCK_HASH_SIZE 4
+template <class C, class ABlockHashFns> class BlockHash :
+ public NBlockHash<C, ABlockHashFns, DEFAULT_BLOCK_HASH_SIZE> {};
+typedef BlockHash<cchar *, StringHashFns> StringBlockHash;
+
+template <class K, class C, class A = DefaultAlloc> class Env {
+ public:
+ typedef ConsCell<C, A> EnvCons;
+ void put(K akey, C avalue);
+ C get(K akey);
+ void push();
+ void pop();
+ void clear() { store.clear(); scope.clear(); }
+
+ Env() {}
+ Map<K,List<C> *, A> store;
+ List<List<K>, A> scope;
+ List<C, A> *get_bucket(K akey);
+};
+
+/* IMPLEMENTATION */
+
+template <class K, class C, class A> inline C
+Map<K,C,A>::get(K akey) {
+ MapElem<K,C> e(akey, (C)0);
+ MapElem<K,C> *x = set_in(e);
+ if (x)
+ return x->value;
+ return (C)0;
+}
+
+template <class K, class C, class A> inline C *
+Map<K,C,A>::getp(K akey) {
+ MapElem<K,C> e(akey, (C)0);
+ MapElem<K,C> *x = set_in(e);
+ if (x)
+ return &x->value;
+ return 0;
+}
+
+template <class K, class C, class A> inline MapElem<K,C> *
+Map<K,C,A>::put(K akey, C avalue) {
+ MapElem<K,C> e(akey, avalue);
+ MapElem<K,C> *x = set_in(e);
+ if (x) {
+ x->value = avalue;
+ return x;
+ } else
+ return set_add(e);
+}
+
+template <class K, class C, class A> inline MapElem<K,C> *
+Map<K,C,A>::put(K akey) {
+ MapElem<K,C> e(akey, 0);
+ MapElem<K,C> *x = set_in(e);
+ if (x)
+ return x;
+ else
+ return set_add(e);
+}
+
+template <class K, class C, class A> inline void
+Map<K,C,A>::get_keys(Vec<K> &keys) {
+ for (int i = 0; i < n; i++)
+ if (v[i].key)
+ keys.add(v[i].key);
+}
+
+template <class K, class C, class A> inline void
+Map<K,C,A>::get_keys_set(Vec<K> &keys) {
+ for (int i = 0; i < n; i++)
+ if (v[i].key)
+ keys.set_add(v[i].key);
+}
+
+template <class K, class C, class A> inline void
+Map<K,C,A>::get_values(Vec<C> &values) {
+ for (int i = 0; i < n; i++)
+ if (v[i].key)
+ values.set_add(v[i].value);
+ values.set_to_vec();
+}
+
+template <class K, class C, class A> inline void
+Map<K,C,A>::map_union(Map<K,C> &m) {
+ for (int i = 0; i < m.n; i++)
+ if (m.v[i].key)
+ put(m.v[i].key, m.v[i].value);
+}
+
+template <class K, class C, class A> inline int
+Map<K,C,A>::some_disjunction(Map<K,C> &m) {
+ for (int i = 0; i < m.n; i++)
+ if (m.v[i].key && get(m.v[i].key) != m.v[i].value)
+ return 1;
+ for (int i = 0; i < n; i++)
+ if (v[i].key && m.get(v[i].key) != v[i].value)
+ return 1;
+ return 0;
+}
+
+template <class K, class C, class A> inline void
+map_set_add(Map<K,Vec<C,A>*,A> &m, K akey, C avalue) {
+ Vec<C,A> *v = m.get(akey);
+ if (!v)
+ m.put(akey, (v = new Vec<C,A>));
+ v->set_add(avalue);
+}
+
+template <class K, class C, class A> inline void
+map_set_add(Map<K,Vec<C,A>*,A> &m, K akey, Vec<C> *madd) {
+ Vec<C,A> *v = m.get(akey);
+ if (!v)
+ m.put(akey, (v = new Vec<C,A>));
+ v->set_union(*madd);
+}
+
+template <class K, class AHashFns, class C, class A> inline C
+HashSet<K, AHashFns, C, A>::get(K akey) {
+ if (!n)
+ return 0;
+ if (n <= MAP_INTEGRAL_SIZE) {
+ for (C *c = v; c < v + n; c++)
+ if (c)
+ if (AHashFns::equal(akey, *c))
+ return *c;
+ return 0;
+ }
+ uintptr_t h = AHashFns::hash(akey);
+ h = h % n;
+ for (int k = h, j = 0; j < i + 3;j++) {
+ if (!v[k])
+ return 0;
+ else if (AHashFns::equal(akey, v[k]))
+ return v[k];
+ k = (k + open_hash_primes[j]) % n;
+ }
+ return 0;
+}
+
+template <class K, class AHashFns, class C, class A> inline C *
+HashSet<K, AHashFns, C, A>::put(C avalue) {
+ if (n < MAP_INTEGRAL_SIZE) {
+ if (!v)
+ v = e;
+ for (int i = 0; i < n; i++)
+ if (AHashFns::equal(avalue, v[i]))
+ return &v[i];
+ v[n] = avalue;
+ n++;
+ return &v[n-1];
+ }
+ if (n > MAP_INTEGRAL_SIZE) {
+ uintptr_t h = AHashFns::hash(avalue);
+ h = h % n;
+ for (int k = h, j = 0; j < i + 3; j++) {
+ if (!v[k]) {
+ v[k] = avalue;
+ return &v[k];
+ }
+ k = (k + open_hash_primes[j]) % n;
+ }
+ } else
+ i = SET_INITIAL_INDEX-1; // will be incremented in set_expand
+ HashSet<K,AHashFns,C,A> vv(*this);
+ Vec<C,A>::set_expand();
+ for (int i = 0; i < vv.n; i++)
+ if (vv.v[i])
+ put(vv.v[i]);
+ return put(avalue);
+}
+
+template <class K, class AHashFns, class C, class A> inline MapElem<K,C> *
+HashMap<K,AHashFns,C,A>::get_internal(K akey) {
+ if (!n)
+ return 0;
+ if (n <= MAP_INTEGRAL_SIZE) {
+ for (MapElem<K,C> *c = v; c < v + n; c++)
+ if (c->key)
+ if (AHashFns::equal(akey, c->key))
+ return c;
+ return 0;
+ }
+ uintptr_t h = AHashFns::hash(akey);
+ h = h % n;
+ for (int k = h, j = 0; j < i + 3;j++) {
+ if (!v[k].key)
+ return 0;
+ else if (AHashFns::equal(akey, v[k].key))
+ return &v[k];
+ k = (k + open_hash_primes[j]) % n;
+ }
+ return 0;
+}
+
+template <class K, class AHashFns, class C, class A> inline C
+HashMap<K,AHashFns,C,A>::get(K akey) {
+ MapElem<K,C> *x = get_internal(akey);
+ if (!x)
+ return 0;
+ return x->value;
+}
+
+template <class K, class AHashFns, class C, class A> inline MapElem<K,C> *
+HashMap<K,AHashFns,C,A>::put(K akey, C avalue) {
+ MapElem<K,C> *x = get_internal(akey);
+ if (x) {
+ x->value = avalue;
+ return x;
+ } else {
+ if (n < MAP_INTEGRAL_SIZE) {
+ if (!v)
+ v = e;
+ v[n].key = akey;
+ v[n].value = avalue;
+ n++;
+ return &v[n-1];
+ }
+ if (n > MAP_INTEGRAL_SIZE) {
+ uintptr_t h = AHashFns::hash(akey);
+ h = h % n;
+ for (int k = h, j = 0; j < i + 3; j++) {
+ if (!v[k].key) {
+ v[k].key = akey;
+ v[k].value = avalue;
+ return &v[k];
+ }
+ k = (k + open_hash_primes[j]) % n;
+ }
+ } else
+ i = SET_INITIAL_INDEX-1; // will be incremented in set_expand
+ }
+ HashMap<K,AHashFns,C,A> vv(*this);
+ Map<K,C,A>::set_expand();
+ for (int i = 0; i < vv.n; i++)
+ if (vv.v[i].key)
+ put(vv.v[i].key, vv.v[i].value);
+ return put(akey, avalue);
+}
+
+template <class K, class AHashFns, class C, class A> inline void
+HashMap<K,AHashFns,C,A>::get_keys(Vec<K> &keys) { Map<K,C,A>::get_keys(keys); }
+
+template <class K, class AHashFns, class C, class A> inline void
+HashMap<K,AHashFns,C,A>::get_values(Vec<C> &values) { Map<K,C,A>::get_values(values); }
+
+template <class C, class AHashFns, class A> C
+ChainHash<C, AHashFns, A>::put(C c) {
+ uintptr_t h = AHashFns::hash(c);
+ List<C,A> *l;
+ MapElem<uintptr_t,List<C,A> > e(h, (C)0);
+ MapElem<uintptr_t,List<C,A> > *x = set_in(e);
+ if (x)
+ l = &x->value;
+ else {
+ l = &Map<uintptr_t, List<C,A>, A>::put(h, c)->value;
+ return l->head->car;
+ }
+ forc_List(ChainCons, x, *l)
+ if (AHashFns::equal(c, x->car))
+ return x->car;
+ l->push(c);
+ return (C)0;
+}
+
+template <class C, class AHashFns, class A> C
+ChainHash<C, AHashFns, A>::get(C c) {
+ uintptr_t h = AHashFns::hash(c);
+ List<C> empty;
+ MapElem<uintptr_t,List<C,A> > e(h, empty);
+ MapElem<uintptr_t,List<C,A> > *x = set_in(e);
+ if (!x)
+ return 0;
+ List<C> *l = &x->value;
+ forc_List(ChainCons, x, *l)
+ if (AHashFns::equal(c, x->car))
+ return x->car;
+ return 0;
+}
+
+template <class C, class AHashFns, class A> C
+ChainHash<C, AHashFns, A>::put_bag(C c) {
+ uintptr_t h = AHashFns::hash(c);
+ List<C, A> *l;
+ MapElem<uintptr_t,List<C,A> > e(h, (C)0);
+ MapElem<uintptr_t,List<C,A> > *x = set_in(e);
+ if (x)
+ l = &x->value;
+ else {
+ l = &Map<uintptr_t, List<C,A> >::put(h, c)->value;
+ return l->head->car;
+ }
+ l->push(c);
+ return (C)0;
+}
+
+template <class C, class AHashFns, class A> int
+ChainHash<C, AHashFns, A>::get_bag(C c, Vec<C> &v) {
+ uintptr_t h = AHashFns::hash(c);
+ List<C,A> empty;
+ MapElem<uintptr_t,List<C,A> > e(h, empty);
+ MapElem<uintptr_t,List<C,A> > *x = set_in(e);
+ if (!x)
+ return 0;
+ List<C,A> *l = &x->value;
+ forc_List(C, x, *l)
+ if (AHashFns::equal(c, x->car))
+ v.add(x->car);
+ return v.n;
+}
+
+template <class C, class AHashFns, class A> void
+ChainHash<C, AHashFns, A>::get_elements(Vec<C> &elements) {
+ for (int i = 0; i < n; i++) {
+ List<C, A> *l = &v[i].value;
+ forc_List(C, x, *l)
+ elements.add(x);
+ }
+}
+
+template <class C, class AHashFns, class A> int
+ChainHash<C, AHashFns, A>::del(C c) {
+ uintptr_t h = AHashFns::hash(c);
+ List<C> *l;
+ MapElem<uintptr_t,List<C,A> > e(h, (C)0);
+ MapElem<uintptr_t,List<C,A> > *x = set_in(e);
+ if (x)
+ l = &x->value;
+ else
+ return 0;
+ ConsCell<C> *last = 0;
+ forc_List(ConsCell<C>, x, *l) {
+ if (AHashFns::equal(c, x->car)) {
+ if (!last)
+ l->head = x->cdr;
+ else
+ last->cdr = x->cdr;
+ A::free(x);
+ return 1;
+ }
+ last = x;
+ }
+ return 0;
+}
+
+template <class K, class AHashFns, class C, class A> MapElem<K,C> *
+ChainHashMap<K, AHashFns, C, A>::put(K akey, C avalue) {
+ uintptr_t h = AHashFns::hash(akey);
+ List<MapElem<K,C>,A> empty;
+ List<MapElem<K,C>,A> *l;
+ MapElem<K, C> c(akey, avalue);
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = set_in(e);
+ if (x)
+ l = &x->value;
+ else {
+ l = &Map<uintptr_t, List<MapElem<K,C>,A>,A>::put(h, c)->value;
+ return &l->head->car;
+ }
+ for (ConsCell<MapElem<K,C>,A> *p = l->head; p; p = p->cdr)
+ if (AHashFns::equal(akey, p->car.key)) {
+ p->car.value = avalue;
+ return &p->car;
+ }
+ l->push(c);
+ return 0;
+}
+
+template <class K, class AHashFns, class C, class A> C
+ChainHashMap<K, AHashFns, C, A>::get(K akey) {
+ uintptr_t h = AHashFns::hash(akey);
+ List<MapElem<K,C>, A> empty;
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = set_in(e);
+ if (!x)
+ return 0;
+ List<MapElem<K,C>,A> *l = &x->value;
+ if (l->head)
+ for (ConsCell<MapElem<K,C>,A> *p = l->head; p; p = p->cdr)
+ if (AHashFns::equal(akey, p->car.key))
+ return p->car.value;
+ return 0;
+}
+
+template <class K, class AHashFns, class C, class A> MapElem<K,C> *
+ChainHashMap<K, AHashFns, C, A>::put_bag(K akey, C avalue) {
+ uintptr_t h = AHashFns::hash(akey);
+ List<MapElem<K,C>,A> empty;
+ List<MapElem<K,C>,A> *l;
+ MapElem<K, C> c(akey, avalue);
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = set_in(e);
+ if (x)
+ l = &x->value;
+ else {
+ l = &Map<uintptr_t, List<MapElem<K,C>,A>,A>::put(h, c)->value;
+ return &l->head->car;
+ }
+ for (ConsCell<MapElem<K,C>,A> *p = l->head; p; p = p->cdr)
+ if (AHashFns::equal(akey, p->car.key) && AHashFns::equal_value(avalue, p->car.value))
+ return &p->car;
+ l->push(c);
+ return 0;
+}
+
+template <class K, class AHashFns, class C, class A> int
+ChainHashMap<K, AHashFns, C, A>::get_bag(K akey, Vec<C> &v) {
+ uintptr_t h = AHashFns::hash(akey);
+ List<MapElem<K,C>,A> empty;
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = set_in(e);
+ if (!x)
+ return 0;
+ List<MapElem<K,C>,A> *l = &x->value;
+ for (ConsCell<MapElem<K,C>,A> *p = l->head; p; p = p->cdr)
+ if (AHashFns::equal(akey, p->car.key))
+ return v.add(x->car);
+ return v.n;
+}
+
+template <class K, class AHashFns, class C, class A> int
+ChainHashMap<K, AHashFns, C, A>::del(K akey) {
+ uintptr_t h = AHashFns::hash(akey);
+ List<MapElem<K,C>,A> empty;
+ List<MapElem<K,C>,A> *l;
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > e(h, empty);
+ MapElem<uintptr_t,List<MapElem<K,C>,A> > *x = set_in(e);
+ if (x)
+ l = &x->value;
+ else
+ return 0;
+ ConsCell<MapElem<K,C>,A> *last = 0;
+ for (ConsCell<MapElem<K,C>,A> *p = l->head; p; p = p->cdr) {
+ if (AHashFns::equal(akey, p->car.key)) {
+ if (!last)
+ l->head = p->cdr;
+ else
+ last->cdr = p->cdr;
+ return 1;
+ }
+ last = p;
+ }
+ return 0;
+}
+
+template <class K, class AHashFns, class C, class A> void
+ChainHashMap<K, AHashFns, C, A>::get_keys(Vec<K> &keys) {
+ for (int i = 0; i < n; i++) {
+ List<MapElem<K,C> > *l = &v[i].value;
+ if (l->head)
+ for (ConsCell<MapElem<K,C>,A> *p = l->head; p; p = p->cdr)
+ keys.add(p->car.key);
+ }
+}
+
+template <class K, class AHashFns, class C, class A> void
+ChainHashMap<K, AHashFns, C, A>::get_values(Vec<C> &values) {
+ for (int i = 0; i < n; i++) {
+ List<MapElem<K,C>,A> *l = &v[i].value;
+ if (l->head)
+ for (ConsCell<MapElem<K,C>,A> *p = l->head; p; p = p->cdr)
+ values.add(p->car.value);
+ }
+}
+
+template <class F, class A> inline cchar *
+StringChainHash<F,A>::canonicalize(cchar *s, cchar *e) {
+ uintptr_t h = 0;
+ cchar *a = s;
+ // 31 changed to 27, to avoid prime2 in vec.cpp
+ if (e)
+ while (a != e) h = h * 27 + (unsigned char)*a++;
+ else
+ while (*a) h = h * 27 + (unsigned char)*a++;
+ MapElem<uintptr_t,List<cchar*, A> > me(h, (char*)0);
+ MapElem<uintptr_t,List<cchar*, A> > *x = set_in(me);
+ if (x) {
+ List<cchar*, A> *l = &x->value;
+ typedef ConsCell<cchar *, A> TT;
+ forc_List(TT, x, *l) {
+ a = s;
+ cchar *b = x->car;
+ while (1) {
+ if (!*b) {
+ if (a == e)
+ return x->car;
+ break;
+ }
+ if (a >= e || *a != *b)
+ break;
+ a++; b++;
+ }
+ }
+ }
+ s = _dupstr<A>(s, e);
+ cchar *ss = ChainHash<cchar *, F, A>::put(s);
+ if (ss)
+ return ss;
+ return s;
+}
+
+template <class K, class C, class A> inline C
+Env<K,C,A>::get(K akey) {
+ MapElem<K,List<C, A> *> e(akey, 0);
+ MapElem<K,List<C, A> *> *x = store.set_in(e);
+ if (x)
+ return x->value->first();
+ return (C)0;
+}
+
+template <class K, class C, class A> inline List<C, A> *
+Env<K,C,A>::get_bucket(K akey) {
+ List<C, A> *bucket = store.get(akey);
+ if (bucket)
+ return bucket;
+ bucket = new List<C>();
+ store.put(akey, bucket);
+ return bucket;
+}
+
+template <class K, class C, class A> inline void
+Env<K,C,A>::put(K akey, C avalue) {
+ scope.head->car.push(akey);
+ get_bucket(akey)->push(avalue);
+}
+
+template <class K, class C, class A> inline void
+Env<K,C,A>::push() {
+ scope.push();
+}
+
+template <class K, class C, class A> inline void
+Env<K,C,A>::pop() {
+ forc_List(EnvCons, e, scope.first())
+ get_bucket(e->car)->pop();
+}
+
+template <class C, class AHashFns, int N, class A> inline
+NBlockHash<C, AHashFns, N, A>::NBlockHash() : n(1), i(0) {
+ memset(&e[0], 0, sizeof(e));
+ v = e;
+}
+
+template <class C, class AHashFns, int N, class A> inline C*
+NBlockHash<C, AHashFns, N, A>::first() {
+ return &v[0];
+}
+
+template <class C, class AHashFns, int N, class A> inline C*
+NBlockHash<C, AHashFns, N, A>::last() {
+ return &v[n * N];
+}
+
+template <class C, class AHashFns, int N, class A> inline C
+NBlockHash<C, AHashFns, N, A>::put(C c) {
+ int a;
+ uintptr_t h = AHashFns::hash(c);
+ C *x = &v[(h % n) * N];
+ for (a = 0; a < N; a++) {
+ if (!x[a])
+ break;
+ if (AHashFns::equal(c, x[a]))
+ return x[a];
+ }
+ if (a < N) {
+ x[a] = c;
+ return (C)0;
+ }
+ C *vv = first(), *ve = last();
+ C *old_v = v;
+ i = i + 1;
+ size(i);
+ for (;vv < ve; vv++)
+ if (*vv)
+ put(*vv);
+ if (old_v != &e[0])
+ A::free(old_v);
+ return put(c);
+}
+
+template <class C, class AHashFns, int N, class A> inline void
+NBlockHash<C, AHashFns, N, A>::size(int p2) {
+ n = prime2[p2];
+ v = (C*)A::alloc(n * sizeof(C) * N);
+ memset(v, 0, n * sizeof(C) * N);
+}
+
+template <class C, class AHashFns, int N, class A> inline C
+NBlockHash<C, AHashFns, N, A>::get(C c) {
+ if (!n)
+ return (C)0;
+ uintptr_t h = AHashFns::hash(c);
+ C *x = &v[(h % n) * N];
+ for (int a = 0; a < N; a++) {
+ if (!x[a])
+ return (C)0;
+ if (AHashFns::equal(c, x[a]))
+ return x[a];
+ }
+ return (C)0;
+}
+
+template <class C, class AHashFns, int N, class A> inline C*
+NBlockHash<C, AHashFns, N, A>::assoc_get(C *c) {
+ if (!n)
+ return (C*)0;
+ uintptr_t h = AHashFns::hash(*c);
+ C *x = &v[(h % n) * N];
+ int a = 0;
+ if (c >= x && c < x + N)
+ a = c - x + 1;
+ for (; a < N; a++) {
+ if (!x[a])
+ return (C*)0;
+ if (AHashFns::equal(*c, x[a]))
+ return &x[a];
+ }
+ return (C*)0;
+}
+
+template <class C, class AHashFns, int N, class A> inline C*
+NBlockHash<C, AHashFns, N, A>::assoc_put(C *c) {
+ int a;
+ uintptr_t h = AHashFns::hash(*c);
+ C *x = &v[(h % n) * N];
+ for (a = 0; a < N; a++) {
+ if (!x[a])
+ break;
+ }
+ if (a < N) {
+ x[a] = *c;
+ return &x[a];
+ }
+ x[i % N] = *c;
+ i++;
+ return &x[i % N];
+}
+
+template <class C, class AHashFns, int N, class A> inline int
+NBlockHash<C, AHashFns, N, A>::del(C c) {
+ int a, b;
+ if (!n)
+ return 0;
+ uintptr_t h = AHashFns::hash(c);
+ C *x = &v[(h % n) * N];
+ for (a = 0; a < N; a++) {
+ if (!x[a])
+ return 0;
+ if (AHashFns::equal(c, x[a])) {
+ if (a < N - 1) {
+ for (b = a + 1; b < N; b++) {
+ if (!x[b])
+ break;
+ }
+ if (b != a + 1)
+ x[a] = x[b - 1];
+ x[b - 1] = (C)0;
+ return 1;
+ } else {
+ x[N - 1] = (C)0;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+template <class C, class AHashFns, int N, class A> inline void
+NBlockHash<C, AHashFns, N, A>::clear() {
+ if (v && v != e) A::free(v);
+ v = e;
+ n = 1;
+}
+
+template <class C, class AHashFns, int N, class A> inline void
+NBlockHash<C, AHashFns, N, A>::reset() {
+ if (v)
+ memset(v, 0, n * N * sizeof(C));
+}
+
+template <class C, class AHashFns, int N, class A> inline int
+NBlockHash<C, AHashFns, N, A>::count() {
+ int nelements = 0;
+ C *l = last();
+ for (C *xx = first(); xx < l; xx++)
+ if (*xx)
+ nelements++;
+ return nelements;
+}
+
+template <class C, class AHashFns, int N, class A> inline void
+NBlockHash<C, AHashFns, N, A>::copy(const NBlockHash<C, AHashFns, N, A> &hh) {
+ clear();
+ n = hh.n;
+ i = hh.i;
+ if (hh.v == &hh.e[0]) {
+ memcpy(e, &hh.e[0], sizeof(e));
+ v = e;
+ } else {
+ if (hh.v) {
+ v = (C*)A::alloc(n * sizeof(C) * N);
+ memcpy(v, hh.v, n * sizeof(C) * N);
+ } else
+ v = 0;
+ }
+}
+
+template <class C, class AHashFns, int N, class A> inline void
+NBlockHash<C, AHashFns, N, A>::move(NBlockHash<C, AHashFns, N, A> &hh) {
+ clear();
+ n = hh.n;
+ i = hh.i;
+ v = hh.v;
+ if (hh.v == &hh.e[0]) {
+ memcpy(e, &hh.e[0], sizeof(e));
+ v = e;
+ }
+ hh.clear();
+}
+
+void test_map();
+
+#endif
View
1 lib/ts/TestHttpHeader.cc
@@ -30,7 +30,6 @@
****************************************************************************/
#include "HttpHeaderTokenizer.h"
#include "ink_assert.h"
-#include <fstream.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
View
204 lib/ts/Vec.cc
@@ -0,0 +1,204 @@
+/* -*-Mode: c++;-*-
+ Various vector related code.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/* UnionFind after Tarjan */
+
+#include <stdint.h>
+#include <assert.h>
+#include "Vec.h"
+
+uintptr_t prime2[] = {
+ 1, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191,
+ 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 2097143,
+ 4194301, 8388593, 16777213, 33554393, 67108859, 134217689,
+ 268435399, 536870909
+};
+
+// primes generated with map_mult.c
+uintptr_t open_hash_primes[256] = {
+0x02D4AF27, 0x1865DFC7, 0x47C62B43, 0x35B4889B, 0x210459A1, 0x3CC51CC7, 0x02ADD945, 0x0607C4D7,
+0x558E6035, 0x0554224F, 0x5A281657, 0x1C458C7F, 0x7F8BE723, 0x20B9BA99, 0x7218AA35, 0x64B10C2B,
+0x548E8983, 0x5951218F, 0x7AADC871, 0x695FA5B1, 0x40D40FCB, 0x20E03CC9, 0x55E9920F, 0x554CE08B,
+0x7E78B1D7, 0x7D965DF9, 0x36A520A1, 0x1B0C6C11, 0x33385667, 0x2B0A7B9B, 0x0F35AE23, 0x0BD608FB,
+0x2284ADA3, 0x6E6C0687, 0x129B3EED, 0x7E86289D, 0x1143C24B, 0x1B6C7711, 0x1D87BB41, 0x4C7E635D,
+0x67577999, 0x0A0113C5, 0x6CF085B5, 0x14A4D0FB, 0x4E93E3A7, 0x5C87672B, 0x67F3CA17, 0x5F944339,
+0x4C16DFD7, 0x5310C0E3, 0x2FAD1447, 0x4AFB3187, 0x08468B7F, 0x49E56C51, 0x6280012F, 0x097D1A85,
+0x34CC9403, 0x71028BD7, 0x6DEDC7E9, 0x64093291, 0x6D78BB0B, 0x7A03B465, 0x2E044A43, 0x1AE58515,
+0x23E495CD, 0x46102A83, 0x51B78A59, 0x051D8181, 0x5352CAC9, 0x57D1312B, 0x2726ED57, 0x2E6BC515,
+0x70736281, 0x5938B619, 0x0D4B6ACB, 0x44AB5E2B, 0x0029A485, 0x002CE54F, 0x075B0591, 0x3EACFDA9,
+0x0AC03411, 0x53B00F73, 0x2066992D, 0x76E72223, 0x55F62A8D, 0x3FF92EE1, 0x17EE0EB3, 0x5E470AF1,
+0x7193EB7F, 0x37A2CCD3, 0x7B44F7AF, 0x0FED8B3F, 0x4CC05805, 0x7352BF79, 0x3B61F755, 0x523CF9A3,
+0x1AAFD219, 0x76035415, 0x5BE84287, 0x6D598909, 0x456537E9, 0x407EA83F, 0x23F6FFD5, 0x60256F39,
+0x5D8EE59F, 0x35265CEB, 0x1D4AD4EF, 0x676E2E0F, 0x2D47932D, 0x776BB33B, 0x6DE1902B, 0x2C3F8741,
+0x5B2DE8EF, 0x686DDB3B, 0x1D7C61C7, 0x1B061633, 0x3229EA51, 0x7FCB0E63, 0x5F22F4C9, 0x517A7199,
+0x2A8D7973, 0x10DCD257, 0x41D59B27, 0x2C61CA67, 0x2020174F, 0x71653B01, 0x2FE464DD, 0x3E7ED6C7,
+0x164D2A71, 0x5D4F3141, 0x5F7BABA7, 0x50E1C011, 0x140F5D77, 0x34E80809, 0x04AAC6B3, 0x29C42BAB,
+0x08F9B6F7, 0x461E62FD, 0x45C2660B, 0x08BF25A7, 0x5494EA7B, 0x0225EBB7, 0x3C5A47CF, 0x2701C333,
+0x457ED05B, 0x48CDDE55, 0x14083099, 0x7C69BDAB, 0x7BF163C9, 0x41EE1DAB, 0x258B1307, 0x0FFAD43B,
+0x6601D767, 0x214DBEC7, 0x2852CCF5, 0x0009B471, 0x190AC89D, 0x5BDFB907, 0x15D4E331, 0x15D22375,
+0x13F388D5, 0x12ACEDA5, 0x3835EA5D, 0x2587CA35, 0x06756643, 0x487C6F55, 0x65C295EB, 0x1029F2E1,
+0x10CEF39D, 0x14C2E415, 0x444825BB, 0x24BE0A2F, 0x1D2B7C01, 0x64AE3235, 0x5D2896E5, 0x61BBBD87,
+0x4A49E86D, 0x12C277FF, 0x72C81289, 0x5CF42A3D, 0x332FF177, 0x0DAECD23, 0x6000ED1D, 0x203CDDE1,
+0x40C62CAD, 0x19B9A855, 0x782020C3, 0x6127D5BB, 0x719889A7, 0x40E4FCCF, 0x2A3C8FF9, 0x07411C7F,
+0x3113306B, 0x4D7CA03F, 0x76119841, 0x54CEFBDF, 0x11548AB9, 0x4B0748EB, 0x569966B1, 0x45BC721B,
+0x3D5A376B, 0x0D8923E9, 0x6D95514D, 0x0F39A367, 0x2FDAD92F, 0x721F972F, 0x42D0E21D, 0x5C5952DB,
+0x7394D007, 0x02692C55, 0x7F92772F, 0x025F8025, 0x34347113, 0x560EA689, 0x0DCC21DF, 0x09ECC7F5,
+0x091F3993, 0x0E0B52AB, 0x497CAA55, 0x0A040A49, 0x6D8F0CC5, 0x54F41609, 0x6E0CB8DF, 0x3DCB64C3,
+0x16C365CD, 0x6D6B9FB5, 0x02B9382B, 0x6A5BFAF1, 0x1669D75F, 0x13CFD4FD, 0x0FDF316F, 0x21F3C463,
+0x6FC58ABF, 0x04E45BE7, 0x1911225B, 0x28CD1355, 0x222084E9, 0x672AD54B, 0x476FC267, 0x6864E16D,
+0x20AEF4FB, 0x603C5FB9, 0x55090595, 0x1113B705, 0x24E38493, 0x5291AF97, 0x5F5446D9, 0x13A6F639,
+0x3D501313, 0x37E02017, 0x236B0ED3, 0x60F246BF, 0x01E02501, 0x2D2F66BD, 0x6BF23609, 0x16729BAF
+};
+
+// binary search over intervals
+static int
+i_find(Intervals *i, int x) {
+ assert(i->n);
+ int l = 0, h = i->n;
+ Lrecurse:
+ if (h <= l + 2) {
+ if (h <= l)
+ return -(l + 1);
+ if (x < i->v[l] || x > i->v[l + 1])
+ return -(l + 1);
+ return h;
+ }
+ int m = (((h - l) / 4) * 2) + l;
+ if (x > i->v[m + 1]) {
+ l = m;
+ goto Lrecurse;
+ }
+ if (x < i->v[m]) {
+ h = m;
+ goto Lrecurse;
+ }
+ return (l + 1);
+}
+
+int
+Intervals::in(int x) {
+ if (!n)
+ return 0;
+ if (i_find(this, x) > 0)
+ return 1;
+ return 0;
+}
+
+// insert into interval with merge
+void
+Intervals::insert(int x) {
+ if (!n) {
+ add(x);
+ add(x);
+ return;
+ }
+ int l = i_find(this, x);
+ if (l > 0)
+ return;
+ l = -l - 1;
+
+ if (x > v[l + 1]) {
+ if (x == v[l + 1] + 1) {
+ v[l + 1]++;
+ goto Lmerge;
+ }
+ l += 2;
+ if (l < n) {
+ if (x == v[l] - 1) {
+ v[l]--;
+ goto Lmerge;
+ }
+ }
+ goto Lmore;
+ } else {
+ assert(x < v[l]);
+ if (x == v[l] - 1) {
+ v[l]--;
+ goto Lmerge;
+ }
+ if (!l)
+ goto Lmore;
+ l -= 2;
+ if (x == v[l + 1] + 1) {
+ v[l + 1]++;
+ goto Lmerge;
+ }
+ }
+ Lmore:
+ fill(n + 2);
+ if (n - 2 - l > 0)
+ memmove(v + l + 2, v + l, sizeof(int) * (n - 2 - l));
+ v[l] = x;
+ v[l+1] = x;
+ return;
+ Lmerge:
+ if (l) {
+ if (v[l] - v[l-1] < 2) {
+ l -= 2;
+ goto Ldomerge;
+ }
+ }
+ if (l < n - 2) {
+ if (v[l + 2] - v[l + 1] < 2)
+ goto Ldomerge;
+ }
+ return;
+ Ldomerge:
+ memmove(v + l + 1, v + l + 3, sizeof(int) * (n - 3 - l));
+ n -= 2;
+ goto Lmerge;
+}
+
+void
+UnionFind::size(int s) {
+ int nn = n;
+ fill(s);
+ for (int i = nn; i < n; i++)
+ v[i] = -1;
+}
+
+int
+UnionFind::find(int n) {
+ int i, t;
+ for (i = n; v[i] >= 0; i = v[i]);
+ while (v[n] >= 0) {
+ t = n;
+ n = v[n];
+ v[t] = i;
+ }
+ return i;
+}
+
+void
+UnionFind::unify(int n, int m) {
+ n = find(n);
+ m = find(m);
+ if (n != m) {
+ if (v[m] < v[n]) {
+ v[m] += (v[n] - 1);
+ v[n] = m;
+ } else {
+ v[n] += (v[m] - 1);
+ v[m] = n;
+ }
+ }
+}
View
815 lib/ts/Vec.h
@@ -0,0 +1,815 @@
+/** @file
+
+ Vector and Set templates with qsort.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef _vec_H_
+#define _vec_H_
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "defalloc.h"
+
+// Simple Vector class, also supports open hashed sets
+
+#define VEC_INTEGRAL_SHIFT_DEFAULT 2 /* power of 2 (1 << VEC_INTEGRAL_SHIFT)*/
+#define VEC_INTEGRAL_SIZE (1 << (S))
+#define VEC_INITIAL_SHIFT ((S)+1)
+#define VEC_INITIAL_SIZE (1 << VEC_INITIAL_SHIFT)
+
+#define SET_LINEAR_SIZE 4 /* must be <= than VEC_INTEGRAL_SIZE */
+#define SET_INITIAL_INDEX 2
+
+template <class C, class A = DefaultAlloc, int S = VEC_INTEGRAL_SHIFT_DEFAULT> // S must be a power of 2
+class Vec {
+ public:
+ int n;
+ int i; // size index for sets, reserve for vectors
+ C *v;
+ C e[VEC_INTEGRAL_SIZE];
+
+ Vec();
+ Vec<C,A,S>(const Vec<C,A,S> &vv);
+ Vec<C,A,S>(const C c);
+ ~Vec();
+
+ C &operator[](int i) const { return v[i]; }
+
+ C get(int i);
+ void add(C a);
+ void push_back(C a) { add(a); } // std::vector name
+ int add_exclusive(C a);
+ C& add();
+ C pop();
+ void reset();
+ void clear();
+ void free();
+ void free_and_clear();
+ void delete_and_clear();
+ void set_clear();
+ C *set_add(C a);
+ void set_remove(C a); // expensive, use BlockHash for cheaper remove
+ C *set_add_internal(C a);
+ int set_union(Vec<C,A,S> &v);
+ int set_intersection(Vec<C,A,S> &v);
+ int some_intersection(Vec<C,A,S> &v);
+ int some_disjunction(Vec<C,A,S> &v);
+ int some_difference(Vec<C,A,S> &v);
+ void set_intersection(Vec<C,A,S> &v, Vec<C,A,S> &result);
+ void set_disjunction(Vec<C,A,S> &v, Vec<C,A,S> &result);
+ void set_difference(Vec<C,A,S> &v, Vec<C,A,S> &result);
+ int set_count();
+ int count();
+ C *in(C a);
+ C *set_in(C a);
+ C first_in_set();
+ C *set_in_internal(C a);
+ void set_expand();
+ int index(C a);
+ void set_to_vec();
+ void vec_to_set();
+ void move(Vec<C,A,S> &v);
+ void copy(const Vec<C,A,S> &v);
+ void fill(int n);
+ void append(const Vec<C> &v);
+ void prepend(const Vec<C> &v);
+ void remove_index(int index);
+ void remove(C a) { int i = index(a); if (i>=0) remove_index(i); }
+ C& insert(int index);
+ void insert(int index, Vec<C> &vv);
+ void insert(int index, C a);
+ void push(C a) { insert(0, a); }
+ void reverse();
+ void reserve(int n);
+ C* end() const { return v + n; }
+ C &first() const { return v[0]; }
+ C &last() const { return v[n-1]; }
+ Vec<C,A,S>& operator=(Vec<C,A,S> &v) { this->copy(v); return *this; }
+ int length () const { return n; }
+ // vector::size() intentionally not implemented because it should mean "bytes" not count of elements
+ int write(int fd);
+ int read(int fd);
+ void qsort(bool (*lt)(C,C));
+
+ // private:
+ void move_internal(Vec<C,A,S> &v);
+ void copy_internal(const Vec<C,A,S> &v);
+ void add_internal(C a);
+ C& add_internal();
+ void addx();
+};
+
+// c -- class, p -- pointer to elements of v, v -- vector
+#define forv_Vec(_c, _p, _v) if ((_v).n) for (_c *qq__##_p = (_c*)0, *_p = (_v).v[0]; \
+ ((intptr_t)(qq__##_p) < (_v).length()) && ((_p = (_v).v[(intptr_t)qq__##_p]) || 1); qq__##_p = (_c*)(((intptr_t)qq__##_p) + 1))
+#define for_Vec(_c, _p, _v) if ((_v).n) for (_c *qq__##_p = (_c*)0, _p = (_v).v[0]; \
+ ((intptr_t)(qq__##_p) < (_v).length()) && ((_p = (_v).v[(intptr_t)qq__##_p]) || 1); qq__##_p = (_c*)(((intptr_t)qq__##_p) + 1))
+#define forvp_Vec(_c, _p, _v) if ((_v).n) for (_c *qq__##_p = (_c*)0, *_p = &(_v).v[0]; \
+ ((intptr_t)(qq__##_p) < (_v).length()) && ((_p = &(_v).v[(intptr_t)qq__##_p]) || 1); qq__##_p = (_c*)(((intptr_t)qq__##_p) + 1))
+
+template <class C, class A = DefaultAlloc, int S = VEC_INTEGRAL_SHIFT_DEFAULT> class Accum { public:
+ Vec<C,A,S> asset;
+ Vec<C,A,S> asvec;
+ void add(C c) { if (asset.set_add(c)) asvec.add(c); }
+ void add(Vec<C,A,S> v) { for (int i = 0; i < v.n; i++) if (v.v[i]) add(v.v[i]); }
+ void clear() { asset.clear(); asvec.clear(); }
+};
+
+// Intervals store sets in interval format (e.g. [1..10][12..12]).
+// Inclusion test is by binary search on intervals.
+// Deletion is not supported
+class Intervals : public Vec<int> {
+ public:
+ void insert(int n);
+ int in(int n);
+};
+
+// UnionFind supports fast unify and finding of
+// 'representitive elements'.
+// Elements are numbered from 0 to N-1.
+class UnionFind : public Vec<int> {
+ public:
+ // set number of elements, initialized to singletons, may be called repeatedly to increase size
+ void size(int n);
+ // return representitive element
+ int find(int n);
+ // unify the sets containing the two elements
+ void unify(int n, int m);
+};
+
+extern uintptr_t prime2[];
+extern uintptr_t open_hash_primes[256];
+
+/* IMPLEMENTATION */
+
+template <class C, class A, int S> inline
+Vec<C,A,S>::Vec() : n(0), i(0), v(0) {
+ memset(&e[0], 0, sizeof(e));
+}
+
+template <class C, class A, int S> inline
+Vec<C,A,S>::Vec(const Vec<C,A,S> &vv) {
+ copy(vv);
+}
+
+template <class C, class A, int S> inline
+Vec<C,A,S>::Vec(C c) {
+ n = 1;
+ i = 0;
+ v = &e[0];
+ e[0] = c;
+}
+
+template <class C, class A, int S> inline C
+Vec<C,A,S>::get(int i) {
+ if (i < n && i >= 0)
+ return v[i];
+ else
+ return 0;
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::add(C a) {
+ if (n & (VEC_INTEGRAL_SIZE-1))
+ v[n++] = a;
+ else if (!v)
+ (v = e)[n++] = a;
+ else
+ add_internal(a);
+}
+
+template <class C, class A, int S> inline C&
+Vec<C,A,S>::add() {
+ C *ret;
+ if (n & (VEC_INTEGRAL_SIZE-1))
+ ret = &v[n++];
+ else if (!v)
+ ret = &(v = e)[n++];
+ else
+ ret = &add_internal();
+ return *ret;
+}
+
+template <class C, class A, int S> inline C
+Vec<C,A,S>::pop() {
+ if (!n)
+ return 0;
+ n--;
+ C ret = v[n];
+ if (!n)
+ clear();
+ return ret;
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::set_clear() {
+ memset(v, 0, n * sizeof(C));
+}
+
+template <class C, class A, int S> inline C *
+Vec<C,A,S>::set_add(C a) {
+ if (n < SET_LINEAR_SIZE) {
+ for (C *c = v; c < v + n; c++)
+ if (*c == a)
+ return 0;
+ add(a);
+ return &v[n-1];
+ }
+ if (n == SET_LINEAR_SIZE) {
+ Vec<C,A,S> vv(*this);
+ clear();
+ for (C *c = vv.v; c < vv.v + vv.n; c++)
+ set_add_internal(*c);
+ }
+ return set_add_internal(a);
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::set_remove(C a) {
+ Vec<C,A,S> tmp;
+ tmp.move(*this);
+ for (C *c = tmp.v; c < tmp.v + tmp.n; c++)
+ if (*c != a)
+ set_add(a);
+}
+
+template <class C, class A, int S> inline int
+Vec<C,A,S>::count() {
+ int x = 0;
+ for (C *c = v; c < v + n; c++)
+ if (*c)
+ x++;
+ return x;
+}
+
+template <class C, class A, int S> inline C*
+Vec<C,A,S>::in(C a) {
+ for (C *c = v; c < v + n; c++)
+ if (*c == a)
+ return c;
+ return NULL;
+}
+
+template <class C, class A, int S> inline int
+Vec<C,A,S>::add_exclusive(C a) {
+ if (!in(a)) {
+ add(a);
+ return 1;
+ } else
+ return 0;
+}
+
+template <class C, class A, int S> inline C *
+Vec<C,A,S>::set_in(C a) {
+ if (n <= SET_LINEAR_SIZE)
+ return in(a);
+ return set_in_internal(a);
+}
+
+template <class C, class A, int S> inline C
+Vec<C,A,S>::first_in_set() {
+ for (C *c = v; c < v + n; c++)
+ if (*c)
+ return *c;
+ return 0;
+}
+
+template <class C, class A, int S> inline int
+Vec<C,A,S>::index(C a) {
+ for (C *c = v; c < v + n; c++)
+ if (*c == a)
+ return c - v;
+ return -1;
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::move_internal(Vec<C,A,S> &vv) {
+ n = vv.n;
+ i = vv.i;
+ if (vv.v == &vv.e[0]) {
+ memcpy(e, &vv.e[0], sizeof(e));
+ v = e;
+ } else
+ v = vv.v;
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::move(Vec<C,A,S> &vv) {
+ move_internal(vv);
+ vv.v = 0;
+ vv.clear();
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::copy(const Vec<C,A,S> &vv) {
+ n = vv.n;
+ i = vv.i;
+ if (vv.v == &vv.e[0]) {
+ memcpy(e, &vv.e[0], sizeof(e));
+ v = e;
+ } else {
+ if (vv.v)
+ copy_internal(vv);
+ else
+ v = 0;
+ }
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::fill(int nn) {
+ for (int i = n; i < nn; i++)
+ add() = 0;
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::append(const Vec<C> &vv) {
+ for (C *c = vv.v; c < vv.v + vv.n; c++)
+ if (*c != 0)
+ add(*c);
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::prepend(const Vec<C> &vv) {
+ if (vv.n) {
+ int oldn = n;
+ fill(n + vv.n);
+ if (oldn)
+ memmove(&v[vv.n], &v[0], oldn * sizeof(v[0]));
+ memcpy(&v[0], vv.v, vv.n * sizeof(v[0]));
+ }
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::add_internal(C a) {
+ addx();
+ v[n++] = a;
+}
+
+template <class C, class A, int S> C&
+Vec<C,A,S>::add_internal() {
+ addx();
+ return v[n++];
+}
+
+template <class C, class A, int S> C *
+Vec<C,A,S>::set_add_internal(C c) {
+ int j, k;
+ if (n) {
+ uintptr_t h = (uintptr_t)c;
+ h = h % n;
+ for (k = h, j = 0; j < i + 3; j++) {
+ if (!v[k]) {
+ v[k] = c;
+ return &v[k];
+ } else if (v[k] == c)
+ return 0;
+ k = (k + open_hash_primes[j]) % n;
+ }
+ }
+ Vec<C,A,S> vv;
+ vv.move_internal(*this);
+ set_expand();
+ if (vv.v)
+ set_union(vv);
+ return set_add(c);
+}
+
+template <class C, class A, int S> C *
+Vec<C,A,S>::set_in_internal(C c) {
+ int j, k;
+ if (n) {
+ uintptr_t h = (uintptr_t)c;
+ h = h % n;
+ for (k = h, j = 0; j < i + 3; j++) {
+ if (!v[k])
+ return 0;
+ else if (v[k] == c)
+ return &v[k];
+ k = (k + open_hash_primes[j]) % n;
+ }
+ }
+ return 0;
+}
+
+template <class C, class A, int S> int
+Vec<C,A,S>::set_union(Vec<C,A,S> &vv) {
+ int changed = 0;
+ for (int i = 0; i < vv.n; i++)
+ if (vv.v[i])
+ changed = set_add(vv.v[i]) || changed;
+ return changed;
+}
+
+template <class C, class A, int S> int
+Vec<C,A,S>::set_intersection(Vec<C,A,S> &vv) {
+ Vec<C,A,S> tv;
+ tv.move(*this);
+ int changed = 0;
+ for (int i = 0; i < tv.n; i++)
+ if (tv.v[i]) {
+ if (vv.set_in(tv.v[i]))
+ set_add(tv.v[i]);
+ else
+ changed = 1;
+ }
+ return changed;
+}
+
+template <class C, class A, int S> int
+Vec<C,A,S>::some_intersection(Vec<C,A,S> &vv) {
+ for (int i = 0; i < n; i++)
+ if (v[i])
+ if (vv.set_in(v[i]))
+ return 1;
+ return 0;
+}
+
+template <class C, class A, int S> int
+Vec<C,A,S>::some_disjunction(Vec<C,A,S> &vv) {
+ for (int i = 0; i < n; i++)
+ if (v[i])
+ if (!vv.set_in(v[i]))
+ return 1;
+ for (int i = 0; i < vv.n; i++)
+ if (vv.v[i])
+ if (!set_in(vv.v[i]))
+ return 1;
+ return 0;
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::set_intersection(Vec<C,A,S> &vv, Vec<C,A,S> &result) {
+ for (int i = 0; i < n; i++)
+ if (v[i])
+ if (vv.set_in(v[i]))
+ result.set_add(v[i]);
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::set_disjunction(Vec<C,A,S> &vv, Vec<C,A,S> &result) {
+ for (int i = 0; i < n; i++)
+ if (v[i])
+ if (!vv.set_in(v[i]))
+ result.set_add(v[i]);
+ for (int i = 0; i < vv.n; i++)
+ if (vv.v[i])
+ if (!set_in(vv.v[i]))
+ result.set_add(vv.v[i]);
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::set_difference(Vec<C,A,S> &vv, Vec<C,A,S> &result) {
+ for (int i = 0; i < n; i++)
+ if (v[i])
+ if (!vv.set_in(v[i]))
+ result.set_add(v[i]);
+}
+
+template <class C, class A, int S> int
+Vec<C,A,S>::some_difference(Vec<C,A,S> &vv) {
+ for (int i = 0; i < n; i++)
+ if (v[i])
+ if (!vv.set_in(v[i]))
+ return 1;
+ return 0;
+}
+
+template <class C, class A, int S> int
+Vec<C,A,S>::set_count() {
+ int x = 0;
+ for (int i = 0; i < n; i++)
+ if (v[i])
+ x++;
+ return x;
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::set_to_vec() {
+ C *x = &v[0], *y = x;
+ for (; y < v + n; y++) {
+ if (*y) {
+ if (x != y)
+ *x = *y;
+ x++;
+ }
+ }
+ if (i) {
+ i = prime2[i]; // convert set allocation to reserve
+ if (i - n > 0)
+ memset(&v[n], 0, (i - n) * (sizeof(C)));
+ } else {
+ i = 0;
+ if (v == &e[0] && VEC_INTEGRAL_SIZE - n > 0)
+ memset(&v[n], 0, (VEC_INTEGRAL_SIZE - n) * (sizeof(C)));
+ }
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::vec_to_set() {
+ Vec<C,A,S> vv;
+ vv.move(*this);
+ for (C *c = vv.v; c < vv.v + vv.n; c++)
+ set_add(*c);
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::remove_index(int index) {
+ if (n > 1)
+ memmove(&v[index], &v[index+1], (n - 1 - index) * sizeof(v[0]));
+ n--;
+ if (n <= 0)
+ v = e;
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::insert(int index, C a) {
+ add();
+ memmove(&v[index+1], &v[index], (n - index - 1) * sizeof(C));
+ v[index] = a;
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::insert(int index, Vec<C> &vv) {
+ fill(n + vv.n);
+ memmove(&v[index+vv.n], &v[index], (n - index - 1) * sizeof(C));
+ for (int x = 0; x < vv.n; x++)
+ v[index + x] = vv[x];
+}
+
+template <class C, class A, int S> C &
+Vec<C,A,S>::insert(int index) {
+ add();
+ memmove(&v[index+1], &v[index], (n - index - 1) * sizeof(C));
+ memset(&v[index], 0, sizeof(C));
+ return v[index];
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::reverse() {
+ for (int i = 0; i < n/2; i++) {
+ C *s = &v[i], *e = &v[n - 1 - i];
+ C t;
+ memcpy(&t, s, sizeof(t));
+ memcpy(s, e, sizeof(t));
+ memcpy(e, &t, sizeof(t));
+ }
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::copy_internal(const Vec<C,A,S> &vv) {
+ int l = n, nl = (1 + VEC_INITIAL_SHIFT);
+ l = l >> VEC_INITIAL_SHIFT;
+ while (l) { l = l >> 1; nl++; }
+ nl = 1 << nl;
+ v = (C*)A::alloc(nl * sizeof(C));
+ memcpy(v, vv.v, n * sizeof(C));
+ memset(v + n, 0, (nl - n) * sizeof(C));
+ if (i > n) // reset reserve
+ i = 0;
+}
+
+template <class C, class A, int S> void
+Vec<C,A,S>::set_expand() {
+ if (!n)
+ i = SET_INITIAL_INDEX;
+ else
+ i = i + 1;
+ n = prime2[i];
+ v = (C*)A::alloc(n * sizeof(C));
+ memset(v, 0, n * sizeof(C));
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::reserve(int x) {
+ if (x <= n)
+ return;
+ int xx = 1 << VEC_INITIAL_SHIFT;
+ while (xx < x) xx *= 2;
+ i = xx;
+ void *vv = (void*)v;
+ v = (C*)A::alloc(i * sizeof(C));
+ if (vv && n)
+ memcpy(v, vv, n * sizeof(C));
+ memset(&v[n], 0, (i-n) * sizeof(C));
+ if (vv && vv != e)
+ A::free(vv);
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::addx() {
+ if (!v) {
+ v = e;
+ return;
+ }
+ if (v == e) {
+ v = (C*)A::alloc(VEC_INITIAL_SIZE * sizeof(C));
+ memcpy(v, &e[0], n * sizeof(C));
+ assert(n < VEC_INITIAL_SIZE);
+ memset(&v[n], 0, (VEC_INITIAL_SIZE - n) * sizeof(C));
+ } else {
+ if ((n & (n-1)) == 0) {
+ int nl = n * 2;
+ if (nl <= i)
+ return;
+ else
+ i = 0;
+ void *vv = (void*)v;
+ v = (C*)A::alloc(nl * sizeof(C));
+ memcpy(v, vv, n * sizeof(C));
+ memset(&v[n], 0, n * sizeof(C));
+ A::free(vv);
+ }
+ }
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::free() {
+ if (v && v != e) A::free(v);
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::reset() {
+ v = NULL;
+ n = 0;
+ i = 0;
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::clear() {
+ if (v && v != e) A::free(v);
+ reset();
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::free_and_clear() {
+ for (int x = 0; x < n; x++)
+ if (v[x])
+ A::free(v[x]);
+ clear();
+}
+
+template <class C, class A, int S> inline void
+Vec<C,A,S>::delete_and_clear() {
+ for (int x = 0; x < n; x++)
+ if (v[x])
+ delete v[x];
+ clear();
+}
+
+template <class C, class A, int S>
+inline Vec<C,A,S>::~Vec() {
+ if (v && v != e) A::free(v);
+}
+
+template <class C, class A, int S>
+inline int marshal_size(Vec<C,A,S> &v) {
+ int l = sizeof(int) * 2;
+ for (int x = 0; x < v.n; x++)
+ l += ::marshal_size(v.v[x]);
+ return l;
+}
+
+template <class C, class A, int S>
+inline int marshal(Vec<C,A,S> &v, char *buf) {
+ char *x = buf;
+ *(int*)x = v.n; x += sizeof(int);
+ *(int*)x = v.i; x += sizeof(int);
+ for (int i = 0; i < v.n; i++)
+ x += ::marshal(v.v[i], x);
+ return x - buf;
+}
+
+template <class C, class A, int S>
+inline int unmarshal(Vec<C,A,S> &v, char *buf) {
+ char *x = buf;
+ v.n = *(int*)x; x += sizeof(int);
+ v.i = *(int*)x; x += sizeof(int);
+ if (v.n) {
+ v.v = (C*)A::alloc(sizeof(C) * v.n);
+ memset(v.v, 0, sizeof(C) * v.n);
+ } else
+ v.v = v.e;
+ for (int i = 0; i < v.n; i++)
+ x += ::unmarshal(v.v[i], x);
+ return x - buf;
+}
+
+template <class C, class A, int S>
+inline int Vec<C,A,S>::write(int fd) {
+ int r = 0, t = 0;
+ if ((r = ::write(fd, this, sizeof(*this))) < 0) return r; t += r;
+ if ((r = ::write(fd, v, n * sizeof(C))) < 0) return r; t += r;
+ return t;
+}
+
+template <class C, class A, int S>
+inline int Vec<C,A,S>::read(int fd) {
+ int r = 0, t = 0;
+ if ((r = ::read(fd, this, sizeof(*this))) < 0) return r; t += r;
+ v = (C*)A::alloc(sizeof(C) * n);
+ memset(v, 0, sizeof(C) * n);
+ if ((r = ::read(fd, v, n * sizeof(C))) < 0) return r; t += r;
+ return t;
+}
+
+template <class C>
+inline void qsort_Vec(C *left, C *right, bool (*lt)(C,C)) {
+ Lagain:
+ if (right - left < 5) {
+ for (C *y = right - 1; y > left; y--) {
+ for (C *x = left; x < y; x++) {
+ if (lt(x[1],x[0])) {
+ C t = x[0];
+ x[0] = x[1];
+ x[1] = t;
+ }
+ }
+ }
+ } else {
+ C *i = left + 1, *j = right - 1;
+ C x = *left;
+ for (;;) {
+ while (lt(x,*j)) j--;
+ while (i < j && lt(*i,x)) i++;
+ if (i >= j) break;
+ C t = *i;
+ *i = *j;
+ *j = t;
+ i++; j--;
+ }
+ if (j == right - 1) {
+ *left = *(right - 1);
+ *(right - 1) = x;
+ right--;
+ goto Lagain;
+ }
+ if (left < j) qsort_Vec<C>(left, j + 1, lt);
+ if (j + 2 < right) qsort_Vec<C>(j + 1, right, lt);
+ }
+}
+
+template <class C>
+inline void qsort_VecRef(C *left, C *right, bool (*lt)(C&,C&)) {
+ Lagain:
+ if (right - left < 5) {
+ for (C *y = right - 1; y > left; y--) {
+ for (C *x = left; x < y; x++) {
+ if (lt(x[1],x[0])) {
+ C t = x[0];
+ x[0] = x[1];
+ x[1] = t;
+ }
+ }
+ }
+ } else {
+ C *i = left + 1, *j = right - 1;
+ C x = *left;
+ for (;;) {
+ while (lt(x,*j)) j--;
+ while (i < j && lt(*i,x)) i++;
+ if (i >= j) break;
+ C t = *i;
+ *i = *j;
+ *j = t;
+ i++; j--;
+ }
+ if (j == right - 1) {
+ *left = *(right - 1);
+ *(right - 1) = x;
+ right--;
+ goto Lagain;
+ }
+ if (left < j) qsort_VecRef<C>(left, j + 1, lt);
+ if (j + 2 < right) qsort_VecRef<C>(j + 1, right, lt);
+ }
+}
+
+template <class C, class A, int S>
+inline void Vec<C,A,S>::qsort(bool (*lt)(C,C)) {
+ if (n)
+ qsort_Vec<C>(&v[0], end(), lt);
+}
+
+void test_vec();
+
+#endif
View
32 lib/ts/defalloc.h
@@ -0,0 +1,32 @@
+/** @file
+
+ Default allocator: malloc/free
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+#ifndef _defalloc_H_
+#define _defalloc_H_
+
+class DefaultAlloc { public:
+ static void *alloc(int s) { return ::malloc(s); }
+ static void free(void *p) { ::free(p); }
+};
+
+#endif
+
View
4 lib/ts/libts.h
@@ -37,6 +37,8 @@
#if !defined (_inktomiplus_h_)
#define _inktomiplus_h_
+#define std *** _FIXME_REMOVE_DEPENDENCY_ON_THE_STL_ ***
+
#include "ink_config.h"
#include "ink_platform.h"
#include "ink_port.h"
@@ -89,6 +91,7 @@
#include "List.h"
#include "INK_MD5.h"
#include "MMH.h"
+#include "Map.h"
#include "MimeTable.h"
#include "ParseRules.h"
#include "Ptr.h"
@@ -103,5 +106,6 @@
#include "Regression.h"
#include "HostLookup.h"
#include "InkErrno.h"
+#include "Vec.h"
#endif /*_inktomiplus_h_*/
View
112 lib/ts/test_Map.cc
@@ -0,0 +1,112 @@
+/** @file
+
+ Test code for the Map templates.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+#include <stdint.h>
+#include "Map.h"
+
+typedef const char cchar;
+
+int main(int argc, char **argv) {
+ typedef Map<cchar *, cchar *> SSMap;
+ typedef MapElem<cchar *, cchar *> SSMapElem;
+#define form_SSMap(_p, _v) form_Map(SSMapElem, _p, _v)
+ SSMap ssm;
+ ssm.put("a", "A");
+ ssm.put("b", "B");
+ ssm.put("c", "C");
+ ssm.put("d", "D");
+ form_SSMap(x, ssm) ;
+
+ StringChainHash<> h;
+ cchar *hi = "hi", *ho = "ho", *hum = "hum", *hhi = "hhi";
+ hhi++;
+ h.put(hi);
+ h.put(ho);
+ assert(h.put(hum) == hum);
+ assert(h.put(hhi) == hi);
+ assert(h.get(hhi) == hi && h.get(hi) == hi && h.get(ho) == ho);
+ assert(h.get("he") == 0 && h.get("hee") == 0);
+ h.del(ho);
+ assert(h.get(ho) == 0);
+
+ StringBlockHash hh;
+ hh.put(hi);
+ hh.put(ho);
+ assert(hh.put(hum) == 0);
+ assert(hh.put(hhi) == hi);
+ assert(hh.get(hhi) == hi && hh.get(hi) == hi && hh.get(ho) == ho);
+ assert(hh.get("he") == 0 && hh.get("hee") == 0);
+ hh.del(hi);
+ assert(hh.get(hhi) == 0);
+ assert(hh.get(hi) == 0);
+
+ HashMap<cchar *, StringHashFns, int> sh;
+ sh.put(hi, 1);
+ sh.put(ho, 2);
+ sh.put(hum, 3);
+ sh.put(hhi, 4);
+ assert(sh.get(hi) == 4);
+ assert(sh.get(ho) == 2);
+ assert(sh.get(hum) == 3);
+ sh.put("aa", 5);
+ sh.put("ab", 6);
+ sh.put("ac", 7);
+ sh.put("ad", 8);
+ sh.put("ae", 9);
+ sh.put("af", 10);
+ assert(sh.get(hi) == 4);
+ assert(sh.get(ho) == 2);
+ assert(sh.get(hum) == 3);
+ assert(sh.get("af") == 10);
+ assert(sh.get("ac") == 7);
+
+ ChainHashMap<cchar *, StringHashFns, int> ssh;
+ ssh.put(hi, 1);
+ ssh.put(ho, 2);
+ ssh.put(hum, 3);
+ ssh.put(hhi, 4);
+ assert(ssh.get(hi) == 4);
+ assert(ssh.get(ho) == 2);
+ assert(ssh.get(hum) == 3);
+ ssh.put("aa", 5);
+ ssh.put("ab", 6);
+ ssh.put("ac", 7);
+ ssh.put("ad", 8);
+ ssh.put("ae", 9);
+ ssh.put("af", 10);
+ assert(ssh.get(hi) == 4);
+ assert(ssh.get(ho) == 2);
+ assert(ssh.get(hum) == 3);
+ assert(ssh.get("af") == 10);
+ assert(ssh.get("ac") == 7);
+ ssh.del(ho);
+ assert(ssh.get(ho) == 0);
+
+ Vec<int> ints;
+ ssh.get_values(ints);
+ assert(ints.n == 8);
+ Vec<cchar *> chars;
+ ssh.get_keys(chars);
+ assert(chars.n == 8);
+ printf("test_Map PASSED\n");
+}
+
View
97 lib/ts/test_Vec.cc
@@ -0,0 +1,97 @@
+/* -*-Mode: c++;-*-
+ Various vector related code.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/* UnionFind after Tarjan */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+#include "Vec.h"
+
+int main(int argc, char **argv) {
+ Vec<void *> v, vv, vvv;
+ int tt = 99 * 50, t = 0;
+
+ for (int i = 0; i < 100; i++)
+ v.add((void*)(intptr_t)i);
+ for (int i = 0; i < 100; i++)
+ t += (int)(intptr_t)v.v[i];
+ assert(t == tt);
+
+ t = 0;
+ for (int i = 1; i < 100; i++)
+ vv.set_add((void*)(intptr_t)i);
+ for (int i = 1; i < 100; i++)
+ vvv.set_add((void*)(intptr_t)i);
+ for (int i = 1; i < 100; i++)
+ vvv.set_add((void*)(intptr_t)(i * 1000));
+ vv.set_union(vvv);
+ for (int i = 0; i < vv.n; i++)
+ if (vv.v[i])
+ t += (int)(intptr_t)vv.v[i];
+ assert(t == tt + 1000 * tt);
+
+ v.clear();
+ v.reserve(1000);
+ t = 0;
+ for (int i = 0; i < 1000; i++)
+ v.add((void*)(intptr_t)i);
+ for (int i = 0; i < 1000; i++)
+ t += (int)(intptr_t)v.v[i];
+ assert(t == 999 * 500);
+ printf("%d %d\n", v.n, v.i);
+
+ Intervals in;
+ in.insert(1);
+ assert(in.n == 2);
+ in.insert(2);
+ assert(in.n == 2);
+ in.insert(6);
+ assert(in.n == 4);
+ in.insert(7);
+ assert(in.n == 4);
+ in.insert(9);
+ assert(in.n == 6);
+ in.insert(4);
+ assert(in.n == 8);
+ in.insert(5);
+ assert(in.n == 6);
+ in.insert(3);
+ assert(in.n == 4);
+ in.insert(8);
+ assert(in.n == 2);
+
+ UnionFind uf;
+ uf.size(4);
+ uf.unify(0,1);
+ uf.unify(2,3);
+ assert(uf.find(2) == uf.find(3));
+ assert(uf.find(0) == uf.find(1));
+ assert(uf.find(0) != uf.find(3));
+ assert(uf.find(1) != uf.find(3));
+ assert(uf.find(1) != uf.find(2));
+ assert(uf.find(0) != uf.find(2));
+ uf.unify(1,2);
+ assert(uf.find(0) == uf.find(3));
+ assert(uf.find(1) == uf.find(3));