apop_settings.c 4.75 KB
 Jerome Benoit committed Aug 15, 2014 1 2 /** \file Specifying model characteristics and details of estimation methods. */  Jerome Benoit committed Jul 10, 2015 3 /* Copyright (c) 2008--2009, 2011, 2013 by Ben Klemens. Licensed under the GPLv2; see COPYING. */  Jerome Benoit committed Aug 15, 2014 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 #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  Jerome Benoit committed Jul 10, 2015 80 the first (i.e., the arguments are in memcpy order).  Jerome Benoit committed Aug 15, 2014 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  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); }