扩展Boost库对tbb::concurrent_hash_map的序列化支持

        工作中用到了tbb::concurrent_hash_map,但是同时用到了boost的serialize,boost没有提供对tbb::concurrent_hash_map的序列化支持,因此自己参考boost对stl中hash_map的实现,实现了使用boost库序列化tbb::concurrent_hash_map。本人水平有限,boost中hash_map序列化相关代码未完全看透,下面代码不保证在各种环境的可靠性。如果文中有错误,欢迎不吝指点。

       实现文件:concurrent_hash_map.hpp

#ifndef _CONCURRENT_HASH_MAP_HPP_
#define _CONCURRENT_HASH_MAP_HPP_

#include "tbb/concurrent_hash_map.h"
#include 
#include 
#include 
#include 

namespace boost
{
	namespace serialization
	{
		namespace tbb
		{
			template
			struct archive_input_hash_map
			{
				inline void operator()(
					Archive &ar,
					Container &s,
					const unsigned int v
					){
					typedef typename Container::value_type type;
					detail::stack_construct t(ar, v);
					// borland fails silently w/o full namespace
					ar >> boost::serialization::make_nvp("item", t.reference());

					//-▽-modified by me 2016/1/20---------//
					
					Container::accessor a;
					bool bResult = s.insert(a, t.reference());
					//std::pair result =  
					//	s.insert(t.reference());
					// note: the following presumes that the map::value_type was NOT tracked
					// in the archive.  This is the usual case, but here there is no way
					// to determine that.  
					//if (result.second){            
					//	ar.reset_object_address(     
					//		&(result.first->second), 
					//		&t.reference().second    
					//		);                       
					//}                             
					if (bResult)
					{
						ar.reset_object_address(
							&(a->second), 
							&t.reference().second
							);
					}
					//-△-modified by me 2016/1/20----------//
				}
			};

			template
			inline void save_hash_collection(Archive & ar, const Container &s)
			{
				collection_size_type count(s.size());
				const collection_size_type bucket_count(s.bucket_count());
				const item_version_type item_version(
					version::value
					);

#if 0
				/* should only be necessary to create archives of previous versions
				* which is not currently supported.  So for now comment this out
				*/
				boost::archive::library_version_type library_version(
					ar.get_library_version()
					);
				// retrieve number of elements
				if (boost::archive::library_version_type(6) != library_version){
					ar << BOOST_SERIALIZATION_NVP(count);
					ar << BOOST_SERIALIZATION_NVP(bucket_count);
				}
				else{
					// note: fixup for error in version 6.  collection size was
					// changed to size_t BUT for hashed collections it was implemented
					// as an unsigned int.  This should be a problem only on win64 machines
					// but I'll leave it for everyone just in case.
					const unsigned int c = count;
					const unsigned int bc = bucket_count;
					ar << BOOST_SERIALIZATION_NVP(c);
					ar << BOOST_SERIALIZATION_NVP(bc);
				}
				if (boost::archive::library_version_type(3) < library_version){
					// record number of elements
					// make sure the target type is registered so we can retrieve
					// the version when we load
					ar << BOOST_SERIALIZATION_NVP(item_version);
				}
#else
				ar << BOOST_SERIALIZATION_NVP(count);
				ar << BOOST_SERIALIZATION_NVP(bucket_count);
				ar << BOOST_SERIALIZATION_NVP(item_version);
#endif

				typename Container::const_iterator it = s.begin();
				while (count-- > 0){
					// note borland emits a no-op without the explicit namespace
					boost::serialization::save_construct_data_adl(
						ar,
						&(*it),
						boost::serialization::version<
						typename Container::value_type
						>::value
						);
					ar << boost::serialization::make_nvp("item", *it++);
				}
			}

			template
			inline void load_hash_collection(Archive & ar, Container &s)
			{
				collection_size_type count;
				collection_size_type bucket_count;
				boost::serialization::item_version_type item_version(0);
				boost::archive::library_version_type library_version(
					ar.get_library_version()
					);
				// retrieve number of elements
				if (boost::archive::library_version_type(6) != library_version){
					ar >> BOOST_SERIALIZATION_NVP(count);
					ar >> BOOST_SERIALIZATION_NVP(bucket_count);
				}
				else{
					// note: fixup for error in version 6.  collection size was
					// changed to size_t BUT for hashed collections it was implemented
					// as an unsigned int.  This should be a problem only on win64 machines
					// but I'll leave it for everyone just in case.
					unsigned int c;
					unsigned int bc;
					ar >> BOOST_SERIALIZATION_NVP(c);
					count = c;
					ar >> BOOST_SERIALIZATION_NVP(bc);
					bucket_count = bc;
				}
				if (boost::archive::library_version_type(3) < library_version){
					ar >> BOOST_SERIALIZATION_NVP(item_version);
				}
				s.clear();
#if ! defined(__MWERKS__)
				//s.resize(bucket_count);  //delete  by me 2016/1/20
#endif
				InputFunction ifunc;
				while (count-- > 0){
					ifunc(ar, s, item_version);
				}
			}
		}
	}
}

