nana/include/nana/gui/detail/handle_manager.hpp
2015-12-03 20:24:20 +01:00

292 lines
6.3 KiB
C++

/*
* Handle Manager Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/gui/detail/handle_manager.hpp
*
* @description:
* this manages all the window handles
*/
#ifndef NANA_GUI_DETAIL_HANDLE_MANAGER_HPP
#define NANA_GUI_DETAIL_HANDLE_MANAGER_HPP
#include <nana/traits.hpp>
#include <nana/config.hpp>
#if defined(STD_THREAD_NOT_SUPPORTED)
#include <nana/std_mutex.hpp>
#else
#include <mutex>
#endif
#include <map>
#include <iterator>
namespace nana
{
namespace detail
{
template<typename Key, typename Value, std::size_t CacheSize>
class cache
: noncopyable
{
public:
typedef Key key_type;
typedef Value value_type;
typedef std::pair<key_type, value_type> pair_type;
typedef std::size_t size_type;
cache()
:addr_(reinterpret_cast<pair_type*>(::operator new(sizeof(pair_type) * CacheSize)))
{
for(std::size_t i = 0; i < CacheSize; ++i)
{
bitmap_[i] = 0;
seq_[i] = nana::npos;
}
}
~cache()
{
for(std::size_t i = 0; i < CacheSize; ++i)
{
if(bitmap_[i])
addr_[i].~pair_type();
}
::operator delete(addr_);
}
bool insert(key_type k, value_type v)
{
size_type pos = _m_find_key(k);
if(pos != nana::npos)
{
addr_[pos].second = v;
}
else
{
//No key exists
pos = _m_find_pos();
if(pos == nana::npos)
{ //No room, and remove the last pair
pos = seq_[CacheSize - 1];
(addr_ + pos)->~pair_type();
}
if(seq_[0] != nana::npos)
{//Need to move
for(int i = CacheSize - 1; i > 0; --i)
seq_[i] = seq_[i - 1];
}
seq_[0] = pos;
new (addr_ + pos) pair_type(k, v);
bitmap_[pos] = 1;
}
return v;
}
value_type * get(key_type k)
{
size_type pos = _m_find_key(k);
if(pos != nana::npos)
return &(addr_[pos].second);
return 0;
}
private:
size_type _m_find_key(key_type k) const
{
for(std::size_t i = 0; i < CacheSize; ++i)
{
if(bitmap_[i] && (addr_[i].first == k))
return i;
}
return nana::npos;
}
size_type _m_find_pos() const
{
for(std::size_t i = 0; i < CacheSize; ++i)
{
if(bitmap_[i] == 0)
return i;
}
return nana::npos;
}
private:
char bitmap_[CacheSize];
size_type seq_[CacheSize];
pair_type * addr_;
};
//handle_manager
//@brief
// handle_manager maintains handles of a type. removing a handle dose not destroy it,
// it will be inserted to a trash queue for deleting at a safe time.
// For efficiency, this class is not a thread-safe.
template<typename HandleType, typename Condition, typename Deleter>
class handle_manager
: nana::noncopyable
{
public:
typedef HandleType handle_type;
typedef Condition cond_type;
typedef Deleter deleter_type;
typedef std::map<handle_type, unsigned> handle_map_t;
typedef std::pair<handle_type, unsigned> holder_pair;
~handle_manager()
{
delete_trash(0);
}
void insert(handle_type handle, unsigned tid)
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
holder_[handle] = tid;
is_queue<std::is_same<cond_type, nana::null_type>::value, std::vector<handle_type> >::insert(handle, queue_);
cacher_.insert(handle, true);
}
void operator()(const handle_type handle)
{
remove(handle);
}
void remove(const handle_type handle)
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto i = static_cast<const handle_map_t&>(holder_).find(handle);
if(holder_.cend() != i)
{
is_queue<std::is_same<cond_type, nana::null_type>::value, std::vector<handle_type> >::erase(handle, queue_);
cacher_.insert(handle, false);
trash_.emplace_back(i->first, i->second);
holder_.erase(i);
}
}
void delete_trash(unsigned tid)
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
if(trash_.size())
{
deleter_type del_functor;
if(tid == 0)
{
for(auto & m : trash_)
del_functor(m.first);
trash_.clear();
}
else
{
for(auto i = trash_.begin(), end = trash_.end(); i != end;)
{
if(tid == i->second)
{
del_functor(i->first);
i = trash_.erase(i);
end = trash_.end();
}
else
++i;
}
}
}
}
handle_type last() const
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
if(queue_.size())
return queue_.back();
return handle_type();
}
std::size_t size() const
{
return holder_.size();
}
handle_type get(unsigned index) const
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
if(index < queue_.size())
return queue_[index];
return handle_type();
}
bool available(const handle_type handle) const
{
if (nullptr == handle)
return false;
std::lock_guard<decltype(mutex_)> lock(mutex_);
bool * v = cacher_.get(handle);
if(v) return *v;
return cacher_.insert(handle, (holder_.count(handle) != 0));
}
void all(std::vector<handle_type> & v) const
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
std::copy(queue_.cbegin(), queue_.cend(), std::back_inserter(v));
}
private:
template<bool IsQueueOperation, typename Container>
struct is_queue
{
public:
static void insert(handle_type handle, Container& queue)
{
if(cond_type::is_queue(handle))
queue.push_back(handle);
}
static void erase(handle_type handle, Container& queue)
{
if(cond_type::is_queue(handle))
{
for (auto i = queue.begin(); i != queue.end(); ++i)
{
if (handle == *i)
{
queue.erase(i);
break;
}
}
}
}
};
template<typename Container>
struct is_queue<true, Container>
{
public:
static void insert(handle_type handle, Container& queue){}
static void erase(handle_type handle, Container& queue){}
};
private:
mutable std::recursive_mutex mutex_;
mutable cache<const handle_type, bool, 5> cacher_;
handle_map_t holder_;
std::vector<handle_type> queue_;
std::vector<holder_pair> trash_;
};//end class handle_manager
}//end namespace detail
}// end namespace nana
#endif