Add dap::initialize() and terminate() functions

Can be used to explicitly control when the TypeInfo static initializers / destructors are called.
Usually not needed.

Issue: #40
diff --git a/include/dap/dap.h b/include/dap/dap.h
new file mode 100644
index 0000000..587e80c
--- /dev/null
+++ b/include/dap/dap.h
@@ -0,0 +1,35 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef dap_dap_h
+#define dap_dap_h
+
+namespace dap {
+
+// Explicit library initialization and termination functions.
+//
+// cppdap automatically initializes and terminates its internal state using lazy
+// static initialization, and so will usually work fine without explicit calls
+// to these functions.
+// However, if you use cppdap types in global state, you may need to call these
+// functions to ensure that cppdap is not uninitialized before the last usage.
+//
+// Each call to initialize() must have a corresponding call to terminate().
+// It is undefined behaviour to call initialize() after terminate().
+void initialize();
+void terminate();
+
+}  // namespace dap
+
+#endif  // dap_dap_h
diff --git a/include/dap/typeinfo.h b/include/dap/typeinfo.h
index 11f1f12..d99f277 100644
--- a/include/dap/typeinfo.h
+++ b/include/dap/typeinfo.h
@@ -37,6 +37,21 @@
   virtual void destruct(void*) const = 0;
   virtual bool deserialize(const Deserializer*, void*) const = 0;
   virtual bool serialize(Serializer*, const void*) const = 0;
+
+  // create() allocates and constructs the TypeInfo of type T, registers the
+  // pointer for deletion on cppdap library termination, and returns the pointer
+  // to T.
+  template <typename T, typename... ARGS>
+  static T* create(ARGS&&... args) {
+    auto typeinfo = new T(std::forward<ARGS>(args)...);
+    deleteOnExit(typeinfo);
+    return typeinfo;
+  }
+
+ private:
+  // deleteOnExit() ensures that the TypeInfo is destructed and deleted on
+  // library termination.
+  static void deleteOnExit(TypeInfo*);
 };
 
 }  // namespace dap
diff --git a/include/dap/typeof.h b/include/dap/typeof.h
index ba2b045..1ed0dc7 100644
--- a/include/dap/typeof.h
+++ b/include/dap/typeof.h
@@ -29,18 +29,20 @@
   constexpr BasicTypeInfo(std::string&& name) : name_(std::move(name)) {}
 
   // TypeInfo compliance
