1 #ifndef UTIL_NCBITABLE__HPP
2 #define UTIL_NCBITABLE__HPP
3
4 /* $Id: ncbi_table.hpp 574980 2018-11-21 14:24:48Z ucko $
5 * ===========================================================================
6 *
7 * public DOMAIN NOTICE
8 * National Center for Biotechnology Information
9 *
10 * This software/database is a "United States Government Work" under the
11 * terms of the United States Copyright Act. It was written as part of
12 * the author's official duties as a United States Government employee and
13 * thus cannot be copyrighted. This software/database is freely available
14 * to the public for use. The National Library of Medicine and the U.S.
15 * Government have not placed any restriction on its use or reproduction.
16 *
17 * Although all reasonable efforts have been taken to ensure the accuracy
18 * and reliability of the software and data, the NLM and the U.S.
19 * Government do not and cannot warrant the performance or results that
20 * may be obtained by using this software or data. The NLM and the U.S.
21 * Government disclaim all warranties, express or implied, including
22 * warranties of performance, merchantability or fitness for any particular
23 * purpose.
24 *
25 * Please cite the author in any work or product based on this material.
26 *
27 * ===========================================================================
28 *
29 * Author: Anatoliy Kuznetsov
30 *
31 * File Description:
32 * NCBI table
33 *
34 */
35 #include <corelib/ncbistd.hpp>
36 #include <corelib/ncbiexpt.hpp>
37
38 BEGIN_NCBI_SCOPE
39
40 class NCBI_XUTIL_EXPORT CNcbiTable_Exception : EXCEPTION_VIRTUAL_BASE public CException
41 {
42 public:
43 /// Exception types
44 enum EErrCode {
45 eRowNotFound, ///< Row not found
46 eColumnNotFound, ///< Column not found
47 eRowAlreadyExists, ///< Row id has been assigned before
48 eColumnAlreadyExists ///< Column id has been assigned before
49 };
50
51 virtual const char* GetErrCodeString(void) const override;
52
53 NCBI_EXCEPTION_DEFAULT(CNcbiTable_Exception, CException);
54 };
55
56
57
58 /// Template class to create a table with custom row-column access
59 ///
60 /// Table provides two access modes one is using custom types
61 /// associated with rows and columns and another using rows and columns
62 /// integer indexes.
63 ///
64 template<class TValue, class TRow, class TColumn>
65 class CNcbiTable
66 {
67 public:
68 typedef map<TRow, unsigned int> TRowMap;
69 typedef map<TColumn, unsigned int> TColumnMap;
70 typedef TValue TValueType;
71
72 typedef vector<TValue> TRowType;
73
74 public:
75 CNcbiTable();
76 /// Construction.
77 /// Creates row x cols table without any row-column association
78 CNcbiTable(unsigned int rows, unsigned int cols);
79
80 CNcbiTable(const CNcbiTable& table);
operator =(const CNcbiTable & table)81 CNcbiTable& operator=(const CNcbiTable& table)
82 {
83 x_Free();
84 x_Copy(table);
85 return *this;
86 }
87
88 ~CNcbiTable();
89
90
91 /// Number of rows
92 unsigned int Rows() const;
93 /// Number of column
94 unsigned int Cols() const;
95
96 /// Add column to the table, column recieves name "col"
97 void AddColumn(const TColumn& col);
98 /// Add row to the table, column recieves name "row"
99 void AddRow(const TRow& row);
100
101 /// Set up row name
102 void AssociateRow(const TRow& row, unsigned int row_idx);
103 /// Set up column name
104 void AssociateColumn(const TColumn& col, unsigned int col_idx);
105
106 /// Change table size
107 void Resize(unsigned int rows,
108 unsigned int cols);
109
110 /// Change table size, new table elements initialized with value
111 void Resize(unsigned int rows,
112 unsigned int cols,
113 const TValue& v);
114
115 /// Get table row
116 const TRowType& GetRow(const TRow& row) const;
117 /// Get table row by row index
118 const TRowType& GetRowVector(unsigned int row_idx) const;
119 /// Get table row by row index
120 TRowType& GetRowVector(unsigned int row_idx);
121
122 /// Get table element
123 const TValueType& GetElement(const TRow& row, const TColumn& col) const;
124 /// Get table element
125 TValueType& GetElement(const TRow& row, const TColumn& col);
126
127 /// Get table element
operator ()(const TRow & row,const TColumn & col) const128 const TValue& operator()(const TRow& row, const TColumn& col) const
129 {
130 return GetElement(row, col);
131 }
132 /// Get table element
operator ()(const TRow & row,const TColumn & col)133 TValue& operator()(const TRow& row, const TColumn& col)
134 {
135 return GetElement(row, col);
136 }
137
138 /// Get column index
139 unsigned int ColumnIdx(const TColumn& col) const;
140 /// Get row index
141 unsigned int RowIdx(const TRow& row) const;
142
143 /// Get column name
144 const TColumn& Column(unsigned int idx) const;
145 /// Get row name
146 const TRow& Row(unsigned int idx) const;
147
148 /// Access table element by index
149 const TValueType& GetCell(unsigned int row_idx, unsigned int col_idx) const;
150
151 /// Access table element by index
152 TValueType& GetCell(unsigned int row_idx, unsigned int col_idx);
153 protected:
154
155 void x_Free();
156 void x_Copy(const CNcbiTable& table);
157
158 protected:
159 typedef vector<TRowType*> TRowCollection;
160
161 protected:
162 unsigned int m_Rows; ///< Number of rows
163 unsigned int m_Cols; ///< Number of columns
164
165 TRowMap m_RowMap; ///< Row name to index
166 TColumnMap m_ColumnMap; ///< Column name to index
167
168 TRowCollection m_Table;
169 };
170
171 /////////////////////////////////////////////////////////////////////////////
172 //
173 // CNcbiTable<TValue, TRow, TColumn>
174 //
175
176 template<class TValue, class TRow, class TColumn>
CNcbiTable()177 CNcbiTable<TValue, TRow, TColumn>::CNcbiTable()
178 : m_Rows(0),
179 m_Cols(0)
180 {
181 }
182
183 template<class TValue, class TRow, class TColumn>
CNcbiTable(unsigned int rows,unsigned int cols)184 CNcbiTable<TValue, TRow, TColumn>::CNcbiTable(unsigned int rows,
185 unsigned int cols)
186 : m_Rows(rows),
187 m_Cols(cols)
188 {
189 m_Table.reserve(m_Rows);
190 for (unsigned int i = 0; i < m_Rows; ++i) {
191 TRowType* r = new TRowType(m_Cols);
192 m_Table.push_back(r);
193 }
194 }
195
196 template<class TValue, class TRow, class TColumn>
CNcbiTable(const CNcbiTable<TValue,TRow,TColumn> & table)197 CNcbiTable<TValue, TRow, TColumn>::CNcbiTable(
198 const CNcbiTable<TValue, TRow, TColumn>& table)
199 {
200 x_Copy(table);
201 }
202
203 template<class TValue, class TRow, class TColumn>
x_Copy(const CNcbiTable & table)204 void CNcbiTable<TValue, TRow, TColumn>::x_Copy(const CNcbiTable& table)
205 {
206 m_Rows = table.Rows();
207 m_Cols = table.Cols();
208
209 m_Table.resize(0);
210 m_Table.reserve(m_Rows);
211 for (unsigned int i = 0; i < m_Rows; ++i) {
212 const TRowType& src_row = table.GetRowVector(i);
213 TRowType* r = new TRowType(src_row);
214 m_Table.push_back(r);
215 }
216
217 m_RowMap = table.m_RowMap;
218 m_ColumnMap = table.m_ColumnMap;
219 }
220
221
222 template<class TValue, class TRow, class TColumn>
~CNcbiTable()223 CNcbiTable<TValue, TRow, TColumn>::~CNcbiTable()
224 {
225 x_Free();
226 }
227
228 template<class TValue, class TRow, class TColumn>
x_Free()229 void CNcbiTable<TValue, TRow, TColumn>::x_Free()
230 {
231 NON_CONST_ITERATE(typename TRowCollection, it, m_Table) {
232 TRowType* r = *it;
233 delete r;
234 }
235 m_Table.resize(0);
236 }
237
238
239 template<class TValue, class TRow, class TColumn>
Rows() const240 unsigned int CNcbiTable<TValue, TRow, TColumn>::Rows() const
241 {
242 return m_Rows;
243 }
244
245 template<class TValue, class TRow, class TColumn>
Cols() const246 unsigned int CNcbiTable<TValue, TRow, TColumn>::Cols() const
247 {
248 return m_Cols;
249 }
250
251 template<class TValue, class TRow, class TColumn>
AddColumn(const TColumn & col)252 void CNcbiTable<TValue, TRow, TColumn>::AddColumn(const TColumn& col)
253 {
254 unsigned int cidx = m_Cols;
255 AssociateColumn(col, cidx);
256 NON_CONST_ITERATE(typename TRowCollection, it, m_Table) {
257 TRowType* r = *it;
258 r->push_back(TValue());
259 }
260 ++m_Cols;
261 }
262
263 template<class TValue, class TRow, class TColumn>
AddRow(const TRow & row)264 void CNcbiTable<TValue, TRow, TColumn>::AddRow(const TRow& row)
265 {
266 unsigned int ridx = m_Rows;
267 TRowType* r = new TRowType(m_Cols);
268 m_Table.push_back(r);
269
270 AssociateRow(row, ridx);
271 ++m_Rows;
272 }
273
274 template<class TValue, class TRow, class TColumn>
AssociateRow(const TRow & row,unsigned int row_idx)275 void CNcbiTable<TValue, TRow, TColumn>::AssociateRow(const TRow& row,
276 unsigned int row_idx)
277 {
278 typename TRowMap::const_iterator it = m_RowMap.find(row);
279 if (it == m_RowMap.end()) {
280 m_RowMap.insert(pair<TRow, unsigned int>(row, row_idx));
281 } else {
282 NCBI_THROW(
283 CNcbiTable_Exception,
284 eRowAlreadyExists, "Cannot assign row key (already assigned).");
285 }
286 }
287
288 template<class TValue, class TRow, class TColumn>
AssociateColumn(const TColumn & col,unsigned int col_idx)289 void CNcbiTable<TValue, TRow, TColumn>::AssociateColumn(const TColumn& col,
290 unsigned int col_idx)
291 {
292 typename TColumnMap::const_iterator it = m_ColumnMap.find(col);
293 if (it == m_ColumnMap.end()) {
294 m_ColumnMap.insert(pair<TColumn, unsigned int>(col, col_idx));
295 } else {
296 NCBI_THROW(
297 CNcbiTable_Exception,
298 eRowAlreadyExists, "Cannot assign column key (already assigned).");
299 }
300
301 }
302
303 template<class TValue, class TRow, class TColumn>
Resize(unsigned int rows,unsigned int cols)304 void CNcbiTable<TValue, TRow, TColumn>::Resize(unsigned int rows,
305 unsigned int cols)
306 {
307 m_Rows = rows;
308
309 if (rows < m_Rows) {
310 m_Table.resize(rows);
311 if (m_Cols == cols)
312 return; // nothing to do
313 } else {
314 m_Table.resize(rows, 0);
315 }
316 m_Cols = cols;
317
318 NON_CONST_ITERATE(typename TRowCollection, it, m_Table) {
319 TRowType* r = *it;
320 if (r == 0) { // new row
321 r = new TRowType();
322 r->resize(cols);
323 *it = r;
324 } else {
325 if (r->size() != cols) { // resize required
326 r->resize(cols);
327 }
328 }
329 }
330 }
331
332 template<class TValue, class TRow, class TColumn>
Resize(unsigned int rows,unsigned int cols,const TValue & v)333 void CNcbiTable<TValue, TRow, TColumn>::Resize(unsigned int rows,
334 unsigned int cols,
335 const TValue& v)
336 {
337 m_Rows = rows;
338
339 if (rows < m_Rows) {
340 m_Table.resize(rows);
341 if (m_Cols == cols)
342 return; // nothing to do
343 } else {
344 m_Table.resize(rows, 0);
345 }
346 m_Cols = cols;
347
348 NON_CONST_ITERATE(typename TRowCollection, it, m_Table) {
349 TRowType* r = *it;
350 if (r == 0) { // new row
351 r = new TRowType();
352 r->resize(cols, v);
353 *it = r;
354 } else {
355 if (r->size() != cols) { // resize required
356 r->resize(cols, v);
357 }
358 }
359 }
360 }
361
362
363 template<class TValue, class TRow, class TColumn>
364 const typename CNcbiTable<TValue, TRow, TColumn>::TRowType&
GetRow(const TRow & row) const365 CNcbiTable<TValue, TRow, TColumn>::GetRow(const TRow& row) const
366 {
367 typename TRowMap::const_iterator it = m_RowMap.find(row);
368 if (it == m_RowMap.end()) {
369 NCBI_THROW(
370 CNcbiTable_Exception,
371 eRowNotFound, "Row not found.");
372 }
373 unsigned int idx = it->second;
374 return *(m_Table[idx]);
375 }
376
377 template<class TValue, class TRow, class TColumn>
378 const typename CNcbiTable<TValue, TRow, TColumn>::TRowType&
GetRowVector(unsigned int row_idx) const379 CNcbiTable<TValue, TRow, TColumn>::GetRowVector(unsigned int row_idx) const
380 {
381 return *(m_Table[row_idx]);
382 }
383
384 template<class TValue, class TRow, class TColumn>
385 typename CNcbiTable<TValue, TRow, TColumn>::TRowType&
GetRowVector(unsigned int row_idx)386 CNcbiTable<TValue, TRow, TColumn>::GetRowVector(unsigned int row_idx)
387 {
388 return *(m_Table[row_idx]);
389 }
390
391
392 template<class TValue, class TRow, class TColumn>
393 const typename CNcbiTable<TValue, TRow, TColumn>::TValueType&
GetElement(const TRow & row,const TColumn & col) const394 CNcbiTable<TValue, TRow, TColumn>::GetElement(const TRow& row, const TColumn& col) const
395 {
396 unsigned int ridx = RowIdx(row);
397 unsigned int cidx = ColumnIdx(col);
398
399 return GetCell(ridx, cidx);
400 }
401
402 template<class TValue, class TRow, class TColumn>
403 typename CNcbiTable<TValue, TRow, TColumn>::TValueType&
GetElement(const TRow & row,const TColumn & col)404 CNcbiTable<TValue, TRow, TColumn>::GetElement(const TRow& row, const TColumn& col)
405 {
406 unsigned int ridx = RowIdx(row);
407 unsigned int cidx = ColumnIdx(col);
408
409 return GetCell(ridx, cidx);
410 }
411
412
413 template<class TValue, class TRow, class TColumn>
414 unsigned int
ColumnIdx(const TColumn & col) const415 CNcbiTable<TValue, TRow, TColumn>::ColumnIdx(const TColumn& col) const
416 {
417 typename TColumnMap::const_iterator it = m_ColumnMap.find(col);
418 if (it == m_ColumnMap.end()) {
419 NCBI_THROW(
420 CNcbiTable_Exception,
421 eColumnNotFound, "Column not found.");
422 }
423 return it->second;
424 }
425
426 template<class TValue, class TRow, class TColumn>
427 unsigned int
RowIdx(const TRow & row) const428 CNcbiTable<TValue, TRow, TColumn>::RowIdx(const TRow& row) const
429 {
430 typename TRowMap::const_iterator it = m_RowMap.find(row);
431 if (it == m_RowMap.end()) {
432 NCBI_THROW(
433 CNcbiTable_Exception,
434 eRowNotFound, "Row not found.");
435 }
436 return it->second;
437 }
438
439 template<class TValue, class TRow, class TColumn>
440 const TColumn&
Column(unsigned int idx) const441 CNcbiTable<TValue, TRow, TColumn>::Column(unsigned int idx) const
442 {
443 typename TColumnMap::const_iterator it = m_ColumnMap.begin();
444 for(it=m_ColumnMap.begin(); it!=m_ColumnMap.end(); ++it) {
445 if ( (*it).second == idx )
446 return (*it).first;
447 }
448
449 NCBI_THROW(CNcbiTable_Exception, eColumnNotFound, "Column not found.");
450 }
451
452 template<class TValue, class TRow, class TColumn>
453 const TRow&
Row(unsigned int idx) const454 CNcbiTable<TValue, TRow, TColumn>::Row(unsigned int idx) const
455 {
456 typename TRowMap::const_iterator it = m_RowMap.begin();
457 for(it=m_RowMap.begin(); it!=m_RowMap.end(); ++it) {
458 if ( (*it).second == idx )
459 return (*it).first;
460 }
461
462 NCBI_THROW(CNcbiTable_Exception, eRowNotFound, "Row not found.");
463 }
464
465 template<class TValue, class TRow, class TColumn>
466 const typename CNcbiTable<TValue, TRow, TColumn>::TValueType&
GetCell(unsigned int row_idx,unsigned int col_idx) const467 CNcbiTable<TValue, TRow, TColumn>::GetCell(unsigned int row_idx,
468 unsigned int col_idx) const
469 {
470 const TRowType& r = *(m_Table[row_idx]);
471 return r[col_idx];
472 }
473
474 template<class TValue, class TRow, class TColumn>
475 typename CNcbiTable<TValue, TRow, TColumn>::TValueType&
GetCell(unsigned int row_idx,unsigned int col_idx)476 CNcbiTable<TValue, TRow, TColumn>::GetCell(unsigned int row_idx,
477 unsigned int col_idx)
478 {
479 TRowType& r = *(m_Table[row_idx]);
480 return r[col_idx];
481 }
482
483
484 END_NCBI_SCOPE
485
486 #endif /* UTIL_NCBITABLE__HPP */
487