IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 179


Ignore:
Timestamp:
Mar 9, 2004, 3:07:27 PM (22 years ago)
Author:
rhl
Message:

Updated

Location:
trunk/doc/draft
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/draft/metadata.tex

    r130 r179  
    5959\section{Metadata Representation}
    6060
    61 We propose that an item of metadata be represented as a C structure:
     61We propose that an item of metadata be represented as a C structure with at least the following
     62fields:
    6263\begin{verbatim}
    6364/*
     
    7576    } val;                              // value of metadata
    7677    char *comment;                      // optional comment ("", not NULL)
    77 
    78 } psMetaData;
     78} psMetaDataItem;
    7979\end{verbatim}
    8080
     
    8989
    9090The possible types of metadata are identified by the enumerated type
    91 \code{psMetaDataType} (see also table \ref{tabMetaDataTypes}):
     91\code{psMetaDataType} (see also table \ref{tabMetaDataTypes}); the initial defined values are:
    9292\begin{verbatim}
    9393/*
     
    9595 */
    9696typedef enum {                          // type of val is:
    97     psMetaFloat = 0,                    // float (.f)
     97    psMetaFloat,                        // float (.f)
    9898    psMetaInt,                          // int (.i)
    9999    psMetaStr,                          // string (.v)
     
    129129\section{Collections of Metadata}
    130130
    131 We also need to support a container class for metadata.  We propose
    132 using the standard \PS{} doubly-linked list type \code{psDlist}
    133 (see \href{file:utils#psDlist}{utils.pdf} for details). For example:
    134 \begin{verbatim}
    135     psDlist *list = psDlistNew(NULL);   // list of metadata
    136 
    137     psDlistAppend(list, psMetaDataNew("const.ten", psMetaInt, &ten, NULL, 0));
    138     psDlistAppend(list, psMetaDataNew("const.sqrt2", psMetaFloat, &sqrt2,
    139                                       "square root of two", 0));
    140     psDlistAppend(list, psMetaDataNew("lang.hello", psMetaStr, "Bonjour",
    141                                       "French", 0));
    142     /*
    143      * Print all metadata to stdout
    144      */
    145     (void)psDlistGet(list, psDlistTail); // initialise iterator
    146     while ((ms = psDlistGet(list, psDlistPrev)) != NULL) {
    147         psMetaDataPrint(stdout, ms);
    148     }
    149     /*
    150      * Clean up
    151      */
    152     psDlistDel(list, (void (*)(void *))psMetaDataDel);
     131\begin{verbatim}
     132typedef struct {
     133    psDlist *list;                      // list of psMetaDataItem
     134    psHash *table;                      // hash table of the same metadata
     135} psMetaDataSet;
     136\end{verbatim}
     137
     138The type \code{psMetaDataSet} is a container class for metadata. Note that there are
     139in fact \emph{two} representations of the metadata (each \code{psMetaDataItem} appears
     140on both).
     141
     142We are using the standard \PS{} doubly-linked list types \code{psDlist} and  \code{psHash}
     143(see \href{file:utils#psDlist}{utils.pdf:psDlist} and \href{file:utils#psHash}{utils.pdf:psHash} for details).
     144For example:
     145\begin{verbatim}
     146    for (int i = 0; i < 10; i += 5) {
     147        float sqrti = sqrt(i);
     148        psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_INT, &i, NULL, "const.%d", i));
     149        psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_FLOAT, &sqrti, "square root", "const.sqrt%d", i));
     150    }
     151    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR, "Bonjour", "French", "lang.hello"));
     152    /*
     153     * Remove a key
     154     */
     155    psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello"));
     156    /*
     157     * Print all metadata
     158     */
     159    fprintf(stdout, "------\n");
     160    psMetaDataSetIterator(ms);
     161    while ((meta = psMetaDataGetNext(ms, NULL)) != NULL) {
     162        psMetaDataItemPrint(stdout, meta, "");
     163    }
     164    /*
     165     * Look up a key by name
     166     */
     167    fprintf(stdout, "------\n");
     168    fprintf(stdout, "Looking up by name:\n");
     169    meta = psMetaDataLookup(ms, "const.5");
     170    if (meta != NULL) {
     171        psMetaDataItemPrint(stdout, meta, "");
     172    }
    153173\end{verbatim}
    154174
    155175\section{Naming convention for MetaData}
    156176
    157 The \code{psMetaData} struct includes a name.  This name should be of
     177The \code{psMetaDataItem} struct includes a name.  This name should be of
    158178the form \code{name1.name2.name3$\cdots$}, e.g.\hfil\break
    159179\null\qquad\qquad\code{IPP.phase1.ota12.biassec}.
     
    163183all metadata names in use throughout the project.
    164184
     185\subsection{Support for Multiple Values for a Given Name}
     186
     187\begin{verbatim}
     188    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
     189                                           "Bonjour", "French", "lang.hello"));
     190    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
     191                                           "Aloha", "Hawaiian", "lang.hello"));
     192    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
     193                                           "Good Morning", "English", "lang.hello"));
     194    /*
     195     * Print all metadata starting "lang"
     196     */
     197    psMetaDataSetIterator(ms);
     198    while ((meta = psMetaDataGetNext(ms, "lang")) != NULL) {
     199        psMetaDataItemPrint(stdout, meta, "");
     200    }
     201\end{verbatim}
     202
     203It is an unfortunate fact that certain metadata keywords (such as \code{COMMENT} in a FITS header)
     204may be repeated with different values.  The \code{psMetaDataAppend} routine is required
     205to check that all metadata names are unique unless the type is qualified as \code{PS_META_NON_UNIQUE};
     206in this case a unique integer will be added to each name that you specify. In this case,
     207you may either delete individual element separately or as a complete set:
     208\begin{verbatim}
     209psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello.0"));
     210psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello"));
     211\end{verbatim}
     212
     213\appendix
     214\section{MetaData APIs}
     215
     216\begin{verbatim}
     217psMetaDataItem *psMetaDataItemAlloc(
     218    psMetaDataType type,                // type of this piece of metadata
     219    const void *val,                    // value of new item
     220                                        // N.b. a pointer even if the item
     221                                        // is of type e.g. int
     222    const char *comment,                // comment associated with item
     223    const char *name,                   // name of new item of metadata (may be an sprintf format)
     224    ...);                               // possible arguments for name format
     225
     226void psMetaDataItemFree(psMetaDataItem *ms); // piece of metadata to destroy
     227
     228psMetaDataSet *psMetaDataSetAlloc(void);          // make a new set of metadata
     229void psMetaDataSetDel(psMetaDataSet *ms); // destroy a set of metadata
     230
     231/*****************************************************************************/
     232/*
     233 * Utilities
     234 */
     235psMetaDataItem *psMetaDataAppend(psMetaDataSet *restrict ms, psMetaDataItem *restrict item);
     236psMetaDataItem *psMetaDataRemove(psMetaDataSet *restrict ms, const char *restrict key);
     237
     238void psMetaDataSetIterator(psMetaDataSet *ms);
     239psMetaDataItem *psMetaDataGetNext(psMetaDataSet *ms);
     240psMetaDataItem *psMetaDataLookup(const psMetaDataSet *ms, const char *key);
     241
     242void psMetaDataItemPrint(FILE *fd,              // file descriptor to write to
     243                         const psMetaDataItem *ms); // item of metadata to print
     244\end{verbatim}
    165245
    166246\bibliographystyle{plain}
  • trunk/doc/draft/utils.tex

    r139 r179  
    5858The \PS{} software system will need a level of memory management
    5959placed between the operating system (malloc/free) and the high level
    60 routines (e.g. \code{psMetaDataNew}).
     60routines (e.g. \code{psMetaDataAlloc}).
    6161
    6262This layer is in addition to the possibility that specific heavily
    6363used data types may need their own special-purpose memory managers;
    6464but as we have specified that all user-level objects be allocated via
    65 \code{typeNew/typeDel} functions, we will easily be able to
     65\code{typeAlloc/typeFree} functions, we will easily be able to
    6666implement such functionality without impacting on the facilities
    6767described here.
     
    6969All of the memory management APIs should be provided in a header file
    7070\file{psMemory.h} which is included by \file{psUtils.h}.
    71 
    72 \textit{Do we want to rename \code{psAlloc} to \code{psNew} and
    73   \code{psFree} to \code{psDel}? Or is it too late? XXX}
    7471
    7572\subsection{Rationale}
     
    9289  We need to provide a mechanism for tracking and fixing memory
    9390  leaks.  While it is possible to do this by linking with external
    94   libraries (XXX reference), it is convenient to do so within the
     91  libraries (\tbd{reference}), it is convenient to do so within the
    9592  \PS{} framework.
    9693
     
    376373} psSimple;
    377374
    378 psSimple *psSimpleNew(const char *name, int val)
     375psSimple *psSimpleAlloc(const char *name, int val)
    379376{
    380377    psSimple *simp = psAlloc(sizeof(psSimple));
     
    385382}
    386383
    387 void psSimpleDel(psSimple *simp)
     384void psSimpleFree(psSimple *simp)
    388385{
    389386    if (simp == NULL) { return; }
     
    411408\goodbreak
    412409\begin{verbatim}
    413 simp = psSimpleNew("RHL", 0);
     410simp = psSimpleAlloc("RHL", 0);
    414411psDlistAppend(list1, psMemIncrRefCounter(simp));
    415412psDlistAppend(list2, psMemIncrRefCounter(simp));
    416 psSimpleDel(simp);
     413psSimpleFree(simp);
    417414\end{verbatim}
    418415
     
    447444                    int level);         // desired trace level
    448445int psGetTraceLevel(const char *name);  // facilty of interest
     446
     447void psTraceReset(void);                // turn off all tracing, and free trace's allocated memory
    449448
    450449void psPrintTraceLevels(void);          // print trace levels
     
    513512      within the functions that implement \file{psTrace.h}
    514513      or \file{psMemory.h} systems.
     514
     515    \item
     516      \code{psTraceReset} shall reset all tracing to the state that it
     517      had at program initiation, including freeing any memory that the
     518      tracing subsystem may have allocated.
    515519\end{itemize}
    516520
     
    581585
    582586int psSetLogDestination(int dest);
     587void psSetLogFormat(const char *fmt);
     588
    583589int psSetLogLevel(int level);
    584590  \end{verbatim}
     
    634640write to \code{stderr} and \code{stdout} respectively.
    635641
    636 \section{The Pan-STARRS \texttt{psDlist} doubly-linked list type}
     642The fields included in the log message may be controlled using \code{psSetLogFormat} which
     643expects a string consisting of the letters \code{H} (host), \code{L} (level), \code{M} (message),
     644\code{N} (name), and \code{T} (time).  The default is \code{HLMNT}.
     645
     646\section{The Pan-STARRS \code{psDlist} doubly-linked list type}
    637647\hlabel{psDlist}
    638648
     
    667677
    668678\begin{verbatim}
    669 psDlist *psDlistNew(void *data);        // initial data item; may be NULL
    670 
    671 void psDlistDel(psDlist *list,          // list to destroy
    672                 void (*elemDel)(void *)); // destructor for list data, or NULL
     679psDlist *psDlistAlloc(void *data);        // initial data item; may be NULL
     680
     681void psDlistFree(psDlist *list,          // list to destroy
     682                void (*elemFree)(void *)); // destructor for list data, or NULL
    673683
    674684/*
     
    702712their reference counter.
    703713
    704 If \code{psDlistDel}'s argument \code{elemDel} is NULL, the
     714If \code{psDlistFree}'s argument \code{elemFree} is NULL, the
    705715list should be deleted, but not the elements on it (although their
    706716\code{refcounter}'s should be decremented).
    707717
    708 The \code{psDlistGet} routine may be used to provide an iterator. The
    709 call \code{psDlistGet(list, psDlistHead)} returns the data from the
    710 head link of the list, but also sets the iteration cursor to the head.
    711 A seried of calls to \code{psDlistGet(list, psDlistNext)} return the
    712 elements of the list in order (you may also use \code{psDlistTail} and
    713 \code{psDlistPrev} to traverse the list backwards).
     718Iteration over all elements of the list is provided by the functions:
     719\begin{verbatim}
     720void psDlistSetIterator(psDlist *list, int where, int which);
     721void *psDlistGetNext(psDlist *list, int which);
     722void *psDlistGetPrev(psDlist *list, int which);
     723\end{verbatim}
     724in which the \code{where} argument must be \code{PS_DLIST_HEAD} or \code{PS_DLIST_TAIL},
     725to start at the head or tail of the list, and \code{psDlistGetNext} and \code{psDlistGetPrev}
     726return the next/previous element. The argument \code{which} identifies which of potentially
     727many iteration cursors should be used; it must currently always be \code{0}.
    714728
    715729Explicit traversal of the list using the \code{psDlistElem}'s
     
    746760with associated constructors and a destructor:
    747761\begin{verbatim}
    748 psTypeArray *psTypeNew(int n, int size);
     762psTypeArray *psTypeAlloc(int n, int size);
    749763psTypeArray *psTypeRealloc(psTypeArray *arr, int n);
    750 void psTypeDel(psTypeArray *arr); 
     764void psTypeFree(psTypeArray *arr); 
    751765\end{verbatim}
    752766
     
    760774and declares the prototypes (and is thus suitable for use in a
    761775header file); the latter generates the code for the three functions
    762 \code{psType(New|Realloc|Del} (and should thus appear in exactly one
     776\code{psType(Alloc|Realloc|Free} (and should thus appear in exactly one
    763777source file for a given type).
    764778
     
    772786contains an array of \code{psType}s not
    773787pointers to \code{psType}s; this means that the individual elements are
    774 not allocated using \code{psTypeNew}, are not correctly initialized,
    775 and shouldn't be individually deleted with \code{psTypeDel};
     788not allocated using \code{psTypeAlloc}, are not correctly initialized,
     789and shouldn't be individually deleted with \code{psTypeFree};
    776790
    777791If you wish to use arrays of pointers, use the macros
     
    788802with associated constructors and a destructor:
    789803\begin{verbatim}
    790 psTypePtrArray *psTypePtrNew(int n, int size);
     804psTypePtrArray *psTypePtrAlloc(int n, int size);
    791805psTypePtrArray *psTypePtrRealloc(psTypePtrArray *arr, int n);
    792 void psTypePtrArrayDel(psTypePtrArray *arr); 
     806void psTypePtrArrayFree(psTypePtrArray *arr); 
    793807\end{verbatim}
    794808
    795809These constructors create arrays of \code{psType *} and call
    796 \code{psTypeNew} and \code{psTypeDel} to allocate and free the
     810\code{psTypeAlloc} and \code{psTypeFree} to allocate and free the
    797811elements. As for the simple arrays, The former defines the typedef and
    798812declares the prototypes (and is thus suitable for use in a header
    799813file) and the latter generates the code for the three functions
    800 \code{psType(New|Realloc|Del} (and should thus appear in exactly one
     814\code{psType(Alloc|Realloc|Free} (and should thus appear in exactly one
    801815source file for a given type).
    802816
     
    805819need to say something like:
    806820\begin{verbatim}
    807   psTypePtrArray *pt = psTypePtrArrayNew(10, 10);
     821  psTypePtrArray *pt = psTypePtrArrayAlloc(10, 10);
    808822  psType *xy = psMemDecrRefCounter(pt->arr[0]);
    809823  pt->arr[0] = NULL;
    810824\end{verbatim}
    811825
    812 \subsubsection{Arrays of \texttt{void *}}
     826\subsubsection{Arrays of \code{void *}}
    813827\hlabel{secArrayVoidPtr}
    814828
     
    825839except that its destructor is specified as:
    826840\begin{verbatim}
    827 void psVoidPtrArrayDel(psVoidPtrArray *arr,      // array to destroy
    828                        void (*elemDel)(void *)); // destructor for array data
    829 \end{verbatim}
    830 
    831 The routine \code{psVoidPtrArrayDel} assumes that all pointers
     841void psVoidPtrArrayFree(psVoidPtrArray *arr,      // array to destroy
     842                       void (*elemFree)(void *)); // destructor for array data
     843\end{verbatim}
     844
     845The routine \code{psVoidPtrArrayFree} assumes that all pointers
    832846had their reference counters incremented
    833847when they were inserted onto the array.\footnote{%
    834848  \eg{} \code{va->arr[i] = psMemIncrRefCounter(ptr);}}
    835849
    836 If \code{psVoidPtrArrayDel}'s argument \code{elemDel} is NULL, the
     850If \code{psVoidPtrArrayFree}'s argument \code{elemFree} is NULL, the
    837851list should be deleted, but not the elements on it (although their
    838852\code{refcounter}'s should be decremented).
     
    849863} psXY;
    850864
    851 psXY *psXYNew(void)
     865psXY *psXYAlloc(void)
    852866{
    853867    return psAlloc(sizeof(psXY));
    854868}
    855869
    856 void psXYDel(psXY *xy)
     870void psXYFree(psXY *xy)
    857871{
    858872    psFree(xy);
     
    867881int main(void)
    868882{
    869     psXYArray *t = psXYArrayNew(10, 15);
    870     psXYPtrArray *pt = psXYPtrArrayNew(10, 10);
     883    psXYArray *t = psXYArrayAlloc(10, 15);
     884    psXYPtrArray *pt = psXYPtrArrayAlloc(10, 10);
    871885
    872886    for (int i = 0; i < t->n; i++) {
     
    883897    printf("\n");
    884898   
    885     psXYArrayDel(t);
     899    psXYArrayFree(t);
    886900
    887901    psXY *xy = psMemDecrRefCounter(pt->arr[0]);
    888902    pt->arr[0] = NULL;
    889     psXYDel(xy);   
     903    psXYFree(xy);   
    890904   
    891     psXYPtrArrayDel(pt);
     905    psXYPtrArrayFree(pt);
    892906
    893907    psMemCheckLeaks(0, NULL, stderr);
     
    904918typedef struct HashTable psHash;
    905919
    906 psHash *psHashNew(int nbucket);         // initial number of buckets
    907 void psHashDel(psHash *table,           // hash table to be freed
    908                void (*itemDel)(void *item)); // how to free hashed data;
    909                                         // or NULL
    910 
    911 void *psHashInsert(psHash *table,       // table to insert in
    912                    const char *key,     // key to use
    913                    void *data,          // data to insert
    914                    void (*itemDel)(void *item)); // how to free hashed data;
    915                                         // or NULL
    916 void *psHashLookup(psHash *table,       // table to lookup key in
    917                    const char *key);    // key to lookup
     920psHash *psHashAlloc(int nbucket);       // initial number of buckets
     921void psHashFree(psHash *table,          // hash table to be freed
     922               void (*itemFree)(void *item)); // how to free hashed data;
     923                                        // or NULL
     924
     925void *psHashInsert(psHash *table,       // table to insert in
     926                   const char *key,     // key to use
     927                   void *data,          // data to insert
     928                   void (*itemFree)(void *item)); // how to free hashed data;
     929                                        // or NULL
     930void *psHashLookup(psHash *table,       // table to lookup key in
     931                   const char *key);    // key to lookup
     932
     933void *psHashRemove(psHash *table,       // table to lookup key in
     934                   const char *key);    // key to lookup
    918935  \end{verbatim}
    919936  \begin{caption}{The public API for hash tables from \file{psHash.h}}
     
    926943is included by \file{psUtils.h}.
    927944\footnote{
    928   We choose not to use the posix function \texttt{hcreate},
    929   \texttt{hdestroy}, and \code{hsearch} as they only support
     945  We choose not to use the posix function \code{hcreate},
     946  \code{hdestroy}, and \code{hsearch} as they only support
    930947  a single hash table at any one time.}
    931948
    932 A hash table is an abstract type \texttt{psHash}.  The argument
    933 \texttt{nbucket} to \texttt{psHashNew} is a non-binding suggestion
     949A hash table is an abstract type \code{psHash}.  The argument
     950\code{nbucket} to \code{psHashAlloc} is a non-binding suggestion
    934951from the user for the initial size of the hash table.
    935952
    936 If the \texttt{itemDel} argument to \texttt{psHashDel} is non-NULL,
     953If the \code{itemFree} argument to \code{psHashFree} is non-NULL,
    937954it will be used to delete the data items that have been stored
    938955in the hash table; if it is NULL this is the responsibility of
    939956the caller.
    940957
    941 The routine \texttt{psHashInsert} must provide a non-NULL \texttt{itemDel}
     958The routine \code{psHashInsert} must provide a non-NULL \code{itemFree}
    942959argument if it wishes to change the value previously inserted keys;
    943 if \texttt{itemDel} is NULL attempting to insert a pre-existing key
    944 is an error, and the routine will return NULL.  If  \texttt{psHashInsert}
    945 succeeds it returns \texttt{data}.
    946 
    947 \texttt{psHashLookup} returns the \texttt{data} associated with the
     960if \code{itemFree} is NULL attempting to insert a pre-existing key
     961is an error, and the routine will return NULL.  If  \code{psHashInsert}
     962succeeds it returns \code{data}.
     963
     964\code{psHashLookup} returns the \code{data} associated with the
    948965key, or NULL if the key's invalid.
     966
     967\code{psHashRemove} removes the entry associated with the
     968key from the table, and returns the \code{data}; if the key's invalid it returns NULL.
    949969
    950970\section{Miscellaneous Utilities}
Note: See TracChangeset for help on using the changeset viewer.