/      English

TWENETeastl - EASTLライブラリ

静的メモリ確保による C++ の STL の実装
EASTLライブラリについての補足解説を行います。

TWENETeastl - EASTLライブラリ

EASTL は Electronic Arts 社が整備した標準テンプレートライブラリ(コンテナ・アルゴリズム)で、C++ の STL (Standard Template Library) に倣い実装されていますが、制約の多いゲーム機の開発で整備されてきた経緯があり、メモリの取り扱いに制約が大きい環境を意識したコンテナやアルゴリズムが用意されています。

本ライブラリは EASTL を TWENET 内で利用できるようにしています。

以下に特徴的な要素を記載します。

  • メモリ固定確保のコンテナ (fixed_) : 動的確保を行わず、固定長の要素数を持つコンテナの宣言が可能です。グローバル宣言すれば、コンパイル時に固定的にメモリ領域が確保され、ローカル宣言すればスタックエリアに確保されそのスコープ内で利用できます。
  • Intrusive コンテナ:通常のコンテナは任意のデータ構造を格納できますが、Intrusiveコンテナはデータ構造に対して専用の基底クラスを継承することで、コンテナ内のリンク構造などを維持するためのリンク情報などを保持します。コンテナ内の各要素はそのコンテナ専用になりますが、リストやマップ構造では非常にメモリ利用効率の良くなります。(参考: Intrusive and non-intrusive containers

2007年の記事EASTL (open-std.org)に開発動機などが記されています。(関連記事:EASTL から垣間見るゲームソフトウェア開発現場の現状 その 1, その 2)

EASTL ライブラリ添付資料

doc 以下の html ファイルを参照して下さい。

配布時に最上位ディレクトリに格納されている README.md, CONTRIBUTING.md は doc/ に移動しています。

TWENETでの利用

以下に留意してください。

当社ではライブラリの動作については包括的な検証は行っておりません。お客様での動作検証をお願いいたします。また EASTL の利用方法についてのお問い合わせについても当社では対応できません。配布元の開設資料・ライブラリソースコードなどの情報を参照してください。

  • EASTL3.07 (2018/1/31) のバージョンを利用します。(C++11でコンパイルできる一番最後のバージョン)
  • 以下のライブラリは組み込んでいません。
    • test/packages/EAAssert, source/assert.cpp
    • test/packages/EATest
    • test/packages/EAThread, source/thread_support.cpp
  • テストコード test/source の動作移植はしていません。
  • sprintf関連ではEA::StdC::Vsnprintf(char8_t*, ...) のみを printf.h ライブラリ中の vsnprintf_() を呼び出すことで解決しています。

組み込み・コンパイル方法

EASTL はアクト Act の記述の際に利用できます。

TWELITE 向けの開発環境で必要なインクルードパスの追加、ライブラリの追加は行います。作成するコード中でライブラリヘッダのインクルードを行ってください。

#include <TWELITE>
#include <EASTL/fixed_string.h>

using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;

void setup() {
    tstr128 s1;
    s1 = "Hello World";
    Serial << s1.c_str();
}
void loop() {
    ;
}

組み込み方法(詳細)

  • EASTL/source 内のコードをコンパイルして、ライブラリアーカイブとしておく (libEASTL.a)。リンク時にはこのライブラリの参照が必須です。
  • コンパイル時に以下のインクルードパスを追加しておく。

$(PATH_EASTL)を EASTL ディレクトリとした場合、インクルードパスは以下となります。

-I$(PATH_EASTL)/include
-I$(PATH_EASTL)/test/packages/EAAssert/include
-I$(PATH_EASTL)/test/packages/EABase/include/Common
-I$(PATH_EASTL)/test/packages/EAMain/include
-I$(PATH_EASTL)/test/packages/EAStdC/include
-I$(PATH_EASTL)/test/packages/EATest/include
-I$(PATH_EASTL)/test/packages/EAThread/include

コーディングについて

std::eastl:: について

標準ライブラリ (std::) と EASTL(eastl::)では同じ名前で同じ機能を持つものが定義されています。これらは混在できる場合もありますが、使用するとエラーになる場合もあります。つまりEASTLで使用するものは、通常はEASTL内の定義を用います(例:std::unique_ptreastl::fixed_string を格納しようとするとコンパイラエラーになる)。

グローバルオブジェクトの初期化1 (配置new)

TWENET の開発では、コンパイラの制約により、グローバル宣言のオブジェクトのコンストラクタが実行されません。グローバル宣言宣言したオブジェクトのメモリ領域がゼロクリアされるだけです。そのまま、コードを実行すると大抵の場合 null pointer access によりハングアップします。

このオブジェクトを初期化するためには*placement new (配置new)*を用います。

#include <TWELITE>
#include <EASTL/fixed_string.h>

using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;

tstr128 g_str1; // constructor is NOT called! needs to be initialized before use.

void setup() {
    (void) new ((void*)&g_str1) tstr128("Hello World");
    Serial << g_str1.c_str();
}

placement new のコードは少し乱雑に見えるため、補助関数mwx::pnew() を用意しています。先ほどの例を以下のように書き換えることができます。

(void) new ((void*)&g_str1) tstr128("Hello World");
// ↓
mwx::pnew(g_str1, "Hello World");

※ 2番目の引数以降は可変数で、コンストラクタにそのまま渡されます。

グローバルオブジェクトの初期化2 (unique_ptr)

グローバルオブジェクトの初期化方法として unique_ptr(std::unique_ptrの解説)を用いる方法もあります。unique_ptrstd:: にも eastl:: にもありますが、EASTLのクラスではeastl::のものを使用します。

以下のように初期化のタイミングで .reset() を呼び出します。

#include <TWELITE>
#include <EASTL/unique_ptr.h>
#include <EASTL/fixed_string.h>

using namespace eastl;
using tstr128 = fixed_string<char, 127 + 1, false>;

eastl::unique_ptr<tstr128> uq_str1;

void setup() {
	uq_str1.reset(new tstr128("Hello World"));
    if (uq_str1) { // true: object is stored.
        Serial << uq_str1->c_str();
    }
}

intrusive コンテナについて

以下の例は intrusive_list の要素定義例です。メンバーは int mX のみです。

struct IntNode : public eastl::intrusive_list_node {
    int mX;
    IntNode(int x = 0) : mX(x) { }
        // no need to call super class's constructor eastl::intrusive_list_node()
};

inline bool operator<(const IntNode& a, const IntNode& b) { return a.mX < b.mX; }
inline bool operator>(const IntNode& a, const IntNode& b) { return a.mX > b.mX; }

intrusive_listの要素は、必ず intrusive_list_node を基底クラスに持っている必要があります。基底クラス内にはリストを維持するためのリンクポインタが含まれます。ここではさらに sortなどで使用する比較演算子の定義も行います。

using tiList = intrusive_list<IntNode>;

void setup() {
    IntNode nodeA(5);
    IntNode nodeB(1);
    IntNode nodeC(9);
    IntNode nodeD(2);
    IntNode nodeE(4);

    tiList l; // intrusive_list body

    l.push_front(nodeA); // forming list strucure
                         //   by updating link info in intrusive_list_node.
    l.push_front(nodeB);
    l.push_front(nodeC);
    l.push_front(nodeD);
    l.push_front(nodeE);

    l.sort(); // sort, using < operator
    l.sort(eastl::greater<tilist::value_type>()); // sort, using > operator
}

参考資料

本サンプルについて

EASTLのライセンス記述は以下です。

Modified BSD License (3-Clause BSD license) see the file LICENSE in the project root.

/*
Copyright (C) 2015 Electronic Arts Inc.  All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1.  Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
2.  Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
3.  Neither the name of Electronic Arts, Inc. ("EA") nor the names of
    its contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

サンプルコードは MWSLA-1J/E を適用します。