/usr/include/SurgSim/Framework/Accessible.h is in libopensurgsim-dev 0.7.0-6ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | // This file is a part of the OpenSurgSim project.
// Copyright 2013-2015, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SURGSIM_FRAMEWORK_ACCESSIBLE_H
#define SURGSIM_FRAMEWORK_ACCESSIBLE_H
#include <boost/any.hpp>
#include <boost/preprocessor.hpp>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <yaml-cpp/yaml.h>
#include "SurgSim/Math/Matrix.h"
namespace SurgSim
{
namespace Framework
{
/// Mixin class for enabling a property system on OSS classes, the instance still needs to initialize properties in
/// the constructor by using either addSetter, addGetter, addAccessors or the macro for each member variable
/// that should be made accessible.
class Accessible
{
public:
/// Default Constructor
Accessible();
/// Destructor
~Accessible();
typedef std::function<boost::any(void)> GetterType;
typedef std::function<void (boost::any)> SetterType;
typedef std::function<YAML::Node(void)> EncoderType;
typedef std::function<void(const YAML::Node*)> DecoderType;
/// Retrieves the value with the name by executing the getter if it is found and tries to convert
/// it to the given type.
/// \throws SurgSim::Framework::AssertionFailure If the conversion fails or the property cannot be found.
/// \tparam T The requested type for the property.
/// \param name The name of the property.
/// \return The value of the property if the getter was found
template <class T>
T getValue(const std::string& name) const;
/// Retrieves the value with the name by executing the getter if it is found.
/// \throws SurgSim::Framework::AssertionFailure if the property cannot be found
/// \param name The name of the property.
/// \return The value of the property if the getter was found
boost::any getValue(const std::string& name) const;
/// Retrieves the value with the name by executing the getter if it is found, and converts it to
/// the type of the output parameter. This does not throw.
/// \tparam T the type of the property, usually can be deduced automatically
/// \param name The name of the property.
/// \param [out] value If non-null, will receive the value of the given property.
/// \return true if value != nullptr and the getter can be found.
template <class T>
bool getValue(const std::string& name, T* value) const;
/// Sets a value of a property that has setter.
/// \throws SurgSim::Framework::AssertionFailure If the property cannot be found.
/// \param name The name of the property.
/// \param value The value that it should be set to.
void setValue(const std::string& name, const boost::any& value);
/// Check whether a property is readable
/// \param name Name of the property to be checked.
/// \return true if the property exists and has a getter
bool isReadable(const std::string& name) const;
/// Check whether a property is writable
/// \param name Name of the property to be checked.
/// \return true if the property exists and has a setter
bool isWriteable(const std::string& name) const;
/// Sets a getter for a given property.
/// \throws SurgSim::Framework::AssertionFailure if func is a nullptr.
/// \param name The name of the property.
/// \param func The getter function.
void setGetter(const std::string& name, GetterType func);
/// Sets a setter for a given property.
/// \throws SurgSim::Framework::AssertionFailure if func is a nullptr.
/// \param name The name of the property.
/// \param func The setter function.
void setSetter(const std::string& name, SetterType func);
/// Sets the accessors getter and setter in one function.
/// \throws SurgSim::Framework::AssertionFailure if either getter or setter is a nullptr.
/// \param name The name of the property.
/// \param getter The getter.
/// \param setter The setter.
void setAccessors(const std::string& name, GetterType getter, SetterType setter);
/// Removes all the accessors (getter and setter) for a given property
/// \param name The name of the property
void removeAccessors(const std::string& name);
/// Adds a property with the given name that uses the targets accessors, in effect forwarding the value
/// to the target
/// \note This will copy the appropriate calls into the local function table of this accessible, in effect
/// exposing a pointer to the target, if the target goes out of scope, the behavior is undefined
/// \throws SurgSim::Framework::AssertionFailure if the target does not contain the property named in this call.
/// \param name The name of the new property
/// \param target The instance that provides the actual property
/// \param targetProperty The name of the property that should be used.
void forwardProperty(const std::string& name, const Accessible& target, const std::string& targetProperty);
/// Sets the functions used to convert data from and to a YAML::Node. Will throw an exception
/// if the data type that is passed to YAML cannot be converted into a YAML::Node
/// \param name The name of the property.
/// \param encoder The function to be used to put the property into the node.
/// \param decoder The function to be used to read the property from the node and set it
/// in the instance.
void setSerializable(const std::string& name, EncoderType encoder, DecoderType decoder);
/// Sets the functions used to convert data from a YAML::Node.
/// This leaves the encoder (class -> YAML) conversion empty, this can be used to let the user decide how to
/// model the data in the data file, inside the class this should all result in one member to be created/changed.
/// \param name The name of the property.
/// \param decoder The function to be used to read the property from the node and set it
/// in the instance.
void setDecoder(const std::string& name, DecoderType decoder);
/// Encode this Accessible to a YAML::Node
/// \return The encoded version of this instance.
YAML::Node encode() const;
/// Decode this Accessible from a YAML::Node, will throw an exception if the data type cannot
/// be converted.
/// \throws SurgSim::Framework::AssertionFailure if node is not of YAML::NodeType::Map.
/// \param node The node that carries the data to be decoded, properties with names that don't
/// match up with properties in the Accessible will be reported.
/// \param ignoredProperties Properties that will be ignored.
void decode(const YAML::Node& node, const std::vector<std::string>& ignoredProperties = std::vector<std::string>());
private:
/// @{
/// Prevent default copy construction and default assignment
Accessible(const Accessible& other) /*= delete*/;
Accessible& operator=(const Accessible& other) /*= delete*/;
/// @}
/// Private struct to keep the map under control
struct Functors
{
Functors() : getter(nullptr), setter(nullptr), encoder(nullptr), decoder(nullptr) {}
GetterType getter;
SetterType setter;
EncoderType encoder;
DecoderType decoder;
};
std::unordered_map<std::string, Functors> m_functors;
};
/// Public struct to pair an accessible with its appropriate property
struct Property
{
std::weak_ptr<Accessible> accessible;
std::string name;
};
template <>
boost::any Accessible::getValue(const std::string& name) const;
/// Wrap boost::any_cast to use in std::bind, for some reason it does not work by itself. This function will
/// throw an exception if the cast does not work, this usually means that the types do not match up at all.
/// \tparam T target type for conversion.
/// \param val The value to be converted.
/// \return An object converted from boost::any to T, will throw an exception if the conversion fails
template <class T>
T convert(boost::any val);
/// Specialization for convert<T>() to correctly cast Matrix44d to Matrix44f, will throw if the val is not casteable to
/// Matrix44[fd]. This is necessary as we need Matrix44f as outputs in some cases but all our Matrices are Matrix44d.
/// This lets the user define a property that does a type conversion, without having to implement an accessor.
/// \param val The value to be converted, should be a Matrix44[df].
/// \return A matrix val converted to Matrix44f.
template <>
SurgSim::Math::Matrix44f convert(boost::any val);
/// Specialization for convert<T>() to correctly cast const char* to std::string
/// \param val The value to be converted, should be a const char*
/// \return A std::string
template <>
std::string convert(boost::any val);
/// A macro to register getter and setter for a property that is readable and writeable,
/// order of getter and setter agrees with 'RW'. Note that the property should not be quoted in the original
/// macro call.
#define SURGSIM_ADD_RW_PROPERTY(class, type, property, getter, setter) \
setAccessors(#property, \
std::bind(&class::getter, this),\
std::bind(&class::setter, this, std::bind(SurgSim::Framework::convert<type>,std::placeholders::_1)))
/// A macro to register a getter for a property that is read only
#define SURGSIM_ADD_RO_PROPERTY(class, type, property, getter) \
setGetter(#property, \
std::bind(&class::getter, this))
/// A macro to register a serializable property, this needs to support reading, writing and all the
/// conversions to and from YAML::Node
#define SURGSIM_ADD_SERIALIZABLE_PROPERTY(class, type, property, getter, setter) \
setAccessors(#property, \
std::bind(&class::getter, this),\
std::bind(&class::setter, this, std::bind(SurgSim::Framework::convert<type>,std::placeholders::_1)));\
setSerializable(#property,\
std::bind(&YAML::convert<type>::encode, std::bind(&class::getter, this)),\
std::bind(&class::setter, this, std::bind(&YAML::Node::as<type>,std::placeholders::_1)))
/// A macro to register a setter that can be used from YAML, and as a writeable property
/// use this to provide alternatives to more complicated values, e.g. setModelFilename() vs generate and set Model
/// Enables the alternative use of the model file instead of the actual mesh object
#define SURGSIM_ADD_SETTER(class, type, property, setter) \
{\
setDecoder(#property, std::bind((void(class::*)(const type&))&class::setter, this,\
std::bind(&YAML::Node::as<type>,std::placeholders::_1))); \
setSetter(#property, std::bind((void(class::*)(const type&))&class::setter, this,\
std::bind(SurgSim::Framework::convert<type>,std::placeholders::_1)));\
}
}; // Framework
}; // SurgSim
#define SURGSIM_ENUM_TOSTRING(r, data, elem) \
case data::elem: \
result = BOOST_PP_STRINGIZE(elem); \
break;
#define SURGSIM_ENUM_FROMSTRING(r, data, elem) \
if (value == BOOST_PP_STRINGIZE(elem)) \
{ \
rhs = data::elem; \
return true; \
}
/// Required type of enums used by SURGSIM_SERIALIZABLE_ENUM
#define SURGSIM_ENUM_TYPE int8_t
/// A macro to create an enum that can be easily serialized
/// During serialization, the enum will be converted to its string based named,
/// back to an enum during deserialization. The enum must already be forward
/// declared in its namespace before calling this macro in the global namespace.
#define SURGSIM_SERIALIZABLE_ENUM(name, enumerators) \
enum name : SURGSIM_ENUM_TYPE\
{ \
BOOST_PP_SEQ_ENUM(enumerators) \
}; \
namespace YAML \
{ \
template <> \
struct convert<name> \
{ \
static Node encode(const name& rhs) \
{ \
Node result; \
switch (rhs) \
{ \
BOOST_PP_SEQ_FOR_EACH(SURGSIM_ENUM_TOSTRING, name, enumerators) \
default: \
SURGSIM_FAILURE() << "Can not find enum value in " << #name << ": " << rhs; \
} \
return result; \
} \
static bool decode(const Node& node, name& rhs) \
{ \
std::string value = node.as<std::string>(); \
std::transform(value.begin(), value.end(), value.begin(), ::toupper); \
BOOST_PP_SEQ_FOR_EACH(SURGSIM_ENUM_FROMSTRING, name, enumerators) \
SURGSIM_FAILURE() << "Unknown " << #name << ": " << value; \
return false; \
} \
}; \
}
#include "SurgSim/Framework/Accessible-inl.h"
#endif
|