-  inline std::string name() const { return name_; }
-  inline size_t size() const { return sizeof(T); }
-  inline size_t alignment() const { return alignof(T); }
-  inline void construct(void* ptr) const { new (ptr) T(); }
-  inline void copyConstruct(void* dst, const void* src) const {
+  inline std::string name() const override { return name_; }
+  inline size_t size() const override { return sizeof(T); }
+  inline size_t alignment() const override { return alignof(T); }
+  inline void construct(void* ptr) const override { new (ptr) T(); }
+  inline void copyConstruct(void* dst, const void* src) const override {
     new (dst) T(*reinterpret_cast<const T*>(src));
   }
-  inline void destruct(void* ptr) const { reinterpret_cast<T*>(ptr)->~T(); }
-  inline bool deserialize(const Deserializer* d, void* ptr) const {
+  inline void destruct(void* ptr) const override {
+    reinterpret_cast<T*>(ptr)->~T();
+  }
+  inline bool deserialize(const Deserializer* d, void* ptr) const override {
     return d->deserialize(reinterpret_cast<T*>(ptr));
   }
-  inline bool serialize(Serializer* s, const void* ptr) const {
+  inline bool serialize(Serializer* s, const void* ptr) const override {
     return s->serialize(*reinterpret_cast<const T*>(ptr));
   }
 
@@ -88,45 +90,33 @@
   static const TypeInfo* type();
 };
 
-// TypeOf for template types requires dynamic generation of type information,
-// triggering the clang -Wexit-time-destructors warning.
-// TODO(bclayton): See if there's a way to avoid this, without requiring manual
-// instantiation of each type.
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wexit-time-destructors"
-#endif  // __clang__
-
 template <typename T>
 struct TypeOf<array<T>> {
   static inline const TypeInfo* type() {
-    static BasicTypeInfo<array<T>> typeinfo("array<" +
-                                            TypeOf<T>::type()->name() + ">");
-    return &typeinfo;
+    static auto typeinfo = TypeInfo::create<BasicTypeInfo<array<T>>>(
+        "array<" + TypeOf<T>::type()->name() + ">");
+    return typeinfo;
   }
 };
 
 template <typename T0, typename... Types>
 struct TypeOf<variant<T0, Types...>> {
   static inline const TypeInfo* type() {
-    static BasicTypeInfo<variant<T0, Types...>> typeinfo("variant");
-    return &typeinfo;
+    static auto typeinfo =
+        TypeInfo::create<BasicTypeInfo<variant<T0, Types...>>>("variant");
+    return typeinfo;
   }
 };
 
 template <typename T>
 struct TypeOf<optional<T>> {
   static inline const TypeInfo* type() {
-    static BasicTypeInfo<optional<T>> typeinfo("optional<" +
-                                               TypeOf<T>::type()->name() + ">");
-    return &typeinfo;
+    static auto typeinfo = TypeInfo::create<BasicTypeInfo<optional<T>>>(
+        "optional<" + TypeOf<T>::type()->name() + ">");
+    return typeinfo;
   }
 };
 
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif  // __clang__
-
 // DAP_OFFSETOF() macro is a generalization of the offsetof() macro defined in
 // <cstddef>. It evaluates to the offset of the given field, with fewer
 // restrictions than offsetof(). We cast the address '32' and subtract it again,
diff --git a/src/dap_test.cpp b/src/dap_test.cpp
index c895d0f..f31be46 100644
--- a/src/dap_test.cpp
+++ b/src/dap_test.cpp
@@ -12,10 +12,61 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "dap/dap.h"
+
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <vector>
+
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
 }
+
+TEST(DAP, PairedInitializeTerminate) {
+  dap::initialize();
+  dap::terminate();
+}
+
+TEST(DAP, NestedInitializeTerminate) {
+  dap::initialize();
+  dap::initialize();
+  dap::initialize();
+  dap::terminate();
+  dap::terminate();
+  dap::terminate();
+}
+
+TEST(DAP, MultiThreadedInitializeTerminate) {
+  const size_t numThreads = 64;
+
+  std::mutex mutex;
+  std::condition_variable cv;
+  size_t numInits = 0;
+
+  std::vector<std::thread> threads;
+  threads.reserve(numThreads);
+  for (size_t i = 0; i < numThreads; i++) {
+    threads.emplace_back([&] {
+      dap::initialize();
+      {
+        std::unique_lock<std::mutex> lock(mutex);
+        numInits++;
+        if (numInits == numThreads) {
+          cv.notify_all();
+        } else {
+          cv.wait(lock, [&] { return numInits == numThreads; });
+        }
+      }
+      dap::terminate();
+    });
+  }
+
+  for (auto& thread : threads) {
+    thread.join();
+  }
+}
diff --git a/src/typeof.cpp b/src/typeof.cpp
index 77c85ae..a5685d3 100644
--- a/src/typeof.cpp
+++ b/src/typeof.cpp
@@ -14,58 +14,131 @@
 
 #include "dap/typeof.h"
 
+#include <atomic>
+#include <memory>
+#include <vector>
+
 namespace {
 
-struct NullTI : public dap::TypeInfo {
-  using null = dap::null;
-  inline std::string name() const { return "null"; }
-  inline size_t size() const { return sizeof(null); }
-  inline size_t alignment() const { return alignof(null); }
-  inline void construct(void* ptr) const { new (ptr) null(); }
-  inline void copyConstruct(void* dst, const void* src) const {
-    new (dst) null(*reinterpret_cast<const null*>(src));
+// TypeInfos owns all the dap::TypeInfo instances.
+struct TypeInfos {
+  // get() returns the TypeInfos singleton pointer.
+  // TypeInfos is constructed with an internal reference count of 1.
+  static TypeInfos* get();
+
+  // reference() increments the TypeInfos reference count.
+  inline void reference() {
+    assert(refcount.load() > 0);
+    refcount++;
   }
-  inline void destruct(void* ptr) const {
-    reinterpret_cast<null*>(ptr)->~null();
+
+  // release() decrements the TypeInfos reference count.
+  // If the reference count becomes 0, then the TypeInfos is destructed.
+  inline void release() {
+    if (--refcount == 0) {
+      this->~TypeInfos();
+    }
   }
-  inline bool deserialize(const dap::Deserializer*, void*) const {
-    return true;
-  }
-  inline bool serialize(dap::Serializer*, const void*) const { return true; }
+
+  struct NullTI : public dap::TypeInfo {
+    using null = dap::null;
+    inline std::string name() const override { return "null"; }
+    inline size_t size() const override { return sizeof(null); }
+    inline size_t alignment() const override { return alignof(null); }
+    inline void construct(void* ptr) const override { new (ptr) null(); }
+    inline void copyConstruct(void* dst, const void* src) const override {
+      new (dst) null(*reinterpret_cast<const null*>(src));
+    }
+    inline void destruct(void* ptr) const override {
+      reinterpret_cast<null*>(ptr)->~null();
+    }
+    inline bool deserialize(const dap::Deserializer*, void*) const override {
+      return true;
+    }
+    inline bool serialize(dap::Serializer*, const void*) const override {
+      return true;
+    }
+  };
+
+  dap::BasicTypeInfo<dap::boolean> boolean = {"boolean"};
+  dap::BasicTypeInfo<dap::string> string = {"string"};
+  dap::BasicTypeInfo<dap::integer> integer = {"integer"};
+  dap::BasicTypeInfo<dap::number> number = {"number"};
+  dap::BasicTypeInfo<dap::object> object = {"object"};
+  dap::BasicTypeInfo<dap::any> any = {"any"};
+  NullTI null;
+  std::vector<std::unique_ptr<dap::TypeInfo>> types;
+
+ private:
+  TypeInfos() = default;
+  ~TypeInfos() = default;
+  std::atomic<uint64_t> refcount = {1};
 };
 
-static dap::BasicTypeInfo<dap::boolean> booleanTI("boolean");
-static dap::BasicTypeInfo<dap::string> stringTI("string");
-static dap::BasicTypeInfo<dap::integer> integerTI("integer");
-static dap::BasicTypeInfo<dap::number> numberTI("number");
-static dap::BasicTypeInfo<dap::object> objectTI("object");
-static dap::BasicTypeInfo<dap::any> anyTI("any");
-static NullTI nullTI;
+// aligned_storage() is a replacement for std::aligned_storage that isn't busted
+// on older versions of MSVC.
+template <size_t SIZE, size_t ALIGNMENT>
+struct aligned_storage {
+  struct alignas(ALIGNMENT) type {
+    unsigned char data[SIZE];
+  };
+};
+
+TypeInfos* TypeInfos::get() {
+  static aligned_storage<sizeof(TypeInfos), alignof(TypeInfos)>::type memory;
+
+  struct Instance {
+    TypeInfos* ptr() { return reinterpret_cast<TypeInfos*>(memory.data); }
+    Instance() { new (ptr()) TypeInfos(); }
+    ~Instance() { ptr()->release(); }
+  };
+
+  static Instance instance;
+  return instance.ptr();
+}
 
 }  // namespace
 
 namespace dap {
 
 const TypeInfo* TypeOf<boolean>::type() {
-  return &booleanTI;
+  return &TypeInfos::get()->boolean;
 }
+
 const TypeInfo* TypeOf<string>::type() {
-  return &stringTI;
+  return &TypeInfos::get()->string;
 }
+
 const TypeInfo* TypeOf<integer>::type() {
-  return &integerTI;
+  return &TypeInfos::get()->integer;
 }
+
 const TypeInfo* TypeOf<number>::type() {
-  return &numberTI;
+  return &TypeInfos::get()->number;
 }
+
 const TypeInfo* TypeOf<object>::type() {
-  return &objectTI;
+  return &TypeInfos::get()->object;
 }
+
 const TypeInfo* TypeOf<any>::type() {
-  return &anyTI;
+  return &TypeInfos::get()->any;
 }
+
 const TypeInfo* TypeOf<null>::type() {
-  return &nullTI;
+  return &TypeInfos::get()->null;
+}
+
+void TypeInfo::deleteOnExit(TypeInfo* ti) {
+  return TypeInfos::get()->types.emplace_back(std::unique_ptr<TypeInfo>(ti));
+}
+
+void initialize() {
+  TypeInfos::get()->reference();
+}
+
+void terminate() {
+  TypeInfos::get()->release();
 }
 
 }  // namespace dap