Skip to content

Commit dacab8b

Browse files
author
Divya Kamath
committed
Updated documentation
1 parent 3115f37 commit dacab8b

File tree

1 file changed

+83
-70
lines changed

1 file changed

+83
-70
lines changed

docs/Developer/Serialization.md

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,35 @@
22

33
This guide explains how to implement serialization using the Cereal library within Graphitti. If you're looking to add serialization to your class, follow this guide. For more comprehensive information on Cereal, refer to their [official documentation](https://uscilab.github.io/cereal/index.html).
44

5-
<details>
6-
<summary><strong>
5+
<strong>
76
Understanding Serialization and Deserialization
8-
</strong></summary>
7+
</strong>
98

109
Serialization involves converting an object or data structure into a format that can be stored or transmitted, while deserialization is the reverse process— reconstructing an object from the serialized format.
11-
</details>
1210
<br>
13-
<details>
14-
<summary><strong>
11+
12+
<strong>
1513
What is Cereal?
16-
</strong></summary>
14+
</strong>
1715

1816
Cereal is a lightweight C++11 library designed for object serialization and deserialization. It provides a straightforward interface for serializing objects and supports a wide range of data types. Cereal is efficient and well-suited for handling large data sets, making it a preferred choice for serialization tasks in Graphitti.
19-
</details>
2017
<br>
2118

22-
<details>
23-
<summary><strong>
19+
20+
<strong>
2421
Why Graphitti Uses Serialization?
25-
</strong></summary>
22+
</strong>
2623

2724
Graphitti utilizes Cereal to enable efficient serialization and deserialization of the network structure. Serialized data can serve as a checkpoint for large simulations or as input for subsequent simulations with varying conditions. This flexibility enhances Graphitti's efficiency and adaptability in modeling scenarios.
28-
</details>
2925
<br>
3026

31-
## Basics of Cereal
27+
## Understand Cereal at a High Level
3228

3329
### C++ Features Supported by Cereal
3430

