ホップスコッチハッシュリングを用いた高速なハッシュマップとハッシュセットのためのC++実装

2026/06/27 6:18

ホップスコッチハッシュリングを用いた高速なハッシュマップとハッシュセットのためのC++実装

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

hopscotch-map ライブラリは、拒否サービス(DoS)攻撃に耐性のある安全なハッシュマップとセットの生成を可能にする、高効率でヘッダーだけの C++ ソリューションを提供します。その主な利点は、特別な成長ポリシー——例えば素数成長戦略——によるものであり、これは悪質なハッシュ関数を効率的に扱いながらバイナリサイズを増加させません。標準コンテナとは異なり、これらの安全なバージョンは開くアドレスと hopscotch ハッシングを利用して定数の衝突を効率的に管理しており、敵対的シミュレーション中のベンチマークで二元探索木に基づく代替案(例えば

tsl::bhopscotch_map
)に対して明確な性能優位を示しました。API は
std::unordered_map
/
set
に密接に似ていますが、イテレーターの無効化規則と値のアクセス方法を独自のものにしています。このライブラリは、移動のみキー、多様なルックアップ、事前計算されたハッシュストレージ、コンパイラフラグを使用した例外フリーなビルドといった高度な機能をサポートします。CMake とのシームレスな統合を目的とし、C++17 コンパイラーのみが必要で、データ構造の整合性を悪意のあるトラフィックに対して保証することが重要な業界にとって最適な選択となります。MIT ライセンスの下で提供されています。

本文

hopskotch-map ライブラリ

hopskotch-map
ライブラリは、open addressing および hopskotch 解析(ホップスコッチ・ハッシング) を採用した高速なハッシュマップとハッシュセットの C++ 実装です。

  • 衝突解決: この手法により衝突を効率的に解決します。
  • パフォーマンス: キャッシュフレンドリーなデータ構造であり、
    std::unordered_map
    よりも大多数のケースで優れたパフォーマンス
    を発揮します。
  • 代替案:
    google::dense_hash_map
    と似た挙動を示しつつ、メモリ使用量の削減と多様な機能の提供を実現します。

クラス群と特徴

本ライブラリは以下のクラス群を提供します:

  • tsl::hopscotch_map
    /
    tsl::hopscotch_set
  • tsl::hopscotch_pg_map
    /
    tsl::hopscotch_pg_set
  • tsl::bhopscotch_map
    /
    tsl::bhopscotch_set
  • tsl::bhopscotch_pg_map
    /
    tsl::bhopscotch_pg_set

クラスの違い

クラス名特徴ポリシー推奨用途
hopscotch (基本)高速冪乗 (Power of Two)一般用途。デフォルトの選択として最適です。
hopscotch_pg (素数)堅牢性向上素数 (Prime)ハッシュ関数が劣悪な場合や、ハッシュ値の下位ビットにパターンがある場合(例:ポインタ識別子)。
bhopscotch (バインド)安全性向上冪乗DoS 攻撃対策。最悪ケースを $O(\log n)$ に抑えます。
bhopscotch_pg安全性+堅牢性素数DoS 防御かつ劣悪ハッシュへの耐性を両立します。

注意:

LessThanComparable
な追加の要件を持つ
bhopscotch_*
クラスは、検索および削除時の最上界(worst-case upper bound)を $O(\log n)$ に改善しますが、通常の攻撃がない限り
hopscotch_map
が十分であることが多いです。

