PROJ C++ API
util.hpp
1 /******************************************************************************
2  *
3  * Project: PROJ
4  * Purpose: ISO19111:2018 implementation
5  * Author: Even Rouault <even dot rouault at spatialys dot com>
6  *
7  ******************************************************************************
8  * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #ifndef UTIL_HH_INCLUDED
30 #define UTIL_HH_INCLUDED
31 
32 #if !(__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900))
33 #error Must have C++11 or newer.
34 #endif
35 
36 #include <exception>
37 #include <map>
38 #include <memory>
39 #include <string>
40 #include <vector>
41 
42 #ifndef NS_PROJ
43 
44 namespace osgeo {
46 namespace proj {}
47 } // namespace osgeo
48 #endif
49 
51 
52 #ifndef PROJ_DLL
53 #ifdef PROJ_MSVC_DLL_EXPORT
54 #define PROJ_DLL __declspec(dllexport)
55 #elif defined(PROJ_MSVC_DLL_IMPORT)
56 #define PROJ_DLL __declspec(dllimport)
57 #else
58 #define PROJ_DLL
59 #endif
60 #endif
61 
62 #include "nn.hpp"
63 
64 /* To allow customizing the base namespace of PROJ */
65 #ifndef NS_PROJ
66 #define NS_PROJ osgeo::proj
67 #define NS_PROJ_START \
68  namespace osgeo { \
69  namespace proj {
70 #define NS_PROJ_END \
71  } \
72  }
73 #endif
74 
75 // Private-implementation (Pimpl) pattern
76 #define PROJ_OPAQUE_PRIVATE_DATA \
77  private: \
78  struct Private; \
79  std::unique_ptr<Private> d; \
80  \
81  protected: \
82  Private *getPrivate() noexcept { return d.get(); } \
83  const Private *getPrivate() const noexcept { return d.get(); } \
84  \
85  private:
86 
87 // To include in the protected/private section of a class definition,
88 // to be able to call make_shared on a protected/private constructor
89 #define INLINED_MAKE_SHARED \
90  template <typename T, typename... Args> \
91  static std::shared_ptr<T> make_shared(Args &&... args) { \
92  return std::shared_ptr<T>(new T(std::forward<Args>(args)...)); \
93  } \
94  template <typename T, typename... Args> \
95  static util::nn_shared_ptr<T> nn_make_shared(Args &&... args) { \
96  return util::nn_shared_ptr<T>( \
97  util::i_promise_i_checked_for_null, \
98  std::shared_ptr<T>(new T(std::forward<Args>(args)...))); \
99  }
100 
101 // To include in the protected/private section of a class definition,
102 // to be able to call make_unique on a protected/private constructor
103 #define INLINED_MAKE_UNIQUE \
104  template <typename T, typename... Args> \
105  static std::unique_ptr<T> make_unique(Args &&... args) { \
106  return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); \
107  }
108 
109 #ifdef DOXYGEN_ENABLED
110 #define PROJ_FRIEND(mytype)
111 #define PROJ_FRIEND_OPTIONAL(mytype)
112 #else
113 #define PROJ_FRIEND(mytype) friend class mytype
114 #define PROJ_FRIEND_OPTIONAL(mytype) friend class util::optional<mytype>
115 #endif
116 
117 #ifndef PROJ_PRIVATE
118 #define PROJ_PRIVATE public
119 #endif
120 
121 #if defined(__GNUC__)
122 #define PROJ_NO_INLINE __attribute__((noinline))
123 #define PROJ_NO_RETURN __attribute__((noreturn))
124 // Applies to a function that has no side effect, and its return will not
125 // change if the arguments are the same. But is return may change
126 // if the object state changes. So this is for getters of mutable objects.
127 #define PROJ_PURE_DECL const noexcept __attribute__((pure))
128 // Applies to a function that has no side effect, and its return will not
129 // change if the arguments are the same, and their pointed value must not
130 // be modified. So this is for getters of immutable objets. This is stronger
131 // than PROJ_PURE_DECL.
132 #define PROJ_CONST_DECL const noexcept __attribute__((const))
133 #else
134 #define PROJ_NO_RETURN
135 #define PROJ_NO_INLINE
136 #define PROJ_PURE_DECL const noexcept
137 #define PROJ_CONST_DECL const noexcept
138 #endif
139 #define PROJ_PURE_DEFN const noexcept
140 #define PROJ_CONST_DEFN const noexcept
141 
143 
144 NS_PROJ_START
145 
151 namespace util {
152 
154 // Import a few classes from nn.hpp to expose them under our ::util namespace
155 // for conveniency.
156 using ::dropbox::oxygen::i_promise_i_checked_for_null;
157 using ::dropbox::oxygen::nn;
158 using ::dropbox::oxygen::nn_dynamic_pointer_cast;
159 using ::dropbox::oxygen::nn_make_shared;
160 
161 // For return statements, to convert from derived type to base type
162 using ::dropbox::oxygen::nn_static_pointer_cast;
163 
164 template <typename T> using nn_shared_ptr = nn<std::shared_ptr<T>>;
165 
166 #define NN_NO_CHECK(p) \
167  ::dropbox::oxygen::nn<typename std::remove_const< \
168  typename std::remove_reference<decltype(p)>::type>::type>( \
169  dropbox::oxygen::i_promise_i_checked_for_null, (p))
170 
172 
173 // To avoid formatting differences between clang-format 3.8 and 7
174 #define PROJ_NOEXCEPT noexcept
175 
178 template <class T> class optional {
179  public:
181  inline optional() : hasVal_(false) {}
182  inline explicit optional(const T &val) : hasVal_(true), val_(val) {}
183  inline explicit optional(T &&val)
184  : hasVal_(true), val_(std::forward<T>(val)) {}
185 
186  inline optional(const optional &other) = default;
187  inline optional(optional &&other) PROJ_NOEXCEPT
188  : hasVal_(other.hasVal_),
189  // cppcheck-suppress functionStatic
190  val_(std::forward<T>(other.val_)) {
191  other.hasVal_ = false;
192  }
193 
194  inline optional &operator=(const T &val) {
195  hasVal_ = true;
196  val_ = val;
197  return *this;
198  }
199  inline optional &operator=(T &&val) noexcept {
200  hasVal_ = true;
201  val_ = std::forward<T>(val);
202  return *this;
203  }
204  inline optional &operator=(const optional &other) = default;
205  inline optional &operator=(optional &&other) noexcept {
206  hasVal_ = other.hasVal_;
207  val_ = std::forward<T>(other.val_);
208  other.hasVal_ = false;
209  return *this;
210  }
211 
212  inline T *operator->() { return &val_; }
213  inline T &operator*() { return val_; }
214 
216 
218  inline const T *operator->() const { return &val_; }
219 
221  inline const T &operator*() const { return val_; }
222 
224  inline explicit operator bool() const noexcept { return hasVal_; }
225 
227  inline bool has_value() const noexcept { return hasVal_; }
228 
229  private:
230  bool hasVal_;
231  T val_{};
232 };
233 
234 // ---------------------------------------------------------------------------
235 
236 class BaseObject;
238 using BaseObjectPtr = std::shared_ptr<BaseObject>;
239 #if 1
240 
241 struct BaseObjectNNPtr : public util::nn<BaseObjectPtr> {
242  // This trick enables to avoid inlining of the destructor.
243  // This is mostly an alias of the base class.
245  template <class T>
246  // cppcheck-suppress noExplicitConstructor
247  BaseObjectNNPtr(const util::nn<std::shared_ptr<T>> &x)
248  : util::nn<BaseObjectPtr>(x) {}
249  template <class T>
250  BaseObjectNNPtr(util::nn<std::shared_ptr<T>> &&x) noexcept
251  : util::nn<BaseObjectPtr>(NN_NO_CHECK(std::move(x.as_nullable()))) {}
252  explicit BaseObjectNNPtr(::dropbox::oxygen::i_promise_i_checked_for_null_t,
253  BaseObjectPtr &&arg) noexcept
254  : util::nn<BaseObjectPtr>(i_promise_i_checked_for_null,
255  std::move(arg)) {}
256  BaseObjectNNPtr(const BaseObjectNNPtr &) = default;
257  BaseObjectNNPtr &operator=(const BaseObjectNNPtr &) = default;
258 
259  PROJ_DLL ~BaseObjectNNPtr();
261 };
262 #else
263 using BaseObjectNNPtr = util::nn<BaseObjectPtr>;
264 #endif
265 
268 class BaseObject {
269  public:
271  virtual PROJ_DLL ~BaseObject();
273 
274  PROJ_PRIVATE :
276  PROJ_DLL BaseObjectNNPtr
277  shared_from_this() const;
279 
280  protected:
281  PROJ_DLL BaseObject();
282  PROJ_DLL void assignSelf(const BaseObjectNNPtr &self);
283 
284  private:
285  PROJ_OPAQUE_PRIVATE_DATA
286 };
287 
288 // ---------------------------------------------------------------------------
289 
292 class IComparable {
293  public:
295  PROJ_DLL virtual ~IComparable();
297 
299  enum class PROJ_DLL Criterion {
301  STRICT,
303  EQUIVALENT
304  };
305 
311  PROJ_DLL virtual bool
312  isEquivalentTo(const IComparable *other,
313  Criterion criterion = Criterion::STRICT) const = 0;
314 };
315 
316 // ---------------------------------------------------------------------------
317 
320 class BoxedValue final : public BaseObject {
321  public:
323 
324  enum class Type {
326  STRING,
328  INTEGER,
330  BOOLEAN
331  };
333 
334  // cppcheck-suppress noExplicitConstructor
335  PROJ_DLL BoxedValue(const char *stringValueIn); // needed to avoid the bool
336  // constructor to be taken !
337  // cppcheck-suppress noExplicitConstructor
338  PROJ_DLL BoxedValue(const std::string &stringValueIn);
339  // cppcheck-suppress noExplicitConstructor
340  PROJ_DLL BoxedValue(int integerValueIn);
341  // cppcheck-suppress noExplicitConstructor
342  PROJ_DLL BoxedValue(bool booleanValueIn);
343 
344  PROJ_PRIVATE :
346  PROJ_DLL
347  BoxedValue(const BoxedValue &other);
348 
349  PROJ_DLL ~BoxedValue() override;
350 
351  PROJ_DLL const Type &type() const;
352  PROJ_DLL const std::string &stringValue() const;
353  PROJ_DLL int integerValue() const;
354  PROJ_DLL bool booleanValue() const;
356 
357  private:
358  PROJ_OPAQUE_PRIVATE_DATA
359  BoxedValue &operator=(const BoxedValue &) = delete;
360 
361  BoxedValue();
362 };
363 
365 using BoxedValuePtr = std::shared_ptr<BoxedValue>;
367 using BoxedValueNNPtr = util::nn<BoxedValuePtr>;
368 
369 // ---------------------------------------------------------------------------
370 
371 class ArrayOfBaseObject;
373 using ArrayOfBaseObjectPtr = std::shared_ptr<ArrayOfBaseObject>;
375 using ArrayOfBaseObjectNNPtr = util::nn<ArrayOfBaseObjectPtr>;
376 
379 class ArrayOfBaseObject final : public BaseObject {
380  public:
382  PROJ_DLL ~ArrayOfBaseObject() override;
384 
385  PROJ_DLL void add(const BaseObjectNNPtr &obj);
386 
387  PROJ_DLL static ArrayOfBaseObjectNNPtr create();
388 
389  PROJ_PRIVATE :
391  std::vector<BaseObjectNNPtr>::const_iterator
392  begin() const;
393  std::vector<BaseObjectNNPtr>::const_iterator end() const;
394  bool empty() const;
396 
397  protected:
399  INLINED_MAKE_SHARED
400 
401  private:
402  ArrayOfBaseObject(const ArrayOfBaseObject &other) = delete;
403  ArrayOfBaseObject &operator=(const ArrayOfBaseObject &other) = delete;
404  PROJ_OPAQUE_PRIVATE_DATA
405 };
406 
407 // ---------------------------------------------------------------------------
408 
410 class PropertyMap {
411  public:
412  PROJ_DLL PropertyMap();
414  PROJ_DLL PropertyMap(const PropertyMap &other);
415  PROJ_DLL ~PropertyMap();
417 
418  PROJ_DLL PropertyMap &set(const std::string &key,
419  const BaseObjectNNPtr &val);
420 
422  template <class T>
423  inline PropertyMap &set(const std::string &key,
424  const nn_shared_ptr<T> &val) {
425  return set(
426  key, BaseObjectNNPtr(i_promise_i_checked_for_null,
427  BaseObjectPtr(val.as_nullable(), val.get())));
428  }
430 
431  // needed to avoid the bool constructor to be taken !
432  PROJ_DLL PropertyMap &set(const std::string &key, const char *val);
433 
434  PROJ_DLL PropertyMap &set(const std::string &key, const std::string &val);
435 
436  PROJ_DLL PropertyMap &set(const std::string &key, int val);
437 
438  PROJ_DLL PropertyMap &set(const std::string &key, bool val);
439 
440  PROJ_DLL PropertyMap &set(const std::string &key,
441  const std::vector<std::string> &array);
442 
443  PROJ_PRIVATE :
445  std::map<std::string, BaseObjectNNPtr>::iterator
446  find(const std::string &key) const;
447  std::map<std::string, BaseObjectNNPtr>::iterator end() const;
448 
449  // throw(InvalidValueTypeException)
450  bool getStringValue(const std::string &key, std::string &outVal) const;
451 
452  static PropertyMap createAndSetName(const char *name);
453  static PropertyMap createAndSetName(const std::string &name);
455 
456  private:
457  PropertyMap &operator=(const PropertyMap &) = delete;
458 
459  PropertyMap &set(const std::string &key, const BoxedValue &val);
460 
461  PROJ_OPAQUE_PRIVATE_DATA
462 };
463 
464 // ---------------------------------------------------------------------------
465 
466 class LocalName;
468 using LocalNamePtr = std::shared_ptr<LocalName>;
470 using LocalNameNNPtr = util::nn<LocalNamePtr>;
471 
472 class NameSpace;
474 using NameSpacePtr = std::shared_ptr<NameSpace>;
476 using NameSpaceNNPtr = util::nn<NameSpacePtr>;
477 
478 class GenericName;
480 using GenericNamePtr = std::shared_ptr<GenericName>;
482 using GenericNameNNPtr = util::nn<GenericNamePtr>;
483 
484 // ---------------------------------------------------------------------------
485 
492 class GenericName : public BaseObject {
493  public:
495  PROJ_DLL virtual ~GenericName() override;
497 
499  PROJ_DLL virtual const NameSpacePtr scope() const = 0;
500 
502  PROJ_DLL virtual std::string toString() const = 0;
503 
508  PROJ_DLL virtual GenericNameNNPtr toFullyQualifiedName() const = 0;
509 
510  protected:
511  GenericName();
512  GenericName(const GenericName &other);
513 
514  private:
515  PROJ_OPAQUE_PRIVATE_DATA
516  GenericName &operator=(const GenericName &other) = delete;
517 };
518 
519 // ---------------------------------------------------------------------------
520 
527 class NameSpace {
528  public:
530  PROJ_DLL ~NameSpace();
532 
533  PROJ_DLL bool isGlobal() const;
534  PROJ_DLL const GenericNamePtr &name() const;
535 
536  protected:
537  PROJ_FRIEND(NameFactory);
538  PROJ_FRIEND(LocalName);
539  explicit NameSpace(const GenericNamePtr &name);
540  NameSpace(const NameSpace &other);
541  NameSpaceNNPtr getGlobalFromThis() const;
542  const std::string &separator() const;
543  static const NameSpaceNNPtr GLOBAL;
544  INLINED_MAKE_SHARED
545 
546  private:
547  PROJ_OPAQUE_PRIVATE_DATA
548  NameSpace &operator=(const NameSpace &other) = delete;
549 
550  static NameSpaceNNPtr createGLOBAL();
551 };
552 
553 // ---------------------------------------------------------------------------
554 
564 class LocalName : public GenericName {
565  public:
567  PROJ_DLL ~LocalName() override;
569 
570  PROJ_DLL const NameSpacePtr scope() const override;
571  PROJ_DLL std::string toString() const override;
572  PROJ_DLL GenericNameNNPtr toFullyQualifiedName() const override;
573 
574  protected:
575  PROJ_FRIEND(NameFactory);
576  PROJ_FRIEND(NameSpace);
577  explicit LocalName(const std::string &nameIn);
578  LocalName(const LocalName &other);
579  LocalName(const NameSpacePtr &ns, const std::string &name);
580  INLINED_MAKE_SHARED
581 
582  private:
583  PROJ_OPAQUE_PRIVATE_DATA
584  LocalName &operator=(const LocalName &other) = delete;
585 };
586 
587 // ---------------------------------------------------------------------------
588 
595 class NameFactory {
596  public:
597  PROJ_DLL static NameSpaceNNPtr
598  createNameSpace(const GenericNameNNPtr &name,
599  const PropertyMap &properties);
600  PROJ_DLL static LocalNameNNPtr createLocalName(const NameSpacePtr &scope,
601  const std::string &name);
602  PROJ_DLL static GenericNameNNPtr
603  createGenericName(const NameSpacePtr &scope,
604  const std::vector<std::string> &parsedNames);
605 };
606 
607 // ---------------------------------------------------------------------------
608 
611 class CodeList {
612  public:
614  PROJ_DLL ~CodeList();
616 
618  // cppcheck-suppress functionStatic
619  inline const std::string &toString() PROJ_CONST_DECL { return name_; }
620 
622  inline operator std::string() PROJ_CONST_DECL { return toString(); }
623 
625  inline bool operator==(const CodeList &other) PROJ_CONST_DECL {
626  return name_ == other.name_;
627  }
628  inline bool operator!=(const CodeList &other) PROJ_CONST_DECL {
629  return name_ != other.name_;
630  }
632  protected:
633  explicit CodeList(const std::string &nameIn) : name_(nameIn) {}
634  CodeList(const CodeList &other) = default;
635  CodeList &operator=(const CodeList &other);
636 
637  private:
638  std::string name_{};
639 };
640 
641 // ---------------------------------------------------------------------------
642 
645 class Exception : public std::exception {
646  std::string msg_;
647 
648  public:
650  PROJ_DLL explicit Exception(const char *message);
651  PROJ_DLL explicit Exception(const std::string &message);
652  PROJ_DLL Exception(const Exception &other);
653  PROJ_DLL ~Exception() override;
655  PROJ_DLL virtual const char *what() const noexcept override;
656 };
657 
658 // ---------------------------------------------------------------------------
659 
664  public:
666  PROJ_DLL explicit InvalidValueTypeException(const char *message);
667  PROJ_DLL explicit InvalidValueTypeException(const std::string &message);
668  PROJ_DLL InvalidValueTypeException(const InvalidValueTypeException &other);
669  PROJ_DLL ~InvalidValueTypeException() override;
671 };
672 
673 // ---------------------------------------------------------------------------
674 
679  public:
681  PROJ_DLL explicit UnsupportedOperationException(const char *message);
682  PROJ_DLL explicit UnsupportedOperationException(const std::string &message);
683  PROJ_DLL
684  UnsupportedOperationException(const UnsupportedOperationException &other);
685  PROJ_DLL ~UnsupportedOperationException() override;
687 };
688 
689 } // namespace util
690 
691 NS_PROJ_END
692 
693 #endif // UTIL_HH_INCLUDED
Interface for an object that can be compared to another.
Definition: util.hpp:292
Abstract class to define an enumeration of values.
Definition: util.hpp:611
Definition: util.hpp:241
std::shared_ptr< NameSpace > NameSpacePtr
Definition: util.hpp:474
std::shared_ptr< ArrayOfBaseObject > ArrayOfBaseObjectPtr
Definition: util.hpp:373
std::shared_ptr< LocalName > LocalNamePtr
Definition: util.hpp:468
A sequence of identifiers rooted within the context of a namespace.
Definition: util.hpp:492
Factory for generic names.
Definition: util.hpp:595
Root exception class.
Definition: util.hpp:645
bool has_value() const noexcept
Definition: util.hpp:227
std::shared_ptr< BaseObject > BaseObjectPtr
Definition: util.hpp:238
Array of BaseObject.
Definition: util.hpp:379
Encapsulate standard datatypes in an object.
Definition: util.hpp:320
Criterion
Comparison criterion.
Definition: util.hpp:299
Exception thrown when an invalid value type is set as the value of a key of a PropertyMap.
Definition: util.hpp:663
std::shared_ptr< GenericName > GenericNamePtr
Definition: util.hpp:480
util::nn< LocalNamePtr > LocalNameNNPtr
Definition: util.hpp:470
util::nn< ArrayOfBaseObjectPtr > ArrayOfBaseObjectNNPtr
Definition: util.hpp:375
const T * operator->() const
Definition: util.hpp:218
Wrapper of a std::map<std::string, BaseObjectNNPtr>
Definition: util.hpp:410
const std::string & toString() PROJ_CONST_DECL
Definition: util.hpp:619
Definition: common.cpp:63
Class that can be derived from, to emulate Java&#39;s Object behaviour.
Definition: util.hpp:268
util::nn< GenericNamePtr > GenericNameNNPtr
Definition: util.hpp:482
Exception Thrown to indicate that the requested operation is not supported.
Definition: util.hpp:678
std::shared_ptr< BoxedValue > BoxedValuePtr
Definition: util.hpp:365
Identifier within a NameSpace for a local object.
Definition: util.hpp:564
util::nn< BoxedValuePtr > BoxedValueNNPtr
Definition: util.hpp:367
Loose transposition of std::optional available from C++17.
Definition: util.hpp:178
const T & operator*() const
Definition: util.hpp:221
A domain in which names given by strings are defined.
Definition: util.hpp:527
util::nn< NameSpacePtr > NameSpaceNNPtr
Definition: util.hpp:476