I have a muti_index for a database. First I'll say, this will be so much
better than my old way of running an SQL every time I wanted to change
the order. Thanks. I never see a database bigger than some 1200 records,
usually <200, so I'm not worried about memory bloat.
So I've wrapped the multi_index in a class that will hide the boost
includes from the rest of my app. I'll include the work below. I'd like
to treat some kind of interface, like a generic iterator, depending on
what order I have set. I would only use one iterator at a time. But the
iterators are templated and have no base so that I can easily keep a set
of iterators handy, say in a container, and then supply the appropriate
iterator through an interface.
In my class, RaOrderRecords, I'd something like:
set.GetIt( )
set.IncIt( )
set.IsEndIt( )
etc.
Or even overload so I could set++
And a member like SetOrder( [enum of new order] ) to have the internal
iterator switched.
I'm sure there is an elegant way to deal with this, but it escapes me.
Thanks, Dan.
~~~~~ .hpp
#pragma once
//
// ............................................................
namespace RsOrderIndex
{
struct ord_key{ };
struct ord_id{ };
struct ord_desc{ };
struct ord_sevice{ };
struct ord_remain{ };
struct ord_cat{ };
struct ord_group{ };
enum RecOrderIndex
{
ordNull,
ordKey,
ordId,
ordDesc,
ordService,
ordRemain,
ordCat,
ordGroup,
};
};
// ............................................................
class RaOrderRecords;
struct ord_record_item
{
//properties
RaOrderRecords* pParent;
size_t absPos;
//indexed properties
long key;
std::string strId;
std::string strDescription;
COleDateTime dtInService;
long remaining;
long catKey;
long groupKey;
//one and only constructor
ord_record_item( RaOrderRecords *pInParent, long inKey, CString&
inId, CString& inDesc,
COleDateTime& indtIns, long inRemain, long inCatKey, long
inGroupKey, size_t inPos )
:pParent( pInParent )
,key( inKey )
,strId( inId )
,strDescription( inDesc )
,dtInService( indtIns )
,remaining( inRemain )
,catKey( inCatKey )
,groupKey( inGroupKey )
,absPos( inPos )
{ }
//useful members
size_t GetAbsPos( ) const { return absPos; }
//indexing members
bool operator < ( const ord_record_item& e ) const { return key <
e.key; }
unsigned long cat_pos( ) const;
unsigned long group_pos( ) const;
};
// ............................................................
#ifdef INCLUDE_ORDRECORD_BASE //to isolate boost headers
typedef boost::multi_index::multi_index_container <
ord_record_item,
boost::multi_index::indexed_by
<
// sort by primary database key, ord_record_item comp
boost::multi_index::ordered_unique
<
boost::multi_index::tag< RsOrderIndex::ord_key >,
boost::multi_index::identity< ord_record_item >
>,
// sort by less<string> on strId
boost::multi_index::ordered_non_unique
<
boost::multi_index::tag< RsOrderIndex::ord_id >,
BOOST_MULTI_INDEX_MEMBER( ord_record_item, std::string, strId )
>,
// sort by less<string> on strDescription
boost::multi_index::ordered_non_unique
<
boost::multi_index::tag< RsOrderIndex::ord_desc >,
BOOST_MULTI_INDEX_MEMBER( ord_record_item, std::string,
strDescription )
>,
// sort by less<COleDateTime> on dtInService
boost::multi_index::ordered_non_unique
<
boost::multi_index::tag< RsOrderIndex::ord_sevice >,
BOOST_MULTI_INDEX_MEMBER( ord_record_item, COleDateTime,
dtInService )
>,
// sort by less<COleDateTime> on remaining, Description
boost::multi_index::ordered_non_unique
<
boost::multi_index::tag< RsOrderIndex::ord_remain >,
boost::multi_index::composite_key
<
ord_record_item,
BOOST_MULTI_INDEX_MEMBER( ord_record_item, long,
remaining ),
BOOST_MULTI_INDEX_MEMBER( ord_record_item, std::string,
strDescription )
>
>,
// sort by category, description
boost::multi_index::ordered_non_unique
<
boost::multi_index::tag< RsOrderIndex::ord_cat >,
boost::multi_index::composite_key
<
ord_record_item,
BOOST_MULTI_INDEX_CONST_MEM_FUN( ord_record_item,
unsigned long, cat_pos ),
BOOST_MULTI_INDEX_MEMBER( ord_record_item, std::string,
strDescription )
>
>,
// sort by group, description
boost::multi_index::ordered_non_unique
<
boost::multi_index::tag< RsOrderIndex::ord_group >,
boost::multi_index::composite_key
<
ord_record_item,
BOOST_MULTI_INDEX_CONST_MEM_FUN( ord_record_item,
unsigned long, group_pos ),
BOOST_MULTI_INDEX_MEMBER( ord_record_item, std::string,
strDescription )
>
>
>
>ord_record_set;
typedef ord_record_set::index< RsOrderIndex::ord_key >::type::iterator
It_key_ord;
typedef ord_record_set::index< RsOrderIndex::ord_id >::type::iterator
It_id_ord;
typedef ord_record_set::index< RsOrderIndex::ord_desc >::type::iterator
It_desc_ord;
typedef ord_record_set::index< RsOrderIndex::ord_sevice
>::type::iterator It_service_ord;
typedef ord_record_set::index< RsOrderIndex::ord_remain
>::type::iterator It_remain_ord;
typedef ord_record_set::index< RsOrderIndex::ord_cat >::type::iterator
It_cat_ord;
typedef ord_record_set::index< RsOrderIndex::ord_group >::type::iterator
It_group_ord;
nth_index_iterator
#else // INCLUDE_ORDRECORD_BASE
//forward declared for general use, no multi record boost headers
class ord_record_set;
#endif // INCLUDE_ORDRECORD_BASE
// ............................................................
class RaOrderRecords
{
ord_record_set* pOrder;
RaCatGroupMap catSet;
RaCatGroupMap groupSet;
//RSKeyPosSet keyPosSet;
public:
RaOrderRecords( );
~RaOrderRecords( );
bool ReadRecordSet( RaRecordset* pRS );
unsigned long GetCatPos( long inCatKey )
{
RaCatGroupMapIt it= catSet.find( inCatKey );
if( it != catSet.end( ) )
return it->second.ordered;
else
return -1;//max unsigned
}
unsigned long GetGroupPos( long inGroupKey )
{
RaCatGroupMapIt it= groupSet.find( inGroupKey );
if( it != groupSet.end( ) )
return it->second.ordered;
else
return -1;//max unsigned
}
#ifdef _DEBUG
void Dump( RsOrderIndex::RecOrderIndex index );
#else
void Dump( RsOrderIndex::RecOrderIndex index ) { }
#endif
};
~~~~~~.cpp
#include "stdafx.h"
#if !defined(NDEBUG)
#include <boost/multi_index/safe_mode_errors.hpp>
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/composite_key.hpp>
#include "records.h"
#define INCLUDE_ORDRECORD_BASE
#include "RecordsOrd.hpp"
// .........................................................
using namespace boost::multi_index;
using namespace RsOrderIndex;
unsigned long ord_record_item::cat_pos( ) const
{
return pParent->GetCatPos( catKey );
}
unsigned long ord_record_item::group_pos( ) const
{
return pParent->GetGroupPos( groupKey );
}
RaOrderRecords::RaOrderRecords( )
{
pOrder= new ord_record_set;
}
RaOrderRecords::~RaOrderRecords( )
{
delete pOrder;
}
bool RaOrderRecords::ReadRecordSet( RaRecordset* pRS )
{
pOrder->clear( );
LoadCategories( catSet );
LoadGroups( groupSet );
COleDateTime dtNo( 10000.0 );// TODO !!!!
try
{
int i= 1;
for( pRS->MoveFirst( ); ! pRS->IsEOF( ); pRS->MoveNext( ) )
{
pOrder->insert(
ord_record_item(
this,
pRS->ds_id,
pRS->ds_number,
pRS->ds_description,
pRS->IsFieldNull( &pRS->ds_inService ) ? dtNo :
pRS->ds_inService,
pRS->GetRemaining( ),
pRS->ds_catKey,
pRS->ds_groupKey,
i
) );
// keyPosSet.SetKeyPos( pRS->ds_id, i++ );
}
}
catch( CDBException* e )
{
e->Delete( );
return false;
}
return true;
}
#ifdef _DEBUG
void RaOrderRecords::Dump( RecOrderIndex index )
{
std::string strT;
strT.c_str( );
It_cat_ord it= pOrder->get< ord_cat >( ).begin( );
for( int i= 1; it != pOrder->get< ord_cat >( ).end( ); ++it, ++i )
{
CString strT;
RaCatGroupMapIt cat= catSet.find( it->catKey );
if( cat != catSet.end( ) )
strT= cat->second.title;
else
strT= _T("(null)");
TRACE( "%3.0d %s---%s\n", i, strT, it->strDescription.c_str( ) );
}
//It_service_ord sit= pOrder->get< ord_sevice >( ).begin( );
//for( ; sit != pOrder->get< ord_sevice >( ).end( ); ++sit )
// TRACE( "%s---%s\n", sit->strDescription.c_str( ),
sit->dtInService.Format( _T("%m/%d/%y") ) );
}
#endif //_DEBUG