メイン機能

  • ヘッダーのみ (Header-only): インクルードディレクトリとパスに加えれば即座に使用可能。CMake ならエクスポートされたターゲットも利用できます。
  • 高速なハッシュテーブル: ベンチマーク結果が示す通り非常に高速です。
  • ムーブ・オンリー (Move-only) / デフォルト構築不可キー: ムーブのみおよびデフォルトで構築できないキー/バリューをサポートします。
  • 不均一なルックアップ (Heterogeneous lookups):
    Key
    以外の型(例:ポインタ)で検索・削除が可能です(詳細は後述)。
  • 哨兵値の予約不要: リスト末尾などの哨兵値を保持する必要がありません。
  • ハッシュ値保存オプション (
    StoreHash
    ):
    ハッシュ計算コストが高い場合に、挿入時の計算を再使用してルックアップを高速化できます。
  • 事前計算されたハッシュの利用: ルックアップ直前のハッシュ値をパラメータとして渡すことで検索を高速化できます(API の
    precalculated_hash
    パラメータ参照)。
  • DoS 攻撃対策 (
    bhopscotch_*
    ):
    最悪ケースを $O(\log n)$ に抑え、ハッシュテーブル型拒否サービス攻撃に耐性があります。
  • 例外不使用環境での利用: Clang/GCC (
    -fno-exceptions
    ) や MSVC (
    /EH
    オプションなし)、または
    TSL_NO_EXCEPTIONS
    の定義により、例外無効化環境で動作します(
    throw
    代わりに
    std::terminate
    を使用)。
  • API の親和性: インタフェースは
    std::unordered_map/set
    に非常に類似しています。

std::unordered_map との違い

tsl::hopscotch_map
std::unordered_map
に似たインターフェースを目指していますが、以下の違いがあります(
unordered_set
も同様):

  • 挿入時のイテレータ無効化: 変更操作(消去

    erase
    など)では、すべてのイテレータが無効化されます。

  • 参照/ポインタの無効化: キーまたはバリューへのリファレンスおよびポインタも挿入時に無効化されます。

  • イテレータ操作の変更:

    operator*()
    および
    operator->()
    std::pair<const Key, T>
    ではなく、
    const std::pair<Key, T>
    の参照・ポインタ
    を返します。

    • バリューを直接修正できません(バリューは不変)。
    • 修正には
      .value()
      メソッドが必要です。
    tsl::hopscotch_map<int, int> map = {{1, 1}, {2, 1}, {3, 1}};
    for(auto it = map.begin(); it != map.end(); ++it) {
        // it->second = 2;   // ❌ 無効
        it.value() = 2;     // ✅ 有効
    }
    
  • ムーブ・オンリー型: ノズロシフト(nothrow)移動コンスルクターが必要です。再ハッシュ時に SGE (Strong Exception Guarantee) を保つために、例外を投げる移動コンスルクターは使用できません。

  • バケット情報の不足:

    bucket_size
    ,
    bucket
    などのメソッドはサポートされていません。

成長ポリシー (Growth Policy)

GrowthPolicy
テンプレートパラメータを通じて以下のポリシーをサポートしています:

  1. tsl::hh::power_of_two_growth_policy
    (デフォルト)

    • バケット配列サイズを冪数に保ちます。
    • modulo 代わりに
      hash & (2^n - 1)
      を使用して高速化します。
    • 弱点: 劣悪なハッシュ関数の場合、上位ビットのみをマスキングするため多数の衝突が起きる可能性があります。
  2. tsl::hh::prime_growth_policy
    (
    *_pg
    クラス用)

    • バケット配列サイズを素数に保ちます。
    • modulo を使用してハッシュ値を均等に分布させます。
    • コンパイラ最適化のため定数の素数 modulo ルックアップテーブルを使用します。
    • メリット: 冪乗ポリシーより少し遅いですが、**頑健(堅牢)**です。
  3. tsl::hh::mod_growth_policy

    • カスタマイズ可能な成長係数に応じて拡大し、単純な modulo を使用します。
    • 特徴: 遅いですが最も柔軟です。

警告: パフォーマンス低下(衝突多数)が疑われる場合は

overflow_size()
を確認してください。ハッシュ関数の改善や、主に
tsl::hh::prime_growth_policy
の採用を試してください。また、DoS 攻撃を防ぐには
bhopscotch_map/set
の検討を推奨します。

カスタムポリシーの実装例

独自のポリシーを実装するには、以下のインターフェースを実装してください:

struct custom_policy {
    // ハッシュテーブルの構築および再ハッシュ時に呼ばれます。min_bucket_count_in_out は必要な最小バケット数です。
    explicit custom_policy(std::size_t& min_bucket_count_in_out);
    
    // ハッシュに属するバケット [0, bucket_count()) を返します。
    std::size_t bucket_for_hash(std::size_t hash) const noexcept;
    
    // 次の成長時に使用すべきバケット数を返します。
    std::size_t next_bucket_count() const;
    
    // クリア後、bucket_for_hash() は常に 0 を返すようポリシーをリセットします。
    void clear() noexcept;
};

インストール方法

ヘッダーのみライブラリのため、単にインクルードディレクトリを含めるだけで使用可能です(CMake なら

add_subdirectory
または
find_package
で使用)。

CMake リスト例:

# third-party/hopscotch-map にプロジェクトを格納している場合
add_subdirectory(third-party/hopscotch-map)
target_link_libraries(your_target PRIVATE tsl::hopscotch_map)  

ビルドとテスト実行: コードは C++17 準拠のコンパイラと互換性があります。Boost.Test と CMake が別途必要です。

git clone https://github.com/Tessil/hopscotch-map.git
cd hopscotch-map/tests
mkdir build && cd build
cmake ..
cmake --build .
./tsl_hopscotch_map_tests 

使用方法と例

API は

std::unordered_map/set
に非常に類似しています。詳細は 公式ドキュメント を参照してください。

基本操作の例:

#include <cstdint>
#include <iostream>
#include <string>
#include <tsl/hopscotch_map.h>
#include <tsl/hopscotch_set.h>

int main() {
    // 初期化と挿入
    tsl::hopscotch_map<std::string, int> map = {{"a", 1}, {"b", 2}};
    map["c"] = 3;
    map.insert({"e", 5});

    // 削除
    map.erase("b");

    // 値の修正(直接は不可、.value() で修正)
    for(auto it = map.begin(); it != map.end(); ++it) {
        // it->second += 2;   // ❌ 無効
        it.value() += 2;     // ✅ 有効
    }

    // ループ出力(順序はバケット配置に依存)
    for(const auto& [key, val] : map) {
        std::cout << "{" << key << ", " << val << "}" << std::endl;
    }

    // ハッシュを活用した高速検索
    const std::size_t precalculated_hash = std::hash<std::string>()("a");
    if(map.find("a", precalculated_hash) != map.end()) {
        std::cout << "\"a\" を見つけました。" << std::endl;
    }

    // StoreHash オプションでハッシュを内部保存(計算コストが高い場合)
    /* 
       6 つ目のテンプレート引数 (hasher), 7 番目 (equal_to), 8 番目 (allocator) の後、
       9 番目に初期サイズ 30, 10 番目に true を指定。
    */
    tsl::hopscotch_map<std::string, int, std::hash<std::string>, 
                       std::equal_to<std::string>,
                       std::allocator<std::pair<std::string, int>>,
                       30, true> map2;
                       
    map2["a"] = 1;
    map2["b"] = 2;

    tsl::hopscotch_set<int> set;
    set.insert({1, 9, 0}); // 要素追加
}

不均一なルックアップ (Heterogeneous Lookups)

検索・削除時に

Key
とは異なる型(例:ポインタ)を使用可能にする機能です。有効にするには、コンパレータに 限定 ID (qualified-id)
KeyEqual::is_transparent
を有している必要があります。

#include <functional>
#include <string>
#include <tsl/hopscotch_map.h>

struct employee {
    int id;
    std::string name;
    
    // オプション:独自のコンパレータ
    friend bool operator==(const employee& e, int id) { return e.id == id; }
};

struct hash_employee {
    std::size_t operator()(const employee& e) const { 
        return std::hash<int>()(e.id); 
    }
    std::size_t operator()(int id) const { 
        return std::hash<int>()(id); 
    }
};

struct equal_employee {
    using is_transparent = void; // 必須
    
    bool operator()(const employee& e, int id) const { return e.id == id; }
    bool operator()(int id, const employee& e) const { return id == e.id; }
};

int main() {
    // 1. std::equal_to<> を使用(自動推論と転送)
    tsl::hopscotch_map<employee, int, hash_employee, std::equal_to<>> map; 
    map.insert({{1, "John"}, 2001});

    // ID で直接検索可能
    auto it = map.find(1);
    if(it != map.end()) {
        std::cout << it->name << " (" << it->id << ")" << std::endl;
    }

    // 2. カスタムコンパレータを使用
    tsl::hopscotch_map<employee, int, hash_employee, equal_employee> map2;
    map2.at(1); // 整数 ID で値アクセス可能
}

DoS 攻撃への対処

tsl::bhopscotch_map/set
(および
_pg
バージョン)は、ハッシュテーブル型拒否サービス (DoS) 攻撃に対して耐性があります。

  • 通常の版 (
    hopscotch
    ):
    ハッシュ値の衝突が極端に多い場合、検索・削除が $O(n)$ になることがあります。
  • 安全な版 (
    bhopscotch
    ):
    最悪ケースも挿入時も $O(\log n)$ を維持します(内部にバイナリ検索木を使用)。

ベンチマーク例(劣悪ハッシュ関数での性能比較):

#include <chrono>
#include <cstdint>
#include <tsl/hopscotch_map.h>
#include <tsl/bhopscotch_map.h>

struct dos_attack_simulation_hash {
    std::size_t operator()(int id) const { return 1; } // 常に同じハッシュ値
};

int main() {
    // --- 通常の版 (脆弱) ---
    tsl::hopscotch_map<int, int, dos_attack_simulation_hash> map;
    
    auto start = std::chrono::high_resolution_clock::now();
    for(int i=0; i < 10000; ++i) { map.insert({i, 0}); } // O(n) の挙動
    auto end = std::chrono::high_resolution_clock::now();
    
    // 約 110 ms (遅い)
    std::cout << "hopscotch_map: " 
              << std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count() 
              << " ms" << std::endl;

    // --- 安全な版 (耐性あり) ---
    tsl::bhopscotch_map<int, int, dos_attack_simulation_hash> map_secure;
    
    start = std::chrono::high_resolution_clock::now();
    for(int i=0; i < 10000; ++i) { map_secure.insert({i, 0}); } // O(log n) の挙動
    end = std::chrono::high_resolution_clock::now();
    
    // 約 2 ms (非常に速い)
    std::cout << "bhopscotch_map: " 
              << std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count() 
              << " ms" << std::endl;
}

ライセンス

コードは MIT ライセンス で公開されています。詳細は LICENSE ファイルを参照してください。

同じ日のほかのニュース

一覧に戻る →

2026/06/27 2:06

次世代モデル「GPT‑5.6 Sol」の事前公開

## Japanese Translation: OpenAI は、GPT-5.6 シリーズの限定プレビューを発表しました。本シリーズには、以下の 3 つの専用モデルが含まれます:Sol(最も堅牢な安全スタックを備えたフラグシップモデル)、Terra(バランス型/コストパフォーマンス型)、Luna(高速型/最低コスト型)。リリースでは、高リスク向けアプリケーションにおけるセキュリティと論理処理に重点を置き、Terminal-Bench 2.1 でコーディングに関する業界最高水準のベンチマークを設定し、GeneBench v1 でゲノム解析分野でも同様に最良の結果を示しました。Sol モデルは特筆すべき点として、「ultra mode」を搭載しており、サブエージェントを活用して複雑なタスクの処理を加速させるとともに、ExploitBench² において優れた結果を達成しています(同時に自律的に全チェーンエクスプロイトを生産することには達しておらず、すなわち Cyber Critical の閾値を越えていません)。Sol は 70 万以上の GPU タイムに及ぶ自動化および人間によるレッドチーム検証を通じて開発され、リアルタイムクラシファイアやアカウントレベルでの審査など、多層的なサファガードスタックを有しています。一般公開前には、アクセスは信頼されたパートナーと米政府関係者に限られ、7 月に専用 Cerebras ハードウェア上で選定顧客向けに展開される予定です。利用者からはキャッシュ読み取りに対する大幅な割引を通じてコスト削減を提供する差別化された価格設定層が提供されますが、初期段階ではフル API アクセスには制限があります。結果として、このリリースは高い機能性と厳格な安全プロトコル、そして明確なパフォーマンス・コストバリエーションを両立させた責任ある AI 導入のための新たな業界基準を確立しました。

2026/06/27 12:30

ワードスター:作家のためのワープロソフト(1996)

