I actually mislead myself on how I wanted it to determine the validity of body, but here is the new technique I use:
Every time the body is created, the body pointer (in
long form) is added to a hash (
std::map). The body pointer in long form acts as hash key, and a
true acts as key's value. Whenever a body is destroyed the body pointer (key) is deleted from hash.
To determine if body poitner is valid, you simply attempt to link it in hash. If it fails to link, or the return value of the linked object is false, then the body is invalid; otherwise, it's valid.
The data itself associated with the body is created when the body is created and destroyed when the body is destroyed. So, accessing body data after the body is destroyed will not work, neither it would be necessary. The validity hash will be there to determine if the body is valid and simply for security reasons, since the user can pass any sort of body address they might wish. If the user wants to access particular body data, they will have to use a function, like
body_get_data(body). The function itself will check whether the specified body exists before attempting to return data, simply by linking it in hash. If the specified body pointer is not linked, the function will return NULL or raise an argument error saying,
"The specified body does not exist!" If the body does exist, then the function will proceed to returning body data.
Same security technique is applied to all functions to avoid crashes or unexpected results. Who knows what the user might pass as a parameter? Validity checks are essential to make the API crash-proof.
Using hash (
std::map) is a huge advantage over arrays or other iterating forms as they don't require iterating to determine if something is there. Along with that, hashes have no limit in size, which is a big plus over arrays. For example, if you wanted to determine if the body is valid, you would have had to iterate through an array contain all valid bodies to check if the specified body is valid (or exists), but with hashes the key (body address) is directly linked with it's value, so iterating through all keys won't be required.
Here is a little code snippet if any one is interested.
- Code: Select all
std::map<long, bool> valid_bodies;
void body_destructor_callback(const NewtonBody* const body)
{
if( valid_bodies.find((long)body) != valid_bodies.end() )
valid_bodies.erase((long)body);
BodyData* body_data = (BodyData*)NewtonBodyGetUserData(body);
delete body_data;
}
VALUE body_is_valid(VALUE self, VALUE v_body)
{
return (valid_bodies.find(NUM2LONG(v_body)) == valid_bodies.end()) ? Qfalse : Qtrue;
}
VALUE body_create_dynamic(VALUE self, VALUE v_world, VALUE v_collision, VALUE v_matrix)
{
dFloat matrix[16];
for( int i = 0; i < 16; i++ )
matrix[i] = (dFloat)NUM2DBL(rb_ary_entry(v_matrix, i));
matrix[12] *= INCH_TO_METER;
matrix[13] *= INCH_TO_METER;
matrix[14] *= INCH_TO_METER;
NewtonBody* body = NewtonCreateDynamicBody((NewtonWorld*)NUM2LONG(v_world), (NewtonCollision*)NUM2LONG(v_collision), matrix);
valid_bodies[(long)body] = true;
BodyData* data = new BodyData;
data->elasticity = DEFAULT_ELASTICITY;
data->softness = DEFAULT_SOFTNESS;
data->static_friction = DEFAULT_STATIC_FRICTION;
data->dynamic_friction = DEFAULT_DYNAMIC_FRICTION;
data->friction_enabled = DEFAULT_ENABLE_FRICTION;
NewtonBodySetUserData(body, data);
NewtonBodySetForceAndTorqueCallback(body, force_and_torque_callback);
NewtonBodySetDestructorCallback(body, body_destructor_callback);
return LONG2NUM((LONG_PTR)body);
}
// @return [Bool] success
VALUE body_destroy(VALUE self, VALUE v_body)
{
if( valid_bodies.find(NUM2LONG(v_body)) == valid_bodies.end() )
return Qfalse;
NewtonDestroyBody((NewtonBody*)NUM2LONG(v_body));
return Qtrue;
}
VALUE body_get_elasticity(VALUE self, VALUE v_body)
{
if( valid_bodies.find(NUM2LONG(v_body)) == valid_bodies.end() )
return Qnil;
BodyData* data = (BodyData*)NewtonBodyGetUserData((NewtonBody*)NUM2LONG(v_body));
return DBL2NUM(data->elasticity);
}
VALUE body_set_elasticity(VALUE self, VALUE v_body, VALUE v_elasticity)
{
if( valid_bodies.find(NUM2LONG(v_body)) == valid_bodies.end() )
return Qfalse;
BodyData* data = (BodyData*)NewtonBodyGetUserData((NewtonBody*)NUM2LONG(v_body));
data->elasticity = c_clamp((dFloat)NUM2DBL(v_elasticity), 0.01f, 2.00f);
return Qtrue;
}