Clone
ixen
committed
on 13 Nov 20
Improved serializable container to handle oids properly.
/libserializer/SerializableContainer.h (+51 -4)
1 1 #pragma once
  2 #include "../libchcore/TCoreException.h"
  3 #include "../libchcore/ErrorCodes.h"
2 4
3 5 namespace serializer
4 6 {
5 7         template<class T>
6 8         class SerializableContainer
7 9         {
8 10         public:
  11                 SerializableContainer() = default;
9 12
  13                 SerializableContainer(const SerializableContainer<T>& rSrc)
  14                 {
  15                         for(const T& item : rSrc.m_vEntries)
  16                         {
  17                                 // ensures proper assignment of new oids
  18                                 Add(item);
  19                         }
  20                 }
  21
  22                 SerializableContainer<T>& operator=(const SerializableContainer<T>& rSrc)
  23                 {
  24                         if(this != &rSrc)
  25                         {
  26                                 Clear();
  27                                 for(const T& item : rSrc.m_vEntries)
  28                                 {
  29                                         // ensures proper assignment of new oids
  30                                         Add(item);
  31                                 }
  32                         }
  33
  34                         return *this;
  35                 }
  36
  37                 virtual ~SerializableContainer() = default;
  38
10 39                 void Store(const serializer::ISerializerContainerPtr& spContainer) const
11 40                 {
  41                         if(!spContainer)
  42                                 throw chcore::TCoreException(chcore::eErr_InvalidPointer, L"spContainer", LOCATION);
  43
12 44                         InitColumns(spContainer);
13 45
14 46                         spContainer->DeleteRows(m_setRemovedObjects);
15 47                         m_setRemovedObjects.Clear();
16 48
17 49                         for(const T& rEntry : m_vEntries)
18 50                         {
19 51                                 rEntry.Store(spContainer);
20 52                         }
21 53                 }
22 54
23 55                 void Load(const serializer::ISerializerContainerPtr& spContainer)
24 56                 {
  57                         if(!spContainer)
  58                                 throw chcore::TCoreException(chcore::eErr_InvalidPointer, L"spContainer", LOCATION);
  59
  60                         m_setRemovedObjects.Clear();
  61                         m_vEntries.clear();
  62
25 63                         InitColumns(spContainer);
26 64
27 65                         ISerializerRowReaderPtr spRowReader = spContainer->GetRowReader();
28 66                         while(spRowReader->Next())
29 67                         {
30 68                                 T tEntry;
31 69                                 tEntry.Load(spRowReader);
32 70
33                                   tEntry.ResetModifications();
34  
35 71                                 m_vEntries.push_back(tEntry);
36 72                         }
  73
  74                         // ensure all objects have modification flag stripped to avoid unnecessary writing the same data to db again
  75                         // NOTE: Load() method above should reset modification flag, but storing it in vector will set it again - hence the separate reset
  76                         for(T& rItem : m_vEntries)
  77                         {
  78                                 rItem.ResetModifications();
37 79                         }
  80                 }
38 81
39 82                 virtual void InitColumns(const serializer::ISerializerContainerPtr& spContainer) const = 0;
40 83
41 84                 bool IsEmpty() const
42 85                 {
43 86                         return m_vEntries.empty();
44 87                 }
45 88
46 89                 void Add(const T& rEntry)
47 90                 {
48                           m_vEntries.push_back(rEntry);
  91                         auto iterResult = m_vEntries.insert(m_vEntries.end(), rEntry);
  92                         iterResult->SetObjectID(++m_oidLastObjectID);
49 93                 }
50 94
51 95                 bool SetAt(size_t stIndex, const T& rNewEntry)
52 96                 {
53 97                         BOOST_ASSERT(stIndex < m_vEntries.size());
54 98                         if(stIndex < m_vEntries.size())
55 99                         {
56 100                                 T& rEntry = m_vEntries.at(stIndex);
57 101
  102                                 // set only data, without changing oid
58 103                                 rEntry.SetData(rNewEntry);
59 104                                 return true;
60 105                         }
61 106
62 107                         return false;
63 108                 }
64 109
65 110                 bool InsertAt(size_t stIndex, const T& rNewEntry)
66 111                 {
67 112                         BOOST_ASSERT(stIndex <= m_vEntries.size());
68 113                         if(stIndex <= m_vEntries.size())
69 114                         {
70                                   m_vEntries.insert(m_vEntries.begin() + stIndex, rNewEntry);
  115                                 auto iterResult = m_vEntries.insert(m_vEntries.begin() + stIndex, rNewEntry);
  116                                 iterResult->SetObjectID(++m_oidLastObjectID);
71 117                                 return true;
72 118                         }
73 119
74 120                         return false;
75 121                 }
76 122
77 123                 const T& GetAt(size_t stIndex) const
78 124                 {
79 125                         if(stIndex >= m_vEntries.size())
80 126                                 throw std::out_of_range("stIndex is out of range");
81 127
82 128                         return m_vEntries.at(stIndex);
83 129                 }
84 130
85 131                 T& GetAt(size_t stIndex)
86 132                 {
87 133                         if(stIndex >= m_vEntries.size())
88 134                                 throw std::out_of_range("stIndex is out of range");
89 135
90 136                         return m_vEntries.at(stIndex);
 
102 148                         }
103 149
104 150                         return false;
105 151                 }
106 152
107 153                 size_t GetCount() const
108 154                 {
109 155                         return m_vEntries.size();
110 156                 }
111 157
112 158                 void Clear()
113 159                 {
114 160                         for(const T& rEntry : m_vEntries)
115 161                         {
116 162                                 m_setRemovedObjects.Add(rEntry.GetObjectID());
117 163                         }
118 164                         m_vEntries.clear();
119 165                 }
120 166
121 167         protected:
  168                 serializer::object_id_t m_oidLastObjectID = 0;
122 169                 std::vector<T> m_vEntries;
123 170                 mutable serializer::TRemovedObjects m_setRemovedObjects;
124 171         };
125 172 }