1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef DART_COMMON_COMPOSITE_HPP_
34 #define DART_COMMON_COMPOSITE_HPP_
35 
36 #include "dart/common/ClassWithVirtualBase.hpp"
37 #include "dart/common/detail/CompositeData.hpp"
38 
39 namespace dart {
40 namespace common {
41 
42 /// Composite is a base class that should be virtually inherited by any class
43 /// that wants to be able to manage Aspects.
44 ///
45 /// The base Composite class is completely agnostic to what kind of Aspects it
46 /// is given. Aspects are stored in a std::map, so access to its Aspects happens
47 /// on average in log(N) time. Most often, a class that accepts Aspects will
48 /// have certain Aspect types that it will need to access frequently, and it
49 /// would be beneficial to have constant-time access to those Aspect types. To
50 /// get constant-time access to specific Aspect types, you can use the templated
51 /// class SpecializedForAspect.
52 class Composite
53 {
54 public:
55   using State = detail::CompositeState;
56   using Properties = detail::CompositeProperties;
57 
58   using AspectMap = std::map<std::type_index, std::unique_ptr<Aspect> >;
59   using RequiredAspectSet = std::unordered_set<std::type_index>;
60 
61   template <typename... Aspects>
62   using MakeState = detail::MakeCompositeState<Aspects...>;
63 
64   template <typename... Aspects>
65   using MakeProperties = detail::MakeCompositeProperties<Aspects...>;
66 
67   /// Virtual destructor
68   virtual ~Composite() = default;
69 
70   /// Default constructor
71   Composite() = default;
72 
73   /// It is currently unsafe to copy an Composite
74   // TODO(MXG): Consider making this safe by cloning Aspects into the new copy
75   Composite(const Composite&) = delete;
76 
77   /// It is currently unsafe to move an Composite
78   Composite(Composite&&) = delete;
79 
80   /// It is currently unsafe to copy an Composite
81   Composite& operator=(const Composite&) = delete;
82 
83   /// It is currently unsafe to move an Composite
84   Composite& operator=(Composite&&) = delete;
85 
86   /// Check if this Composite currently has a certain type of Aspect
87   template <class T>
88   bool has() const;
89 
90   /// Get a certain type of Aspect from this Composite
91   template <class T>
92   T* get();
93 
94   /// Get a certain type of Aspect from this Composite
95   template <class T>
96   const T* get() const;
97 
98   /// Make a clone of the aspect and place the clone into this Composite. If
99   /// an Aspect of the same type already exists in this Composite, the
100   /// existing Aspect will be destroyed.
101   template <class T>
102   void set(const T* aspect);
103 
104   /// Use move semantics to place aspect into this Composite. If an Aspect of
105   /// the same type already exists in this Composite, the existing Aspect will
106   /// be destroyed.
107   template <class T>
108   void set(std::unique_ptr<T>&& aspect);
109 
110   /// Construct an Aspect inside of this Composite
111   template <class T, typename... Args>
112   T* createAspect(Args&&... args);
113 
114   /// Remove an Aspect from this Composite.
115   template <class T>
116   void removeAspect();
117 
118   /// Remove an Aspect from this Composite, but return its unique_ptr instead
119   /// of letting it be deleted. This allows you to safely use move semantics to
120   /// transfer an Aspect between two Composites.
121   template <class T>
122   std::unique_ptr<T> releaseAspect();
123 
124   /// Check if this Composite is specialized for a specific type of Aspect.
125   ///
126   /// By default, this simply returns false.
127   template <class T>
128   static constexpr bool isSpecializedFor();
129 
130   /// Check if this Composite requires this specific type of Aspect
131   template <class T>
132   bool requiresAspect() const;
133 
134   /// Set the states of the aspects in this Composite based on the given
135   /// Composite::State. The states of any Aspect types that do not exist
136   /// within this composite will be ignored.
137   void setCompositeState(const State& newStates);
138 
139   /// Get the states of the aspects inside of this Composite
140   State getCompositeState() const;
141 
142   /// Fill outgoingStates with the states of the aspects inside this Composite
143   void copyCompositeStateTo(State& outgoingStates) const;
144 
145   /// Set the properties of the aspects in this Composite based on the given
146   /// Composite::Properties. The properties of any Aspect types that do not
147   /// exist within this composite will be ignored.
148   void setCompositeProperties(const Properties& newProperties);
149 
150   /// Get the properties of the aspects inside of this Composite
151   Properties getCompositeProperties() const;
152 
153   /// Fill outgoingProperties with the properties of the aspects inside this
154   /// Composite
155   void copyCompositePropertiesTo(Properties& outgoingProperties) const;
156 
157   /// Give this Composite a copy of each Aspect from otherComposite
158   void duplicateAspects(const Composite* fromComposite);
159 
160   /// Make the Aspects of this Composite match the Aspects of otherComposite.
161   /// Any Aspects in this Composite which do not exist in otherComposite will be
162   /// erased.
163   void matchAspects(const Composite* otherComposite);
164 
165 protected:
166   /// Add this Aspect to the Composite. This allows derived Composite types to
167   /// call the protected Aspect::setComposite function.
168   void addToComposite(Aspect* aspect);
169 
170   /// Remove this Aspect from the Composite. This allows derived Composite types
171   /// to call the protected Aspect::loseComposite function.
172   void removeFromComposite(Aspect* aspect);
173 
174   /// Non-templated version of set(const T*)
175   void _set(std::type_index type_idx, const Aspect* aspect);
176 
177   /// Non-templated version of set(std::unqiue_ptr<T>&&)
178   void _set(std::type_index type_idx, std::unique_ptr<Aspect> aspect);
179 
180   /// A map that relates the type of Aspect to its pointer
181   AspectMap mAspectMap;
182 
183   /// A set containing type information for Aspects which are not allowed to
184   /// leave this composite.
185   RequiredAspectSet mRequiredAspects;
186 };
187 
188 //==============================================================================
189 /// Attach an arbitrary number of Aspects to the specified Composite type.
190 // TODO(MXG): Consider putting this functionality into the Composite class
191 // itself. Also consider allowing the user to specify arguments for the
192 // constructors of the Aspects.
193 template <class T>
194 void createAspects(T* /*comp*/);
195 
196 //==============================================================================
197 template <class T, class NextAspect, class... Aspects>
198 void createAspects(T* comp);
199 
200 } // namespace common
201 } // namespace dart
202 
203 #include "dart/common/detail/Composite.hpp"
204 
205 #endif // DART_COMMON_COMPOSITE_HPP_
206