Boost logo

Boost Users :

Subject: [Boost-users] [MultiIndex] As if one iterator
From: Dan Bloomquist (danb_at_[hidden])
Date: 2010-06-04 20:07:25


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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net