
順序付きマップ ライブラリは、Python の OrderedDict と同様の方法で挿入順序を保持するハッシュ マップとハッシュ セットを提供します。マップを反復処理すると、値は挿入されたときと同じ順序で返されます。
値は下層の構造に連続して保存され、消去操作後でも値の間に穴が生じることはありません。デフォルトでは、この構造にはstd::dequeが使用されますが、 std::vector使用することも可能です。この構造体には、 values_container()メソッドを通じて直接アクセスできます。構造体がstd::vectorの場合、C API と簡単に対話できるようにdata()メソッドも提供されます。これにより高速な反復が可能になりますが、O(bucket_count) 個の消去操作が必要になるという欠点があります。 O(1) pop_back()と O(1) unordered_erase()関数が利用可能です。順序付け消去を頻繁に使用する場合は、別のデータ構造を推奨します。
ハッシュの衝突を解決するために、ライブラリは後方シフト削除による線形ロビン フード プローブを使用します。
このライブラリは、一意の値を持つstd::deque/std::vectorと同様の動作を提供しますが、検索の平均時間計算量は O(1)、挿入の償却時間計算量は O(1) です。これには、メモリ使用量が少し増えるという代償が伴います (デフォルトではバケットあたり 8 バイト)。
tsl::ordered_mapとtsl::ordered_setという 2 つのクラスが提供されています。
注: ライブラリは、高速モジュロを利用するために、バケット配列のサイズに 2 の累乗を使用します。良好なパフォーマンスを得るには、ハッシュ テーブルに適切に分散されたハッシュ関数が必要です。パフォーマンスの問題が発生した場合は、ハッシュ関数を確認してください。
tsl::ordered_mapターゲットを使用することもできます。std::unordered_mapと同様ですが、挿入が高速になり、メモリ使用量が削減されます (詳細についてはベンチマークを参照)。Keyとは異なる型でのfindの使用が可能になります (たとえば、キーとしてstd::unique_ptr<foo>使用するマップがある場合、キー パラメーターとしてfoo*またはstd::uintptr_tを使用できます)。 std::unique_ptr<foo>を構築せずにfind 。例を参照してください)。precalculated_hashパラメータを参照)。serialize/deserializeメソッドを参照してください)。-fno-exceptionsオプションを使用するか、MSVC では/EHオプションを使用しないか、単にTSL_NO_EXCEPTIONS定義することによって)。 std::terminate例外が無効な場合にthrow命令の代わりに使用されます。std::unordered_mapおよびstd::unordered_setによく似ています。std::unordered_mapとの違いtsl::ordered_map std::unordered_mapと同様のインターフェースを持とうとしますが、いくつかの違いが存在します。
RandomAccessIteratorです。std::vectorおよびstd::dequeに近い方法で動作します (詳細については API を参照)。 std::vector ValueTypeContainerとして使用する場合、 reserve()使用してスペースを事前に割り当て、挿入時のイテレータの無効化を回避できます。erase()操作が遅く、O(bucket_count) の複雑さがあります。より高速な O(1) バージョンのunordered_erase()が存在しますが、挿入順序が壊れます (詳細については API を参照)。 O(1) pop_back()も使用できます。operator==とoperator!=は順序に依存します。同じ値を持つ 2 つのtsl::ordered_map異なる順序で挿入された場合、等しく比較されません。operator*()とoperator->()は、 std::pair<const Key, T> const std::pair<Key, T>への参照とポインタを返し、値T変更できなくなります。値を変更するには、反復子のvalue()メソッドを呼び出して変更可能な参照を取得する必要があります。例: tsl::ordered_map< int , int > map = {{ 1 , 1 }, { 2 , 1 }, { 3 , 1 }};
for ( auto it = map.begin(); it != map.end(); ++it) {
// it->second = 2; // Illegal
it. value () = 2 ; // Ok
}IndexTypeクラス テンプレート パラメーターを通じて発生させることができます。詳細については API を確認してください。bucket_size 、 bucketなど) はサポートされていません。スレッド安全性の保証はstd::unordered_mapと同じです (つまり、ライターなしで複数の同時リーダーを持つことが可能です)。
これらの違いは、 std::unordered_setとtsl::ordered_setの間にも当てはまります。
特に明記されていない限り、関数には強力な例外保証があります。詳細を参照してください。この保証が提供されない場合を以下に示します。
この保証は、 ValueContainer::emplace_back強力な例外保証がある場合にのみ提供されます (これはstd::vector型Tがstd::deque例外、詳細を参照してください)。
tsl::ordered_map::erase_ifとtsl::ordered_set::erase_if関数は、ドキュメントに記載されている前提条件の下でのみ保証されます。
順序付きマップを使用するには、インクルード ディレクトリをインクルード パスに追加するだけです。ヘッダーのみのライブラリです。
CMake を使用する場合は、 target_link_librariesを使用して CMakeLists.txt からエクスポートされたtsl::ordered_mapターゲットを使用することもできます。
# Example where the ordered-map project is stored in a third-party directory
add_subdirectory (third-party/ordered-map)
target_link_libraries (your_target PRIVATE tsl::ordered_map) プロジェクトがmake installによってインストールされている場合は、 add_subdirectoryの代わりにfind_package(tsl-ordered-map REQUIRED)を使用することもできます。
コードは C++11 標準に準拠したコンパイラで動作する必要があり、GCC 4.8.4、Clang 3.5.0、および Visual Studio 2015 でテストされています。
テストを実行するには、Boost Test ライブラリと CMake が必要です。
git clone https://github.com/Tessil/ordered-map.git
cd ordered-map/tests
mkdir build
cd build
cmake ..
cmake --build .
./tsl_ordered_map_tests API はここにあります。
# include < iostream >
# include < string >
# include < cstdlib >
# include < tsl/ordered_map.h >
# include < tsl/ordered_set.h >
int main () {
tsl::ordered_map< char , int > map = {{ ' d ' , 1 }, { ' a ' , 2 }, { ' g ' , 3 }};
map. insert ({ ' b ' , 4 });
map[ ' h ' ] = 5 ;
map[ ' e ' ] = 6 ;
map. erase ( ' a ' );
// {d, 1} {g, 3} {b, 4} {h, 5} {e, 6}
for ( const auto & key_value : map) {
std::cout << " { " << key_value. first << " , " << key_value. second << " } " << std::endl;
}
map. unordered_erase ( ' b ' );
// Break order: {d, 1} {g, 3} {e, 6} {h, 5}
for ( const auto & key_value : map) {
std::cout << " { " << key_value. first << " , " << key_value. second << " } " << std::endl;
}
for ( auto it = map. begin (); it != map. end (); ++it) {
// it->second += 2; // Not valid.
it. value () += 2 ;
}
if (map. find ( ' d ' ) != map. end ()) {
std::cout << " Found 'd'. " << std::endl;
}
const std:: size_t precalculated_hash = std::hash< char >()( ' d ' );
// If we already know the hash beforehand, we can pass it as argument to speed-up the lookup.
if (map. find ( ' d ' , precalculated_hash) != map. end ()) {
std::cout << " Found 'd' with hash " << precalculated_hash << " . " << std::endl;
}
tsl::ordered_set< char , std::hash< char >, std::equal_to< char >,
std::allocator< char >, std::vector< char >> set;
set. reserve ( 6 );
set = { ' 3 ' , ' 4 ' , ' 9 ' , ' 2 ' };
set. erase ( ' 2 ' );
set. insert ( ' 1 ' );
set. insert ( '