GTIRB  v2.1.0
GrammaTech Intermediate Representation for Binaries: C++ API
AuxDataContainer.hpp
Go to the documentation of this file.
1 //===- AuxDataContainer.hpp -------------------------------------*- C++ -*-===//
2 //
3 // Copyright (C) 2020 GrammaTech, Inc.
4 //
5 // This code is licensed under the MIT license. See the LICENSE file in the
6 // project root for license terms.
7 //
8 // This project is sponsored by the Office of Naval Research, One Liberty
9 // Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #
10 // N68335-17-C-0700. The content of the information does not necessarily
11 // reflect the position or policy of the Government and no official
12 // endorsement should be inferred.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef GTIRB_AUXDATACONTAINER_H
17 #define GTIRB_AUXDATACONTAINER_H
18 
19 #include <gtirb/AuxData.hpp>
20 #include <gtirb/Node.hpp>
21 #include <boost/iterator/transform_iterator.hpp>
22 #include <boost/range/iterator_range.hpp>
23 #include <type_traits>
24 
27 
28 namespace gtirb {
29 
30 namespace proto {
31 class IR;
32 class Module;
33 } // namespace proto
34 
36 template <typename MessageType> struct message_has_aux_data_container {
37  static constexpr bool value = false;
38 };
39 template <> struct message_has_aux_data_container<proto::IR> {
40  static constexpr bool value = true;
41 };
42 template <> struct message_has_aux_data_container<proto::Module> {
43  static constexpr bool value = true;
44 };
45 
47 template <typename MessageType>
48 inline constexpr bool message_has_aux_data_container_v =
49  message_has_aux_data_container<MessageType>::value;
51 
55 
57  using AuxDataSet = std::map<std::string, std::unique_ptr<gtirb::AuxData>>;
58 
59 public:
62 
64  template <typename Schema> static void registerAuxDataType() {
65  registerAuxDataTypeInternal(Schema::Name,
66  std::make_unique<AuxDataTypeImpl<Schema>>());
67  }
68 
75  template <typename Schema> void addAuxData(typename Schema::Type&& X) {
76  // Make sure this type matches a registered type.
77  assert(checkAuxDataRegistration(
78  Schema::Name, AuxDataImpl<Schema>::staticGetApiTypeId()) &&
79  "Attempting to add AuxData with unregistered or incorrect type.");
80  this->AuxDatas[Schema::Name] =
81  std::make_unique<AuxDataImpl<Schema>>(std::move(X));
82  }
83 
92  template <typename Schema> typename Schema::Type* getAuxData() {
93  return const_cast<typename Schema::Type*>(
94  const_cast<const AuxDataContainer*>(this)->getAuxData<Schema>());
95  }
96 
105  template <typename Schema> const typename Schema::Type* getAuxData() const {
106  auto Found = this->AuxDatas.find(Schema::Name);
107 
108  if (Found == this->AuxDatas.end())
109  return nullptr;
110 
111  AuxData& AD = *(Found->second);
112 
113  // Is the type of the AuxData registered?
114  if (AD.getApiTypeId() == AuxData::UNREGISTERED_API_TYPE_ID) {
115  // We can get here for two reasons:
116  //
117  // 1) The type is not registered. We treat this as a developer
118  // error and assert. getAuxData should only ever be called for
119  // types that are registered.
120  //
121  // 2) The type is registered, but the attempt to unserialized
122  // the AuxData using the registered type failed. This is a
123  // legitimate runtime error situation. An example might be
124  // loading a GTIRB file that has a previous version of the
125  // AuxData with a different type. In this situation, we don't
126  // want to assert, just return nullptr.
127  assert(checkAuxDataRegistration(
128  Schema::Name, AuxDataImpl<Schema>::staticGetApiTypeId()) &&
129  "Attempting to retrieve AuxData with an unregistered type.");
130  return nullptr;
131  }
132 
133  // Does the type match the type being requested?
134  if (AD.getApiTypeId() != AuxDataImpl<Schema>::staticGetApiTypeId()) {
135  assert(false && "Attempting to retrieve AuxData with incorrect type.");
136  return nullptr;
137  }
138 
139  // If we get here, it should be safe to downcast to the typed AuxDataImpl.
140  auto& ADI = static_cast<AuxDataImpl<Schema>&>(AD);
141  return ADI.get();
142  }
143 
152  template <typename Schema> bool removeAuxData() {
153  assert(checkAuxDataRegistration(
154  Schema::Name, AuxDataImpl<Schema>::staticGetApiTypeId()) &&
155  "Attempting to remove AuxData with an unregistered type.");
156  return this->AuxDatas.erase(Schema::Name) > 0;
157  }
158 
167  bool removeAuxData(std::string Name) {
168  return this->AuxDatas.erase(Name) > 0;
169  }
170 
183  struct AuxDataRaw {
184 
186  const std::string& Key;
187 
189  const std::string& RawBytes;
190 
194  const std::string& ProtobufType;
195 
196  AuxDataRaw(const std::string& K, const std::string& RB,
197  const std::string& PT)
198  : Key(K), RawBytes(RB), ProtobufType(PT) {}
199  };
200 
201 private:
202  struct AccessRawData {
203  auto operator()(const AuxDataSet::value_type& P) const {
204  return AuxDataRaw(P.first, P.second->rawData().RawBytes,
205  P.second->rawData().ProtobufType);
206  }
207  };
208 
209 public:
219  boost::transform_iterator<AccessRawData, AuxDataSet::const_iterator>;
220  using const_aux_data_range = boost::iterator_range<const_aux_data_iterator>;
221 
224  return const_aux_data_iterator(AuxDatas.begin(), AccessRawData());
225  }
226 
230  return const_aux_data_iterator(AuxDatas.end(), AccessRawData());
231  }
232 
235  return boost::make_iterator_range(aux_data_begin(), aux_data_end());
236  }
237 
242  size_t getAuxDataSize() const { return AuxDatas.size(); }
243 
249  bool getAuxDataEmpty() const { return AuxDatas.empty(); }
250 
255  void clearAuxData() { AuxDatas.clear(); }
256 
259 
265  template <
266  class MessageType,
267  class = std::enable_if_t<message_has_aux_data_container_v<MessageType>>>
268  void toProtobuf(MessageType* Message) const {
269  containerToProtobuf(this->AuxDatas, Message->mutable_aux_data());
270  }
271 
277  template <
278  class MessageType,
279  class = std::enable_if_t<message_has_aux_data_container_v<MessageType>>>
280  void fromProtobuf(const MessageType& Message) {
281  this->AuxDatas.clear();
282  for (const auto& M : Message.aux_data()) {
283  std::unique_ptr<AuxData> Val;
284  std::string Key = M.first;
285 
286  // See if the name for this AuxData is registered.
287  if (const auto* ADT = lookupAuxDataType(Key)) {
288  Val = ADT->fromProtobuf(M.second);
289  }
290 
291  // If it wasn't registered or was registered with an incompatible
292  // type wrt the serialized object, unserialized as just the
293  // un-typed raw data.
294  if (!Val) {
295  Val = std::make_unique<AuxData>();
296  AuxData::fromProtobuf(*Val, M.second);
297  }
298  this->AuxDatas.insert(std::make_pair(Key, std::move(Val)));
299  }
301  }
302 
303 protected:
304  AuxDataContainer(Context& C, Kind knd);
305  AuxDataContainer(Context& C, Kind knd, const UUID& U);
306 
307 private:
308  AuxDataSet AuxDatas;
309 
310  struct AuxDataType {
311  virtual ~AuxDataType() = default;
312  virtual std::unique_ptr<AuxData>
313  fromProtobuf(const proto::AuxData& Message) const = 0;
314  virtual std::size_t getApiTypeId() const = 0;
315  };
316 
317  template <typename Schema> struct AuxDataTypeImpl : public AuxDataType {
318  std::unique_ptr<AuxData>
319  fromProtobuf(const proto::AuxData& Message) const override {
320  return AuxDataImpl<Schema>::fromProtobuf(Message);
321  }
322 
323  std::size_t getApiTypeId() const override {
324  return AuxDataImpl<Schema>::staticGetApiTypeId();
325  }
326  };
327 
328  static void registerAuxDataTypeInternal(const char* Name,
329  std::unique_ptr<AuxDataType> ADT);
330  static bool checkAuxDataRegistration(const char* Name, std::size_t Id);
331  static const AuxDataType* lookupAuxDataType(const std::string& Name);
332  friend struct AuxDataTypeMap; // Allows AuxDataTypeMap to use AuxDataType
333 };
334 } // namespace gtirb
335 #endif // GTIRB_AUXDATACONTAINER_H
gtirb::AuxDataContainer::aux_data
const_aux_data_range aux_data() const
Return a constant range of the auxiliary data (AuxData).
Definition: AuxDataContainer.hpp:234
aux_data_begin
const_aux_data_iterator aux_data_begin() const
Return a constant iterator to the first AuxData.
Definition: AuxDataContainer.hpp:168
gtirb::AuxDataContainer::const_aux_data_range
boost::iterator_range< const_aux_data_iterator > const_aux_data_range
Definition: AuxDataContainer.hpp:220
gtirb::AuxDataTypeMap
friend struct AuxDataTypeMap
Definition: AuxDataContainer.hpp:332
gtirb::Node
Represents the base of the Node class hierarchy.
Definition: Node.hpp:39
gtirb::AuxDataContainer::getAuxDataEmpty
bool getAuxDataEmpty() const
Check: Is the number of AuxData objects in this IR zero?
Definition: AuxDataContainer.hpp:249
gtirb::UUID
boost::uuids::uuid UUID
Represents a universally unique identifier used to identify Node objects across serialization boundar...
Definition: Context.hpp:36
gtirb::AuxDataContainer::getAuxDataSize
size_t getAuxDataSize() const
Get the total number of AuxData objects in this IR.
Definition: AuxDataContainer.hpp:242
gtirb::AuxDataContainer::AuxDataRaw
An interface for accessing the serialized form of an AuxData instance.
Definition: AuxDataContainer.hpp:183
gtirb::AuxDataContainer::aux_data_end
const_aux_data_iterator aux_data_end() const
Return a constant iterator to the element following the last AuxData.
Definition: AuxDataContainer.hpp:229
gtirb::AuxDataContainer::AuxDataRaw::AuxDataRaw
AuxDataRaw(const std::string &K, const std::string &RB, const std::string &PT)
Definition: AuxDataContainer.hpp:196
Node.hpp
Class gtirb::Node.
AuxDataSet
std::map< std::string, std::unique_ptr< gtirb::AuxData > > AuxDataSet
Definition: AuxDataContainer.hpp:2
gtirb::AuxDataContainer::addAuxData
void addAuxData(typename Schema::Type &&X)
Add a new AuxData, transferring ownership.
Definition: AuxDataContainer.hpp:75
gtirb::AuxDataContainer::AuxDataRaw::RawBytes
const std::string & RawBytes
The raw bytes of the serialized form of the AuxData.
Definition: AuxDataContainer.hpp:189
GTIRB_EXPORT_API
#define GTIRB_EXPORT_API
This macro controls the visibility of exported symbols (i.e. classes) in shared libraries....
Definition: Export.hpp:52
gtirb
Main namespace for the GTIRB API.
Definition: Addr.hpp:28
gtirb::AuxDataContainer::const_aux_data_iterator
boost::transform_iterator< AccessRawData, AuxDataSet::const_iterator > const_aux_data_iterator
An iterator type for traversing the AuxData in this container.
Definition: AuxDataContainer.hpp:219
gtirb::AuxDataContainer::getAuxData
const Schema::Type * getAuxData() const
Get a reference to the underlying type stored in the AuxData by name.
Definition: AuxDataContainer.hpp:105
gtirb::AuxDataContainer::aux_data_begin
const_aux_data_iterator aux_data_begin() const
Return a constant iterator to the first AuxData.
Definition: AuxDataContainer.hpp:223
aux_data_end
const_aux_data_iterator aux_data_end() const
Return a constant iterator to the element following the last AuxData.
Definition: AuxDataContainer.hpp:174
gtirb::AuxDataContainer::clearAuxData
void clearAuxData()
Clear all AuxData from the IR.
Definition: AuxDataContainer.hpp:255
gtirb::AuxDataContainer
Contains the AuxData Tables and serves as a base class.
Definition: AuxDataContainer.hpp:56
gtirb::AuxDataContainer::removeAuxData
bool removeAuxData()
Remove an AuxData by schema.
Definition: AuxDataContainer.hpp:152
gtirb::AuxDataContainer::getAuxData
Schema::Type * getAuxData()
Get a reference to the underlying type stored in the AuxData by name.
Definition: AuxDataContainer.hpp:92
gtirb::AuxDataContainer::AuxDataRaw::Key
const std::string & Key
The string name of the AuxData field.
Definition: AuxDataContainer.hpp:186
AuxDataRaw
An interface for accessing the serialized form of an AuxData instance.
Definition: AuxDataContainer.hpp:128
AuxData.hpp
Types and operations for auxiliary data.
gtirb::AuxDataContainer::removeAuxData
bool removeAuxData(std::string Name)
Remove an AuxData by name.
Definition: AuxDataContainer.hpp:167
gtirb::AuxDataContainer::registerAuxDataType
static void registerAuxDataType()
Register a type to be used with AuxData of the given name.
Definition: AuxDataContainer.hpp:64
const_aux_data_iterator
boost::transform_iterator< AccessRawData, AuxDataSet::const_iterator > const_aux_data_iterator
An iterator type for traversing the AuxData in this container.
Definition: AuxDataContainer.hpp:164