void FEC_Initialize()

CAPIインタフェースを初期化. この関数は他のCAPI関数よりも先に、かなあらず呼び出さなければならない. アプリケーションスタート時に即呼びだすとよい.

void FEC_Finalize()

CAPIインタフェースをシャットダウン. この関数は CAPIの全ての使用を終えた後に一度呼ぶ. アプリケーション終了時に呼ぶと良い.

void FEC_EnableDebug(int runServer)

Core デバッガを有効化. 有効にした場合コード最適化をオフにし、Dwarfデバッグインフォをコンパイルコードへ埋め込む. 実行サーバ(runServer)が非ゼロの場合、デバッグサーバプロセスもともに起動し、Core プロセスの制御を担う. gdbなどの外部デバッガを使用する場合、実行サーバをゼロに設定.

C言語インタフェース

この節では、C言語インタフェースを通じてCAPIを利用するアプリケーションから必要になる一般的なプラクティスについて深く掘り下げます。C言語インタフェースの利用予定がないのであればこの節を読む必要はありません。

名前空間

C言語インタフェースの全ての型と関数呼び出しは、 FEC_...; として始まります。例えば FEC_ClientCreate() 。これには、CAPI関連のコードの特定と、名前空間の衝突を最小化という2つの目的をより簡単に叶えるためです。

オブジェクト生存サイクル

C言語では、オブジェクトが自動でスコープ外となる機構をそなえないため、Cのインタフェースを用いる CAPI プログラマーには、Cインタフェースから返すオブジェクトのライフサイクルを、手動で管理する責務があります。

参照カウントされるオブジェクト

Cインタフェースにある「高レベルオブジェクト」は全て参照カウントされます。以下を含みます:

参照カウントされるオブジェクトは全て、型 FEC_Ref の基本オブジェクトの 『インスタンス』です。さらに名前末尾に Ref と付与されています。参照カウントされるオブジェクトは常に、 Create あるいは CreateWith... (例 FEC_ClientCreate()) とつけ作成します。不要になったのであればそのオブジェクトの FEC_RefRelease() 関数をプログラマの責務として呼びだします。実行時の FEC_RefRelease() 呼び出し失敗は、全参照カウントオブジェクトはメモリ、リソースリークを引き起こします。

APIレファレンス

FEC_Ref

CAPIにおける一般的な参照型. 多くのCAPI関数でこの型を『継承』した参照を返す. (例参照 FEC_ClientRef and FEC_DGNodeRef). Cインタフェースを使用する際, 参照はプログラマが管理の責務を負う. 不要になったのであれば参照を開放すること. さもないとメモリ、リソースのリークを起こし最悪終了時ハングする.

FEC_Ref FEC_NULL_REF

NULL参照の値. CAPI関数が失敗した際, 本来の戻り値のかわりにこの値を返す. CAPI関数へこのNULL参照の値を渡すと例外を発生する.

void FEC_RefRetain(FEC_Ref ref)

参照を保持する; ある参照の参照カウントを一つ加算, 開放のためには FEC_RefRelease() をさらに一回追加で呼び出す. FEC_NULL_REF 参照に対しこの関数を呼び出しても何もなさない.

この関数は通常必要となることはない.

void FEC_RefRelease(FEC_Ref ref)

参照を開放する; ある参照の参照カウントを一つ減らす. 結果参照カウントがゼロ以下になる場合, 参照は開放される. FEC_NULL_REF 参照に対しこの関数を呼び出しても何もなさない.

多くのCAPI関数が戻り値として参照型を返す; Cインタフェースを使用し, 不要となった参照に対しこれらの関数をよぶことはプログラマの責任である.

int FEC_RefIsNull(FEC_Ref ref)

指定した参照が Nullかどうかを返す. つまりその値が FEC_NULL_REF かどうか.

Variants

参照カウントオブジェクトにはさらに、区別されたオブジェクトのクラス ―Cインタフェースで使用する際手動でライフサイクル管理を必要とする― がある。 variant がヘテロジニアス ―異種起源なデータの一般的なコンテナである。Fabric Core 内外でのデータの受け渡しのための大部分の呼び出しにVariant(s) を使用しています。 variants で詳述します。

Variants は常に FEC_VariantInit... ではじまる呼び出しを使用し作成します。同様 FEC_VariantDispose() ではじまる呼び出しにより(必要なくなったら)破棄します。参照カウントオブジェクトと同じように不要となったら必ず FEC_VariantDispose を呼びます。さもないとメモリ、リソースリークをひきおこします。

注釈

このルールに特記すべき例外はありません: variant が nullである場合(つまり FEC_VariantIsNull() が true を返す)のであれば、FEC_VariantDispose を呼ぶ必要はありません。(まだ安全ではあります)エラーハンドリングのコードを単純化できます。

エラーハンドリング

