4

JavaScript から取得した関数パラメーターを解析するには、多くのチェックを実行する必要があります。たとえば、関数は、JavaScript で次のように見えるオブジェクトをパラメーターとして期待する場合があります。

{
    Fullscreen: [ 'bool',     false         ],
    Size:       [ 'Vector2u', 800, 600      ],
    Title:      [ 'string',   'Hello World' ],
    // more properties...
}

C++ では、すべてのキーをループしてこれを解析し、それらをチェックします。これらのチェックのいずれかが失敗した場合、エラー メッセージが出力され、このキーと値のペアはスキップされます。これが現時点での私の実装の様子です。エンジン固有の呼び出しに気を取られないことを願っています。

ModuleSettings *module = (ModuleSettings*)HelperScript::Unwrap(args.Data());

if(args.Length() < 1 || !args[0]->IsObject())
    return v8::Undefined();
v8::Handle<v8::Object> object = args[0]->ToObject();

auto stg = module->Global->Get<Settings>("settings");

v8::Handle<v8::Array> keys = object->GetPropertyNames();
for(unsigned int i = 0; i < keys->Length(); ++i)
{
    string key = *v8::String::Utf8Value(keys->Get(i));
    if(!object->Get(v8::String::New(key.c_str()))->IsArray())
    {
        HelperDebug::Fail("script", "could not parse (" + key + ") setting");
        continue;
    }
    v8::Handle<v8::Array> values = v8::Handle<v8::Array>::Cast(object->Get(v8::String::New(key.c_str())));

    if(!values->Has(0) || !values->Get(0)->IsString())
    {
        HelperDebug::Fail("script", "could not parse (" + key + ") setting");
        continue;
    }
    string type = *v8::String::Utf8Value(values->Get(0));

    if(type == "bool")
    {
        if(!values->Has(1) || !values->Get(1)->IsBoolean())
        {
            HelperDebug::Fail("script", "could not parse (" + key + ") setting");
            continue;
        }
        stg->Set<bool>(key, values->Get(1)->BooleanValue());
    }
    else if(type == "Vector2u")
    {
        if(!values->Has(1) || !values->Has(2) || !values->Get(1)->IsUint32(), !values->Get(2)->IsUint32())
        {
            HelperDebug::Fail("script", "could not parse (" + key + ") setting");
            continue;
        }
        stg->Set<Vector2u>(key, Vector2u(values->Get(1)->Uint32Value(), values->Get(2)->Uint32Value()));
    }
    else if(type == "string")
    {
        if(!values->Has(1) || !values->Get(1)->IsString())
        {
            HelperDebug::Fail("script", "could not parse (" + key + ") setting");
            continue;
        }
        stg->Set<string>(key, *v8::String::Utf8Value(values->Get(1)));
    }
}

ご覧のとおり、すべてのフィルターでチェックが失敗したときに発生するタイミングを定義しました。

HelperDebug::Fail("script", "could not parse (" + key + ") setting");
continue;

goto一度だけ書きたいのですが、防止したい使い方しか思いつきません。コンストラクトを再構築するためのより良いオプションはありますif elseか?

4

2 に答える 2

4

各タイプの検証ステップを実行するために、一連の小さなクラスから始めると思います。

auto v_string = [](v8::Handle<v8::Array> const &v) { 
    return v->Has(1) && v->Get(1)->IsString(); 
}

auto v_Vector2u = [](v8::Handle<v8::Array> const &v) { 
    return v->Has(1) && v->Has(2) && 
           v->Get(1)->IsUint32() && v->Get(2)->IsUint32(); 
}
// ...

次に、型の名前からその型のベリファイアへのマップを作成します。

std::map<std::string, decltyp(v_string)> verifiers;

verifiers["string"] = v_string;
verifiers["Vector2u"] = v_Vector2u;
// ...

次に、タイプを検証するには、次のようなものを使用します。

// find the verifier for this type:
auto verifier = verifiers.find(type);

// If we can't find a verifier, reject the data:
if (verifier == verifiers.end())
    HelperDebug::Fail("script", "unknown type: " + type);

// found the verifier -- verify the data:
if (!verifier->second(values))
    HelperDebug::Fail("script", "could not parse (" + key + ") setting");
于 2013-06-26T14:29:46.753 に答える
0

このような状況では、マクロを使用するのが非常に一般的な方法です。これは、関数の前または関数内で #defined であり、関数の最後で #undef-ed です。必要continueに応じて、他の方法はほとんどありません。

goto も解決策になりますが、この特定のサンプルでは使用しません。

より軽い方法は、少なくとも失敗の呼び出しを関数またはラムダに入れることです。それでも続行部分が残ります。

おそらく、フィルター式を引数として取り、コードを次のようにするマクロを作成するでしょう。

if(type == "bool")
{
    ENSURE(values->Has(1) && values->Get(1)->IsBoolean());
    stg->Set<bool>(key, values->Get(1)->BooleanValue());
}
...
于 2013-06-26T14:08:08.360 に答える