hpb: introduce ptr.h and break out template helpers into internal/template_help.h

PiperOrigin-RevId: 663441859
diff --git a/hpb/ptr.h b/hpb/ptr.h
new file mode 100644
index 0000000..43fd0f6
--- /dev/null
+++ b/hpb/ptr.h
@@ -0,0 +1,78 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2024 Google LLC.  All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
+
+#ifndef GOOGLE_PROTOBUF_HPB_PTR_H__
+#define GOOGLE_PROTOBUF_HPB_PTR_H__
+
+#include <memory>
+#include <type_traits>
+
+class upb_Message;
+class upb_Arena;
+
+namespace hpb {
+
+template <typename T>
+using Proxy = std::conditional_t<std::is_const<T>::value,
+                                 typename std::remove_const_t<T>::CProxy,
+                                 typename T::Proxy>;
+
+// Provides convenient access to Proxy and CProxy message types.
+//
+// Using rebinding and handling of const, Ptr<Message> and Ptr<const Message>
+// allows copying const with T* const and avoids using non-copyable Proxy types
+// directly.
+template <typename T>
+class Ptr final {
+ public:
+  Ptr() = delete;
+
+  // Implicit conversions
+  Ptr(T* m) : p_(m) {}                // NOLINT
+  Ptr(const Proxy<T>* p) : p_(*p) {}  // NOLINT
+  Ptr(Proxy<T> p) : p_(p) {}          // NOLINT
+  Ptr(const Ptr& m) = default;
+
+  Ptr& operator=(Ptr v) & {
+    Proxy<T>::Rebind(p_, v.p_);
+    return *this;
+  }
+
+  Proxy<T> operator*() const { return p_; }
+  Proxy<T>* operator->() const {
+    return const_cast<Proxy<T>*>(std::addressof(p_));
+  }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wclass-conversion"
+#endif
+  template <typename U = T, std::enable_if_t<!std::is_const<U>::value, int> = 0>
+  operator Ptr<const T>() const {
+    Proxy<const T> p(p_);
+    return Ptr<const T>(&p);
+  }
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+ private:
+  Ptr(upb_Message* msg, upb_Arena* arena) : p_(msg, arena) {}  // NOLINT
+
+  friend class Ptr<const T>;
+  friend typename T::Access;
+
+  Proxy<T> p_;
+};
+
+// Suppress -Wctad-maybe-unsupported with our manual deduction guide
+template <typename T>
+Ptr(T* m) -> Ptr<T>;
+
+}  // namespace hpb
+
+#endif  // GOOGLE_PROTOBUF_HPB_PTR_H__