How to use if and else efficiently for a filter construct?

To parse the parameters of the function that I get from JavaScript, I need to do a lot of checks. For example, a function can expect an object as a parameter that looks like this in JavaScript.

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

In C ++, I parse this by looping through all the keys and checking them. If one of these checks fails, an error message should be printed and this pair of key values ​​should be skipped. Here's what my implementation looks like at the moment. I hope you do not get distracted by some of the challenges associated with the engine.

 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))); } } 

As you can see, I determined when this happens, when the check fails with each filter.

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

I would like to write this only once, but I can only come up with a way using goto that I would like to prevent. Is there a better option for restructuring the if else ?

+4
source share
2 answers

I think I would start with a set of small classes to make a validation step for each type:

 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(); } // ... 

Then I would create a map with the type name in the verifier for this type:

 std::map<std::string, decltyp(v_string)> verifiers; verifiers["string"] = v_string; verifiers["Vector2u"] = v_Vector2u; // ... 

Then, to check the type, you should use something like this:

 // 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"); 
+4
source

A fairly common way for such situations is to use a macro. This is #defined before or in funciton and # undef-ed at the end of the function. Since you need to continue there, the other methods are pretty tightly closed.

goto would also be a solution, but for this particular sample, I would not go with it.

An easier way is to at least cause a crash call to a function or lambda, which still leaves you with a continuation.

I would probably make a macro that takes a filter expression as an argument, leaving the code similar.

 if(type == "bool") { ENSURE(values->Has(1) && values->Get(1)->IsBoolean()); stg->Set<bool>(key, values->Get(1)->BooleanValue()); } ... 
0
source

Source: https://habr.com/ru/post/1488309/


All Articles