fix ast memory leak in tests
[scilab.git] / scilab / modules / ast / includes / analysis / tools.hxx
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014 - 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-en.txt
10  *
11  */
12
13 #ifndef __TOOLS_HXX__
14 #define __TOOLS_HXX__
15
16 #include <bitset>
17 #include <cmath>
18 #include <cstdint>
19 #include <iostream>
20 #include <limits>
21 #include <map>
22 #include <set>
23
24 #ifdef _MSC_VER
25 #include "stdint.h"
26 #include <intrin.h>
27 #endif
28
29 #include "core_math.h"
30
31 namespace analysis
32 {
33
34 namespace tools
35 {
36
37 #ifdef _MSC_VER
38 inline static double trunc(const double x)
39 {
40     return x > 0 ? floor(x) : ceil(x);
41 }
42
43 inline static uint32_t clz(const uint32_t x)
44 {
45     unsigned long r = 0;
46     _BitScanForward(&r, x);
47     return r;
48 }
49
50 inline static uint32_t clzll(const uint64_t x)
51 {
52 #ifdef _WIN64
53     unsigned long r = 0;
54     _BitScanForward64(&r, x);
55     return r;
56 #else
57     uint32_t u32 = (x >> 32);
58     uint32_t result = u32 ? clz(u32) : 32;
59     if (result == 32)
60     {
61         u32 = x & 0xFFFFFFFFUL;
62         result += (u32 ? clz(u32) : 32);
63     }
64     return result;
65 #endif
66 }
67 #else
68 inline static double trunc(const double x)
69 {
70 #ifdef __APPLE__
71     // Needed for compilation with GCC 4.8.2
72     return x > 0 ? floor(x) : ceil(x);
73 #else
74     return std::trunc(x);
75 #endif
76 }
77
78 inline static uint32_t clz(const uint32_t x)
79 {
80     return __builtin_clz(x);
81 }
82
83 inline static uint32_t clzll(const uint64_t x)
84 {
85     return __builtin_clzll(x);
86 }
87 #endif
88
89 inline static double NaN()
90 {
91     return std::numeric_limits<double>::quiet_NaN();
92 }
93
94 inline static bool isNaN(const double x)
95 {
96     return ISNAN(x) != 0;
97 }
98
99 inline static bool isFinite(const double x)
100 {
101     return finite(x) != 0;
102 }
103
104 inline static bool isInfinite(const double x)
105 {
106     return !isFinite(x);
107 }
108
109 enum IntType { NOTANINT, SIGNED, UNSIGNED };
110
111 inline static IntType getIntType(const double x)
112 {
113     if (x == trunc(x))
114     {
115         if (x >= 0)
116         {
117             if (x <= (double)std::numeric_limits<uint64_t>::max())
118             {
119                 return UNSIGNED;
120             }
121         }
122         else if (x >= (double)std::numeric_limits<int64_t>::min())
123         {
124             return SIGNED;
125         }
126     }
127
128     return NOTANINT;
129 }
130
131 inline static bool isAnInt(const double x)
132 {
133     return getIntType(x) != NOTANINT;
134 }
135
136 template<typename T>
137 inline static T cast(const double x)
138 {
139     if (x < static_cast<double>(std::numeric_limits<T>::max()))
140     {
141         if (x > static_cast<double>(std::numeric_limits<T>::min()))
142         {
143             return static_cast<T>(x);
144         }
145         else
146         {
147             return std::numeric_limits<T>::min();
148         }
149     }
150     else
151     {
152         return std::numeric_limits<T>::max();
153     }
154 }
155
156 inline std::wostream & operator<<(std::wostream & out, const IntType & it)
157 {
158     switch (it)
159     {
160         case IntType::NOTANINT :
161             out << L"NAI";
162             break;
163         case IntType::SIGNED :
164             out << L"S";
165             break;
166         case IntType::UNSIGNED :
167             out << L"U";
168             break;
169     }
170     return out;
171 }
172
173 template<typename T>
174 inline static unsigned char popcount(const T x)
175 {
176     return std::bitset<sizeof(T)>(x).count();
177 }
178
179 inline static unsigned char log2(const unsigned int x)
180 {
181     return (unsigned char)((sizeof(unsigned int) << 3) - clz(x) - 1);
182 }
183
184 inline static unsigned char log2(const unsigned long long x)
185 {
186     return (unsigned char)((sizeof(unsigned long long) << 3) - clzll(x) - 1);
187 }
188
189 template<typename T>
190 static void printSet(const T & set, std::wostream & out)
191 {
192     if (set.empty())
193     {
194         out << L"{}";
195     }
196     else
197     {
198         out << L"{";
199         typename T::const_iterator e = --set.end();
200         for (typename T::const_iterator i = set.begin(); i != e; ++i)
201         {
202             out << *i << L",";
203         }
204         out << *e << L"}";
205     }
206 }
207
208 template<typename T>
209 static void printMapInfo(std::wostream & out, const T & map, const bool show_collisions = false)
210 {
211     double mean = 0;
212     double variance = 0;
213     double count = map.bucket_count();
214     unsigned int empty_bucket_count = 0;
215     unsigned int collision_count = 0;
216
217     out << L"Map size: " << map.size() << std::endl;
218     out << L"Number of buckets: " << count << std::endl;
219
220     for (unsigned int i = 0; i < map.bucket_count(); ++i)
221     {
222         if (unsigned int s = map.bucket_size(i))
223         {
224             mean += s;
225             if (s > 1)
226             {
227                 ++collision_count;
228             }
229         }
230         else
231         {
232             ++empty_bucket_count;
233         }
234     }
235     mean /= count;
236
237     for (unsigned int i = 0; i < map.bucket_count(); ++i)
238     {
239         const unsigned int s = map.bucket_size(i);
240         variance += (mean - s) * (mean - s);
241     }
242     variance /= count;
243
244     out << L"Number of elements by buckets: mean=" << mean << L", sigma=" << std::sqrt(variance) << std::endl;
245     out << L"Number of empty buckets: " << empty_bucket_count << std::endl;
246     out << L"Number of collisions: " << collision_count << std::endl;
247
248     if (show_collisions)
249     {
250         std::multimap<unsigned int, typename T::key_type> collisions;
251         for (const auto & p : map)
252         {
253             collisions.emplace(map.bucket(p.first), p.first);
254         }
255
256         for (const auto & p : collisions)
257         {
258             out << L"Bucket " << p.first << L": " << p.second << L", hash=" << (typename T::hasher()(p.second)) << std::endl;
259         }
260     }
261 }
262
263 inline static std::size_t hash_combine(const std::size_t seed)
264 {
265     return seed;
266 }
267
268 template<typename... Args>
269 inline static std::size_t hash_combine(const std::size_t seed, Args... args)
270 {
271     // it is the way Boost has implemented hash_combine:
272     // http://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html
273     return seed ^ (hash_combine(args...) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
274 }
275
276 } // namespace tools
277
278 } // namespace analysis
279
280 #endif // __TOOLS_HXX__