CFHT HOME ArgMap Types


up: Data Structure Information next: ArgMap Utilities
Data generally floats around inside a C program as strings, floats, integers, or bit flags. User interfaces often read most of these in only as strings. In the case of HTML, all this stuff is passed around as strings. Each of these strings has an identifier or key or name, which is passed as yet another string. So essentially, there are a lot of "string-key"="string-value" pairs which the data structure below attempts to deal with.

ArgMap type

ArgMap's are C++ data structures that store name/value pairs. The names are used as keys (type ArgKey) for getting at the values (type ArgVal). This type was generated with Gnu's AVLMap template class. It has all the features of this class, along with a few from Gnu's Set template class. They are stored internally as AVL trees, but this is of little consequence to the rest of the code. ArgMap's are accessed like arrays and can be traversed with a for-loop in the same was as any of Gnu's data structures, using what they call Pixes. The pages on Gnu's data structure libraries give good examples of how to use these features.

ArgKey type

ArgKey's are just constant character strings. They are passed as a type of array index to an ArgMap in the same way that integer-indexed arrays are passed integers. For example, to access the value in the fifth slot of array a, one would use a[5]. In the case of ArgMap's, the slots are simply named instead of numbered. So to look up or assign a slot named "foo" in an ArgMap b, the code just looks like b["foo"]. This would return, or be assigned the type ArgVal, described below.

By default, the keys are case insensitive. A function could be added to the main ArgMap class in the future to support turning on case sensitivity for a particular map.

ArgVal type

ArgVal's are more versatile than the key type. They can be strings, integers, and/or floats, depending on how they are accessed or assigned. The operators (=,==,!=) for accessing and assigning this type have been linked to function calls (overloaded) which automatically carry out any conversions on the fly, if necessary. The three types currently supported are
  1. int, accessed by any of the "*int*" functions that are part of the class definition, or by typecasting the ArgVal to a type (int)
  2. double, accessed by and of the "*flt*" functions or by typecasting to (double)
  3. String&, accessed by any of the "*str*" functions, or by typecasting to (String&) or (char*)
If code only ever uses one of the types, no conversions will be carried out, so there is very little overhead except for a couple of extra pointers and internal flags stored within each ArgVal that you allocate. A small price to pay for something that is very intuitive to use. For example, if a user has entered a strings into the ArgVals params["WIDTH"] and params["HEIGHT"], the code for printing the area would only need to use
{
  ArgMap params;
  ...
  printf( "The area is %f.\n",
          (double)params["WIDTH"]*(double)params["HEIGHT"]);
}
Since they are typecast as double floats, the approriate function will be called to convert the user's string to a float, even from sexagesimal notation. Effectively, the code above triggers a call to cfht_number(). If there is a possibility that the string could contain invalid characters, then the _OK() functions built into ArgVal should be used as follows:
{
  ArgMap params;
  ...
  if ( !params["WIDTH"].flt_OK() || !params["HEIGHT"].flt_OK() )
  {
    printf( "Couldn't convert `%s' or `%s' to a float!\n",
            (char*)params["WIDTH"],(char*)params["HEIGHT"] );
  }
  else
  {
    printf( "The area is %f.\n",
            (double)params["WIDTH"]*(double)params["HEIGHT"] );
  }
}
In this case, the conversions happen at the if statement, and are retained for the printf. If the initial value had been assigned as a type double to begin with, the conversion would never have been carried out at all, and the _OK() function would simply have checked a bit and returned.

The _OK() functions and conversions are only functions in the sense that they can be conveniently coded as such. They are compiled as in-lined function calls, and thus do not even have the overhead of a normal function call.

Getting data into an ArgVal is just as straight-forward. All of statements below have effectively the same result:

{ ...
  params["AREA"]=2*3;
  params["AREA"]=6.0000;
  params["AREA"]="6";
  params["AREA"]="6.0";
}
The same is true for the comparison operators:
{ ...
  if (params["AREA"]=="6")...   // true, in the context of the above example
  if (params["AREA"]==6)...     // true   "
  if (params["AREA"]!="6.3")... // true statement.
}
But (>,>=,<, and, <=) have not been defined for strings for this data type. You should typecast to an int or float first for these types to let the built-in C-language behavior of these operators take effect:
{ ...
  if ((char*)params["AREA"]<"6.3")... // wrong!
  if ((double)params["AREA"]<6.3)...  // right, and true in context
}
Summary of ArgVal class functions
member functionsOverloaded Op.Description
a.get_str()operator char*() returns the value as a string, regardless of how it was originally stored
a.get_flt()operator double() returns the value converted to a float, or returns a bogus value, in which case a.flt_OK() would test 0.
a.get_int()operator int() returns the value converted to an int. If a fractional part had to be truncated, a.int_OK() would also test 0.
a.set_str()operator=(char*) stores a copy of string. Subsequent calls to get_int() and get_flt() result in a new conversion on the first call.
a.set_flt()operator=(double) stores the float. Subsequent calls to get_int() and get_str() result in a new conversion on the first call.
a.set_int()operator=(int) stores the integer value. Subsequent calls to get_flt() and get_str() result in a new conversion on the first call.
operator==(char*) Returns non-zero if strcmp() says the strings are identical
operator!=(char*) Returns non-zero if strcmp says the strings are different.
a.has_value() Returns non-zero if `a' has been assigned a value.
a.has_changed() Returns non-zero if `a' has been assigned and then re-assigned a *different* value from the first assignment.
a.str_OK() Same as a.has_value() since all strings are valid.
a.flt_OK() Returns non-zero if the call to cfht_number() was successful.
a.int_OK() Returns non-zero if the value is an OK flt and has no fractional component