Created
August 6, 2015 09:03
-
-
Save khlus/a664d515e176585bcaa6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
//BOOST | |
#include <boost/multi_index_container.hpp> | |
#include <boost/multi_index/indexed_by.hpp> | |
#include <boost/multi_index/member.hpp> | |
#include <boost/multi_index/ordered_index.hpp> | |
#include <boost/multi_index/identity.hpp> | |
#include <boost/multi_index/mem_fun.hpp> | |
#include <boost/multi_index/composite_key.hpp> | |
// #include <boost/algorithm/string.hpp> | |
// #include <boost/functional/hash.hpp> | |
#include <boost/interprocess/containers/string.hpp> | |
#include <boost/container/scoped_allocator.hpp> | |
#include <boost/interprocess/managed_mapped_file.hpp> | |
#include <boost/interprocess/offset_ptr.hpp> | |
///#include <boost/chrono.hpp> | |
#include <boost/tokenizer.hpp> | |
#include <boost/variant.hpp> | |
//LIBS | |
//#include "libs/helpers/boost_signal_helpers.hpp" | |
//#include <boost/mpl/vector.hpp> | |
#include "TypeTraits.h" | |
namespace WSIndexer | |
{ | |
namespace | |
{ | |
const char WS_FILEINFO_REGISTRY_NAME[] = "ws_fileinfo_registry"; | |
} | |
// Warning! Use only fixed-size value types | |
struct file_metadata | |
{ | |
HashType hash;// | |
bool isDir; | |
size_t filesize; | |
time_t last_change; | |
}; | |
class file_registry | |
{ | |
//Declare string type that can be allocated on mapped file | |
typedef boost::interprocess::basic_string < | |
wchar_t, std::char_traits<wchar_t>, | |
boost::interprocess::allocator < wchar_t, boost::interprocess::managed_mapped_file::segment_manager > | |
> mapped_wstring; | |
//Declare a pointer type | |
template<typename T> | |
using mapped_ptr = boost::interprocess::offset_ptr < T > ; | |
struct file_entry | |
{ | |
mapped_wstring name; | |
mapped_ptr<file_entry> parent_ptr; | |
file_metadata content; | |
HashType by_hash_index() const { return content.hash; } | |
size_t by_size_index() const { return content.filesize; } | |
}; | |
/// Declare tags for tagged multi_index_container | |
struct by_name_tag{}; | |
struct by_hash_tag{}; | |
struct by_size_tag{}; | |
/// Declare unique key fields | |
struct name_key : boost::multi_index::composite_key < | |
file_entry, | |
boost::multi_index::member<file_entry, mapped_ptr<file_entry>, &file_entry::parent_ptr>, | |
boost::multi_index::member < file_entry, mapped_wstring, &file_entry::name > | |
> {}; | |
struct hash_key : boost::multi_index::const_mem_fun < file_entry, HashType, &file_entry::by_hash_index > {}; | |
struct size_key : boost::multi_index::const_mem_fun < file_entry, size_t, &file_entry::by_size_index > {}; | |
/// Define a multi_index_container of registry fields | |
typedef boost::multi_index_container < | |
file_entry, | |
boost::multi_index::indexed_by < | |
boost::multi_index::ordered_unique <boost::multi_index::tag<by_name_tag>, name_key>, | |
boost::multi_index::ordered_non_unique < boost::multi_index::tag<by_hash_tag>, hash_key>, | |
boost::multi_index::ordered_non_unique < boost::multi_index::tag<by_size_tag>, size_key> | |
> | |
, boost::interprocess::allocator < file_entry, boost::interprocess::managed_mapped_file::segment_manager > | |
> file_registry_storage; | |
/// Declare iterators type | |
typedef boost::multi_index::index<file_registry_storage, by_name_tag>::type::iterator by_name_iterator; | |
typedef boost::multi_index::index<file_registry_storage, by_hash_tag>::type::iterator by_hash_iterator; | |
typedef boost::multi_index::index<file_registry_storage, by_size_tag>::type::iterator by_size_iterator; | |
///default values | |
enum | |
{ | |
mapped_file_size = 65536 /*?granularity?*/ * 1024 /** 16*/,//1 Gb | |
}; | |
public: | |
class iterator/* : public std::iterator< std::input_iterator_tag, int >*/ | |
{ | |
struct increment_visitor : public boost::static_visitor < void > | |
{ | |
template<typename T> | |
void operator()(T& iter) const{ ++iter; } | |
}; | |
struct get_visitor : public boost::static_visitor < const file_entry& > | |
{ | |
template<typename T> | |
const file_entry& operator()(T& iter) const { return *iter; } | |
}; | |
public: | |
template<typename Iter> | |
iterator(const Iter& iter) | |
{ | |
m_variants = iter; | |
} | |
iterator& operator ++ () | |
{ | |
boost::apply_visitor(increment_visitor(), m_variants); | |
return *this; | |
} | |
// int/*C_Buffer*/ operator * () const | |
// { | |
// | |
// } | |
bool operator == (const iterator& left) | |
{ | |
if (this == &left) | |
return true; | |
return m_variants == left.m_variants; | |
} | |
bool operator != (const iterator& left) | |
{ | |
return !(operator == (left)); | |
} | |
std::wstring path() | |
{ | |
std::wstring path; | |
const file_entry& entry = boost::apply_visitor(get_visitor(), m_variants); | |
path += entry.name.c_str(); | |
mapped_ptr<file_entry> pi = entry.parent_ptr; | |
while (pi != 0) | |
{ | |
std::wstring name = pi->name.c_str(); | |
path = name + L"/" + path; | |
pi = pi->parent_ptr; | |
} | |
return path; | |
} | |
std::wstring name() | |
{ | |
const file_entry& entry = boost::apply_visitor(get_visitor(), m_variants); | |
return entry.name.c_str(); | |
} | |
file_metadata metadata() | |
{ | |
const file_entry& entry = boost::apply_visitor(get_visitor(), m_variants); | |
return entry.content; | |
} | |
private: | |
boost::variant <by_name_iterator, by_hash_iterator, by_size_iterator> m_variants; | |
}; | |
public: | |
//Ctor | |
file_registry(const std::string& path) : m_segMgr(boost::interprocess::open_or_create, path.c_str(), mapped_file_size) | |
{ | |
m_pStorage = m_segMgr.find_or_construct<file_registry_storage>(WS_FILEINFO_REGISTRY_NAME)( | |
file_registry_storage::ctor_args_list(), | |
file_registry_storage::allocator_type(m_segMgr.get_segment_manager())); | |
} | |
//Dtor | |
~file_registry() | |
{ | |
m_pStorage = nullptr; | |
} | |
// hide assignment operator | |
file_registry& operator=(const file_registry &) = delete; | |
file_registry& operator=(const file_registry &&) = delete; | |
//hide copy constructor | |
file_registry(const file_registry &) = delete; | |
file_registry(const file_registry &&) = delete; | |
public: | |
size_t count() | |
{ | |
return m_pStorage->size(); | |
} | |
void insert(iterator parent, const std::wstring& name, const file_metadata& metadata = file_metadata()) | |
{ | |
} | |
void insert(const std::wstring& path, const file_metadata& metadata = file_metadata()) | |
{ | |
if (path.empty())// check for "." and ".." in path | |
return; | |
typedef boost::tokenizer < boost::char_separator<wchar_t>, | |
std::wstring::const_iterator, std::wstring > tokenizer; | |
tokenizer tok(path, boost::char_separator<wchar_t>(L"/")); | |
mapped_ptr<file_entry> current_entry = 0; | |
for (tokenizer::iterator beg = tok.begin(); beg != tok.end(); ++beg) | |
{ | |
mapped_wstring dir(m_segMgr.get_segment_manager()); | |
dir.assign((*beg).c_str()); | |
by_name_iterator it = m_pStorage->find(boost::make_tuple(current_entry, dir)); | |
if (it == m_pStorage->end()) | |
{ | |
//std::cout << "non-existent directory" << std::endl; | |
file_entry entry({ dir, current_entry, metadata }); | |
auto result = m_pStorage->insert(entry); | |
if (!result.second) | |
{ | |
//std::cout << "directory already exists" << std::endl; | |
} | |
current_entry = const_cast<file_entry*>(&(*result.first)); | |
} | |
else | |
{ | |
current_entry = const_cast<file_entry*>(&(*it)); | |
} | |
} | |
} | |
void remove(const std::wstring& path) | |
{ | |
typedef boost::tokenizer < boost::char_separator<wchar_t>, | |
std::wstring::const_iterator, std::wstring > tokenizer; | |
tokenizer tok(path, boost::char_separator<wchar_t>(L"/")); | |
mapped_ptr<file_entry> current_dir = 0; | |
for (tokenizer::iterator beg = tok.begin(); beg != tok.end(); ++beg) | |
{ | |
mapped_wstring dir(m_segMgr.get_segment_manager()); | |
dir.assign((*beg).c_str()); | |
by_name_iterator it = m_pStorage->find(boost::make_tuple(current_dir, dir)); | |
if (it == m_pStorage->end()) | |
{ | |
// std::cout << "non-existent directory" << std::endl; | |
return; | |
} | |
current_dir = const_cast<file_entry*>(&(*it)); | |
} | |
by_name_iterator it0, it1; | |
boost::tie(it0, it1) = m_pStorage->equal_range(boost::make_tuple(current_dir)); | |
for (it0; it0 != it1;) | |
{ | |
std::wstring name = it0->name.c_str(); | |
remove(path + L"/" + name); | |
boost::tie(it0, it1) = m_pStorage->equal_range(boost::make_tuple(current_dir)); | |
} | |
// | |
// std::list< item * >::iterator iter = items.begin(); | |
// std::list< item * >::iterator end = items.end(); | |
// | |
// while (iter != items.end()) | |
// { | |
// item * pItem = *iter; | |
// | |
// if (pItem->update() == true) | |
// { | |
// other_code_involving(pItem); | |
// ++iter; | |
// } | |
// else | |
// { | |
// // BTW, who is deleting pItem, a.k.a. (*iter)? | |
// iter = items.erase(iter); | |
// } | |
// } | |
by_name_iterator iter = m_pStorage->find(boost::make_tuple(current_dir->parent_ptr, current_dir->name)); | |
std::wstring name = iter->name.c_str(); | |
m_pStorage->erase(iter); | |
} | |
std::pair<iterator, iterator> equal_hash_range(const HashType& hash) | |
{ | |
return m_pStorage->get<by_hash_tag>().equal_range(hash); | |
} | |
void replace(const std::wstring& path, const file_metadata& metadata) | |
{ | |
typedef boost::tokenizer < boost::char_separator<wchar_t>, | |
std::wstring::const_iterator, std::wstring > tokenizer; | |
tokenizer tok(path, boost::char_separator<wchar_t>(L"/")); | |
mapped_ptr<file_entry> current_dir = 0; | |
for (tokenizer::iterator beg = tok.begin(); beg != tok.end(); ++beg) | |
{ | |
mapped_wstring dir(m_segMgr.get_segment_manager()); | |
dir.assign((*beg).c_str()); | |
by_name_iterator it = m_pStorage->find(boost::make_tuple(current_dir, dir)); | |
if (it == m_pStorage->end()) | |
{ | |
// std::cout << "non-existent directory" << std::endl; | |
return; | |
} | |
current_dir = const_cast<file_entry*>(&(*it)); | |
} | |
by_name_iterator iter = m_pStorage->find(boost::make_tuple(current_dir->parent_ptr, current_dir->name)); | |
file_entry entry({ current_dir->name, current_dir->parent_ptr, metadata }); | |
m_pStorage->replace(iter, entry); | |
} | |
iterator begin() | |
{ | |
return m_pStorage->begin(); | |
} | |
iterator end() | |
{ | |
return m_pStorage->end(); | |
} | |
private: | |
private: | |
/// Memory allocator | |
boost::interprocess::managed_mapped_file m_segMgr; | |
/// Pointer to allocated in shared memory data | |
file_registry_storage* m_pStorage; | |
}; | |
}//WSIndexer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment