Improve performance on structs
[scilab.git] / scilab / modules / ast / src / cpp / types / singlestruct.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2011 - DIGITEO - Antoine ELIAS
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-en.txt
10 *
11 */
12
13 #include <sstream>
14 #include "symbol.hxx"
15 #include "singlestruct.hxx"
16 #include "string.hxx"
17 #include "double.hxx"
18 #include "scilabexception.hxx"
19 #include "localization.hxx"
20 #include "scilabWrite.hxx"
21
22 namespace types
23 {
24 SingleStruct::SingleStruct()
25 {
26 #ifndef NDEBUG
27     Inspector::addItem(this);
28 #endif
29 }
30
31 SingleStruct::~SingleStruct()
32 {
33     if (isDeletable() == true)
34     {
35         for (auto data : m_Data)
36         {
37             data->DecreaseRef();
38             data->killMe();
39         }
40     }
41 #ifndef NDEBUG
42     Inspector::removeItem(this);
43 #endif
44 }
45
46 SingleStruct::SingleStruct(SingleStruct *_oSingleStructCopyMe) : m_wstFields(_oSingleStructCopyMe->getFields()), m_Data(_oSingleStructCopyMe->getData())
47 {
48     for (auto data : m_Data)
49     {
50         data->IncreaseRef();
51     }
52 #ifndef NDEBUG
53     Inspector::addItem(this);
54 #endif
55 }
56
57 std::vector<InternalType *> & SingleStruct::getData()
58 {
59     return m_Data;
60 }
61
62 std::unordered_map<std::wstring, int> & SingleStruct::getFields()
63 {
64     return m_wstFields;
65 }
66
67 std::vector<std::wstring> SingleStruct::getFieldsName()
68 {
69     std::vector<std::wstring> names;
70     names.reserve(m_wstFields.size());
71     for (const auto & p : m_wstFields)
72     {
73         names.emplace_back(p.first);
74     }
75
76     return names;
77 }
78
79 int SingleStruct::getFieldIndex(const std::wstring & _field)
80 {
81     const auto i = m_wstFields.find(_field);
82     if (i != m_wstFields.end())
83     {
84         return i->second;
85     }
86
87     return -1;
88 }
89
90 bool SingleStruct::set(const std::wstring& _sKey, InternalType *_typedValue)
91 {
92     const int index = getFieldIndex(_sKey);
93     if (index == -1)
94     {
95         return false;
96     }
97
98     InternalType* pOld = m_Data[index];
99     if (pOld != _typedValue)
100     {
101         /* Look if we are replacing some existing value */
102         if (pOld != nullptr)
103         {
104             pOld->DecreaseRef();
105             pOld->killMe();
106         }
107
108         if (_typedValue)
109         {
110             _typedValue->IncreaseRef();
111             m_Data[index] = _typedValue;
112         }
113         else
114         {
115             m_Data[index] = nullptr;
116         }
117     }
118     return true;
119 }
120
121
122 InternalType* SingleStruct::get(const std::wstring& _sKey)
123 {
124     int index = getFieldIndex(_sKey);
125     if (index == -1)
126     {
127         return nullptr;
128     }
129
130     return m_Data[index];
131 }
132
133 bool SingleStruct::exists(const std::wstring& _sKey)
134 {
135     return (getFieldIndex(_sKey) != -1);
136 }
137
138 SingleStruct* SingleStruct::clone()
139 {
140     return new SingleStruct(this);
141 }
142
143 InternalType* SingleStruct::insert(typed_list* _pArgs, InternalType* _pSource)
144 {
145     //check input param
146     if (_pArgs->size() != 1)
147     {
148         std::wostringstream os;
149         os << _W("Unable to insert multiple item in a struct.\n");
150         throw ast::ScilabError(os.str());
151     }
152
153     if ((*_pArgs)[0]->isString() == false)
154     {
155         std::wostringstream os;
156         os << _W("Assignment between unlike types is not allowed.\n");
157         throw ast::ScilabError(os.str());
158     }
159
160     String* pstKey = (*_pArgs)[0]->getAs<String>();
161     for (int i = 0 ; i < pstKey->getSize() ; ++i)
162     {
163         set(pstKey->get(i), _pSource);
164     }
165
166     return this;
167 }
168
169 std::vector<InternalType*> SingleStruct::extract(std::vector<std::wstring> & _stFields)
170 {
171     std::vector<InternalType*> Result;
172
173     for (const auto & f : _stFields)
174     {
175         if (!exists(f))
176         {
177             return Result;
178         }
179     }
180
181     for (const auto & f : _stFields)
182     {
183         Result.push_back(get(f));
184     }
185
186     return Result;
187 }
188
189 String* SingleStruct::getFieldNames()
190 {
191     std::set<std::wstring> names;
192     for (const auto & p : m_wstFields)
193     {
194         names.emplace(p.first);
195     }
196
197     String* pOut = new String((int)names.size(), 1);
198     int i = 0;
199     for (const auto & name : names)
200     {
201         pOut->set(i++, name.c_str());
202     }
203     return pOut;
204 }
205
206 bool SingleStruct::removeField(const std::wstring & _sKey)
207 {
208     const auto i = m_wstFields.find(_sKey);
209     if (i != m_wstFields.end())
210     {
211         const int pos = i->second;
212         m_Data[pos]->DecreaseRef();
213         m_Data[pos]->killMe();
214         m_wstFields.erase(i);
215
216         for (auto & p : m_wstFields)
217         {
218             if (p.second > pos)
219             {
220                 --p.second;
221             }
222         }
223
224         m_Data.erase(m_Data.begin() + pos);
225     }
226
227     return true;
228 }
229
230 bool SingleStruct::addField(const std::wstring& _sKey)
231 {
232     if (exists(_sKey))
233     {
234         //field already exists, do nothing and return false
235         return false;
236     }
237
238     //not found so add field with []
239     InternalType* pIT = Double::Empty();
240     pIT->IncreaseRef();
241     m_Data.push_back(pIT);
242     m_wstFields.emplace(_sKey, m_Data.size() - 1);
243
244     return true;
245 }
246
247 bool SingleStruct::addFieldFront(const std::wstring& _sKey)
248 {
249     if (exists(_sKey))
250     {
251         //field already exists, do nothing and return false
252         return false;
253     }
254
255     //not found so add field with []
256     InternalType* pIT = Double::Empty();
257     pIT->IncreaseRef();
258     m_Data.insert(m_Data.begin(), pIT);
259
260     for (auto & p : m_wstFields)
261     {
262         p.second++;
263     }
264
265     m_wstFields.emplace(_sKey, 0);
266     return true;
267 }
268
269 bool SingleStruct::toString(std::wostringstream& ostr)
270 {
271     if (m_Data.size() == 0)
272     {
273         ostr << L"empty SingleStruct";
274         return true;
275     }
276     else
277     {
278
279         for (auto & p : m_wstFields)
280         {
281             ostr << p.first << L" : " << m_Data[p.second]->getTypeStr() << std::endl;
282         }
283     }
284
285     return true;
286 }
287
288 bool SingleStruct::operator==(const InternalType& it)
289 {
290     if (const_cast<InternalType &>(it).isSingleStruct() == false)
291     {
292         return false;
293     }
294
295     SingleStruct* other = const_cast<InternalType &>(it).getAs<SingleStruct>();
296
297     std::unordered_map<std::wstring, int> & otherFieldNames = other->getFields();
298     std::vector<InternalType*> & otherFieldData = other->getData();
299
300     if (m_wstFields.size() != otherFieldNames.size())
301     {
302         return false;
303     }
304
305     for (const auto & p : m_wstFields)
306     {
307         const auto i = otherFieldNames.find(p.first);
308         if (i == otherFieldNames.end() || (*m_Data[p.second] != *otherFieldData[i->second]))
309         {
310             return false;
311         }
312     }
313
314     return true;
315 }
316
317 bool SingleStruct::operator!=(const InternalType& it)
318 {
319     return !(*this == it);
320 }
321 }