Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
rename Lib to Facetable
[simgrid.git] / include / xbt / Facetable.hpp
1 /* Copyright (c) 2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #ifndef SIMGRID_XBT_LIB_HPP
8 #define SIMGRID_XBT_LIB_HPP
9
10 #include <cstddef>
11
12 #include <vector>
13
14 namespace simgrid {
15 namespace xbt {
16
17 /** A Facetable is an object that you can extend with external facets.
18  *
19  * Facets are similar to the concept of mixins, that is, a set of behavior that is injected into a class without derivation.
20  *
21  * Imagine that you want to write a plugin dealing with the energy in SimGrid.
22  * You will have to store some information about each and every host.
23  *
24  * You could modify the Host class directly (but your code will soon become messy).
25  * You could create a class EnergyHost deriving Host, but it is not easily combinable
26  *    with a notion of Host extended with another concept (such as mobility).
27  * You could completely externalize these data with an associative map Host->EnergyHost.
28  *    It would work, provided that you implement this classical feature correctly (and it would induce a little performance penalty).
29  * Instead, you should add a new facet to the Host class, that happens to be Facetable.
30  *
31  */
32
33 template<class T>
34 class Facetable {
35 private:
36   static std::vector<void(*)(void*)> deleters_;
37 protected:
38   std::vector<void*> facets_;
39 public:
40   static std::size_t add_level(void (*deleter)(void*))
41   {
42     std::size_t res = deleters_.size();
43     deleters_.push_back(deleter);
44     return res;
45   }
46   template<class U> static
47   std::size_t add_level()
48   {
49     return add_level([](void* p){ delete (U*)p; });
50   }
51   Facetable() : facets_(deleters_.size(), nullptr) {}
52   ~Facetable()
53   {
54     for (std::size_t i = 0; i < facets_.size(); ++i)
55       if (facets_[i] != nullptr)
56         deleters_[i](facets_[i]);
57   }
58
59   // TODO, make type-safe versions of this
60   void* facet(std::size_t level)
61   {
62     if (level >= facets_.size())
63       return nullptr;
64     else
65       return facets_.at(level);
66   }
67   void set_facet(std::size_t level, void* value, bool use_dtor = true)
68   {
69     if (level >= facets_.size())
70       facets_.resize(level + 1, nullptr);
71     void* old_value = this->facet(level);
72     facets_.at(level) = value;
73     if (use_dtor && old_value != nullptr && deleters_[level])
74       deleters_[level](old_value);
75   }
76 };
77
78 template<class T>
79 std::vector<void(*)(void*)> Facetable<T>::deleters_ = {};
80
81 }
82 }
83
84 #endif