Skip to content

Commit

Permalink
Add support for a custom deleter to ReusableObjectHolder
Browse files Browse the repository at this point in the history
  • Loading branch information
fwyzard committed Mar 14, 2019
1 parent 2ebb643 commit 89fab9b
Showing 1 changed file with 58 additions and 52 deletions.
110 changes: 58 additions & 52 deletions FWCore/Utilities/interface/ReusableObjectHolder.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//
/**\class edm::ReusableObjectHolder ReusableObjectHolder "ReusableObjectHolder.h"
Description: Thread safe way to do create and reuse a group of the same object type.
Description: Thread safe way to create and reuse a group of the same object type.
Usage:
This class can be used to safely reuse a series of objects created on demand. The reuse
Expand Down Expand Up @@ -65,90 +65,96 @@
// Created: Fri, 31 July 2014 14:29:41 GMT
//

#include <memory>
#include <cassert>
#include <atomic>
#include "tbb/task.h"
#include "tbb/concurrent_queue.h"

#include <cassert>
#include <memory>
#include <tbb/concurrent_queue.h>
#include <tbb/task.h>

namespace edm {
template<class T>
template<class T, class Deleter = std::default_delete<T>>
class ReusableObjectHolder {
public:
ReusableObjectHolder():m_outstandingObjects(0){}
ReusableObjectHolder():
m_outstandingObjects(0)
{}

ReusableObjectHolder(ReusableObjectHolder const& iOther) = delete;

ReusableObjectHolder(ReusableObjectHolder&& iOther):
m_availableQueue(std::move(iOther.m_availableQueue)),
m_outstandingObjects(0) {
assert(0== iOther.m_outstandingObjects);
m_availableQueue(std::move(iOther.m_availableQueue)),
m_outstandingObjects(0),
m_deleter(std::move(iOther.m_deleter))
{
assert(0 == iOther.m_outstandingObjects);
}

~ReusableObjectHolder() {
assert(0==m_outstandingObjects);
T* item = 0;
while( m_availableQueue.try_pop(item)) {
delete item;
T* item = 0;
while (m_availableQueue.try_pop(item)) {
m_deleter(item);
}
}

///Adds the item to the cache.
/// Use this function if you know ahead of time
/// how many cached items you will need.
void add(std::unique_ptr<T> iItem){
if(0!=iItem) {
m_availableQueue.push(iItem.release());
}
}
void add(std::unique_ptr<T, Deleter> iItem){
if(0!=iItem) {
m_availableQueue.push(iItem.release());
}
}

///Tries to get an already created object,
/// if none are available, returns an empty shared_ptr.
/// if none are available, returns an empty shared_ptr.
/// Use this function in conjunction with add()
std::shared_ptr<T> tryToGet() {
T* item = 0;
m_availableQueue.try_pop(item);
if (0==item) {
return std::shared_ptr<T>{};
}
//instead of deleting, hand back to queue
std::shared_ptr<T> tryToGet() {
T* item = 0;
m_availableQueue.try_pop(item);
if (0==item) {
return std::shared_ptr<T>{};
}
//instead of deleting, hand back to queue
auto pHolder = this;
++m_outstandingObjects;
return std::shared_ptr<T>{item, [pHolder](T* iItem) {pHolder->addBack(iItem);} };
}
return std::shared_ptr<T>{item, [pHolder](T* iItem) {pHolder->addBack(iItem);} };
}

///If there isn't an object already available, creates a new one using iFunc
template< typename F>
std::shared_ptr<T> makeOrGet( F iFunc) {
std::shared_ptr<T> returnValue;
while ( ! ( returnValue = tryToGet()) ) {
add( std::unique_ptr<T>(iFunc()) );
}
return returnValue;
}
template< typename F>
std::shared_ptr<T> makeOrGet( F iFunc) {
std::shared_ptr<T> returnValue;
while ( not ( returnValue = tryToGet()) ) {
add( std::unique_ptr<T, Deleter>(iFunc()) );
}
return returnValue;
}

///If there is an object already available, passes the object to iClearFunc and then
/// returns the object.
///If there is not an object already available, creates a new one using iMakeFunc
template< typename FM, typename FC>
std::shared_ptr<T> makeOrGetAndClear( FM iMakeFunc, FC iClearFunc) {
std::shared_ptr<T> returnValue;
while ( ! ( returnValue = tryToGet()) ) {
add( std::unique_ptr<T>(iMakeFunc()) );
}
iClearFunc(returnValue.get());
return returnValue;
}
template< typename FM, typename FC>
std::shared_ptr<T> makeOrGetAndClear( FM iMakeFunc, FC iClearFunc) {
std::shared_ptr<T> returnValue;
while ( not ( returnValue = tryToGet()) ) {
add( std::unique_ptr<T, Deleter>(iMakeFunc() ) );
}
iClearFunc(returnValue.get());
return returnValue;
}

private:
void addBack(T* iItem){
m_availableQueue.push(iItem);
m_availableQueue.push(iItem);
--m_outstandingObjects;
}
tbb::concurrent_queue<T*> m_availableQueue;
}
tbb::concurrent_queue<T*> m_availableQueue;
std::atomic<size_t> m_outstandingObjects;
Deleter m_deleter;
};

}



#endif /* end of include guard: FWCore_Utilities_ReusableObjectHolder_h */

0 comments on commit 89fab9b

Please sign in to comment.