1 /*
2  * LibrePCB - Professional EDA for everyone!
3  * Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
4  * https://librepcb.org/
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef LIBREPCB_SERIALIZABLEOBJECT_H
21 #define LIBREPCB_SERIALIZABLEOBJECT_H
22 
23 /*******************************************************************************
24  *  Includes
25  ******************************************************************************/
26 #include "sexpression.h"
27 
28 #include <QtCore>
29 
30 /*******************************************************************************
31  *  Namespace / Forward Declarations
32  ******************************************************************************/
33 namespace librepcb {
34 
35 /*******************************************************************************
36  *  Class SerializableObject
37  ******************************************************************************/
38 
39 /**
40  * @brief The SerializableObject class is the base class for all classes which
41  * need to be serializable/deserializable from/to librepcb::SExpression nodes
42  */
43 class SerializableObject {
44 public:
SerializableObject()45   SerializableObject() noexcept {}
~SerializableObject()46   virtual ~SerializableObject() noexcept {}
47 
48   /**
49    * @brief Serialize the object to a new S-Expression node
50    *
51    * This method creates a new S-Expression node, serializes the whole object
52    * into it and then returns the whole S-Expression node. See #serialize() for
53    * details.
54    *
55    * @param name          The root name of the returned S-Expression node
56    *
57    * @return The created S-Expression node (the caller takes the ownership!)
58    *
59    * @throw Exception     This method throws an exception if an error occurs.
60    *
61    * @see #serialize()
62    */
serializeToDomElement(const QString & name)63   SExpression serializeToDomElement(const QString& name) const {
64     SExpression root = SExpression::createList(name);
65     serialize(root);
66     return root;
67   }
68 
69   /**
70    * @brief Serialize the object into an existing S-Expression node
71    *
72    * This method inserts/appends all attributes and childs of the object to an
73    * existing S-Expression node. The content which already exists in the given
74    * S-Expression node will not be removed.
75    *
76    * @note    The generated S-Expression node has always the format of the
77    *          application's major version (it's not possible to generate DOMs of
78    *          older versions).
79    *
80    * @param root          The target DOM root node
81    *
82    * @throw Exception     This method throws an exception if an error occurs.
83    */
84   virtual void serialize(SExpression& root) const = 0;
85 
86   template <typename T>
serializeObjectContainer(SExpression & root,const T & container,const QString & itemName)87   static void serializeObjectContainer(SExpression& root, const T& container,
88                                        const QString& itemName) {
89     for (const auto& object : container) {
90       root.appendChild(object.serializeToDomElement(itemName),
91                        true);  // can throw
92     }
93   }
94 
95   template <typename T>
serializePointerContainer(SExpression & root,const T & container,const QString & itemName)96   static void serializePointerContainer(SExpression& root, const T& container,
97                                         const QString& itemName) {
98     for (const auto& pointer : container) {
99       root.appendChild(pointer->serializeToDomElement(itemName),
100                        true);  // can throw
101     }
102   }
103 
104   template <typename T>
serializePointerContainerUuidSorted(SExpression & root,const T & container,const QString & itemName)105   static void serializePointerContainerUuidSorted(SExpression& root,
106                                                   const T& container,
107                                                   const QString& itemName) {
108     T copy = container;
109     std::sort(
110         copy.begin(), copy.end(),
111         [](const typename T::value_type& a, const typename T::value_type& b) {
112           return a->getUuid() < b->getUuid();
113         });
114     serializePointerContainer(root, copy, itemName);
115   }
116 };
117 
118 // Make sure that the SerializableObject class does not contain any data (except
119 // the vptr). Otherwise it could introduce issues when using multiple
120 // inheritance.
121 static_assert(sizeof(SerializableObject) == sizeof(void*),
122               "SerializableObject must not contain any data!");
123 
124 /*******************************************************************************
125  *  End of File
126  ******************************************************************************/
127 
128 }  // namespace librepcb
129 
130 #endif  // LIBREPCB_SERIALIZABLEOBJECT_H
131