Repository: trafficserver
Updated Branches:
  refs/heads/master 2b5a16426 -> 9a80e8757


TS-2943: Add scoped resource class.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/9a80e875
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/9a80e875
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/9a80e875

Branch: refs/heads/master
Commit: 9a80e875770a33044ac0cd80662680a5688c3952
Parents: 2b5a164
Author: Alan M. Carroll <[email protected]>
Authored: Tue Jul 22 13:13:49 2014 -0500
Committer: Alan M. Carroll <[email protected]>
Committed: Tue Jul 22 13:13:49 2014 -0500

----------------------------------------------------------------------
 lib/ts/ink_memory.h | 291 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 291 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9a80e875/lib/ts/ink_memory.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_memory.h b/lib/ts/ink_memory.h
index 908685c..e0b3291 100644
--- a/lib/ts/ink_memory.h
+++ b/lib/ts/ink_memory.h
@@ -176,6 +176,12 @@ ink_zero(T& t) {
     The memory is also freed when the object is destructed. This makes
     handling temporary memory in a function more robust.
 
+    @DEPRECATED
+
+    Use @c ats_scoped_str for @c xptr<char>
+    Use @c ats_scoped_mem<T> for @c xptr<T> (uses @c ats_malloc / @c ats_free )
+    Use @c ats_scoped_obj<T> for pointers to other types using @c new and @c 
delete.
+
     @internal A poor substitute for a real shared pointer copy on write
     class but one step at a time. It's better than doing this by
     hand every time.
@@ -275,6 +281,291 @@ path_join (xptr<char> const& lhs, xptr<char> const& rhs)
   return x;
 }
 
