summaryrefslogtreecommitdiff
path: root/graphics/sam2p/mapping.hpp
blob: e7c798b0ac0ca6c1d36247a0583c4a659797c876 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* mapping.hpp -- an associative array that maps strings into arbitrary fixed-length values
 * by pts@fazekas.hu at Sat Mar 23 16:01:55 CET 2002
 */

#ifdef __GNUC__
#ifndef __clang__
#pragma interface
#endif
#endif

#ifndef MAPPING_HPP
#define MAPPING_HPP 1

#include "config2.h"
#include "gensi.hpp"

class Mapping {
  /** A mapping is an assicative array whose keys are arbitrary binary strings
   * and its values are arbirary fixed-length data. The Mapping class is
   * abstract. The longest key which can be stored in a Mapping::Gen has
   * length `(slen_t)-3'. The caller must verify that she doesn't try to
   * call us with a longer string.
   */
  class Gen {
   public:
    inline virtual ~Gen() {}
    /** Returns the length of one data value (same for all values, determined
     * at construction of Gen).
     */
    inline slen_t getDataLen() const { return datalen; }
    /** Returns the number of keys currently in this Mapping. */
    inline slen_t getLength() const { return len; }
    /** Returns the number of key positions allocated for this Mapping. This
     * number may or may not have meaning, depending on the implementation.
     */
    inline slen_t getAlloced() const { return len; }
    /**
     * Updates or extends the mapping with the specified key/value pair.
     * @param data must point to an area of length getDataLen(). That
     *        area will be copied (memcpy()) by set().
     * @return true if key previously hasn't existed
     */
    virtual bool set(char const*key, slen_t keylen, char const*data) =0;
    /** @return the address of the data that corresponds to param
     * `key', or NULLP if `key' was not found. The returned value is valid
     * until the next modification (.set(), deletee() methods).
     */
    virtual char* get(char const*key, slen_t keylen) =0;
    /**
     * Updates mapping with the specified key/value pair. Leaves it unchanged
     * if the specified key doesn't exist. Calls get() and memcpy() to do the
     * job.
     * @param data must point to an area of length getDataLen(). That
     *        area will be copied by set().
     * @return true if key previously hasn't existed
     */
    bool update(char const*key, slen_t keylen, char const*data);
    
    /** Calls get to do the job. */
    inline bool exists(char const*key, slen_t keylen) { return NULLP!=get(key, keylen); }
    
    /**
     * Deletes the specified `key' from the mapping.
     * @param data must point to an area of length getDataLen(). That
     *        area will be copied by set().
     * @return true if key previously hasn't existed
     */
    virtual bool deletee(char const*key, slen_t keylen) =0;
    
    /** The user must ensure that she isn't updating the mapping while walking.
     * @param key (out) is set to NULLP on empty mapping.
     */
    virtual void getFirst(char const*const*& key, slen_t &keylen, char *& data) =0;
    /** The user must ensure that she isn't updating the mapping while walking.
     * @param key (out) is set to NULLP if there are no more elements
     */
    virtual void getNext (char const*const*& key, slen_t &keylen, char *& data) =0;

   protected:
    slen_t datalen, len, alloced;
  };
  
  /** Double hashing. Still abstract. */
  class DoubleHash: public Gen {
   public:
    inline virtual ~DoubleHash() {}
    /** If it modifies `scale', then it must modify alloced, may modify minlen
     * and maxused, and must not modify anything else. If it does not modify
     * `scale', it must not modify anything else. After it returns,
     * obj_assert() must hold. Must not copy or (re)allocate memory,
     * rehashing is not done by vi_scale(). rehash() calls vi_scale(), and
     * rehash() does the real reallocation.
     */
    virtual void vi_scale() =0;
    /** First hash function.  Must return a value in 0..alloced-1 */
    virtual slen_t vi_h1(char const*key, slen_t keylen) =0;
    /** Second hash function. Must return a value in 1..alloced-1, which is
     * realatively prime to the value returned by vi_h2().
     */
    virtual slen_t vi_h2(char const*key, slen_t keylen) =0;
    /** Destruct and free resources used by data. Called by deletee(). */
    virtual void vi_dtor(char *data) =0;
    
    /** Called by set() and deletee() ?? */
    virtual bool set     (char const*  key, slen_t  keylen, char const*data);
    virtual char*get     (char const*  key, slen_t  keylen);
    virtual bool deletee (char const*  key, slen_t  keylen);
    virtual void getFirst(char const*const*&key, slen_t &keylen, char *& data);
    virtual void getNext (char const*const*&key, slen_t &keylen, char *& data);
    /** Delete everything. */
    void clear();
   protected:
    void rehash();
    /** @return true */
    bool obj_assert();
    /** `keylen==(slen_t)-1' indicates a place never used,
     *  `keylen==(slen_t)-2' indicates a deleted place
     * Before changing the value of NEVER_USED, please update the memset(...)
     * in rehash().
     */
    BEGIN_STATIC_ENUM1(slen_t) NEVER_USED=(slen_t)-1, DELETED=(slen_t)-2 END_STATIC_ENUM()
    // static const slen_t NEVER_USED=(slen_t)-1, DELETED=(slen_t)-2;
    struct Ary {
      slen_t keylen;
      /** data is located at keydata, key is located keydata-datalen */
      char *keydata;
    } *ary;
    /* The minimum number of keys before rehashing. */
    slen_t minlen;
    /* The maximum number of keys before rehashing. */
    slen_t maxused;
    /* The number of used places. A place is used unless it is NEVER_USED */
    slen_t used;
    /** Used by the implementor of vi_scale. */
    unsigned scale;
  };
  
  /** Simple prime modulus double hashing with a factor of around 1.5
   * between `alloced' scales. This class is not abstract anymore.
   */
  class DoubleHash15: public DoubleHash {
   public:
    DoubleHash15(slen_t datalen_);
    virtual ~DoubleHash15();
    virtual void vi_scale();
    /** @return key % Prime */
    virtual slen_t vi_h1(char const*key, slen_t keylen);
    /** @return (key % (Prime-1))+1 */
    virtual slen_t vi_h2(char const*key, slen_t keylen);
    /** No-op. */
    virtual void vi_dtor(char *data);
  };
 public:  
  typedef DoubleHash15 H;
};

#endif