#include #include #include #include #include #include #include #include #include #include #include namespace // anonymous { // ===================================================================== // misc helpers std::string quoteChar( const char c ) { if ( c == '\0' ) return "\\0"; else if ( c == '\a' ) return "\\a"; else if ( c == '\b' ) return "\\b"; else if ( c == '\f' ) return "\\f"; else if ( c == '\n' ) return "\\n"; else if ( c == '\r' ) return "\\r"; else if ( c == '\t' ) return "\\t"; else if ( c == '\v' ) return "\\v"; else if ( c == '\\' ) return "\\\\"; else if ( c == '\'' ) return "\\'"; else if ( c == '\"' ) return "\\\""; else if ( ! std::isprint( c ) ) { static boost::format hex( "\\x%02x" ); hex % static_cast< unsigned int >( c ); return hex.str(); } else { char s[2] = " "; s[0] = c; return s; } } template < typename S > inline std::string quoteString( const S & s ) { std::string rv; rv.append( "\"" ); BOOST_FOREACH( const char & c, s ) rv.append( quoteChar( c ) ); rv.append( "\"" ); return rv; } template < typename MapType, typename KeyArgType, typename ValueArgType > typename MapType::iterator efficientAddOrUpdateUnordered( MapType & m, const KeyArgType & k, const ValueArgType & v ) { // find where k is (or should be) typename MapType::iterator i = m.find( k ); // did we find it? if ( i != m.end() ) { // yup; just replace the value i->second = v; return i; } else { // nope; insert new key/value pair typedef typename MapType::value_type MVT; typedef std::pair< typename MapType::iterator, bool > InsertType; InsertType rv( m.insert( MVT( k, v ) ) ); return rv.first; } } // ===================================================================== // actual shared memory bits. // use a simple manager typedef boost::interprocess::managed_shared_memory ShmManagerType; // what type of character are we storing in our shared strings? typedef char ShmCharType; // we need an allocator for the string class to use; this // allocator is used to grab zero or more contiguous characters. typedef boost::interprocess::allocator< ShmCharType, ShmManagerType::segment_manager > ShmCharAllocatorType; // finally, we specify exactly what our shared strings are. typedef boost::interprocess::basic_string< ShmCharType, std::char_traits< ShmCharType >, ShmCharAllocatorType > ShmStringType; typedef std::string KeyType; typedef std::string ValueType; typedef ShmStringType StoredKeyType; typedef ShmStringType StoredValueType; // next, we need to define the pair type that is actually stored // in the map typedef std::pair< const StoredKeyType, StoredValueType > ShmPairType; // and we'll need to give the map a way to allocate new pairs typedef boost::interprocess::allocator< ShmPairType, ShmManagerType::segment_manager > ShmPairAllocatorType; // we finish defining the data storage by specifying a map that // uses ShmPairTypes to keep the key/value pairs in shared memory. // (the keys and values themselves are ShmStringTypes, so those // strings will also be in shared memory.) typedef boost::unordered_map< StoredKeyType, StoredValueType, boost::hash< StoredKeyType >, std::equal_to< StoredKeyType >, ShmPairAllocatorType > ShmMapType; inline KeyType toKey( const StoredKeyType & storedKey ) { return KeyType( storedKey.begin(), storedKey.end() ); } inline ValueType toValue( const StoredValueType & storedValue ) { return ValueType( storedValue.begin(), storedValue.end() ); } inline StoredKeyType toStoredKey( const KeyType & key, ShmManagerType & m_manager ) { return StoredKeyType( key.begin(), key.end(), m_manager.get_allocator< ShmCharType >() ); } inline StoredValueType toStoredValue( const ValueType & value, ShmManagerType & m_manager ) { return StoredValueType( value.begin(), value.end(), m_manager.get_allocator< ShmCharType >() ); } } // end namespace [anonymous] int test_main( int /* argc */, char * /* argv */ [] ) { const std::string & shmName( "ipstring" ); const std::size_t shmSize( 1024 * 1024 ); system( "rm -rf /dev/shm/ipstring" ); ShmManagerType m_manager( boost::interprocess::open_or_create, shmName.c_str(), shmSize ); ShmMapType * m_pMap( m_manager.find_or_construct< ShmMapType >( "map" )( 10 /* = initBucketCount */, boost::hash< StoredKeyType >(), std::equal_to< StoredKeyType >(), m_manager.get_allocator< ShmPairType >() ) ); BOOST_REQUIRE( m_pMap ); ShmMapType::iterator i; ShmMapType::iterator end( m_pMap->end() ); // ----------------------------------------------------------------- const StoredKeyType key( toStoredKey( "key", m_manager ) ); StoredValueType val1( toStoredValue( "x", m_manager ) ); efficientAddOrUpdateUnordered( *m_pMap, key, val1 ); i = m_pMap->find( key ); BOOST_REQUIRE( i != end ); BOOST_CHECK( i->second == val1 ); if ( i->second != val1 ) std::clog << "i->second=" << quoteString( i->second ) << ", " << "val1=" << quoteString( val1 ) << std::endl; StoredValueType val2( toStoredValue( "xxx", m_manager ) ); efficientAddOrUpdateUnordered( *m_pMap, key, val2 ); i = m_pMap->find( key ); BOOST_REQUIRE( i != end ); BOOST_CHECK( i->second == val2 ); if ( i->second != val2 ) std::clog << "i->second=" << quoteString( i->second ) << ", " << "val2=" << quoteString( val2 ) << std::endl; StoredValueType val3( toStoredValue( "xxxxxxxxxxxxxxxx", m_manager ) ); efficientAddOrUpdateUnordered( *m_pMap, key, val3 ); i = m_pMap->find( key ); BOOST_REQUIRE( i != end ); BOOST_CHECK( i->second == val3 ); if ( i->second != val3 ) std::clog << "i->second=" << quoteString( i->second ) << ", " << "val3=" << quoteString( val3 ) << std::endl; // ----------------------------------------------------------------- StoredValueType sv1( toStoredValue( "y", m_manager ) ); StoredValueType sv3( toStoredValue( "yyy", m_manager ) ); StoredValueType sv5( toStoredValue( "yyyyyy", m_manager ) ); sv1 = sv3; BOOST_CHECK( sv1 == sv3 ); if ( sv1 != sv3 ) std::clog << "sv1=" << quoteString( sv1 ) << ", " << "sv3=" << quoteString( sv3 ) << std::endl; sv1 = sv3; BOOST_CHECK( sv1 == sv3 ); if ( sv1 != sv3 ) std::clog << "sv1=" << quoteString( sv1 ) << ", " << "sv3=" << quoteString( sv3 ) << std::endl; sv1 = sv5; BOOST_CHECK( sv1 == sv5 ); if ( sv1 != sv5 ) std::clog << "sv1=" << quoteString( sv1 ) << ", " << "sv5=" << quoteString( sv5 ) << std::endl; sv1 = sv5; BOOST_CHECK( sv1 == sv5 ); if ( sv1 != sv5 ) std::clog << "sv1=" << quoteString( sv1 ) << ", " << "sv5=" << quoteString( sv5 ) << std::endl; return boost::exit_success; }