From 4c0c225a1928316fca026da2269a42f1f7f43735 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 18 Dec 2006 13:17:08 +0100 Subject: [PATCH] initial go at smart pointer implementation --- SConstruct | 2 + src/core/ptr.cc | 103 ++++++++++++++++++ src/core/ptr.h | 270 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 375 insertions(+) create mode 100644 src/core/ptr.cc create mode 100644 src/core/ptr.h diff --git a/SConstruct b/SConstruct index 090b6b764..dda9a9192 100644 --- a/SConstruct +++ b/SConstruct @@ -18,6 +18,7 @@ ns3.add(core) core.add_sources([ 'reference-list-test.cc', 'callback-test.cc', + 'ptr.cc', 'test.cc' ]) env = Environment() @@ -37,6 +38,7 @@ core.add_inst_headers([ 'system-wall-clock-ms.h', 'reference-list.h', 'callback.h', + 'ptr.h', 'test.h' ]) diff --git a/src/core/ptr.cc b/src/core/ptr.cc new file mode 100644 index 000000000..1c2b240b0 --- /dev/null +++ b/src/core/ptr.cc @@ -0,0 +1,103 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "ptr.h" + +#ifdef RUN_SELF_TESTS + +#include "test.h" +#include "callback.h" + +namespace ns3 { + +class NoCount +{ +public: + NoCount (Callback cb); + ~NoCount (); +private: + Callback m_cb; +}; +NoCount::NoCount (Callback cb) + : m_cb (cb) +{} +NoCount::~NoCount () +{ + m_cb (); +} + +class PtrTest : Test +{ +public: + PtrTest (); + virtual ~PtrTest (); + virtual bool RunTests (void); +private: + void DestroyNotify (void); + bool m_destroyed; +}; + +PtrTest::PtrTest () + : Test ("Ptr") +{} + +PtrTest::~PtrTest () +{} + +void +PtrTest::DestroyNotify (void) +{ + m_destroyed = true; +} + + +bool +PtrTest::RunTests (void) +{ + bool ok = true; + + Callback cb = MakeCallback (&PtrTest::DestroyNotify, this); + m_destroyed = false; + { + Ptr p = new NoCount (cb); + } + if (!m_destroyed) + { + ok = false; + } + m_destroyed = false; + { + Ptr p; + p = new NoCount (cb); + } + if (!m_destroyed) + { + ok = false; + } + + + return ok; +} + +PtrTest g_ptr_test; + +}; // namespace ns3 + +#endif /* RUN_SELF_TESTS */ diff --git a/src/core/ptr.h b/src/core/ptr.h new file mode 100644 index 000000000..ba496bf0b --- /dev/null +++ b/src/core/ptr.h @@ -0,0 +1,270 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef PTR_H +#define PTR_H + +#include +#include + +namespace ns3 { + +/** + * \brief smart pointer class similar to boost::shared_ptr + * + * This smart-pointer class is supposed to be used to manage + * heap-allocated objects: when it decides it does not need + * the object it references, it invokes operator delete on it. + * This implementation allows you to manipulate the smart pointer + * as if it was a normal pointer: you can compare it with zero, + * compare it against other pointers, etc. However, the only + * operation we are careful to avoid is the conversion back to + * raw pointers: if you need to convert back, you need to invoke + * the Ptr::Remove method which returns a raw pointer and + * makes the smart pointer forget about the raw pointer. + */ +template +class Ptr +{ +private: + T *m_ptr; + uint32_t *m_count; + class Tester { + private: + void operator delete (void *); + }; + static uint32_t *AllocCount (void); + static void DeallocCount (uint32_t *count); +public: + /** + * Create an empty smart pointer + */ + Ptr (); + /** + * \param ptr raw pointer to manage + * + * Create a smart pointer which points to the + * input raw pointer. This method takes ownershipt + * of the input raw pointer. That is, the smart pointer + * becomes responsible for calling delete on the + * raw pointer when needed. + */ + Ptr (T *ptr); + Ptr (Ptr const&o); + // allow conversions from T to T const. + template + Ptr (Ptr const &o); + ~Ptr () ; + Ptr &operator = (Ptr const& o); + T *operator -> () const; + T *operator -> (); + // allow if (!sp) + bool operator! (); + // allow if (sp) + operator Tester * () const; + // allow if (sp == 0) + template + inline friend bool operator == (Ptr const &lhs, T2 const *rhs); + // allow if (0 == sp) + template + inline friend bool operator == (T1 const *lhs, Ptr &rhs); + // allow if (sp != 0) + template + inline friend bool operator != (Ptr const &lhs, T2 const *rhs); + // allow if (0 != sp) + template + inline friend bool operator != (T1 const *lhs, Ptr &rhs); + + /** + * \returns raw pointer + * + * It is a programming error to invoke this method when + * the reference count of the smart pointer is not one. + * If you try to do it anyway, an assert will be triggered. + * If asserts are disabled, bad things will happen. + * Once you have successfully called Ptr::Remove on + * a smart pointer, the smart pointer will forget + * about the raw pointer and will stop managing it. As such, + * you, as the caller, become responsible for invoking + * operator delete on the returned raw pointer. + */ + T *Remove (void); +}; + +template +uint32_t * +Ptr::AllocCount (void) +{ + return new uint32_t [1] (); +} +template +void +Ptr::DeallocCount (uint32_t *count) +{ + delete [] count; +} + +template +Ptr::Ptr () + : m_ptr (0), + m_count (Ptr::AllocCount ()) +{} + +template +Ptr::Ptr (T *ptr) + : m_ptr (ptr), + m_count (Ptr::AllocCount ()) +{ + if (m_ptr != 0) + { + *m_count = 1; + } +} + +template +Ptr::Ptr (Ptr const&o) + : m_ptr (o.m_ptr), + m_count (o.m_count) +{ + if (m_ptr != 0) + { + (*m_count)++; + } +} +template +template +Ptr::Ptr (Ptr const &o) + : m_ptr (o.m_ptr), + m_count (o.m_count) +{ + if (m_ptr != 0) + { + (*m_count)++; + } +} + +template +Ptr::~Ptr () +{ + if (m_ptr != 0) + { + (*m_count)--; + if ((*m_count) == 0) + { + delete m_ptr; + Ptr::DeallocCount (m_count); + } + } +} + +template +Ptr & +Ptr::operator = (Ptr const& o) +{ + if (o.m_ptr != 0) + { + (*(o.m_count))++; + } + if (m_ptr != 0) + { + (*m_count)--; + if ((*m_count) == 0) + { + delete m_ptr; + Ptr::DeallocCount (m_count); + } + } + m_ptr = o.m_ptr; + m_count = o.m_count; + return *this; +} + +template +T * +Ptr::operator -> () +{ + return m_ptr; +} + +template +T * +Ptr::operator -> () const +{ + return m_ptr; +} + +template +bool +Ptr::operator! () +{ + return m_ptr == 0; +} + +template +Ptr::operator Tester * () const +{ + if (m_ptr == 0) + { + return 0; + } + static Tester test; + return &test; +} + +template +T * +Ptr::Remove (void) +{ + assert (m_ptr.m_count == 1); + T *retval = m_ptr; + m_ptr = 0; + return retval; +} + +// non-member friend functions. +template +bool +operator == (Ptr const &lhs, T2 const *rhs) +{ + return lhs.m_ptr == rhs; +} +template +bool +operator == (T1 const *lhs, Ptr &rhs) +{ + return lhs == rhs.m_ptr; +} +template +bool +operator != (Ptr const &lhs, T2 const *rhs) +{ + return lhs.m_ptr != rhs; +} +template +bool +operator != (T1 const *lhs, Ptr &rhs) +{ + return lhs != rhs.m_ptr; +} + +}; // namespace ns3 + +#endif /* PTR_H */