Packets: Keep annotation registry sorted by type name
[senf.git] / senf / Packets / PacketImpl.ih
1 // $Id$
2 //
3 // Copyright (C) 2010
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief PacketImpl internal header */
25
26 #ifndef IH_SENF_senf_Packets_PacketImpl_
27 #define IH_SENF_senf_Packets_PacketImpl_ 1
28
29 // Custom includes
30 #include <iostream>
31 #include <map>
32 #include <string>
33 #include <ext/functional>
34 #include <boost/iterator/transform_iterator.hpp>
35 #include <boost/type_traits/is_convertible.hpp>
36 #include <boost/mpl/sizeof.hpp>
37 #include <boost/mpl/int.hpp>
38 #include <boost/mpl/or.hpp>
39 #include <boost/mpl/greater.hpp>
40 #include <boost/ptr_container/ptr_map.hpp>
41 #include <senf/Utils/TypeInfo.hh>
42 #include <senf/Utils/singleton.hh>
43 #include <senf/config.hh>
44 #include <senf/Utils/IgnoreValue.hh>
45
46 ///////////////////////////////ih.p////////////////////////////////////////
47
48 namespace senf {
49
50     struct ComplexAnnotation;
51     void dumpPacketAnnotationRegistry(std::ostream & os);
52
53 namespace detail {
54
55     template <class Annotation>
56     struct IsComplexAnnotation
57         : public boost::mpl::or_< boost::is_convertible<Annotation*, ComplexAnnotation*>,
58                                   boost::mpl::greater<
59                                       boost::mpl::sizeof_<Annotation>,
60                                       boost::mpl::int_<SENF_PACKET_ANNOTATION_SLOTSIZE> > >
61     {};
62
63     class AnnotationRegistry
64         : public senf::singleton<AnnotationRegistry>
65     {
66     public:
67         typedef int key_type;
68
69     private:
70         struct RegistrationBase
71         {
72             virtual ~RegistrationBase () {};
73             key_type key;
74             virtual void v_dump(std::ostream & os, void * annotation) const = 0;
75             virtual std::string v_name() const = 0;
76             virtual bool v_isComplex() const = 0;
77             virtual unsigned v_size() const = 0;
78         };
79
80         template <class Annotation>
81         struct Registration
82             : public RegistrationBase
83         {
84             void v_dump(std::ostream & os, void * annotation) const
85                 { os << * static_cast<Annotation*>(annotation); }
86             std::string v_name() const
87                 { return prettyName(typeid(Annotation)); }
88             bool v_isComplex() const
89                 { return boost::is_convertible<Annotation*, ComplexAnnotation*>::value; }
90             unsigned v_size() const
91                 { return sizeof(Annotation); }
92         };
93
94         typedef boost::ptr_map<key_type, RegistrationBase> Registry;
95         // Index must be a multi-map since two identically named classes
96         // both in the anonymous namespace both have the same demangled name.
97         // we could sort on the mangled name instead ...
98         typedef std::multimap<std::string, key_type> Index;
99
100     public:
101         typedef boost::transform_iterator< ::__gnu_cxx::select2nd<Index::value_type>,
102                                            Index::const_iterator > iterator;
103
104         using senf::singleton<AnnotationRegistry>::instance;
105
106         template <class Annotation> class RegistrationProxy;
107
108         class EntryBase;
109         template <class Annotation> class Entry;
110
111         template <class Annotation>
112         key_type registerAnnotation();
113
114         void dump(key_type key, std::ostream & os, void * annotation) const;
115         std::string name(key_type key) const;
116         bool isComplex(key_type key) const;
117         unsigned size(key_type key) const;
118
119         template <class Annotation>
120         static key_type lookup();
121
122         iterator begin() const;
123         iterator end() const;
124
125         void dumpRegistrations(std::ostream & os);
126
127     private:
128         AnnotationRegistry();
129
130         key_type simpleAnnotationCount_;
131         key_type complexAnnotationCount_;
132
133         Registry registry_;
134         // The index is needed to ensure a persistent and reproducible
135         // ordering of the annotations when dumping
136         Index index_;
137
138         friend class senf::singleton<AnnotationRegistry>;
139     };
140
141     template <class Annotation>
142     class AnnotationRegistry::RegistrationProxy
143     {
144     public:
145         RegistrationProxy()
146             {
147                 AnnotationRegistry::Entry<Annotation>::key_ =
148                     AnnotationRegistry::instance().registerAnnotation<Annotation>();
149             }
150     };
151
152     class AnnotationRegistry::EntryBase
153     {
154     public:
155         virtual ~EntryBase() {}
156
157         virtual void * get() = 0;
158     };
159
160     template <class Annotation>
161     class AnnotationRegistry::Entry
162         : public AnnotationRegistry::EntryBase
163     {
164         static RegistrationProxy<Annotation> proxy_;
165         static AnnotationRegistry::key_type key_;
166     public:
167         // We use this member to force instantiation of proxy_ ...
168         static AnnotationRegistry::key_type key()
169             { senf::IGNORE(&proxy_); return key_; }
170
171         virtual void * get() { return & annotation_; }
172
173     private:
174         Annotation annotation_;
175
176         friend class AnnotationRegistry::RegistrationProxy<Annotation>;
177     };
178
179 }}
180
181 ///////////////////////////////ih.e////////////////////////////////////////
182 #endif
183
184 \f
185 // Local Variables:
186 // mode: c++
187 // fill-column: 100
188 // comment-column: 40
189 // c-file-style: "senf"
190 // indent-tabs-mode: nil
191 // ispell-local-dictionary: "american"
192 // compile-command: "scons -u test"
193 // End: