C++ のライブラリ集 abseil

abseil

abseil は Google が社内で使っている C++ コードを オープンソースとして公開したものです。 https://abseil.io/about/

API リファレンス がなく、 使い方はヘッダーファイルを読んでね。 という風に、とっつき難い。

ネットを検索しても、 使ってみたという情報も少ない。

簡単なドキュメントはある。 https://abseil.io/docs/cpp/guides/

しかし、コピペして、 すんなり動くサンプルコードがない。

試行錯誤しながら、一通り試してみた。

以下、ドキュメントの日本語訳をつけて、簡単に紹介する。

インストール

ドキュメントでは自分でビルドすることになっているが、 debian ではパッケージ化されている。 https://packages.debian.org/unstable/libabsl-dev

MACの場合は、brew コマンドが使える。 https://formulae.brew.sh/formula/abseil

インストールが終わると、 ヘッダーファイルが 140個 ライブリファイルが 56個 できる。 何を使ったらいいんだと戸惑う。

機能別に pkgconfig の設定ファイルを作成することから始める。 https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/setup/pkgconfig

文字列ライブラリ (Strings Library)

一番使う機会が多いと思うので、最初に紹介する。

文字列ライブラリは、文字列の操作と比較、他の型(整数など)の文字列への変換、または他の用途のための文字列の評価のためのクラスとユーティリティ関数を提供する。 さらに、文字列ライブラリには、連続したメモリ内にデータを格納する のようなクラスのユーティリティ関数も含まれている。 https://abseil.io/docs/cpp/guides/strings

下記の関数が用意されている。 - absl::string_view - StrJoin() - StrSplit() - StrAppend() - StripAsciiWhitespace() - StrCat() - StrContains() - SimpleAtoi() - StrReplaceAll() - StripPrefix() - StripSuffix() - Substitute()

サンプルコードはこちらに。 https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/string

文字列を効率的に扱う仕組みが用意されている。

absl :: string_viewコンテナ 多くの場合、文字列データにアクセスする必要があるが、それを所有する必要はなく、変更する必要もない。 このため、Abseilはabsl :: string_viewクラスを定義する。 これは、文字の連続したスパン、多くの場合、別のstd :: string、二重引用符で囲まれた文字列リテラル、文字配列、または別のstring_viewの一部またはすべてを指す。 string_viewは、その名前が示すように、関連付けられた文字列データの読み取り専用ビューを提供する。

文字列の連結のための関数 absl::StrCat() と absl::StrAppend() C ++文字列の使用に関するほとんどのドキュメントには、他の言語とは異なり、C ++の文字列は変更可能であると記載されている。 ただし、文字列には大量のデータが含まれることが多く、多くのパターンでは一時コピーの作成が必要になるため、文字列の変更にはコストがかかる可能性があり、かなりのオーバーヘッドが発生する可能性がある。

余談 「c++ string split」で検索しても、abseil はヒットしない。

文字列フォーマッター (String Formatting)

文字列フォーマッターライブラリは、 標準ライブラリヘッダー内のprintf() 文字列フォーマット関数の代替品です。 https://abseil.io/docs/cpp/guides/format

下記の関数が用意されている。 - StrForma

サンプルコードはこちらに。 https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/string_formatting

このライブラリは、printf() タイプの文字列フォーマットのほとんどの機能といくつかの追加の利点を提供する。

  • std :: string およびabsl :: string_view のネイティブサポートを含む型安全性(Type safety)

  • 標準ライブラリに依存しない信頼性の高い動作

POSIX位置拡張のサポート (Support for the POSIX positional extensions)

  • absl :: CordなどのAbseilタイプをネイティブにサポートし、他のタイプをサポートするように拡張できる。 (Supports Abseil types such as absl::Cord natively and can be extended to support other types)

  • ネイティブのprintf関数よりもはるかに高速(通常は2〜3倍高速)

  • さまざまな既存のシンク(sink)) にストリーミング可能

似たような関数 absl::Substitute も用意されている。 こちらは、書式 %s %d でなく。 位置修飾子 $1 $2 で指定する。

hash ライブラリ (Hash Library)

このライブラリは、std :: hash およびその他のさまざまなハッシュ関数の代わりとして使用するように設計されている。 https://abseil.io/docs/cpp/guides/hash

下記の関数が用意されている。 - absl::Hash

サンプルコードはこちらに。 https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/hash

absl :: Hashは、「スイステーブル (Swiss Tables) 」を実装している。

abseil(Google)がhash tableを高速化 https://note.com/usop/n/ncf8ca154c1ce

Swiss Tables Design Notes https://abseil.io/about/design/swisstables

フラグライブラリ (Flags Library)

フラグライブラリを使用すると、コマンドラインでバイナリに渡されるフラグ値にプログラムからアクセスできる。 - https://abseil.io/docs/cpp/guides/flags

下記の関数が用意されている。 - ABSL_FLAG() - absl::ParseCommandLine() - absl::GetFlag()

サンプルコードはこちら。 https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/flags

注意: getopt() とは異なり、Abseilフラグライブラリは、shortオプションとlongオプションの両方のフラグをサポートしていない。 -v と --verboseは、同じコマンドラインオプションとなる。

同種のライブラリに gflags もある。 Google では、とどう使い分けしているのかな。

数値ライブラリ (Numeric Library)

