Fix memory leak at startup / exit
[scilab.git] / scilab / modules / xml / src / cpp / VariableScope.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 #include "VariableScope.hxx"
14 #include "XMLObject.hxx"
15 #include "XMLNodeList.hxx"
16
17 namespace org_modules_xml
18 {
19 xmlFreeFunc VariableScope::XMLFreeFunc = 0;
20 std::map < void *, XMLObject * > VariableScope::mapLibXMLToXMLObject = std::map < void *, XMLObject * >();
21 std::map < void *, XMLNodeList * > VariableScope::mapLibXMLToXMLNodeList = std::map < void *, XMLNodeList * >();
22 std::map < const XMLObject *, std::vector < const XMLObject *>*> VariableScope::parentToChildren = std::map < const XMLObject *, std::vector < const XMLObject *>*>();
23
24 VariableScope::VariableScope(int _initialSize)
25 {
26     position = -1;
27     initialSize = _initialSize;
28     scope = new std::vector < XMLObject * >();
29     freePlaces = new std::stack < int >();
30     initXMLMemory();
31 }
32
33 VariableScope::~VariableScope()
34 {
35     for (unsigned int i = 0; i < scope->size(); i++)
36     {
37         if ((*scope)[i])
38         {
39             delete(*scope)[i];
40         }
41     }
42     delete scope;
43     delete freePlaces;
44 }
45
46 /**
47  * To avoid unused place in the vector, we use a stack which contains the empty places.
48  */
49 int VariableScope::getVariableId(const XMLObject & obj)
50 {
51     int returnValue;
52     const XMLObject *parent = obj.getXMLObjectParent();
53
54     if (freePlaces->size() != 0)
55     {
56         returnValue = freePlaces->top();
57         freePlaces->pop();
58         (*scope)[returnValue] = const_cast < XMLObject * >(&obj);
59     }
60     else
61     {
62         returnValue = (int)scope->size();
63         scope->push_back(const_cast < XMLObject * >(&obj));
64     }
65
66     if (parent)
67     {
68         std::map < const XMLObject *, std::vector < const XMLObject *>*>::const_iterator it = parentToChildren.find(parent);
69
70         if (it != parentToChildren.end())
71         {
72             it->second->push_back(&obj);
73         }
74         else
75         {
76             parentToChildren[parent] = new std::vector < const XMLObject *>();
77
78             parentToChildren[parent]->push_back(&obj);
79         }
80     }
81
82     return returnValue;
83 }
84
85 XMLObject *VariableScope::getVariableFromId(int id)
86 {
87     if (id >= 0 && id < (int)scope->size())
88     {
89         return (*scope)[id];
90     }
91
92     return 0;
93 }
94
95 /**
96  * There are two motivations to register libxml pointers:
97  *   i) if a XMLObject is associated to a libxml node, then when this node will be removed
98  *      the XMLObject must be destroyed. This job is done in _xmlFreeFunc which is called
99  *      by libxml when a libxml node is freed.
100  *   ii) To avoid multiple instances of a XMLObject which wraps the same node, the function
101  *       getXMLObjectFromLibXMLPtr is used to know if a XMLObject already exists for the
102  *       libxml node.
103  */
104 void VariableScope::registerPointers(void *libxml, XMLObject * obj)
105 {
106     if (libxml)
107     {
108         mapLibXMLToXMLObject[libxml] = obj;
109     }
110 }
111
112 void VariableScope::registerPointers(void *libxml, XMLNodeList * nodeList)
113 {
114     if (libxml)
115     {
116         mapLibXMLToXMLNodeList[libxml] = nodeList;
117     }
118 }
119
120 void VariableScope::unregisterPointer(void *libxml)
121 {
122     if (libxml)
123     {
124         mapLibXMLToXMLObject.erase(libxml);
125     }
126 }
127
128 void VariableScope::unregisterNodeListPointer(void *libxml)
129 {
130     if (libxml)
131     {
132         mapLibXMLToXMLNodeList.erase(libxml);
133     }
134 }
135
136 XMLObject *VariableScope::getXMLObjectFromLibXMLPtr(void *libxml) const
137 {
138     if (libxml)
139     {
140         std::map < void *, XMLObject * >::const_iterator it = mapLibXMLToXMLObject.find(libxml);
141         if (it != mapLibXMLToXMLObject.end())
142         {
143             return it->second;
144         }
145     }
146
147     return 0;
148 }
149
150 XMLNodeList *VariableScope::getXMLNodeListFromLibXMLPtr(void *libxml)const
151 {
152     if (libxml)
153     {
154         std::map < void *, XMLNodeList * >::const_iterator it = mapLibXMLToXMLNodeList.find(libxml);
155         if (it != mapLibXMLToXMLNodeList.end())
156         {
157             return it->second;
158         }
159     }
160
161     return 0;
162 }
163
164 void VariableScope::removeId(int id)
165 {
166     if (id >= 0 && id < (int)scope->size() && (*scope)[id])
167     {
168         removeChildFromParent((*scope)[id]);
169         removeDependencies((*scope)[id]);
170         (*scope)[id] = 0;
171         freePlaces->push(id);
172     }
173 }
174
175 void VariableScope::removeDependencies(XMLObject * obj)
176 {
177     std::map < const XMLObject *, std::vector < const XMLObject *>*>::const_iterator it = parentToChildren.find(obj);
178
179     if (it != parentToChildren.end())
180     {
181         for (unsigned int i = 0; i < it->second->size(); i++)
182         {
183             const XMLObject *child = (*(it->second))[i];
184
185             if (child && getVariableFromId(child->getId()) == child)
186             {
187                 delete child;
188             }
189         }
190         delete it->second;
191
192         parentToChildren.erase(obj);
193     }
194 }
195
196 void VariableScope::initXMLMemory()
197 {
198     xmlFreeFunc freeFunc;
199     xmlMallocFunc mallocFunc;
200     xmlReallocFunc reallocFunc;
201     xmlStrdupFunc strdupFunc;
202
203     xmlMemGet(&freeFunc, &mallocFunc, &reallocFunc, &strdupFunc);
204     freeFunc = getFreeFunc(freeFunc);
205     xmlMemSetup(freeFunc, mallocFunc, reallocFunc, strdupFunc);
206 }
207
208 xmlFreeFunc VariableScope::getFreeFunc(xmlFreeFunc freeFunc)
209 {
210     if (!XMLFreeFunc)
211     {
212         XMLFreeFunc = freeFunc;
213     }
214
215     return &_xmlFreeFunc;
216 }
217
218 void VariableScope::_xmlFreeFunc(void *mem)
219 {
220     std::map < void *, XMLObject * >::const_iterator it = mapLibXMLToXMLObject.find(mem);
221
222     if (it != mapLibXMLToXMLObject.end())
223     {
224         delete it->second;
225
226         mapLibXMLToXMLObject.erase(mem);
227     }
228
229     std::map < void *, XMLNodeList * >::const_iterator itnl = mapLibXMLToXMLNodeList.find(mem);
230
231     if (itnl != mapLibXMLToXMLNodeList.end())
232     {
233         delete itnl->second;
234
235         mapLibXMLToXMLNodeList.erase(mem);
236     }
237
238     XMLFreeFunc(mem);
239 }
240
241 inline void VariableScope::removeChildFromParent(const XMLObject * child)
242 {
243     const XMLObject *parent = child->getXMLObjectParent();
244     std::map < const XMLObject *, std::vector < const XMLObject *>*>::const_iterator it = parentToChildren.find(parent);
245
246     if (it != parentToChildren.end())
247     {
248         for (unsigned int i = 0; i < it->second->size(); i++)
249         {
250             if (child == (*(it->second))[i])
251             {
252                 (*(it->second))[i] = 0;
253             }
254         }
255     }
256 }
257 }