Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

401 lines
14KB

  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>
  6. *
  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.
  11. *
  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.
  16. *
  17. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  18. */
  19. #ifndef CARLA_SCOPE_UTILS_HPP_INCLUDED
  20. #define CARLA_SCOPE_UTILS_HPP_INCLUDED
  21. #include "CarlaUtils.hpp"
  22. #include <algorithm>
  23. #include <clocale>
  24. #if ! (defined(CARLA_OS_HAIKU) || defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN))
  25. # define CARLA_USE_NEWLOCALE
  26. #endif
  27. #if defined(CARLA_OS_WIN) && __MINGW64_VERSION_MAJOR >= 5
  28. # define CARLA_USE_CONFIGTHREADLOCALE
  29. #endif
  30. // -----------------------------------------------------------------------
  31. // CarlaScopedEnvVar class
  32. class CarlaScopedEnvVar {
  33. public:
  34. CarlaScopedEnvVar(const char* const envVar, const char* const valueOrNull) noexcept
  35. : key(nullptr),
  36. origValue(nullptr)
  37. {
  38. CARLA_SAFE_ASSERT_RETURN(envVar != nullptr && envVar[0] != '\0',);
  39. key = carla_strdup_safe(envVar);
  40. CARLA_SAFE_ASSERT_RETURN(key != nullptr,);
  41. if (const char* const envVarValue = std::getenv(key))
  42. {
  43. origValue = carla_strdup_safe(envVarValue);
  44. CARLA_SAFE_ASSERT_RETURN(origValue != nullptr,);
  45. }
  46. // change env var if requested
  47. if (valueOrNull != nullptr)
  48. carla_setenv(key, valueOrNull);
  49. // if null, unset. but only if there is in an active env var value
  50. else if (origValue != nullptr)
  51. carla_unsetenv(key);
  52. }
  53. ~CarlaScopedEnvVar() noexcept
  54. {
  55. bool hasOrigValue = false;
  56. if (origValue != nullptr)
  57. {
  58. hasOrigValue = true;
  59. carla_setenv(key, origValue);
  60. delete[] origValue;
  61. origValue = nullptr;
  62. }
  63. if (key != nullptr)
  64. {
  65. if (! hasOrigValue)
  66. carla_unsetenv(key);
  67. delete[] key;
  68. key = nullptr;
  69. }
  70. }
  71. private:
  72. const char* key;
  73. const char* origValue;
  74. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopedEnvVar)
  75. CARLA_PREVENT_HEAP_ALLOCATION
  76. };
  77. // -----------------------------------------------------------------------
  78. // CarlaScopedLocale class
  79. class CarlaScopedLocale {
  80. #ifdef CARLA_USE_NEWLOCALE
  81. static constexpr locale_t kNullLocale = (locale_t)nullptr;
  82. #endif
  83. public:
  84. CarlaScopedLocale() noexcept
  85. #ifdef CARLA_USE_NEWLOCALE
  86. : newloc(::newlocale(LC_NUMERIC_MASK, "C", kNullLocale)),
  87. oldloc(newloc != kNullLocale ? ::uselocale(newloc) : kNullLocale) {}
  88. #else
  89. # ifdef CARLA_USE_CONFIGTHREADLOCALE
  90. : oldthreadloc(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)),
  91. # else
  92. :
  93. # endif
  94. oldloc(carla_strdup_safe(::setlocale(LC_NUMERIC, nullptr)))
  95. {
  96. ::setlocale(LC_NUMERIC, "C");
  97. }
  98. #endif
  99. ~CarlaScopedLocale() noexcept
  100. {
  101. #ifdef CARLA_USE_NEWLOCALE
  102. if (oldloc != kNullLocale)
  103. ::uselocale(oldloc);
  104. if (newloc != kNullLocale)
  105. ::freelocale(newloc);
  106. #else // CARLA_USE_NEWLOCALE
  107. if (oldloc != nullptr)
  108. {
  109. ::setlocale(LC_NUMERIC, oldloc);
  110. delete[] oldloc;
  111. }
  112. # ifdef CARLA_USE_CONFIGTHREADLOCALE
  113. if (oldthreadloc != -1)
  114. _configthreadlocale(oldthreadloc);
  115. # endif
  116. #endif // CARLA_USE_NEWLOCALE
  117. }
  118. private:
  119. #ifdef CARLA_USE_NEWLOCALE
  120. locale_t newloc, oldloc;
  121. #else
  122. # ifdef CARLA_USE_CONFIGTHREADLOCALE
  123. const int oldthreadloc;
  124. # endif
  125. const char* const oldloc;
  126. #endif
  127. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopedLocale)
  128. CARLA_PREVENT_HEAP_ALLOCATION
  129. };
  130. //=====================================================================================================================
  131. /**
  132. This class holds a pointer which is automatically deleted when this object goes
  133. out of scope.
  134. Once a pointer has been passed to a CarlaScopedPointer, it will make sure that the pointer
  135. gets deleted when the CarlaScopedPointer is deleted. Using the CarlaScopedPointer on the stack or
  136. as member variables is a good way to use RAII to avoid accidentally leaking dynamically
  137. created objects.
  138. A CarlaScopedPointer can be used in pretty much the same way that you'd use a normal pointer
  139. to an object. If you use the assignment operator to assign a different object to a
  140. CarlaScopedPointer, the old one will be automatically deleted.
  141. A const CarlaScopedPointer is guaranteed not to lose ownership of its object or change the
  142. object to which it points during its lifetime. This means that making a copy of a const
  143. CarlaScopedPointer is impossible, as that would involve the new copy taking ownership from the
  144. old one.
  145. If you need to get a pointer out of a CarlaScopedPointer without it being deleted, you
  146. can use the release() method.
  147. Something to note is the main difference between this class and the std::auto_ptr class,
  148. which is that CarlaScopedPointer provides a cast-to-object operator, whereas std::auto_ptr
  149. requires that you always call get() to retrieve the pointer. The advantages of providing
  150. the cast is that you don't need to call get(), so can use the CarlaScopedPointer in pretty much
  151. exactly the same way as a raw pointer. The disadvantage is that the compiler is free to
  152. use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult
  153. to return a CarlaScopedPointer as the result of a function. To avoid this causing errors,
  154. CarlaScopedPointer contains an overloaded constructor that should cause a syntax error in these
  155. circumstances, but it does mean that instead of returning a CarlaScopedPointer from a function,
  156. you'd need to return a raw pointer (or use a std::auto_ptr instead).
  157. */
  158. template<class ObjectType>
  159. class CarlaScopedPointer
  160. {
  161. public:
  162. //=================================================================================================================
  163. /** Creates a CarlaScopedPointer containing a null pointer. */
  164. CarlaScopedPointer() noexcept
  165. : object(nullptr) {}
  166. /** Creates a CarlaScopedPointer that owns the specified object. */
  167. CarlaScopedPointer(ObjectType* const objectToTakePossessionOf) noexcept
  168. : object(objectToTakePossessionOf) {}
  169. /** Creates a CarlaScopedPointer that takes its pointer from another CarlaScopedPointer.
  170. Because a pointer can only belong to one CarlaScopedPointer, this transfers
  171. the pointer from the other object to this one, and the other object is reset to
  172. be a null pointer.
  173. */
  174. CarlaScopedPointer(CarlaScopedPointer& objectToTransferFrom) noexcept
  175. : object(objectToTransferFrom.object)
  176. {
  177. objectToTransferFrom.object = nullptr;
  178. }
  179. /** Destructor.
  180. This will delete the object that this CarlaScopedPointer currently refers to.
  181. */
  182. ~CarlaScopedPointer()
  183. {
  184. delete object;
  185. }
  186. /** Changes this CarlaScopedPointer to point to a new object.
  187. Because a pointer can only belong to one CarlaScopedPointer, this transfers
  188. the pointer from the other object to this one, and the other object is reset to
  189. be a null pointer.
  190. If this CarlaScopedPointer already points to an object, that object
  191. will first be deleted.
  192. */
  193. CarlaScopedPointer& operator=(CarlaScopedPointer& objectToTransferFrom)
  194. {
  195. if (this != objectToTransferFrom.getAddress())
  196. {
  197. // Two CarlaScopedPointers should never be able to refer to the same object - if
  198. // this happens, you must have done something dodgy!
  199. CARLA_SAFE_ASSERT_RETURN(object == nullptr || object != objectToTransferFrom.object, *this);
  200. ObjectType* const oldObject = object;
  201. object = objectToTransferFrom.object;
  202. objectToTransferFrom.object = nullptr;
  203. delete oldObject;
  204. }
  205. return *this;
  206. }
  207. /** Changes this CarlaScopedPointer to point to a new object.
  208. If this CarlaScopedPointer already points to an object, that object
  209. will first be deleted.
  210. The pointer that you pass in may be a nullptr.
  211. */
  212. CarlaScopedPointer& operator=(ObjectType* const newObjectToTakePossessionOf)
  213. {
  214. if (object != newObjectToTakePossessionOf)
  215. {
  216. ObjectType* const oldObject = object;
  217. object = newObjectToTakePossessionOf;
  218. delete oldObject;
  219. }
  220. return *this;
  221. }
  222. //=================================================================================================================
  223. /** Returns the object that this CarlaScopedPointer refers to. */
  224. operator ObjectType*() const noexcept { return object; }
  225. /** Returns the object that this CarlaScopedPointer refers to. */
  226. ObjectType* get() const noexcept { return object; }
  227. /** Returns the object that this CarlaScopedPointer refers to. */
  228. ObjectType& operator*() const noexcept { return *object; }
  229. /** Lets you access methods and properties of the object that this CarlaScopedPointer refers to. */
  230. ObjectType* operator->() const noexcept { return object; }
  231. //=================================================================================================================
  232. /** Removes the current object from this CarlaScopedPointer without deleting it.
  233. This will return the current object, and set the CarlaScopedPointer to a null pointer.
  234. */
  235. ObjectType* release() noexcept { ObjectType* const o = object; object = nullptr; return o; }
  236. //=================================================================================================================
  237. /** Swaps this object with that of another CarlaScopedPointer.
  238. The two objects simply exchange their pointers.
  239. */
  240. void swapWith(CarlaScopedPointer<ObjectType>& other) noexcept
  241. {
  242. // Two CarlaScopedPointers should never be able to refer to the same object - if
  243. // this happens, you must have done something dodgy!
  244. CARLA_SAFE_ASSERT_RETURN(object != other.object || this == other.getAddress() || object == nullptr,);
  245. std::swap(object, other.object);
  246. }
  247. private:
  248. //=================================================================================================================
  249. ObjectType* object;
  250. // (Required as an alternative to the overloaded & operator).
  251. const CarlaScopedPointer* getAddress() const noexcept { return this; }
  252. #ifdef CARLA_PROPER_CPP11_SUPPORT
  253. CarlaScopedPointer(const CarlaScopedPointer&) = delete;
  254. CarlaScopedPointer& operator=(const CarlaScopedPointer&) = delete;
  255. #else
  256. CarlaScopedPointer(const CarlaScopedPointer&);
  257. CarlaScopedPointer& operator=(const CarlaScopedPointer&);
  258. #endif
  259. };
  260. //=====================================================================================================================
  261. /** Compares a CarlaScopedPointer with another pointer.
  262. This can be handy for checking whether this is a null pointer.
  263. */
  264. template<class ObjectType>
  265. bool operator==(const CarlaScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
  266. {
  267. return static_cast<ObjectType*>(pointer1) == pointer2;
  268. }
  269. /** Compares a CarlaScopedPointer with another pointer.
  270. This can be handy for checking whether this is a null pointer.
  271. */
  272. template<class ObjectType>
  273. bool operator!=(const CarlaScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
  274. {
  275. return static_cast<ObjectType*>(pointer1) != pointer2;
  276. }
  277. //=====================================================================================================================
  278. /**
  279. Helper class providing an RAII-based mechanism for temporarily setting and
  280. then re-setting a value.
  281. E.g. @code
  282. int x = 1;
  283. {
  284. CarlaScopedValueSetter setter (x, 2);
  285. // x is now 2
  286. }
  287. // x is now 1 again
  288. {
  289. CarlaScopedValueSetter setter (x, 3, 4);
  290. // x is now 3
  291. }
  292. // x is now 4
  293. @endcode
  294. */
  295. template <typename ValueType>
  296. class CarlaScopedValueSetter
  297. {
  298. public:
  299. /** Creates a CarlaScopedValueSetter that will immediately change the specified value to the
  300. given new value, and will then reset it to its original value when this object is deleted.
  301. Must be used only for 'noexcept' compatible types.
  302. */
  303. CarlaScopedValueSetter(ValueType& valueToSet, ValueType newValue) noexcept
  304. : value(valueToSet),
  305. originalValue(valueToSet)
  306. {
  307. valueToSet = newValue;
  308. }
  309. /** Creates a CarlaScopedValueSetter that will immediately change the specified value to the
  310. given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
  311. */
  312. CarlaScopedValueSetter(ValueType& valueToSet, ValueType newValue, ValueType valueWhenDeleted) noexcept
  313. : value(valueToSet),
  314. originalValue(valueWhenDeleted)
  315. {
  316. valueToSet = newValue;
  317. }
  318. ~CarlaScopedValueSetter() noexcept
  319. {
  320. value = originalValue;
  321. }
  322. private:
  323. //=================================================================================================================
  324. ValueType& value;
  325. const ValueType originalValue;
  326. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopedValueSetter)
  327. CARLA_PREVENT_HEAP_ALLOCATION
  328. };
  329. // -----------------------------------------------------------------------
  330. #endif // CARLA_SCOPE_UTILS_HPP_INCLUDED