這篇文章簡單介紹一下 boost 中十分實用的庫函數 --- 多重索引 multi_index , 它的底層結構是用來存放 結構體的 map 的資料結構,
但不同於 stl,boost 中普通的map,它可以根據使用者的需要來指定索引的類型,即 key 的值可以根據需要的不同而變化的。
比如說,現在我定義了一個 fruit 的結構體,其中包含屬性 { fruit_name , fruit_color , fruit_shape }
然後使用 fruit 結構體分別存放三種水果,將其設定為 fruit_table
{apple | fruit_name = apple , fruit_color = red , fruit_shape = cycle }
{banana | fruit_name = banana , fruit_color = yellow , fruit_shape = line }
{grape | fruit_name = grape , fruit_colo r= purple , fruit_shape = cycle }
對於 multi_index 來說,僅僅為每個fruit /水果 執行個體提供一份儲存空間,但是卻可以分別將 fruit_name , fruit_color , fruit_shape 設定為該結構體的索引,
不同的索引對應的結構體中的 fruit 排序方式是不同的。
這裡定義的多重索引的功能與含義完全可以等同於資料庫中所建立的索引, 那麼通過訪問 映射底層儲存資料上的不同類型的索引
所直接擷取的並不是儲存底層資料實體, 而是該儲存實體的一個視圖,相當於是擷取到一個對象實體的指標一樣。
不同的視圖中元素屬性排列的方式是不同的,
如果我們將 fruit_name 設為多重索引之一,那麼我們通過 fruit_name 屬性訪問 fruit_table 將會得到一個按照 fruit_name 屬性進行排列的 fruit_table 的視圖 "view" 即
1.{apple| ...} , 2. {banana|...} , 3. {grape|... }
如果按照 fruit_color 我們將會擷取到一個按照 fruit_color 進行排序的 fruit_table 的視圖 "view"
1.{grape| fruit_color=purple} 2. {apple|fruit_color= red} 3.{banana | fruit_color = yellow }
fruit_shape 屬性建立索引 也是同理
索引的一點好處就是,可以根據需要來設定,在不修改底層儲存列表順序的基礎上, 可以將列表中的元素快速的按照 屬性進行順序訪問。
不然的話,就只能將底層存放的資料一一全部讀取到記憶體中,再根據某一個屬性進行升序、降序的排列。
因為將底層資料(存放到電腦硬碟上的檔案)通過 I/O 讀入到記憶體中,一是需要耗費大量的時間進行掃描硬碟,而是記憶體空間可能容納不下
清單項目中全部的資訊條目的(實際工作中的資訊條目可並不像是 fruit_node 中的屬性那樣少,有可能一個條目就對應上 GB 的視頻檔案) ,
這樣讀入本身就是問題,在跑個排序演算法,後果就可想而知了。
這就是我們為何要使用索引的原因,為何要使用多重索引呢?
1.實際工作中需要頻繁的針對資料列表中的多個屬性進行排序,這樣便有了針對該資料列表建立一個多重索引。
2.用於排序的索引屬性並不全都主索引(也就是索引與資料記錄/表項 之間是一一映射的關係)不能夠確定資料列表的排序次序,
就像是 fruit 例子中的僅僅通過 fruit_shape 屬性是無法將 grape 和 apple 進行排序的,因為沒有其他的索引屬性可供參考了。
這種情況,就需要添加其他的索引{fruit_name ,fruit_color }用作參考,當然這種情況下是優先參考有著 unique 性質的索引 。
現在我們要通過建立一個檔案清單的多重索引來介紹使用 boost::multi_index 的規則和如何調用自訂的多重索引來 擷取視圖,通過視圖來訪問底層儲存實體的各類屬性
如果運行平台是 windows 直接運行源碼即可, 不過要根據需要修改一下對應讀入的檔案路徑
如果運行平台是 linux ,
請結合後續的 configure.in 和 Makefile 以及 build.sh 檔案來 使用 autotools 流程來編譯 , 參考文檔
linux平台上,要配合程式中的設定在 /tmp/路徑下面建立名稱為 rsa_key.pub,rsa_key{0|1|2|3|4}.txt 的檔案,如果不想改來源程式的話
點擊(此處)摺疊或開啟 #if !defined(NDEBUG)
#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
#endif
#include <cstdio>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/shared_ptr.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
using boost::multi_index_container ;
using namespace boost::multi_index ;
struct file_node
{
int id ; // ---- 這個是檔案的 id 號碼
std::string path_name ; // ---- 這個是檔案的 路徑, 在設定索引的時候,我們將其設定為非重複的主索引項目
long length ; // ---- 這個是檔案的 長度, 在本實驗中沒有用到
std::string creator ; // ---- 這個是檔案的 作者, 在設定索引的時候,我們將其設定為可重複的輔助索引項目
file_node( int id , std::string path_name , std::string creator ): // 這個是 檔案-節點 結構體的建構函式
id(id) , path_name(path_name) , length(0), creator(creator)
{
}
friend std::ostream & operator<<(std::ostream &os , const file_node & f ) ; // 這裡重載了 operator<< 並將其設定為友元方法, // 為了方便將 file-node 中的屬性資訊轉換為流
} ;
std::ostream &operator<< ( std::ostream &os , const file_node &f ) // 在這雷根據檔案路徑開啟檔案,並讀取檔案的內容
{ // 將檔案中的內容進行格式化並轉換為 流 對象,並返回
char file_buffer[1024] ;
std::string file_content ;
bool isOpen = false ;
FILE *fp = fopen(f.path_name.c_str() , "r") ;
if ( fp != NULL )
isOpen = true ;
if ( isOpen )
{
int ret = fread((void*)file_buffer , sizeof(char) , sizeof(file_bu