35-
- **Standard Library Support**: Cereal fully supports the C++11 [standard library](http://en.cppreference.com/w/). You can include the necessary headers from Cereal to enable support for various types (e.g., `<cereal/types/vector.hpp>`). Refer to the [Cereal Doxygen docs](https://uscilab.github.io/cereal/assets/doxygen/group__STLSupport.html) for a complete list of supported types.
31+
- **Standard Library Support**: Cereal fully supports the C++11 [standard library](http://en.cppreference.com/w/). You can include the necessary headers from Cereal to enable support for various types (e.g., If you need to serialize a `std::vector`, add `<cereal/types/vector.hpp>`). Refer to the complete list of supported types below or in [Cereal Doxygen docs](https://uscilab.github.io/cereal/assets/doxygen/group__STLSupport.html).
3632

37-
- **Smart Pointers**: Cereal supports modern smart pointers (`std::shared_ptr` and `std::unique_ptr`) via `<cereal/types/memory.hpp>`. However, raw pointers or references are not supported.
33+
- **Smart Pointers**: Cereal supports modern smart pointers (`std::shared_ptr` and `std::unique_ptr`) via `<cereal/types/memory.hpp>`. <strong> However, raw pointers or references are NOT supported.</strong>
3834

3935
- **Inheritance and Polymorphism**: Cereal can seamlessly handles inheritance and polymorphism- more on this in the coming section.
4036

@@ -50,25 +46,30 @@ Graphitti utilizes Cereal to enable efficient serialization and deserialization
5046

5147
- **Defining Serialization Functions**: Cereal requires to know which data members to serialize in a class. By implementing a serialization function `serialize` within a class, you indicate to Cereal which data members should be serialized.
5248

53-
- **Default Constructor Requirement**:Cereal requires access to a default constructor for classes it serializes to construct the object during deserialization.
49+
- **Default Constructor Requirement**: Cereal requires access to a default constructor for classes it serializes to construct the object during deserialization.
5450

5551
- **Name-Value Pairs**: Cereal supports name-value pairs, allowing you to attach names to serialized objects. This feature is particularly useful for XML archives and is adopted in Graphitti's serialization process.
5652

5753
- **Class Versioning**: While still in work in progress in Graphitti, Cereal supports class versioning, enabling compatibility between different versions of serialized objects.
5854

5955
## Incorporate Cereal in your class
6056

61-
- Cereal supports two approaches for serialization functions: internal or external. Cereal also provides two types of serialization function `serialize` and `load and save`. For consistency within Graphitti, it's recommended to use an internal single `serialize` function.
62-
57+
- Cereal supports two approaches for serialization functions: internal or external. Cereal also provides two types of serialization function `serialize` and `load and save`. For consistency within Graphitti, use an internal single `serialize` function.
6358
- Throughout Graphitti, we typically serialize all data members (private, protected, and public) of a class.
64-
<br>
6559

66-
### **Step 01: Include Necessary Cereal Headers**
67-
Include the necessary Cereal headers for the data member types you want to serialize. If you are using a custom data member type, follow these steps for the custom data type class or struct as well.
60+
### **STEP 01: ADD CEREAL HEADERS**
61+
Before implementing serialization in your class, you need to include the appropriate Cereal headers for the types of data members you want to serialize. Cereal provides headers for various standard types, such as vectors, strings, and other containers.
62+
63+
- For example, if you're serializing a `std::vector<int>`, you'll need to include the following header:
64+
```cpp
65+
#include <cereal/types/vector.hpp>
66+
```
67+
68+
- If you are using custom types, ensure the serialization process is correctly implemented for those types as well. The same approach applies to user-defined types, so include the appropriate headers and define the serialize function in that class or struct.
6869

6970
<details>
7071

71-
<summary>Refer to the table below for a reference on commonly used C++ data types and their corresponding Cereal headers</summary>
72+
<summary><strong>Commonly used C++ data types and their corresponding Cereal headers</strong></summary>
7273

7374

7475
| Type | Header to include |
@@ -101,11 +102,27 @@ Graphitti utilizes Cereal to enable efficient serialization and deserialization
101102

102103
<br>
103104

104-
### **Step 02: Include and Define the Serialize Function**
105+
### **STEP 02: ADD SERIALIZE FUNCTION**
105106

106107
Within your class header file
107-
1. Declare the `serialize` function under the public section.
108-
2. At the end of your header file, define the `serialize` function for your class.
108+
- Firstly, declare the `serialize` function inside the class:
109+
- Add the following template function signature in the public section of your class to allow serialization for any archive type.
110+
```cpp
111+
template <class Archive>
112+
void serialize(Archive & archive);
113+
```
114+
- Secondly, define the `serialize` function outside the class:
115+
- After your class declaration, define the serialize function at the end of the header file.
116+
- This function specifies which member variables are serialized and deserialized, and how that process occurs.
117+
```cpp
118+
template <class Archive>
119+
void YOUR_CLASS_NAME::serialize(Archive &archive)
120+
{
121+
archive(ADD_YOUR_MEMBER_VARIABLES_HERE);
122+
// Refer to the example below
123+
}
124+
```
125+
Here’s a sample implementation to guide you:
109126

110127
``` cpp
111128

@@ -125,37 +142,40 @@ class MyCoolClass
125142
int X_;
126143
};
127144

128-
//STEP 02 (b): Define the serialize function at the bottom of the header file
145+
//STEP 02 (b): Define the serialize function outside the class
146+
129147
template <class Archive>
130148
void MyCoolClass::serialize(Archive &archive)
131149
{
132-
archive(cereal::make_nvp("myVector", myVector_), cereal::make_nvp("X", X_));
150+
archive(cereal::make_nvp("myVector", myVector_), cereal::make_nvp("myInt", X_));
133151
}
134152

135153

136154
```
137155
138156
Adjust the function names and data member names as per your specific requirements.
139157
140-
### **Step 03: Check for any Special Modifications**
158+
NOTE:
159+
- The `template <class Archive>` declaration allows the function to work with any type of Cereal archive (e.g., JSON, XML, binary).
160+
- When defining the `serialize` function, use Cereal’s `make_nvp()` for custom names or `CEREAL_NVP()` for automatic name-value pair serialization.
161+
- Defining the function outside the class maintains a consistent style for serialized code and makes the function easier to locate, especially in larger projects like Graphitti. This approach also keeps your class declaration cleaner and less cluttered.
141162
142-
If you answer "yes" to any of the following questions, follow the corresponding steps. Some classes may fall under multiple categories, so review all questions carefully.
163+
### **STEP 03: SPECIAL CASES**
143164
144-
<details>
145-
<summary><strong>
146-
Is your class a derived class?
147-
</summary></strong>
165+
Cereal requires additional steps for certain special cases such as inheritance, polymorphism, and templates. In this section, we outline specific steps based on whether your class matches one of these conditions. If you answer "yes" to any of the following questions, follow the corresponding steps. Some classes may fall under multiple categories, so be sure to review all the details carefully.
148166
149-
Cereal needs a serialization path from the derived class to the base type(s). This is usually handled with either `cereal::base_class` or `cereal::virtual_base_class`.
167+
### **1. DERIVED CLASS?**
168+
This step explains how to serialize base classes in a derived class. Cereal requires a path from the derived to the base type(s), typically done with `cereal::base_class` or `cereal::virtual_base_class`.
150169
151-
#### [a] Is your class derived from a virtual inheritance ?
152-
When inheriting from objects from a virtual inheritance (e.g.`class Derived : virtual Base`), the recommended method is to utilize `cereal::virtual_base_class<BaseT>(this)` to cast the derived class to the base class.
170+
<details>
171+
<summary><strong> Virtual Inheritance ? </summary></strong>
172+
If your derived class uses virtual inheritance (`class Derived : virtual Base`), use `cereal::virtual_base_class<BaseT>(this)` to cast the derived class to its base class. Ensure this is placed at the start of the `archive` in the `serialize` function before member variables in the derived class.
153173
154174
```cpp
155175
156176
class MyDerived : virtual MyBase
157177
{
158-
int y;
178+
int X_;
159179
template <class Archive>
160180
void serialize( Archive & ar );
161181
};
@@ -164,20 +184,23 @@ template <class Archive>
164184
void MyDerived::serialize( Archive & archive )
165185
{
166186
// We pass this cast to the base type for each base type we need to serialize.
167-
archive(cereal::virtual_base_class<MyBase>(this), y);
187+
archive(cereal::virtual_base_class<MyBase>(this), cereal::make_nvp("myInt", X_));
168188
169189
// For multiple inheritance, link all the base classes one after the other
170-
//archive(cereal::virtual_base_class<MyBase1>(this), cereal::virtual_base_class<MyBase2>(this), y);
190+
//archive(cereal::virtual_base_class<MyBase1>(this), cereal::virtual_base_class<MyBase2>(this), cereal::make_nvp("myInt", X_));
171191
}
172192
```
173-
#### [b] Is your class derived from a normal (non-virtual) inheritance ?
174-
When inheriting from objects without using virtual inheritance (e.g.`class Derived : public Base`), the recommended method is to utilize `cereal::base_class<BaseT>(this)` to cast the derived class to the base class.
193+
</details>
194+
195+
<details>
196+
<summary><strong> Normal Inheritance ?</summary></strong>
197+
For non-virtual inheritance (`class Derived : public Base`), use `cereal::base_class<BaseT>(this) to serialize the base class. Ensure this is placed at the start of the `archive` in the `serialize` function before member variables in the derived class.
175198

176199
```cpp
177200

178201
class MyDerived : public MyBase
179202
{
180-
int y;
203+
int X_;
181204
template <class Archive>
182205
void serialize( Archive & ar );
183206
};
@@ -186,32 +209,33 @@ template <class Archive>
186209
void MyDerived::serialize( Archive & archive )
187210
{
188211
// We pass this cast to the base type for each base type we need to serialize.
189-
archive(cereal::base_class<MyBase>(this), y);
212+
archive(cereal::base_class<MyBase>(this), cereal::make_nvp("myInt", X_));
190213

191214
// For multiple inheritance, link all the base classes one after the other
192-
//archive(cereal::base_class<MyBase1>(this), cereal::base_class<MyBase2>(this), y);
215+
//archive(cereal::base_class<MyBase1>(this), cereal::base_class<MyBase2>(this), cereal::make_nvp("myInt", X_));
193216
}
194217
```
195218
For more details, refer to the official Cereal documentation on [inheritance](https://uscilab.github.io/cereal/inheritance.html)
196219
197220
</details>
198-
<br>
199221
200-
<details>
201-
<summary><strong>
202-
Does your class exhibit polymorphic behavior?
203-
</summary></strong>
222+
### **2. EXHIBIT POLYMORPHISM?**
204223
205224
If you answered "yes" to the previous question about your class being a derived class, this is likely "yes" as well.
206225
207-
If your class exhibits polymorphic behavior, particularly if it's a derived class, follow these steps:
226+
<details>
227+
<summary><strong>
228+
Follow these steps if your class exhibits polymorphic behavior:
229+
</summary></strong>
208230
209231
1. Include Necessary Headers:
210-
Make sure to include the polymorphic header to enable support for polymorphism in Cereal.
232+
233+
Make sure to include the polymorphic header to enable support for polymorphism in Cereal in the derived class.
211234
``` #include <cereal/types/polymorphic.hpp> ```
212235
213236
2. Register Your Derived Types:
214-
Register each derived class using `CEREAL_REGISTER_TYPE(DerivedClassName)`.
237+
238+
Register each derived class above the definition of the `serialize` function using `CEREAL_REGISTER_TYPE(DerivedClassName)` in the respective derived class.
215239
216240
```cpp
217241
// be sure to include support for polymorphism
@@ -235,7 +259,8 @@ template <class Archive>
235259
```
236260

237261
3. Register Your Base Class (if not registered automatically):
238-
Normally, registering base classes is handled automatically if you serialize a derived type with either `cereal::base_class` or `cereal::virtual_base_class`. However, in situations where neither of these is used, explicit registration is required using the `CEREAL_REGISTER_POLYMORPHIC_RELATION` macro.
262+
263+
Normally, registering base classes is handled automatically if you serialize a derived type with either `cereal::base_class` or `cereal::virtual_base_class`. However, in situations where neither of these is used, explicit registration is required using the `CEREAL_REGISTER_POLYMORPHIC_RELATION` macro in the derived class.
239264

240265
```cpp
241266
struct MyEmptyBase
@@ -266,14 +291,14 @@ template <class Archive>
266291
For more detailed information and examples on polymorphism in Cereal, refer to the official documentation on [Polymorphism](https://uscilab.github.io/cereal/polymorphism.html).
267292
268293
</details>
269-
<br>
270294
295+
### **3. TEMPLATE?**
271296
<details>
272297
<summary><strong>
273-
Is your class a template?
298+
Template involves inheritance?
274299
</summary></strong>
275300
276-
Follow all the steps from Step 01 as if your class is a regular class. However, if the template involves inheritance, you might need to register all potential instantiations of the template during polymorphism handling.
301+
Follow all the steps from STEP 01 as if your class is a regular class. However, if the template involves inheritance, you might need to register all potential instantiations of the template during polymorphism handling.
277302
278303
```cpp
279304
@@ -310,21 +335,13 @@ CEREAL_REGISTER_TYPE(DerivedClassTemplate<float>);
310335
// CEREAL_REGISTER_POLYMORPHIC_RELATION(BaseClass, DerivedClassTemplate<float>);
311336
312337
```
313-
314338
</details>
315-
<br>
316339

317-
<details>
318-
<summary><strong>
319-
Are you serializing smart pointers to objects that do not have a default constructor?
320-
</summary></strong>
340+
### **4. NO DEFAULT CONSTRUCTOR?**
321341

322342
Cereal provides a special overload method to handle this situation. Refer to the [Cereal documentation](https://uscilab.github.io/cereal/pointers) for detailed information on this technique.
323343

324-
</details>
325-
<br>
326-
327-
## Debugging Cereal Errors in Graphitti
344+
## Common Cereal Errors
328345

329346
Encountering a Cereal error during compiling or running Graphitti? Here's a checklist to troubleshoot:
330347

@@ -349,10 +366,6 @@ Encountering a Cereal error during compiling or running Graphitti? Here's a chec
349366
350367
With these checks, you should be able to diagnose and resolve common Cereal errors in Graphitti.
351368
352-
<!-- ## Serialization flow in Graphitti (For Debugging purposes) -->
353-
354-
355-
356369
---------
357370
[<< Go back to the Developer Documentation page](index.md)
358371

0 commit comments

Comments
 (0)