現時点では1つのヘッダーファイル int128.h のみを提供する。 int128.h は128ビット整数型を提供する。 int128.h ヘッダーファイルは、符号付きおよび符号なしの128ビット整数型を定義する。 https://abseil.io/docs/cpp/guides/numeric

APIは、C++の組み込み型に可能な限り似せている。 下記のように記述できる。 int64_t a = 123; absl::int128 v = 123;

下記の関数が用意されている。 - MakeInt128() - Int128Low64() - Int128High64()

サンプルコードはこちら。 https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/numeric

128ビット整数型を使う機会はあまりないと思う。 abseil では、時間の内部表現として使っている。

乱数ライブラリ (Random Library)

乱数ライブラリは、疑似ランダムデータを生成するための関数とユーティリティを提供する。 このライブラリは、 との互換性を維持しながら、 内の乱数ジェネレータおよび分布関数の代わりとして使用するように設計されている。 https://abseil.io/docs/cpp/guides/random

このライブラリには、に比べていくつかの利点がある。

  • 改善されたアルゴリズム ( Improved algorithms ) Abseil 乱数ライブラリは、改良された疑似ランダムアルゴリズムを提供し、新しいアルゴリズムが利用可能になったときにそれを採用できるようにします。ランダムな値の生成は活発な研究の分野であり、今日のアルゴリズムはより迅速に初期化され、より迅速に値を生成し、統計的に推測がより困難なシーケンスを生成します。

  • シードされた生成器による簡単な構築 ( Easy construction of well-seeded generators ) Abseil のビット生成器では、コンストラクター引数を適切にシードする必要はありません。乱数生成器の初期化(つまり「シード(seed) 」)は重要なタスクであり、多くの場合、基礎となるビット生成アルゴリズムの知識が必要です。

  • 簡潔なサンプリング構文 Abseil 乱数ライブラリは、ビット生成を分布サンプリング (distribution sampling) から切り離しながら、分布をオブジェクトではなく関数として表すことにより、よりも簡潔な構文を提供する。

下記の関数が用意されている。 - absl::BitGen - absl::Uniform() absl::Bernoulli()

サンプルコードはこちら https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/random

ステータスライブラリ ( Status )

2つのステータスライブラリが含まれている。

  • absl :: Statusクラス エラー処理情報を保持する 標準的なステータスコード( a set of canonical absl::StatusCode ) 、およびステータスコードを生成および伝播するための関連ユーティリティを含むステータスライブラリ。

  • absl :: StatusOr クラス absl :: StatusエラーまたはタイプTのオブジェクトのいずれかを返すために使用する。 このStatusOr 抽象化は、std :: expectedのC ++提案に似ている。

https://abseil.io/docs/cpp/guides/status

下記のステータスコードが用意されている。 Choosing Canonical Error Codes https://abseil.io/docs/cpp/guides/status-codes

  • OK
  • CANCELLED
  • INVALID_ARGUMENT
  • DEADLINE_EXCEEDED
  • NOT_FOUND
  • ALREADY_EXISTS
  • PERMISSION_DENIED
  • UNAUTHENTICATED
  • RESOURCE_EXHAUSTED
  • FAILED_PRECONDITION
  • ABORTED
  • UNAVAILABLE
  • OUT_OF_RANGE
  • UNIMPLEMENTED
  • INTERNAL
  • DATA_LOSS
  • UNKNOWN

下記の関数が用意されている。 - OkStatus(); - InvalidArgumentError() - NotFoundError()

サンプルコードはこちら https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/status

同期ライブラリ ( Synchronization )

このライブラリには、さまざまなスレッド間でタスクを管理するための抽象化とプリミティブが含まれている。 https://abseil.io/docs/cpp/guides/synchronization

std::mutex に比べて、下記の機能が追加されている。

  • absl :: Mutexは、条件変数の代わりに条件付きクリティカルセクションを追加する。 Mutex :: Await()およびMutex :: LockWhen()により、クライアントは条件変数を必要とせずに条件を待つことができる。クライアントは、whileループを記述する必要も、Signal()を使用する必要はない。
  • Mutexは本質的にデッドロック検出をサポートしている。

下記の関数が用意されている。 - absl::Mutex#Lock - absl::Mutex#Unlock

サンプルコードはこちら https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/synchronization

このライブラリは使い方がよくわからなかった。 ひとまず、Mutex#Lock と Mutex#Unlock を使ったサンプルコードのみ。

時間ライブラリ (Time Library)

時間ライブラリには、絶対時間 (absolute time) と市民時間 (civil time) の両方の観点から時間値を保持するための抽象化が含まれている。 https://abseil.io/docs/cpp/guides/time

絶対時間 (absolute time) とは、UNIX 時間。 市民時間 (civil time) とは、任意のタイムゾーンにおける現地時間。 この概念は cctz ライブラリを継承したもの。 https://github.com/google/cctz

下記の関数が用意されている。 - absl::Now() - absl::FormatTime() - absl::LocalTimeZone() - absl::LoadTimeZone()

サンプルコードはこちら https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil/time

注意 MAC の場合、タイムゾーンの取得に、システムコール CFTimeZoneCopyDefault を使っている。

このライブラリを使う場合は、 コンパイルオプションに、 -framework CoreServices を指定すること。 https://developer.apple.com/documentation/coreservices

Github

サンプルコードは Github で公開してます https://github.com/ohwada/MAC_cpp_Samples/tree/master/abseil