C言語には(良い)一般的な例外機構が存在しないので、CAPI のCインタフェースでは例外機構の提供が限定されたものとなっています。つまり、プログラマが失敗する可能性のある CAPIの呼び出し部分全ての箇所に例外をクエリする必要があります。CAPIでの『例外』とは例外を記述した単純なCの文字列です。例外を最後に捕捉することになるエントリ関数は、 FEC_GetLastExceptionCString(); です。最終例外が存在しないのであれば NULL を返します。

APIレファレンス

char const *FEC_GetLastExceptionCString()

最終例外を C文字列として戻す, 例外が存在しないのであれば NULL を返す.

警告

この関数が返す値は, コール後大半の CAPI関数 ― FEC_ClearLastException() を含むで非値(つまりなくなる)となる.
uint32_t FEC_GetLastExceptionLength()

最終例外の文字列の長さを戻す. 例外が無いのであれば, 0 を戻す.

void FEC_ClearLastException(void)

最終例外をクリアする. FEC_GetLastExceptionCString() は NULL を返す. 最終例外がないのであれば何もなさない.

注釈

この関数の呼び出し後は FEC_GetLastExceptionCString() の返す値は無効(invalid)なものとなる.

Cインタフェースの例

以下のサンプルコードで CAPIへの C言語インタフェースの用例を示す.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <FabricCore.h>

#include <stdio.h>
#include <stdlib.h>

int main( int argc, char **argv )
{
  char const *exceptionCString;
  FEC_ClientCreateOptions createOptions;
  FEC_ClientRef client;
  FEC_KLSourceFile sourceFiles[1] = {
    "vec3.kl",
    "\
struct Vec3 {\n\
  Float32 x, y, z;\n\
};\n\
function Float32 Vec3.normSq() {\n\
  return this.x*this.x + this.y*this.y + this.z*this.z;\n\
}\n\
function Float32 Vec3.norm() {\n\
  return sqrt(this.normSq());\n\
}\n\
"
  };
  FEC_DGOperatorRef dgOperator;
  char const *parameterLayout[2] = { "self.vec3", "self.norm" };
  FEC_DGBindingRef dgBinding;
  FEC_DGNodeRef dgNode;
  float vec3Data[1024*3];
  float normData[1024];
  uint32_t i;

  FEC_Initialize();

  memset( &createOptions, 0, sizeof(createOptions) );
  createOptions.guarded = 1;

  client = FEC_ClientCreate( NULL, NULL, &createOptions );
  exceptionCString = FEC_GetLastExceptionCString();
  if ( exceptionCString )
  {
    printf( "Caught exception: %s\n", exceptionCString );
    exit( 1 );
  }

  FEC_RegisterKLExtension(
    client,
    "Vec3",
    "1.0.0",
    "",
    1,
    sourceFiles,
    true,
    false
    );
  exceptionCString = FEC_GetLastExceptionCString();
  if ( exceptionCString )
  {
    printf( "Caught exception: %s\n", exceptionCString );
    exit( 1 );
  }

  dgOperator = FEC_DGOperatorCreate(
    client,
    "testOperator1",
    "test.kl",
    "\
require Vec3;\n\
\n\
operator testOp(Vec3 vec3, io Float32 norm) {\n\
  norm = vec3.norm();\n\
}\n\
",
    "testOp"
    );

  dgBinding = FEC_DGBindingCreate(
    dgOperator,
    2,
    parameterLayout
    );
  exceptionCString = FEC_GetLastExceptionCString();
  if ( exceptionCString )
  {
    printf( "Caught exception: %s\n", exceptionCString );
    exit( 1 );
  }

  dgNode = FEC_DGNodeCreate( client, "testNode1" );
  FEC_DGContainerAddMember_Variant( dgNode, "vec3", "Vec3", NULL );
  FEC_DGContainerAddMember_Variant( dgNode, "norm", "Float32", NULL );
  FEC_DGContainerSetSize( dgNode, 1024 );
  for ( i=0; i<1024; ++i )
  {
    vec3Data[3*i+0] = (float)(i+0);
    vec3Data[3*i+1] = (float)(2*i+1);
    vec3Data[3*i+2] = (float)(i+2);
  }
  FEC_DGContainerSetMemberAllSlicesData( dgNode, "vec3", sizeof(vec3Data), vec3Data );
  FEC_DGNodeAppendBinding( dgNode, dgBinding );
  exceptionCString = FEC_GetLastExceptionCString();
  if ( exceptionCString )
  {
    printf( "Caught exception: %s\n", exceptionCString );
    exit( 1 );
  }

  FEC_DGNodeEvaluate( dgNode );
  FEC_DGContainerGetMemberAllSlicesData( dgNode, "norm", sizeof(normData), normData );
  for ( i=0; i<8; ++i )
    printf( "norm[%u] = %g\n", (unsigned)i, normData[i] );
  printf( "...\n" );
  for ( i=1016; i<1024; ++i )
    printf( "norm[%u] = %g\n", (unsigned)i, normData[i] );

  FEC_RefRelease( dgNode );
  FEC_RefRelease( dgBinding );
  FEC_RefRelease( dgOperator );
  FEC_RefRelease( client );

  FEC_Finalize();

  return 0;
}