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
|
/** \file
Specifying model characteristics and details of estimation methods. */
/* Copyright (c) 2008--2009, 2011, 2013 by Ben Klemens. Licensed under the GPLv2; see COPYING. */
#include "apop_internal.h"
static size_t get_settings_ct(apop_model *model){
int ct =0;
if (!model->settings) return 0;
while (model->settings[ct].name[0] !='\0') ct++;
return ct;
}
//The Dan J Bernstein string hashing algorithm.
//Could conceivably save a lot of time under certain settings-heavy circumstances.
static unsigned long apop_settings_hash(char *str){
unsigned long int hash = 5381;
char c;
while ((c = *str++)) hash = hash*33 + c;
return hash;
}
/* Remove a settings group from a model.
Use \ref Apop_settings_rm_group. That macro uses this function internally.
*/
void apop_settings_remove_group(apop_model *m, char *delme){
if (!m->settings) return;
int i = 0;
int ct = get_settings_ct(m);
unsigned long delme_hash = apop_settings_hash(delme);
while (m->settings[i].name[0] !='\0'){
if (m->settings[i].name_hash == delme_hash){
((void (*)(void*))m->settings[i].free)(m->settings[i].setting_group);
for (int j=i+1; j< ct+1; j++) //don't forget the null sentinel.
m->settings[j-1] = m->settings[j];
i--;
}
i++;
}
// apop_assert_void(0, 1, 'c', "I couldn't find %s in the input model, so nothing was removed.", delme);
}
/* Don't use this function. It's what the \c Apop_model_add_group macro uses internally. Use that. */
void *apop_settings_group_alloc(apop_model *model, char *type, void *free_fn, void *copy_fn, void *the_group){
if(apop_settings_get_grp(model, type, 'c'))
apop_settings_remove_group(model, type);
int ct = get_settings_ct(model);
model->settings = realloc(model->settings, sizeof(apop_settings_type)*(ct+2));
model->settings[ct] = (apop_settings_type) {
.setting_group = the_group,
.name_hash = apop_settings_hash(type),
.free= free_fn, .copy = copy_fn };
strncpy(model->settings[ct].name, type, 100);
model->settings[ct+1] = (apop_settings_type) { };
return model->settings[ct].setting_group;
}
//need this for the apop_settings_model_group_alloc macro.
apop_model *apop_settings_group_alloc_wm(apop_model *model, char *type, void *free_fn, void *copy_fn, void *the_group){
apop_settings_group_alloc(model, type, free_fn, copy_fn, the_group);
return model;
}
/* This function is used internally by the macro \ref Apop_settings_get_group. Use that. */
void * apop_settings_get_grp(apop_model *m, char *type, char fail){
//Used only for finding the non-blank groups.
Apop_stopif(!m, return NULL, 0, "you gave me a NULL model as input.");
if (!m->settings) return NULL;
int i;
unsigned long type_hash = apop_settings_hash(type);
for (i=0; m->settings[i].name[0] !='\0'; i++)
if (type_hash == m->settings[i].name_hash)
return m->settings[i].setting_group;
Apop_assert(fail != 'f', "I couldn't find the settings group %s in the given model.", type);
return NULL; //else, just return NULL and let the caller sort it out.
}
/** Copy a settings group with the given name from the second model to
the first (i.e., the arguments are in memcpy order).
You probably won't need this often---just use \ref apop_model_copy.
\param outm The model that will receive a copy of the settings group.
\param inm The model that will provide the original.
\param copyme The string naming the group. For example, for an \ref apop_mcmc_settings group, this would be \c "apop_mcmc".
\exception outm->error=='s' Error copying settings group.
*/
void apop_settings_copy_group(apop_model *outm, apop_model *inm, char *copyme){
if (!copyme || !strlen(copyme)) return; //apop_settings_group_alloc takes care of the blank sentinel.
Apop_stopif(!inm, if (outm) outm->error = 's'; return, 0, "you asked me to copy the settings of a NULL model.");
Apop_stopif(!inm->settings, return, 0, "The input model (i.e., the second argument to this function) has no settings.");
void *g = apop_settings_get_grp(inm, copyme, 'c');
Apop_stopif(!g, outm->error='s'; return, 0, "Couldn't find the group you wanted me to copy. Not copying anything; setting outmodel->error='s'.");
int i;
unsigned long type_hash = apop_settings_hash(copyme);
for (i=0; inm->settings[i].name[0] !='\0'; i++)//retrieve the index.
if (type_hash == inm->settings[i].name_hash)
break;
void *gnew = (inm->settings[i].copy)
? ((void *(*)(void*))inm->settings[i].copy)(g)
: g;
apop_settings_group_alloc(outm, copyme, inm->settings[i].free, inm->settings[i].copy, gnew);
}
|