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
|