GemaCoreLib
The GeMA Core library
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 
39 template <class T> class GmHashSparseVector
40 {
41 public:
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 
51 private:
53 };
54 
55 template <class T> class GmLinkedSparseVector
56 {
57 public:
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 
108 private:
110 };
111 
112 
113 template <class T> class GmRleSparseVector
114 {
115 public:
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 
293 private:
296 };
297 
298 
299 
300 
301 #endif
302 
303 
const T & at(int i) const const
Definition: gmSparseVector.h:113
QHash::iterator insert(const Key &key, const T &value)
QLinkedList::iterator erase(QLinkedList::iterator pos)
void append(const T &t)
QVarLengthArray::iterator begin()
QVarLengthArray< int, 1 > _index
_index[i] stores the first index of a block with continuous value given by _data[i].
Definition: gmSparseVector.h:294
QLinkedList::iterator begin()
Declaration of usefull configuration definitions for the Core library.
QLinkedList< QPair< int, T > > _data
Linked list storing (index, value) pairs. Sorted by index.
Definition: gmSparseVector.h:109
QLinkedList::iterator insert(QLinkedList::iterator before, const T &value)
QVarLengthArray::const_iterator constEnd() const const
QHash< int, T > _data
Hash table storing the sparse data keyed by its index.
Definition: gmSparseVector.h:52
QLinkedList::iterator end()
Definition: gmSparseVector.h:39
QVarLengthArray< T, 1 > _data
The value associated with indices _index[i] ... (_index[i+1]-1)
Definition: gmSparseVector.h:295
QVarLengthArray::const_iterator constBegin() const const
QVarLengthArray::iterator erase(QVarLengthArray::const_iterator begin, QVarLengthArray::const_iterator end)
int remove(const Key &key)
void clear()
const T value(const Key &key) const const
bool isEmpty() const const
QVarLengthArray::iterator end()
QLinkedList::const_iterator constBegin() const const
QLinkedList::const_iterator constEnd() const const
void remove(int i)
Definition: gmSparseVector.h:55
int size() const const
void insert(int i, T &&value)
void clear()