Add an RAII class for managing obstacks
authorRichard Sandiford <richard.sandiford@arm.com>
Thu, 17 Dec 2020 00:15:00 +0000 (00:15 +0000)
committerRichard Sandiford <richard.sandiford@arm.com>
Thu, 17 Dec 2020 00:15:00 +0000 (00:15 +0000)
This patch adds an RAII class for managing the lifetimes of objects
on an obstack.  See the comments in the patch for more details and
example usage.

gcc/
* obstack-utils.h: New file.

gcc/obstack-utils.h [new file with mode: 0644]

diff --git a/gcc/obstack-utils.h b/gcc/obstack-utils.h
new file mode 100644 (file)
index 0000000..ee389f8
--- /dev/null
@@ -0,0 +1,86 @@
+// Obstack-related utilities.
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of GCC.
+//
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+//
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef GCC_OBSTACK_UTILS_H
+#define GCC_OBSTACK_UTILS_H
+
+// This RAII class automatically frees memory allocated on an obstack,
+// unless told not to via keep ().  It automatically converts to an
+// obstack, so it can (optionally) be used in place of the obstack
+// to make the scoping clearer.  For example:
+//
+//     obstack_watermark watermark (ob);
+//     auto *ptr1 = XOBNEW (watermark, struct1);
+//     if (...)
+//       // Frees ptr1.
+//       return false;
+//
+//     auto *ptr2 = XOBNEW (watermark, struct2);
+//     if (...)
+//       // Frees ptr1 and ptr2.
+//       return false;
+//
+//     // Retains ptr1 and ptr2.
+//     watermark.keep ();
+//
+//     auto *ptr3 = XOBNEW (watermark, struct3);
+//     if (...)
+//       // Frees ptr3.
+//       return false;
+//
+//     // Retains ptr3 (in addition to ptr1 and ptr2 above).
+//     watermark.keep ();
+//     return true;
+//
+// The move constructor makes it possible to transfer ownership to a caller:
+//
+//     obstack_watermark
+//     foo ()
+//     {
+//       obstack_watermark watermark (ob);
+//       ...
+//       return watermark;
+//     }
+//
+//     void
+//     bar ()
+//     {
+//       // Inherit ownership of everything that foo allocated.
+//       obstack_watermark watermark = foo ();
+//       ...
+//     }
+class obstack_watermark
+{
+public:
+  obstack_watermark (obstack *ob) : m_obstack (ob) { keep (); }
+  constexpr obstack_watermark (obstack_watermark &&) = default;
+  ~obstack_watermark () { obstack_free (m_obstack, m_start); }
+
+  operator obstack *() const { return m_obstack; }
+  void keep () { m_start = XOBNEWVAR (m_obstack, char, 0); }
+
+private:
+  DISABLE_COPY_AND_ASSIGN (obstack_watermark);
+
+protected:
+  obstack *m_obstack;
+  char *m_start;
+};
+
+#endif