## Japanese Translation: Robert J. Sawyer は、確立されたフィクション作家が現代のデジタル時代においても 1978 年のテキストエディタ「WordStar」を使い続けることを情熱的に提唱している。Microsoft Word に代表される現代的なワープロソフトは派手なグラフィックや複雑なメニューを提供するが、執筆モードと編集モードの間でユーザーが精神的にギアを切り替えることを強制し、創造性を阻害することがしばしばある。これに対し、WordStar の安定したクラッシュフリーな環境は、深みのある創造的フローにとって不可欠な妨げのない空間を提供する。このソフトウェアは効率的な「コントロールキー」インターフェースに依存し、物理的な「手書きの頁」を模倣することで、作家が認知的不中断のまま自由にナビゲートすることを可能にしている。そのエルゴノミクス設計はプロのタッチタイピストを支え、カスタマイズ性はユーザーに適応させるため而非公式なワークフローを変えることを求める。このアプローチは、アーサー・C・クラークやジョージ・R・R・マーティンといった伝説的な作家からの称賛を得ており、彼らは新機能よりも安定性を重視している。現代的なアプリケーションによる精神的疲労を避けることで、本物の作家は草稿と作品の精査の間で流体様なる連続性を維持でき、古典的な技術が専門家のサイエンスファンタジー書きの要件に独特に適していることを示している。 ## Text to translate: Robert J. Sawyer passionately argues that established fiction authors should continue using WordStar, a robust text editor from 1978, even in the modern digital age. While contemporary word processors like Microsoft Word offer flashy graphics and complex menus, they often disrupt creativity by forcing users to switch mental gears between writing and editing modes. In contrast, WordStar's stable, crash-free environment provides a distraction-free space essential for deep creative flow. The software relies on an efficient "Control-key" interface and mimics a physical "long-hand page," allowing writers to navigate freely without cognitive interruption. Its ergonomic design supports professional touch typists, and its customizability adapts to the user rather than demanding they change their workflow. This approach has earned praise from legendary authors like Arthur C. Clarke and George R.R. Martin, who value stability over new features. By avoiding the mental fatigue of modern applications, serious writers can maintain a fluid continuum between drafting and refining their work, proving that classic technology remains uniquely suited for the demands of professional science fiction writing.

2026/06/25 13:06

旧ハードウェアでの Linux 運用:完全リバイバルガイド

## Japanese Translation: Linux ディストリビューションは、TPM 2.0 や低容量 RAM など過時硬件要件による電子廃棄物を解決する、Windows 11 の代替手段として有効な選択肢を提供します。Windows 11 はアイドル状態でも 3〜4GB のメモリで起動可能ですが、軽量オプションは遥かに少ない消費量を実現します。例えば、Xfce を使用した Ubuntu は約 650MB を、antiX(約 256MB)や Puppy Linux などの超軽量ディストリビューションは最低 256MB のマシンでも動作可能です。リソースが限られているユーザーには、2GB より少ない RAM のシステムには antiX が推奨され、2〜4GB の場合では Lubuntu(アイドル時約 480MB)、4GB 以上のマシンでは Linux Lite(アイドル時約 650MB)が適しています。なお、BunsenLabs Carbon などがサポートを終了する 2026 年 2 月には、古くからの 32 ビットハードウェアは互換性問題に直面します。 適切な OS を選ぶだけでなく、戦略的なアップグレードと調整により性能を大幅に向上させることも可能です。機械式ハードドライブを SATA SSD に置き換えることで、起動時間を 45 秒以上から 18 秒未満に短縮できます。上級ユーザーは診断のために `free -h`、`lscpu`、`lsblk` などのコマンドを使用し、zram 圧縮を有効化して RAM 容量を増大させるようにシミュレートし、swappiness 設定を 10 に下げて古いドライブへの磨耗を軽減し、不要なサービス(例:bluetooth、cups)を無効化し、キャッシュの無効化や広告ブロッカーを活用してブラウザのメモリ使用量を最適化するなどの措置应采取します。これらのステップにより、高価な新ハードウェア購入なしでレガシーマシンも効果的に動作させることが可能になります。