File: persistent_table.h

package info (click to toggle)
rheolef 7.2-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 88,076 kB
  • sloc: cpp: 110,259; sh: 16,733; makefile: 5,438; python: 1,391; yacc: 218; javascript: 203; xml: 191; awk: 61; sed: 5
file content (190 lines) | stat: -rw-r--r-- 6,180 bytes parent folder | download | duplicates (4)
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#ifndef _RHEOLEF_PERSISTENT_TABLE_H
#define _RHEOLEF_PERSISTENT_TABLE_H
//
// This file is part of Rheolef.
//
// Copyright (C) 2000-2009 Pierre Saramito <Pierre.Saramito@imag.fr>
//
// Rheolef is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Rheolef is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Rheolef; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// =========================================================================
// author: Pierre.Saramito@imag.fr
// date:   5 february 2019

namespace rheolef {
/**
@utilclassfile persistent_table persistent data base
@addindex persistent table

Description
===========
Here is a convenient way to implement a persistent data base
of big object that are long to initialize and then
used only in a read-only mode, via accessors, no modifiers.
Examples of such objects in scientific computing are
are finite element meshes (see @ref geo_2),
that are long to load from file
and requires large memory, or high-order polynomial basis
(see @ref basis_2), that are long to initialize
(e.g. Vandermonde matrix inversion).
When such objects are created independently in different parts
of a code, both memory size and computation time could be save 
by reusing them when these objects was already created.

The aim of the persistent_table class is to automate the implementation
of a persistent data base for a generic object, that could be e.g.
a finite element mesh or a polynomial basis.
It requires very few modification of a pre-existing object.
The implementation of the persistent_table class
bases on those of @ref smart_pointer_7 class
for handling reference counting.
When shared object in the data base are not modifiable, the idea is
to use the `smart_pointer_nocopy` class.
Otherwise, when the object has to be modified,
the name of the object, that is used as a key in an hashtable, 
should also be modified, in order to address the new modified object.
Here is a small minimalist example of the class.

Example
=======
@snippet persistent_table.h verbatim_persistent_table_tst

Implementation
==============
@showfromfile
@snippet persistent_table.h verbatim_persistent_table
*/
} // namespace rheolef

#include "rheolef/smart_pointer.h"
#include <unordered_map>
#include <string>
namespace rheolef {

// [verbatim_persistent_table]
template<class A>
class persistent_table {
  public:
    static A    load   (const std::string& name);
    static void unload (const std::string& name);
    static bool verbose () { return _verbose; }
    static void set_verbose (bool v) { _verbose = v; }
  protected:
    using  loaded_map_type = std::unordered_map<std::string,void*>;
    static loaded_map_type& get_loaded_map() { return _loaded_map; }
  // data:
    static loaded_map_type     _loaded_map;
    static bool                _verbose;
};
// [verbatim_persistent_table]

template<class A>
A
persistent_table<A>::load (const std::string& name) {
  using base = typename A::base;
  using rep  = typename base::handled_type;
  auto iter  = get_loaded_map().find (name);
  if  (iter != get_loaded_map().end()) {
    verbose() && std::cerr << "persistent_table: \""<<name<<"\" reused from table" << std::endl;
    A a;
    a.base::operator= (base((*iter).second,typename base::internal()));
    return a;
  }
  verbose() && std::cerr << "persistent_table: \""<<name<<"\" created" << std::endl;
  rep* ptr = rep::make_ptr (name);
  A a;
  a.base::operator= (ptr);
  get_loaded_map().insert (std::make_pair(name, a.base::get_count())); 
  return a;
}

template <class A>
void
persistent_table<A>::unload (const std::string& name) {
  size_t status_erased = get_loaded_map().erase (name);
  verbose() && std::cerr << "persistent_table: \""<<name<<"\" destroyed and erased from table" << std::endl;
}
// static declaration:
template<class A>
typename persistent_table<A>::loaded_map_type
persistent_table<A>::_loaded_map;

template<class A>
bool
persistent_table<A>::_verbose = false;

} // namespace rheolef

/// =========================================================================
//
// example of persistent table
//
// author: Pierre.Saramito@imag.fr
//
// date: 5 february 2019
//
/// =========================================================================
#ifdef _RHEOLEF_PERSISTENT_TABLE_EXAMPLE
//<verbatim:
#include "rheolef/persistent_table.h"
using namespace rheolef;
using namespace std;

// [verbatim_persistent_table_tst]
struct A_rep {
  public:
    A_rep (const string& name1) : _name(name1) { /* long init */ }
    ~A_rep();
    string name() const { return _name; }
    static A_rep* make_ptr (const string& name) { return new A_rep (name); }
  // data:
  protected:
    string _name;
};
struct A : public smart_pointer_nocopy<A_rep>, public persistent_table<A> {
  public:
    using rep  = A_rep;
    using base = smart_pointer_nocopy<rep>;
    A (const string& name = "");
    string name() const { return base::data().name(); }
};
// implementation of members:
A::A (const string& name)
  : base(),
    persistent_table<A>()
{
  if (name == "") return;
  base::operator= (persistent_table<A>::load (name));	
}
A_rep::~A_rep()
{
  persistent_table<A>::unload (_name);
}
int main() {
  persistent_table<A>::set_verbose (true); // trace table load/unload
  A a("a");	// "a" created
  {
    A b("b");	// "b" created
    A c("a");   // "a" reused from table
  }		// "b" destroyed and erased from table
  {
    A b("b");	// "b" created
    A c("a");	// "a" reused from table
  }		// "b" destroyed and erased from table
}		// "a" destroyed and erased from table
// [verbatim_persistent_table_tst]

#endif // _RHEOLEF_PERSISTENT_TABLE_EXAMPLE
#endif // _RHEOLEF_PERSISTENT_TABLE_H