+/** Scoped resources.
+
+    An instance of this class is used to hold a contingent resource. When this 
object goes out of scope
+    the resource is destroyed. If the resource needs to be kept valid it can 
be released from this container.
+    The standard usage pattern is
+    - Allocate resource.
+    - Perform various other checks or resource allocations which, if they 
fail, require this resource to be destroyed.
+    - Release the resource.
+
+    This serves as a base implementation, actual use is usually through 
specialized subclasses.
+
+    @see ats_scoped_fd
+    @see ats_scoped_mem
+    @see ats_scoped_obj
+
+    For example, if you open a file descriptor and have to do other checks 
which result in having to call
+    @c close in each @c if clause.
+
+    @code
+    int fd = open(...);
+    if (X) { Log(...); close(fd); return -1; }
+    if (Y) { Log(...); close(fd); return -1; }
+    ...
+    return fd;
+    @endcode
+
+    Change this to
+    @code
+    ats_scoped_fd fd(open(...);
+    if (X) { Log(...) return; } // fd is closed upon return.
+    if (Y) { Log(...) return; } // fd is closed upon return.
+    fd.release(); // fd will not be automatically closed after this.
+    return fd;
+    @endcode
+
+    The @a TRAITS class must have the following members.
+
+    @code
+    value_type; // Declaration type of the resource.
+    RT initValue(); // Return canonical initialization value for RT.
+    bool isValid(RT); // Check for validity. Can take a reference or const 
reference.
+    void destroy(RT); // Cleanup. Can take a reference.
+    @endcode
+
+    @c isValid should return @c true if the resource instance is valid and @c 
false if it is not valid.
+
+    @c initValue must be a constant value of @a RT such that @c 
isValid(INVALID) is @c false. This
+    is used to initialize the object when the container is empty.
+
+    @c destroy should perform cleanup on the object.
+
+    @internal One might think the initialization value should be a constant 
but you can't initialize
+    non-integral class constants (such as pointers) in C++ (you can in C++ 
eleventy but we can't
+    require that). We can only hope the compiler is smart enough to optimize 
out functions returning
+    constants.
+
+*/
+
+template <
+  typename TRAITS ///< Traits object.
+>
+class ats_scoped_resource
+{
+public:
+  typedef TRAITS Traits; ///< Make template arg available.
+  typedef typename TRAITS::value_type value_type; ///< Import value type.
+  typedef ats_scoped_resource self; ///< Self reference type.
+
+public:
+
+  /// Default constructor - an empty container.
+  ats_scoped_resource() : _r(Traits::initValue()) {}
+
+  /// Construct with contained resource.
+  explicit ats_scoped_resource(value_type rt) : _r(rt) {}
+
+  /// Destructor.
+  ~ats_scoped_resource() {
+    if (Traits::isValid(_r))
+      Traits::destroy(_r);
+  }
+
+  /// Automatic conversion to resource type.
+  operator value_type () const {
+    return _r;
+  }
+
+  /** Release resource from this container.
+      After this call, the resource will @b not cleaned up when this container 
is destructed.
+
+      @note Although direct assignment is forbidden due to the non-obvious 
semantics, a pointer can
+      be moved (@b not copied) from one instance to another using this method.
+      @code
+      new_ptr = old_ptr.release();
+      @endcode
+      This is by design.
+
+      @return The no longer contained resource.
+  */
+  value_type release() {
+    value_type zret = _r;
+    _r = Traits::initValue();
+    return zret;
+  }
+
+  /** Place a new resource in the container.
+      Any resource currently contained is destroyed.
+  */
+  self& operator = (value_type rt) {
+    if (Traits::isValid(_r)) Traits::destroy(_r);
+    _r = rt;
+    return *this;
+  }
+
+  bool operator == (value_type rt) const {
+    return _r == rt;
+  }
+
+  bool operator != (value_type rt) const {
+    return _r != rt;
+  }
+
+protected:
+  value_type _r; ///< Resource.
+private:
+  ats_scoped_resource(self const&); ///< Copy constructor not permitted.
+  self& operator = (self const&); ///< Self assignment not permitted.
+
+};
+
+namespace detail {
+/** Traits for @c ats_scoped_resource for file descriptors.
+ */
+  struct SCOPED_FD_TRAITS
+  {
+    typedef int value_type;
+    static int initValue() { return -1; }
+    static bool isValid(int fd) { return fd >= 0; }
+    static void destroy(int fd) { close(fd); }
+  };
+}
+/** File descriptor as a scoped resource.
+
+    @internal This needs to be a class and not just a @c typedef because the
+    pseudo-bool operator is required to avoid ambiguity for non-pointer
+    resources, but creates ambiguity for pointer resources.
+ */
+class ats_scoped_fd : public ats_scoped_resource<detail::SCOPED_FD_TRAITS>
+{
+public:
+  typedef ats_scoped_resource<detail::SCOPED_FD_TRAITS> super; ///< Super type.
+  typedef ats_scoped_fd self; ///< Self reference type.
+  typedef bool (self::*pseudo_bool)() const; ///< Bool operator type.
+
+  /// Assign a file descriptor @a fd.
+  self& operator = (int fd) {
+    super::operator=(fd);
+    return *this;
+  }
+
+  /// Enable direct validity check in an @c if statement w/o ambiguity with @c 
int conversion.
+  operator pseudo_bool () const {
+    return Traits::isValid(_r) ?  &self::operator! : 0;
+  }
+
+  /// Not valid check.
+  bool operator ! () const {
+    return ! Traits::isValid(_r);
+  }
+};
+
+namespace detail {
+/** Traits for @c ats_scoped_resource for pointers from @c ats_malloc.
+ */
+  template <
+    typename T ///< Underlying type (not the pointer type).
+  >
+  struct SCOPED_MALLOC_TRAITS
+  {
+    typedef T* value_type;
+    static T*  initValue() { return NULL; }
+    static bool isValid(T* t) { return 0 != t; }
+    static void destroy(T* t) { ats_free(t); }
+  };
+
+  /// Traits for @c ats_scoped_resource for objects using @c new and @c delete.
+  template <
+    typename T ///< Underlying type - not the pointer type.
+  >
+  struct SCOPED_OBJECT_TRAITS
+  {
+    typedef T* value_type;
+    static T* initValue() { return NULL; }
+    static bool isValid(T* t) { return 0 != t; }
+    static void destroy(T* t) { delete t; }
+  };
+}
+
+/** Specialization of @c ats_scoped_resource for strings.
+    This contains an allocated string that is cleaned up if not explicitly 
released.
+*/
+class ats_scoped_str : public 
ats_scoped_resource<detail::SCOPED_MALLOC_TRAITS<char> >
+{
+ public:
+  typedef ats_scoped_resource<detail::SCOPED_MALLOC_TRAITS<char> > super; ///< 
Super type.
+  typedef ats_scoped_str self; ///< Self reference type.
+
+  /// Default constructor (no string).
+  ats_scoped_str()
+  { }
+  /// Construct and allocate @a n bytes for a string.
+  explicit ats_scoped_str(size_t n) : super(static_cast<char*>(ats_malloc(n)))
+  { }
+  /// Put string @a s in this container for cleanup.
+  explicit ats_scoped_str(char* s) : super(s)
+  { }
+  /// Assign a string @a s to this container.
+  self& operator = (char* s) {
+    super::operator=(s);
+    return *this;
+  }
+};
+
+/** Specialization of @c ats_scoped_resource for pointers allocated with @c 
ats_malloc.
+
+    @note This is a drop in replacement for @c xptr<T>.
+ */
+template <
+  typename T ///< Underlying (not pointer) type.
+>
+class ats_scoped_mem : public 
ats_scoped_resource<detail::SCOPED_MALLOC_TRAITS<T> >
+{
+public:
+  typedef ats_scoped_resource<detail::SCOPED_MALLOC_TRAITS<T> > super; ///< 
Super type.
+  typedef ats_scoped_mem self; ///< Self reference.
+
+  self& operator = (T* ptr) {
+    super::operator=(ptr);
+    return *this;
+  }
+};
+
+/** Specialization of @c ats_scoped_resource for objects.
+    This handles a pointer to an object created by @c new and destroyed by @c 
delete.
+*/
+
+template <
+  typename T /// Underlying (not pointer) type.
+>
+class ats_scoped_obj : public 
ats_scoped_resource<detail::SCOPED_OBJECT_TRAITS<T> >
+{
+public:
+  typedef ats_scoped_resource<detail::SCOPED_OBJECT_TRAITS<T> > super; ///< 
Super type.
+  typedef ats_scoped_obj self; ///< Self reference.
+
+  self& operator = (T* obj) {
+    super::operator=(obj);
+    return *this;
+  }
+};
+
+/** Combine two strings as file paths.
+     Trailing and leading separators for @a lhs and @a rhs respectively
+     are handled to yield exactly one separator.
+     @return A newly @x ats_malloc string of the combined paths.
+*/
+inline char*
+path_join (ats_scoped_str const& lhs, ats_scoped_str  const& rhs)
+{
+  size_t ln = strlen(lhs);
+  size_t rn = strlen(rhs);
+  char const* rptr = rhs; // May need to be modified.
+
+  if (ln && lhs[ln-1] == '/') --ln; // drop trailing separator.
+  if (rn && *rptr == '/') --rn, ++rptr; // drop leading separator.
+
+  ats_scoped_str x(ln + rn + 2);
+
+  memcpy(x, lhs, ln);
+  x[ln] = '/';
+  memcpy(x + ln + 1,  rptr, rn);
+  x[ln+rn+1] = 0; // terminate string.
+
+  return x.release();
+}
 #endif  /* __cplusplus */
 
 #endif

Reply via email to