Skip to content

Instantly share code, notes, and snippets.

@khlus
Created August 6, 2015 09:03
Show Gist options
  • Save khlus/a664d515e176585bcaa6 to your computer and use it in GitHub Desktop.
Save khlus/a664d515e176585bcaa6 to your computer and use it in GitHub Desktop.
#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