GemaCoreLib
The GeMA Core library
Loading...
Searching...
No Matches
gmSparseVector.h
Go to the documentation of this file.
1/************************************************************************
2**
3** Copyright (C) 2014 by Carlos Augusto Teixera Mendes
4** All rights reserved.
5**
6** This file is part of the "GeMA" software. It's use should respect
7** the terms in the license agreement that can be found together
8** with this source code.
9** It is provided AS IS, with NO WARRANTY OF ANY KIND,
10** INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR
11** A PARTICULAR PURPOSE.
12**
13************************************************************************/
14
23#ifndef _GEMA_SPARSE_VECTOR_H_
24#define _GEMA_SPARSE_VECTOR_H_
25
26#include "gmCoreConfig.h"
27
28#include <QVarLengthArray>
29#include <QHash>
30#include <QLinkedList>
31#include <QtAlgorithms>
32#include <assert.h>
33
34
35// IMPORTANT: None of the codes below is fit for multi-threaded access and can not be used
36// in a value set data without locking!
37
38
39template <class T> class GmHashSparseVector
40{
41public:
42 const T at(int index, const T& defValue) const { return _data.value(index, defValue); }
43
44 void insert(int index, const T& val) { _data.insert(index, val); }
45
46 void remove(int index, const T& defValue) { Q_UNUSED(defValue); _data.remove(index); }
47
48 void clear(int n, const T& defVal) { Q_UNUSED(n); Q_UNUSED(defVal); _data.clear(); }
49
50
51private:
53};
54
55template <class T> class GmLinkedSparseVector
56{
57public:
58 const T at(int index, const T& defValue) const
59 {
60 QLinkedList<QPair<int, T> >::const_iterator it = _data.constBegin();
61 for(; it != _data.constEnd(); it++)
62 {
63 if(it->first == index)
64 return it->second;
65 else if(it->first > index)
66 return defValue;
67 }
68 return defValue;
69 }
70
71 void insert(int index, const T& val)
72 {
73 QLinkedList<QPair<int, T> >::iterator it = _data.begin();
74 for(; it != _data.end(); it++)
75 {
76 if(it->first == index)
77 {
78 it->second = val;
79 return;
80 }
81 else if(it->first > index)
82 {
83 _data.insert(it, qMakePair<int, T>(index, val));
84 return;
85 }
86 }
87 _data.insert(_data.end(), qMakePair<int, T>(index, val));
88 }
89
90 void remove(int index, const T& defValue)
91 {
92 Q_UNUSED(defValue);
93 QLinkedList<QPair<int, T> >::iterator it = _data.begin();
94 for(; it != _data.end(); it++)
95 {
96 if(it->first == index)
97 {
98 _data.erase(it);
99 return;
100 }
101 else if(it->first > index)
102 return;
103 }
104 }
105
106 void clear(int n, const T& defVal) { Q_UNUSED(n); Q_UNUSED(defVal); _data.clear(); }
107
108private:
110};
111
112
113template <class T> class GmRleSparseVector
114{
115public:
117 {
118 _index.append(0);
119 }
120
121 const T at(int index, const T& defValue) const
122 {
123 Q_UNUSED(defValue);
124 assert(index >= 0 && index < *(_index.end()-1));
125 assert(_index.size() == _data.size() + 1);
126
127 // Make it point to the smaller value in _index that is >= index
128 // There is a sentinel at the end of _index with the highest valid index so
129 // a match will always be found
131 assert(it != _index.constEnd());
132
133 int itPos = it - _index.constBegin();
134
135 if(*it == index)
136 return _data.at(itPos);
137
138 assert(*it > index);
139 assert(itPos > 0);
140
141 return _data.at(itPos - 1);
142 }
143
144 void insert(int index, const T& val)
145 {
146 assert(index >= 0 && index <= *(_index.end()-1));
147 assert(_index.size() == _data.size() + 1);
148
150
151 // Are we appending a new value to the vector?
152 it = _index.end()-1; // it points to the sentinel with the array size
153 if(index == *it)
154 {
155 if(!_data.isEmpty() && val == _data.last())
156 *it = index + 1;
157 else
158 {
159 _data.append(val);
160 _index.append(index+1);
161 }
162#if defined ENABLE_TESTS || defined ENABLE_SPARSE_TESTS
163 validateInternalStructure();
164#endif
165 return;
166 }
167
168 // No. We are CHANGING the value at an EXISTING index
169 // Make 'it' point to the smaller value in _index that is >= index
170 it = qLowerBound(_index.begin(), _index.end(), index);
171 assert(it != _index.end());
172
173 int itPos = it - _index.begin();
174
175 if(*it == index)
176 {
177 if(_data[itPos] == val)
178 return;
179
180 assert(it+1 != _index.end()); // Since the queried index must be less than the sentinel
181
182 if(*(it+1) == index + 1)
183 {
184 // No other index is sharing this value. If it is equal to one (or both) of its
185 // neighbors, merge, else we can just store the new value. We just have to be
186 // carefull to check if the next neighbor is not the sentinel...
187 if(itPos+1 < _data.size() && _data[itPos+1] == val)
188 {
189 if(itPos > 0 && _data[itPos - 1] == val)
190 {
191 // New data is equal to both the next and previous index values.
192 // Removes this value and the next one
193 _index.erase(it, it+2);
194 _data.remove(itPos, 2);
195 }
196 else
197 {
198 // New data is equal to the next value. Removes this value and updates
199 // the index for the next one
200 *(it+1) = index;
201 _index.erase(it);
202 _data.remove(itPos);
203 }
204 }
205 else if(itPos > 0 && _data[itPos - 1] == val)
206 {
207 // New data is the same as the data for the previous index. Just remove this value,
208 // merging it with the previous one
209 _index.erase(it);
210 _data.remove(itPos);
211 }
212 else
213 _data[itPos] = val; // Value is different from both neighbors
214 }
215 else
216 {
217 // The current value is shared, so we must split it (unless the new value is
218 // equal to the value of the previous index in which case we just need to increase
219 // the current index)
220 (*it)++;
221 if(itPos == 0 || _data[itPos-1] != val)
222 {
223 _data.insert(itPos, val);
224 _index.insert(it, index);
225 }
226 }
227 }
228 else
229 {
230 assert(*it > index);
231 assert(itPos > 0);
232
233 if(_data[itPos-1] == val)
234 return;
235
236 if(*it == index + 1)
237 {
238 // The index is just one less than the next stored index, so we just have to insert
239 // a single value pair (unless the value is equal to the next index, in which case
240 // suffices to update the stored index -- just be carefull that the next index might
241 // be the sentinel)
242 if(itPos < _data.size() && _data[itPos] == val)
243 *it = index;
244 else
245 {
246 _data.insert(itPos, val);
247 _index.insert(it, index);
248 }
249 }
250 else
251 {
252 // Two values must be inserted... One to store (index, val) and the other for
253 // the previous value for the rest of the sequence
254 _data.insert(itPos, _data[itPos-1]);
255 it = _index.insert(it, index+1);
256 _data.insert(itPos, val);
257 _index.insert(it, index);
258 }
259 }
260#if defined ENABLE_TESTS || defined ENABLE_SPARSE_TESTS
261 validateInternalStructure();
262#endif
263 }
264
265 void remove(int index, const T& defValue) { insert(index, defValue); }
266
267 void clear(int n, const T& defVal)
268 {
269 _index.clear();
270 _index.append(0);
271 _index.append(n);
272 _data.clear();
273 _data.append(defVal);
274#if defined ENABLE_TESTS || defined ENABLE_SPARSE_TESTS
275 validateInternalStructure();
276#endif
277 }
278
279#if defined ENABLE_TESTS || defined ENABLE_SPARSE_TESTS
280 void validateInternalStructure()
281 {
282 assert(_index.size() == _data.size() + 1);
283
284 assert(_index[0] == 0);
285 for(int i = 1, n = _index.size(); i<n; i++)
286 assert(_index[i] > _index[i-1]);
287
288 for(int i = 1, n = _data.size(); i<n; i++)
289 assert(_data[i] != _data[i-1]);
290 }
291#endif
292
293private:
296};
297
298
299
300
301#endif
302
303
Definition gmSparseVector.h:40
QHash< int, T > _data
Hash table storing the sparse data keyed by its index.
Definition gmSparseVector.h:52
Definition gmSparseVector.h:56
QLinkedList< QPair< int, T > > _data
Linked list storing (index, value) pairs. Sorted by index.
Definition gmSparseVector.h:109
Definition gmSparseVector.h:114
QVarLengthArray< int, 1 > _index
_index[i] stores the first index of a block with continuous value given by _data[i].
Definition gmSparseVector.h:294
QVarLengthArray< T, 1 > _data
The value associated with indices _index[i] ... (_index[i+1]-1)
Definition gmSparseVector.h:295
Declaration of useful configuration definitions for the Core library.
void clear()
QHash::iterator insert(const Key &key, const T &value)
int remove(const Key &key)
const T value(const Key &key) const const
QLinkedList::iterator begin()
void clear()
QLinkedList::const_iterator constBegin() const const
QLinkedList::const_iterator constEnd() const const
QLinkedList::iterator end()
QLinkedList::iterator erase(QLinkedList::iterator pos)
QLinkedList::iterator insert(QLinkedList::iterator before, const T &value)
void append(const T &t)
const T & at(int i) const const
QVarLengthArray::iterator begin()
QVarLengthArray::const_iterator constBegin() const const
QVarLengthArray::const_iterator constEnd() const const
QVarLengthArray::iterator end()
QVarLengthArray::iterator erase(QVarLengthArray::const_iterator begin, QVarLengthArray::const_iterator end)
void insert(int i, T &&value)
bool isEmpty() const const
void remove(int i)
int size() const const