Fix last commit
[carla.git] / source / utils / CarlaScopeUtils.hpp
blob89bfd5047c3b63258d2a1241980905f7aa8ddd8d
1 /*
2 * Carla Scope-related classes and tools (pointer and setter taken from JUCE v4)
3 * Copyright (C) 2013 Raw Material Software Ltd.
4 * Copyright (c) 2016 ROLI Ltd.
5 * Copyright (C) 2013-2020 Filipe Coelho <falktx@falktx.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
20 #ifndef CARLA_SCOPE_UTILS_HPP_INCLUDED
21 #define CARLA_SCOPE_UTILS_HPP_INCLUDED
23 #include "CarlaUtils.hpp"
25 #include <algorithm>
26 #include <clocale>
28 #if ! (defined(CARLA_OS_HAIKU) || defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN))
29 # define CARLA_USE_NEWLOCALE
30 #endif
32 #if defined(CARLA_OS_WIN) && __MINGW64_VERSION_MAJOR >= 5
33 # define CARLA_USE_CONFIGTHREADLOCALE
34 #endif
36 // -----------------------------------------------------------------------
37 // CarlaScopedEnvVar class
39 class CarlaScopedEnvVar {
40 public:
41 CarlaScopedEnvVar(const char* const envVar, const char* const valueOrNull) noexcept
42 : key(nullptr),
43 origValue(nullptr)
45 CARLA_SAFE_ASSERT_RETURN(envVar != nullptr && envVar[0] != '\0',);
47 key = carla_strdup_safe(envVar);
48 CARLA_SAFE_ASSERT_RETURN(key != nullptr,);
50 if (const char* const envVarValue = std::getenv(key))
52 origValue = carla_strdup_safe(envVarValue);
53 CARLA_SAFE_ASSERT_RETURN(origValue != nullptr,);
56 // change env var if requested
57 if (valueOrNull != nullptr)
58 carla_setenv(key, valueOrNull);
59 // if null, unset. but only if there is in an active env var value
60 else if (origValue != nullptr)
61 carla_unsetenv(key);
64 ~CarlaScopedEnvVar() noexcept
66 bool hasOrigValue = false;
68 if (origValue != nullptr)
70 hasOrigValue = true;
72 carla_setenv(key, origValue);
74 delete[] origValue;
75 origValue = nullptr;
78 if (key != nullptr)
80 if (! hasOrigValue)
81 carla_unsetenv(key);
83 delete[] key;
84 key = nullptr;
88 private:
89 const char* key;
90 const char* origValue;
92 CARLA_DECLARE_NON_COPYABLE(CarlaScopedEnvVar)
93 CARLA_PREVENT_HEAP_ALLOCATION
96 // -----------------------------------------------------------------------
97 // CarlaScopedLocale class
99 class CarlaScopedLocale {
100 #ifdef CARLA_USE_NEWLOCALE
101 static constexpr locale_t kNullLocale = (locale_t)nullptr;
102 #endif
104 public:
105 CarlaScopedLocale() noexcept
106 #ifdef CARLA_USE_NEWLOCALE
107 : newloc(::newlocale(LC_NUMERIC_MASK, "C", kNullLocale)),
108 oldloc(newloc != kNullLocale ? ::uselocale(newloc) : kNullLocale) {}
109 #else
110 # ifdef CARLA_USE_CONFIGTHREADLOCALE
111 : oldthreadloc(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)),
112 # else
114 # endif
115 oldloc(carla_strdup_safe(::setlocale(LC_NUMERIC, nullptr)))
117 ::setlocale(LC_NUMERIC, "C");
119 #endif
121 ~CarlaScopedLocale() noexcept
123 #ifdef CARLA_USE_NEWLOCALE
124 if (oldloc != kNullLocale)
125 ::uselocale(oldloc);
126 if (newloc != kNullLocale)
127 ::freelocale(newloc);
128 #else // CARLA_USE_NEWLOCALE
129 if (oldloc != nullptr)
131 ::setlocale(LC_NUMERIC, oldloc);
132 delete[] oldloc;
135 # ifdef CARLA_USE_CONFIGTHREADLOCALE
136 if (oldthreadloc != -1)
137 _configthreadlocale(oldthreadloc);
138 # endif
139 #endif // CARLA_USE_NEWLOCALE
142 private:
143 #ifdef CARLA_USE_NEWLOCALE
144 locale_t newloc, oldloc;
145 #else
146 # ifdef CARLA_USE_CONFIGTHREADLOCALE
147 const int oldthreadloc;
148 # endif
149 const char* const oldloc;
150 #endif
152 CARLA_DECLARE_NON_COPYABLE(CarlaScopedLocale)
153 CARLA_PREVENT_HEAP_ALLOCATION
156 //=====================================================================================================================
158 This class holds a pointer which is automatically deleted when this object goes
159 out of scope.
161 Once a pointer has been passed to a CarlaScopedPointer, it will make sure that the pointer
162 gets deleted when the CarlaScopedPointer is deleted. Using the CarlaScopedPointer on the stack or
163 as member variables is a good way to use RAII to avoid accidentally leaking dynamically
164 created objects.
166 A CarlaScopedPointer can be used in pretty much the same way that you'd use a normal pointer
167 to an object. If you use the assignment operator to assign a different object to a
168 CarlaScopedPointer, the old one will be automatically deleted.
170 A const CarlaScopedPointer is guaranteed not to lose ownership of its object or change the
171 object to which it points during its lifetime. This means that making a copy of a const
172 CarlaScopedPointer is impossible, as that would involve the new copy taking ownership from the
173 old one.
175 If you need to get a pointer out of a CarlaScopedPointer without it being deleted, you
176 can use the release() method.
178 Something to note is the main difference between this class and the std::auto_ptr class,
179 which is that CarlaScopedPointer provides a cast-to-object operator, whereas std::auto_ptr
180 requires that you always call get() to retrieve the pointer. The advantages of providing
181 the cast is that you don't need to call get(), so can use the CarlaScopedPointer in pretty much
182 exactly the same way as a raw pointer. The disadvantage is that the compiler is free to
183 use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult
184 to return a CarlaScopedPointer as the result of a function. To avoid this causing errors,
185 CarlaScopedPointer contains an overloaded constructor that should cause a syntax error in these
186 circumstances, but it does mean that instead of returning a CarlaScopedPointer from a function,
187 you'd need to return a raw pointer (or use a std::auto_ptr instead).
189 template<class ObjectType>
190 class CarlaScopedPointer
192 public:
193 //=================================================================================================================
194 /** Creates a CarlaScopedPointer containing a null pointer. */
195 CarlaScopedPointer() noexcept
196 : object(nullptr) {}
198 /** Creates a CarlaScopedPointer that owns the specified object. */
199 CarlaScopedPointer(ObjectType* const objectToTakePossessionOf) noexcept
200 : object(objectToTakePossessionOf) {}
202 /** Creates a CarlaScopedPointer that takes its pointer from another CarlaScopedPointer.
204 Because a pointer can only belong to one CarlaScopedPointer, this transfers
205 the pointer from the other object to this one, and the other object is reset to
206 be a null pointer.
208 CarlaScopedPointer(CarlaScopedPointer& objectToTransferFrom) noexcept
209 : object(objectToTransferFrom.object)
211 objectToTransferFrom.object = nullptr;
214 /** Destructor.
215 This will delete the object that this CarlaScopedPointer currently refers to.
217 ~CarlaScopedPointer()
219 delete object;
222 /** Changes this CarlaScopedPointer to point to a new object.
224 Because a pointer can only belong to one CarlaScopedPointer, this transfers
225 the pointer from the other object to this one, and the other object is reset to
226 be a null pointer.
228 If this CarlaScopedPointer already points to an object, that object
229 will first be deleted.
231 CarlaScopedPointer& operator=(CarlaScopedPointer& objectToTransferFrom)
233 if (this != objectToTransferFrom.getAddress())
235 // Two CarlaScopedPointers should never be able to refer to the same object - if
236 // this happens, you must have done something dodgy!
237 CARLA_SAFE_ASSERT_RETURN(object == nullptr || object != objectToTransferFrom.object, *this);
239 ObjectType* const oldObject = object;
240 object = objectToTransferFrom.object;
241 objectToTransferFrom.object = nullptr;
242 delete oldObject;
245 return *this;
248 /** Changes this CarlaScopedPointer to point to a new object.
250 If this CarlaScopedPointer already points to an object, that object
251 will first be deleted.
253 The pointer that you pass in may be a nullptr.
255 CarlaScopedPointer& operator=(ObjectType* const newObjectToTakePossessionOf)
257 if (object != newObjectToTakePossessionOf)
259 ObjectType* const oldObject = object;
260 object = newObjectToTakePossessionOf;
261 delete oldObject;
264 return *this;
267 //=================================================================================================================
268 /** Returns the object that this CarlaScopedPointer refers to. */
269 operator ObjectType*() const noexcept { return object; }
271 /** Returns the object that this CarlaScopedPointer refers to. */
272 ObjectType* get() const noexcept { return object; }
274 /** Returns the object that this CarlaScopedPointer refers to. */
275 ObjectType& operator*() const noexcept { return *object; }
277 /** Lets you access methods and properties of the object that this CarlaScopedPointer refers to. */
278 ObjectType* operator->() const noexcept { return object; }
280 //=================================================================================================================
281 /** Removes the current object from this CarlaScopedPointer without deleting it.
282 This will return the current object, and set the CarlaScopedPointer to a null pointer.
284 ObjectType* release() noexcept { ObjectType* const o = object; object = nullptr; return o; }
286 //=================================================================================================================
287 /** Swaps this object with that of another CarlaScopedPointer.
288 The two objects simply exchange their pointers.
290 void swapWith(CarlaScopedPointer<ObjectType>& other) noexcept
292 // Two CarlaScopedPointers should never be able to refer to the same object - if
293 // this happens, you must have done something dodgy!
294 CARLA_SAFE_ASSERT_RETURN(object != other.object || this == other.getAddress() || object == nullptr,);
296 std::swap(object, other.object);
299 private:
300 //=================================================================================================================
301 ObjectType* object;
303 // (Required as an alternative to the overloaded & operator).
304 const CarlaScopedPointer* getAddress() const noexcept { return this; }
306 #ifdef CARLA_PROPER_CPP11_SUPPORT
307 CarlaScopedPointer(const CarlaScopedPointer&) = delete;
308 CarlaScopedPointer& operator=(const CarlaScopedPointer&) = delete;
309 #else
310 CarlaScopedPointer(const CarlaScopedPointer&);
311 CarlaScopedPointer& operator=(const CarlaScopedPointer&);
312 #endif
315 //=====================================================================================================================
316 /** Compares a CarlaScopedPointer with another pointer.
317 This can be handy for checking whether this is a null pointer.
319 template<class ObjectType>
320 bool operator==(const CarlaScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
322 return static_cast<ObjectType*>(pointer1) == pointer2;
325 /** Compares a CarlaScopedPointer with another pointer.
326 This can be handy for checking whether this is a null pointer.
328 template<class ObjectType>
329 bool operator!=(const CarlaScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
331 return static_cast<ObjectType*>(pointer1) != pointer2;
334 //=====================================================================================================================
336 Helper class providing an RAII-based mechanism for temporarily setting and
337 then re-setting a value.
339 E.g. @code
340 int x = 1;
343 CarlaScopedValueSetter setter (x, 2);
345 // x is now 2
348 // x is now 1 again
351 CarlaScopedValueSetter setter (x, 3, 4);
353 // x is now 3
356 // x is now 4
357 @endcode
359 template <typename ValueType>
360 class CarlaScopedValueSetter
362 public:
363 /** Creates a CarlaScopedValueSetter that will immediately change the specified value to the
364 given new value, and will then reset it to its original value when this object is deleted.
365 Must be used only for 'noexcept' compatible types.
367 CarlaScopedValueSetter(ValueType& valueToSet, ValueType newValue) noexcept
368 : value(valueToSet),
369 originalValue(valueToSet)
371 valueToSet = newValue;
374 /** Creates a CarlaScopedValueSetter that will immediately change the specified value to the
375 given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
377 CarlaScopedValueSetter(ValueType& valueToSet, ValueType newValue, ValueType valueWhenDeleted) noexcept
378 : value(valueToSet),
379 originalValue(valueWhenDeleted)
381 valueToSet = newValue;
384 ~CarlaScopedValueSetter() noexcept
386 value = originalValue;
389 private:
390 //=================================================================================================================
391 ValueType& value;
392 const ValueType originalValue;
394 CARLA_DECLARE_NON_COPYABLE(CarlaScopedValueSetter)
395 CARLA_PREVENT_HEAP_ALLOCATION
398 // -----------------------------------------------------------------------
400 #endif // CARLA_SCOPE_UTILS_HPP_INCLUDED