blob: 2d9cec32f5ceb5a96a4d4739cd51089e2f23a2a8 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
#ifndef QUICKSTEP_STORAGE_COUNTED_REFERENCE_HPP_
#define QUICKSTEP_STORAGE_COUNTED_REFERENCE_HPP_
#include <type_traits>
#include "storage/EvictionPolicy.hpp"
#include "storage/StorageBlockBase.hpp"
#include "utility/Macros.hpp"
namespace quickstep {
/** \addtogroup Storage
* @{
*/
/**
* @brief A managed pointer to a StorageBlockBase. StorageBlockBase::ref() and
* StorageBlockBase::unref(), as well as EvictionPolicy::blockReferenced()
* and EvictionPolicy::blockUnreferenced(), are called when
* appropriate. This class is a template to allow different type
* modifiers to be applied; however, a static assertion prevents it
* from being used for anything other than a StorageBlockBase.
*
**/
template<class T>
class CountedReference {
static_assert(std::is_base_of<StorageBlockBase, typename std::remove_cv<T>::type>::value,
"CountedReference is for use only with StorageBlockBase and its subclasses");
public:
/**
* @brief Default constructor. Initializes the object without a StorageBlockBase
* to manage.
**/
CountedReference()
: block_(nullptr),
eviction_policy_(nullptr) {}
/**
* @brief Construct a new CountedReference to manage a reference to an
* underlying StorageBlockBase. Calls StorageBlockBase::ref() and
* EvictionPolicy::blockReferenced().
*
* @param block The StorageBlockBase to manage.
* @param eviction_policy The EvictionPolicy inform when this
* CountedReference is constructor or destroyed.
**/
CountedReference(T *block, EvictionPolicy *eviction_policy)
: block_(block), eviction_policy_(eviction_policy) {
eviction_policy_->blockReferenced(block_->getID());
#ifdef QUICKSTEP_DEBUG
block_->ref();
#endif
}
/**
* @brief Move constructor. Transfers management of a block reference away
* from another block. The other reference will not longer be valid.
* @param other The other block.
**/
/* implicit */
CountedReference(CountedReference<T> &&other)
: block_(other.block_), eviction_policy_(other.eviction_policy_) {
other.block_ = nullptr;
other.eviction_policy_ = nullptr;
}
/**
* @brief This is a move constructor that lets you move from a
* MutableBlockReference to a BlockReference. The weird template stuff is to
* ensure that this code is only generated when T = const StorageBlockBase or const
* StorageBlob. See
* http://stackoverflow.com/questions/17842478/select-class-constructor-using-
* enable-if.
* @param other The other block.
**/
/* implicit */
template<typename U = T>
CountedReference(CountedReference<typename std::remove_cv<T>::type> &&other,
typename std::enable_if<std::is_same<U, const T>::value>::type* = nullptr)
: block_(other.block_), eviction_policy_(other.eviction_policy_) {
other.block_ = nullptr;
other.eviction_policy_ = nullptr;
}
/**
* @brief Unrefs the StorageBlockBase before destruction and called
* EvictionPolicy::blockUnreferenced().
**/
~CountedReference() {
if (block_ != nullptr) {
#ifdef QUICKSTEP_DEBUG
block_->unref();
#endif
eviction_policy_->blockUnreferenced(block_->getID());
}
}
/**
* @brief Check whether this CountedReference is valid.
*
* @return true if this object is managing a StorageBlockBase reference false
* otherwise.
**/
inline bool valid() { return block_ != nullptr; }
/**
* @brief Provide pointer access to underlying StorageBlockBase.
*
* @return Pointer to managed StorageBlockBase.
**/
inline T *operator->() const { return block_; }
/**
* @brief Provide reference access to underlying StorageBlockBase.
*
* @return Reference to managed StorageBlockBase.
**/
inline T &operator*() const { return *block_; }
/**
* @brief Move assignment operator for CountedReference. Releases the
* managed StorageBlockBase from other and takes over its management.
* After calling this, other.valid() will return false.
**/
inline CountedReference &operator=(CountedReference &&other) {
if (this == &other) {
return *this;
}
this->~CountedReference();
block_ = other.block_;
eviction_policy_ = other.eviction_policy_;
other.block_ = nullptr;
other.eviction_policy_ = nullptr;
return *this;
}
/**
* @brief Releases management of the underlying StorageBlockBase.
**/
inline void release() {
this->~CountedReference();
block_ = nullptr;
eviction_policy_ = nullptr;
}
private:
friend CountedReference<const T>; // Needed to move from mutable to non-mutable CountedReference objects.
T *block_;
EvictionPolicy *eviction_policy_;
DISALLOW_COPY_AND_ASSIGN(CountedReference<T>);
};
} // namespace quickstep
/** @} */
#endif // QUICKSTEP_STORAGE_COUNTED_REFERENCE_HPP_