template<
	class Archive,
	class Key,
	class HashFcn,
	class EqualKey,
	class Allocator
>
inline void serialize( Archive & ar
               , tbb::concurrent_hash_map &t,
               const unsigned int file_version)
{
	boost::serialization::split_free(ar, t, file_version);
}

	template<
		class Archive,
		class Key,
		class HashFcn,
		class EqualKey,
		class Allocator
	>
	inline void save(
	Archive & ar,
	const tbb::concurrent_hash_map <
	Key, HashFcn, EqualKey, Allocator
	> &t,
	const unsigned int file_version
	){
			boost::serialization::tbb::save_hash_collection <
				Archive,
				tbb::concurrent_hash_map<
				Key, HashFcn, EqualKey, Allocator
				>
			> (ar, t);
		}

		template<
			class Archive,
			class Key,
			class HashFcn,
			class EqualKey,
			class Allocator
		>
		inline void load(
		Archive & ar,
		tbb::concurrent_hash_map<
		Key, HashFcn, EqualKey, Allocator
		> &t,
		const unsigned int file_version
		){
				boost::serialization::tbb::load_hash_collection <
					Archive,
					tbb::concurrent_hash_map<
					Key, HashFcn, EqualKey, Allocator
					>,
					boost::serialization::tbb::archive_input_hash_map <
					Archive,
					tbb::concurrent_hash_map<
					Key, HashFcn, EqualKey, Allocator
					>
					>
				> (ar, t);
			}
#endif _CONCURRENT_HASH_MAP_HPP_

测试程序:

#include "stdafx.h"
#include 
#include 
#include 
#include 

#include "boost/archive/binary_iarchive.hpp"
#include "boost/archive/binary_oarchive.hpp"

#include "tbb/concurrent_hash_map.h"
#include "concurrent_hash_map.hpp"

struct tbb_hash_func  //hash 函数  
{
	// 取hash value
	static size_t hash( std::string str)
	{
		std::hash hash_fn;
		return hash_fn(std::string(str));
	}

	static bool equal(const std::string str1, const std::string str2)
	{
		return memcmp(&str1, &str2, sizeof(str2)) == 0 ? true : false;
	}
};

typedef tbb::concurrent_hash_map Int_TableType;
typedef tbb::concurrent_hash_map < std::string, std::string, tbb_hash_func >String_TableType;

void write_test()
{
	std::fstream file("Text.big", std::ios::binary | std::ios::out);

	Int_TableType Table;
	Int_TableType::accessor a;
	Table.insert(a, Int_TableType::value_type(std::string("First"), 1));
	Table.insert(a, Int_TableType::value_type(std::string("Second"), 2));
	Table.insert(a, Int_TableType::value_type(std::string("Third"), 3));
	Table.insert(a, Int_TableType::value_type(std::string("Fourth"), 4));
	Table.insert(a, Int_TableType::value_type(std::string("Fifth"), 5));
	Table.insert(a, Int_TableType::value_type(std::string("Sixth"), 6));
	Table.insert(a, Int_TableType::value_type(std::string("Seventh"), 7));
	for (int i = 0; i < 1000; ++i)
	{
		if ( i<200)
			Table.insert(a, Int_TableType::value_type(std::string("X"), 8 + i));
		else if ( i>=200 && i<400 )
			Table.insert(a, Int_TableType::value_type(std::string("S"), 8 + i));
		else if ( i>=400 && i<600 )
			Table.insert(a, Int_TableType::value_type(std::string("Y"), 8 + i));
		else if ( i>=600 && i<800 )
			Table.insert(a, Int_TableType::value_type(std::string("Z"), 8 + i));
		else if (i>=800 )
			Table.insert(a, Int_TableType::value_type(std::string("W"), 8 + i));
	}
		

	Int_TableType::iterator it = Table.begin();
	for (; it != Table.end(); ++it)
	{
		std::cout << it->first << "---" << it->second << std::endl;
	}

	std::cout << "SIZE:"<< Table.size() << std::endl;
	boost::archive::binary_oarchive os(file);
	os << Table;
	file.close();
}

void read_test()
{
	std::fstream file("Text.big", std::ios::binary | std::ios::in);

	Int_TableType Table;
	boost::archive::binary_iarchive is(file);

	is >> Table;

	std::cout << "-------------------------------------------" << std::endl;
	Int_TableType::iterator it = Table.begin();
	for (; it != Table.end(); ++it)
	{
		std::cout << it->first << "---" << it->second << std::endl;
	}

	std::cout << "SIZE:" << Table.size() << std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	write_test();
	read_test();

	system("pause");
	return 0;
}


你可能感兴趣的:(C++)