diff options
author | Josh Blum <josh@joshknows.com> | 2010-06-03 01:04:36 +0000 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2010-06-03 01:04:36 +0000 |
commit | 565e46fa1038bebf59257a8b3eefae4487cf0946 (patch) | |
tree | bc5c9085824cc61bf5c5479d5c357e6ec37fdb58 /host/include | |
parent | 66deed6015f2a2bc67f17f6630ca62a41b596090 (diff) | |
parent | b2054a45d45ba85e30ff601159b18f5ebd15dd76 (diff) | |
download | uhd-565e46fa1038bebf59257a8b3eefae4487cf0946.tar.gz uhd-565e46fa1038bebf59257a8b3eefae4487cf0946.tar.bz2 uhd-565e46fa1038bebf59257a8b3eefae4487cf0946.zip |
Merge branch 'master' of ettus.sourcerepo.com:ettus/uhdpriv into usrp_e
Diffstat (limited to 'host/include')
-rw-r--r-- | host/include/uhd/config.hpp | 3 | ||||
-rw-r--r-- | host/include/uhd/transport/CMakeLists.txt | 2 | ||||
-rw-r--r-- | host/include/uhd/transport/alignment_buffer.hpp | 134 | ||||
-rw-r--r-- | host/include/uhd/transport/bounded_buffer.hpp | 146 | ||||
-rw-r--r-- | host/include/uhd/transport/udp_zero_copy.hpp | 2 | ||||
-rw-r--r-- | host/include/uhd/transport/zero_copy.hpp | 264 | ||||
-rw-r--r-- | host/include/uhd/usrp/dboard_base.hpp | 4 | ||||
-rw-r--r-- | host/include/uhd/utils/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/include/uhd/utils/exception.hpp | 7 | ||||
-rw-r--r-- | host/include/uhd/utils/pimpl.hpp | 55 |
10 files changed, 525 insertions, 93 deletions
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index fea95145c..b23a4dc00 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -31,10 +31,11 @@ # pragma warning(disable: 4251) // class 'A<T>' needs to have dll-interface to be used by clients of class 'B' //# pragma warning(disable: 4127) // conditional expression is constant //# pragma warning(disable: 4290) // C++ exception specification ignored except to ... -//# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored +# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored # pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ... //# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data //# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated +# pragma warning(disable: 4250) // 'class' : inherits 'method' via dominance #endif //define logical operators diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 4cefffa24..23a4aae94 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -17,6 +17,8 @@ INSTALL(FILES + alignment_buffer.hpp + bounded_buffer.hpp convert_types.hpp if_addrs.hpp udp_simple.hpp diff --git a/host/include/uhd/transport/alignment_buffer.hpp b/host/include/uhd/transport/alignment_buffer.hpp new file mode 100644 index 000000000..dc6ccc3ed --- /dev/null +++ b/host/include/uhd/transport/alignment_buffer.hpp @@ -0,0 +1,134 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program 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 of the License, or +// (at your option) any later version. +// +// 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, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_HPP +#define INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_HPP + +#include <uhd/config.hpp> +#include <uhd/transport/bounded_buffer.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/shared_ptr.hpp> +#include <utility> +#include <vector> + +namespace uhd{ namespace transport{ + + /*! + * Imlement a templated alignment buffer: + * Used for aligning asynchronously pushed elements with matching ids. + */ + template <typename elem_type, typename seq_type> class alignment_buffer{ + public: + typedef boost::shared_ptr<alignment_buffer<elem_type, seq_type> > sptr; + + /*! + * Make a new alignment buffer object. + * \param capacity the maximum elements per index + * \param width the number of elements to align + */ + static sptr make(size_t capacity, size_t width){ + return sptr(new alignment_buffer(capacity, width)); + } + + /*! + * Push an element with sequence id into the buffer at index. + * \param elem the element to push + * \param seq the sequence identifier + * \param index the buffer index + * \return true if the element fit without popping for space + */ + UHD_INLINE bool push_with_pop_on_full( + const elem_type &elem, + const seq_type &seq, + size_t index + ){ + return _buffs[index]->push_with_pop_on_full(buff_contents_type(elem, seq)); + } + + /*! + * Pop an aligned set of elements from this alignment buffer. + * \param elems a collection to store the aligned elements + * \param time the timeout time + * \return false when the operation times out + */ + template <typename elems_type, typename time_type> + bool pop_elems_with_timed_wait(elems_type &elems, const time_type &time){ + buff_contents_type buff_contents_tmp; + std::list<size_t> indexes_to_do(_all_indexes); + + //do an initial pop to load an initial sequence id + size_t index = indexes_to_do.front(); + if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; + elems[index] = buff_contents_tmp.first; + seq_type expected_seq_id = buff_contents_tmp.second; + indexes_to_do.pop_front(); + + //get an aligned set of elements from the buffers: + while(indexes_to_do.size() != 0){ + //pop an element off for this index + index = indexes_to_do.front(); + if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false; + + //if the sequence id matches: + // store the popped element into the output, + // remove this index from the list and continue + if (buff_contents_tmp.second == expected_seq_id){ + elems[index] = buff_contents_tmp.first; + indexes_to_do.pop_front(); + continue; + } + + //if the sequence id is older: + // continue with the same index to try again + if (buff_contents_tmp.second < expected_seq_id){ + continue; + } + + //if the sequence id is newer: + // store the popped element into the output, + // add all other indexes back into the list + if (buff_contents_tmp.second > expected_seq_id){ + elems[index] = buff_contents_tmp.first; + expected_seq_id = buff_contents_tmp.second; + indexes_to_do = _all_indexes; + indexes_to_do.remove(index); + continue; + } + } + return true; + } + + private: + //a vector of bounded buffers for each index + typedef std::pair<elem_type, seq_type> buff_contents_type; + typedef bounded_buffer<buff_contents_type> bounded_buffer_type; + typedef boost::shared_ptr<bounded_buffer_type> bounded_buffer_sptr; + std::vector<bounded_buffer_sptr> _buffs; + std::list<size_t> _all_indexes; + + //private constructor + alignment_buffer(size_t capacity, size_t width){ + for (size_t i = 0; i < width; i++){ + _buffs.push_back(bounded_buffer_type::make(capacity)); + _all_indexes.push_back(i); + } + } + }; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_HPP */ diff --git a/host/include/uhd/transport/bounded_buffer.hpp b/host/include/uhd/transport/bounded_buffer.hpp new file mode 100644 index 000000000..baecd6382 --- /dev/null +++ b/host/include/uhd/transport/bounded_buffer.hpp @@ -0,0 +1,146 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program 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 of the License, or +// (at your option) any later version. +// +// 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, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_HPP +#define INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_HPP + +#include <uhd/config.hpp> +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/circular_buffer.hpp> +#include <boost/thread/condition.hpp> + +namespace uhd{ namespace transport{ + + /*! + * Imlement a templated bounded buffer: + * Used for passing elements between threads in a producer-consumer model. + * The bounded buffer implemented waits and timed waits with condition variables. + * The pop operation blocks on the bounded_buffer to become non empty. + * The push operation blocks on the bounded_buffer to become non full. + */ + template <typename elem_type> class bounded_buffer{ + public: + typedef boost::shared_ptr<bounded_buffer<elem_type> > sptr; + + /*! + * Make a new bounded buffer object. + * \param capacity the bounded_buffer capacity + */ + static sptr make(size_t capacity){ + return sptr(new bounded_buffer(capacity)); + } + + /*! + * Push a new element into the bounded buffer. + * If the buffer is full prior to the push, + * make room by poping the oldest element. + * \param elem the new element to push + * \return true if the element fit without popping for space + */ + UHD_INLINE bool push_with_pop_on_full(const elem_type &elem){ + boost::unique_lock<boost::mutex> lock(_mutex); + if(_buffer.full()){ + _buffer.pop_back(); + _buffer.push_front(elem); + lock.unlock(); + _empty_cond.notify_one(); + return false; + } + else{ + _buffer.push_front(elem); + lock.unlock(); + _empty_cond.notify_one(); + return true; + } + } + + /*! + * Push a new element into the bounded_buffer. + * Wait until the bounded_buffer becomes non-full. + * \param elem the new element to push + */ + UHD_INLINE void push_with_wait(const elem_type &elem){ + boost::unique_lock<boost::mutex> lock(_mutex); + _full_cond.wait(lock, boost::bind(&bounded_buffer<elem_type>::not_full, this)); + _buffer.push_front(elem); + lock.unlock(); + _empty_cond.notify_one(); + } + + /*! + * Push a new element into the bounded_buffer. + * Wait until the bounded_buffer becomes non-full or timeout. + * \param elem the new element to push + * \param time the timeout time + * \return false when the operation times out + */ + template<typename time_type> UHD_INLINE + bool push_with_timed_wait(const elem_type &elem, const time_type &time){ + boost::unique_lock<boost::mutex> lock(_mutex); + if (not _full_cond.timed_wait(lock, time, boost::bind(&bounded_buffer<elem_type>::not_full, this))) return false; + _buffer.push_front(elem); + lock.unlock(); + _empty_cond.notify_one(); + return true; + } + + /*! + * Pop an element from the bounded_buffer. + * Wait until the bounded_buffer becomes non-empty. + * \param elem the element reference pop to + */ + UHD_INLINE void pop_with_wait(elem_type &elem){ + boost::unique_lock<boost::mutex> lock(_mutex); + _empty_cond.wait(lock, boost::bind(&bounded_buffer<elem_type>::not_empty, this)); + elem = _buffer.back(); _buffer.pop_back(); + lock.unlock(); + _full_cond.notify_one(); + } + + /*! + * Pop an element from the bounded_buffer. + * Wait until the bounded_buffer becomes non-empty or timeout. + * \param elem the element reference pop to + * \param time the timeout time + * \return false when the operation times out + */ + template<typename time_type> UHD_INLINE + bool pop_with_timed_wait(elem_type &elem, const time_type &time){ + boost::unique_lock<boost::mutex> lock(_mutex); + if (not _empty_cond.timed_wait(lock, time, boost::bind(&bounded_buffer<elem_type>::not_empty, this))) return false; + elem = _buffer.back(); _buffer.pop_back(); + lock.unlock(); + _full_cond.notify_one(); + return true; + } + + private: + boost::mutex _mutex; + boost::condition _empty_cond, _full_cond; + boost::circular_buffer<elem_type> _buffer; + + bool not_full(void) const{return not _buffer.full();} + bool not_empty(void) const{return not _buffer.empty();} + + //private constructor + bounded_buffer(size_t capacity) : _buffer(capacity){} + }; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_HPP */ diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp index 525606a9f..818709973 100644 --- a/host/include/uhd/transport/udp_zero_copy.hpp +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -34,7 +34,7 @@ namespace uhd{ namespace transport{ * If no platform specific solution is available, make returns a boost asio * implementation that wraps the functionality around a standard send/recv calls. */ -class UHD_API udp_zero_copy : public zero_copy_if{ +class UHD_API udp_zero_copy : public virtual zero_copy_if{ public: typedef boost::shared_ptr<udp_zero_copy> sptr; diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 52c6d4143..2815e3189 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -19,115 +19,201 @@ #define INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP #include <uhd/config.hpp> +#include <uhd/utils/pimpl.hpp> #include <boost/asio/buffer.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> namespace uhd{ namespace transport{ -/*! - * A managed receive buffer: - * Contains a reference to transport-managed memory, - * and a method to release the memory after reading. - */ -class UHD_API managed_recv_buffer : boost::noncopyable{ -public: - typedef boost::shared_ptr<managed_recv_buffer> sptr; - - /*! - * Managed recv buffer destructor: - * Signal to the transport that we are done with the buffer. - * This should be called to release the buffer to the transport. - * After calling, the referenced memory should be considered invalid. - */ - virtual ~managed_recv_buffer(void){}; - - /*! - * Get the size of the underlying buffer. - * \return the number of bytes - */ - size_t size(void) const{ - return boost::asio::buffer_size(this->get()); - } - - /*! - * Get a pointer to the underlying buffer. - * \return a pointer into memory - */ - template <class T> T cast(void) const{ - return boost::asio::buffer_cast<T>(this->get()); - } - -private: - /*! - * Get a reference to the internal const buffer. - * The buffer has a reference to memory and a size. - * \return a boost asio const buffer - */ - virtual const boost::asio::const_buffer &get(void) const = 0; -}; - -/*! - * A managed send buffer: - * Contains a reference to transport-managed memory, - * and a method to release the memory after writing. - */ -class UHD_API managed_send_buffer : boost::noncopyable{ -public: - typedef boost::shared_ptr<managed_send_buffer> sptr; - - /*! - * Signal to the transport that we are done with the buffer. - * This should be called to commit the write to the transport object. - * After calling, the referenced memory should be considered invalid. - * \param num_bytes the number of bytes written into the buffer - */ - virtual void commit(size_t num_bytes) = 0; - /*! - * Get the size of the underlying buffer. - * \return the number of bytes + * A managed receive buffer: + * Contains a reference to transport-managed memory, + * and a method to release the memory after reading. */ - size_t size(void) const{ - return boost::asio::buffer_size(this->get()); - } + class UHD_API managed_recv_buffer : boost::noncopyable{ + public: + typedef boost::shared_ptr<managed_recv_buffer> sptr; + + /*! + * Managed recv buffer destructor: + * Signal to the transport that we are done with the buffer. + * This should be called to release the buffer to the transport. + * After calling, the referenced memory should be considered invalid. + */ + virtual ~managed_recv_buffer(void) = 0; + + /*! + * Get the size of the underlying buffer. + * \return the number of bytes + */ + size_t size(void) const{ + return boost::asio::buffer_size(this->get()); + } + + /*! + * Get a pointer to the underlying buffer. + * \return a pointer into memory + */ + template <class T> T cast(void) const{ + return boost::asio::buffer_cast<T>(this->get()); + } + + private: + /*! + * Get a reference to the internal const buffer. + * The buffer has a reference to memory and a size. + * \return a boost asio const buffer + */ + virtual const boost::asio::const_buffer &get(void) const = 0; + }; /*! - * Get a pointer to the underlying buffer. - * \return a pointer into memory + * A managed send buffer: + * Contains a reference to transport-managed memory, + * and a method to release the memory after writing. */ - template <class T> T cast(void) const{ - return boost::asio::buffer_cast<T>(this->get()); - } + class UHD_API managed_send_buffer : boost::noncopyable{ + public: + typedef boost::shared_ptr<managed_send_buffer> sptr; + + /*! + * Signal to the transport that we are done with the buffer. + * This should be called to commit the write to the transport object. + * After calling, the referenced memory should be considered invalid. + * \param num_bytes the number of bytes written into the buffer + */ + virtual void commit(size_t num_bytes) = 0; + + /*! + * Get the size of the underlying buffer. + * \return the number of bytes + */ + size_t size(void) const{ + return boost::asio::buffer_size(this->get()); + } + + /*! + * Get a pointer to the underlying buffer. + * \return a pointer into memory + */ + template <class T> T cast(void) const{ + return boost::asio::buffer_cast<T>(this->get()); + } + + private: + /*! + * Get a reference to the internal mutable buffer. + * The buffer has a reference to memory and a size. + * \return a boost asio mutable buffer + */ + virtual const boost::asio::mutable_buffer &get(void) const = 0; + }; -private: /*! - * Get a reference to the internal mutable buffer. - * The buffer has a reference to memory and a size. - * \return a boost asio mutable buffer + * A zero-copy interface for transport objects. + * Provides a way to get send and receive buffers + * with memory managed by the transport object. */ - virtual const boost::asio::mutable_buffer &get(void) const = 0; -}; - -/*! - * A zero-copy interface for transport objects. - * Provides a way to get send and receive buffers - * with memory managed by the transport object. - */ -class UHD_API zero_copy_if : boost::noncopyable{ -public: - typedef boost::shared_ptr<zero_copy_if> sptr; + class UHD_API zero_copy_if : boost::noncopyable{ + public: + typedef boost::shared_ptr<zero_copy_if> sptr; + + /*! + * Get a new receive buffer from this transport object. + */ + virtual managed_recv_buffer::sptr get_recv_buff(void) = 0; + + /*! + * Get the maximum number of receive frames: + * The maximum number of valid managed recv buffers, + * or the maximum number of frames in the ring buffer, + * depending upon the underlying implementation. + * \return number of frames + */ + virtual size_t get_num_recv_frames(void) const = 0; + + /*! + * Get a new send buffer from this transport object. + */ + virtual managed_send_buffer::sptr get_send_buff(void) = 0; + + /*! + * Get the maximum number of send frames: + * The maximum number of valid managed send buffers, + * or the maximum number of frames in the ring buffer, + * depending upon the underlying implementation. + * \return number of frames + */ + virtual size_t get_num_send_frames(void) const = 0; + + }; /*! - * Get a new receive buffer from this transport object. + * A phony-zero-copy interface for transport objects that + * provides a zero-copy interface on top of copying transport. + * This interface implements the get managed recv buffer, + * the base class must implement the private recv method. */ - virtual managed_recv_buffer::sptr get_recv_buff(void) = 0; + class UHD_API phony_zero_copy_recv_if : public virtual zero_copy_if{ + public: + /*! + * Create a phony zero copy recv interface. + * \param max_buff_size max buffer size in bytes + */ + phony_zero_copy_recv_if(size_t max_buff_size); + + //! destructor + virtual ~phony_zero_copy_recv_if(void); + + /*! + * Get a new receive buffer from this transport object. + */ + managed_recv_buffer::sptr get_recv_buff(void); + + private: + /*! + * Perform a private copying recv. + * \param buff the buffer to write data into + * \return the number of bytes written to buff + */ + virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; + + UHD_PIMPL_DECL(impl) _impl; + }; /*! - * Get a new send buffer from this transport object. + * A phony-zero-copy interface for transport objects that + * provides a zero-copy interface on top of copying transport. + * This interface implements the get managed send buffer, + * the base class must implement the private send method. */ - virtual managed_send_buffer::sptr get_send_buff(void) = 0; -}; + class UHD_API phony_zero_copy_send_if : public virtual zero_copy_if{ + public: + /*! + * Create a phony zero copy send interface. + * \param max_buff_size max buffer size in bytes + */ + phony_zero_copy_send_if(size_t max_buff_size); + + //! destructor + virtual ~phony_zero_copy_send_if(void); + + /*! + * Get a new send buffer from this transport object. + */ + managed_send_buffer::sptr get_send_buff(void); + + private: + /*! + * Perform a private copying send. + * \param buff the buffer to read data from + * \return the number of bytes read from buff + */ + virtual size_t send(const boost::asio::const_buffer &buff) = 0; + + UHD_PIMPL_DECL(impl) _impl; + }; }} //namespace diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp index 28bf2ae66..e88d39876 100644 --- a/host/include/uhd/usrp/dboard_base.hpp +++ b/host/include/uhd/usrp/dboard_base.hpp @@ -20,6 +20,7 @@ #include <uhd/config.hpp> #include <uhd/wax.hpp> +#include <uhd/utils/pimpl.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> #include <uhd/usrp/dboard_id.hpp> @@ -58,8 +59,7 @@ protected: dboard_id_t get_tx_id(void); private: - struct dboard_base_impl; - dboard_base_impl *_impl; + UHD_PIMPL_DECL(impl) _impl; }; /*! diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt index f588c6310..391e684c8 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -20,6 +20,7 @@ INSTALL(FILES assert.hpp exception.hpp gain_handler.hpp + pimpl.hpp props.hpp safe_main.hpp static.hpp diff --git a/host/include/uhd/utils/exception.hpp b/host/include/uhd/utils/exception.hpp index 40e81fae0..e74c19b9c 100644 --- a/host/include/uhd/utils/exception.hpp +++ b/host/include/uhd/utils/exception.hpp @@ -35,4 +35,11 @@ " at " + std::string(__FILE__) + ":" + BOOST_STRINGIZE(__LINE__) + "\n" \ ) +/*! + * Throws an invalid code path exception with throw-site information. + * Use this macro in places that code execution is not supposed to go. + */ +#define UHD_THROW_INVALID_CODE_PATH() \ + throw std::runtime_error(UHD_THROW_SITE_INFO("invalid code path")) + #endif /* INCLUDED_UHD_UTILS_EXCEPTION_HPP */ diff --git a/host/include/uhd/utils/pimpl.hpp b/host/include/uhd/utils/pimpl.hpp new file mode 100644 index 000000000..09bf0c0a2 --- /dev/null +++ b/host/include/uhd/utils/pimpl.hpp @@ -0,0 +1,55 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program 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 of the License, or +// (at your option) any later version. +// +// 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, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_UTILS_PIMPL_HPP +#define INCLUDED_UHD_UTILS_PIMPL_HPP + +#include <uhd/config.hpp> +#include <boost/shared_ptr.hpp> + +/*! \file pimpl.hpp + * "Pimpl idiom" (pointer to implementation idiom). + * The UHD_PIMPL_* macros simplify code overhead for declaring and making pimpls. + * + * Each pimpl is implemented as a shared pointer to the implementation: + * - The container class will not have to deallocate the pimpl. + * - The container class will use the pimpl as a regular pointer. + * - Usage: _impl->method(arg0, arg1) + * - Usage: _impl->member = value; + * + * \see http://en.wikipedia.org/wiki/Opaque_pointer + */ + +/*! + * Make a declaration for a pimpl in a header file. + * - Usage: UHD_PIMPL_DECL(impl) _impl; + * \param _name the name of the pimpl class + */ +#define UHD_PIMPL_DECL(_name) \ + struct _name; boost::shared_ptr<_name> + +/*! + * Make an instance of a pimpl in a source file. + * - Usage: _impl = UHD_PIMPL_MAKE(impl, ()); + * - Usage: _impl = UHD_PIMPL_MAKE(impl, (a0, a1)); + * \param _name the name of the pimpl class + * \param _args the constructor args for the pimpl + */ +#define UHD_PIMPL_MAKE(_name, _args) \ + boost::shared_ptr<_name>(new _name _args) + +#endif /* INCLUDED_UHD_UTILS_PIMPL_HPP */ |