Changeset 179
- Timestamp:
- Mar 9, 2004, 3:07:27 PM (22 years ago)
- Location:
- trunk/doc/draft
- Files:
-
- 2 edited
-
metadata.tex (modified) (6 diffs)
-
utils.tex (modified) (23 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/doc/draft/metadata.tex
r130 r179 59 59 \section{Metadata Representation} 60 60 61 We propose that an item of metadata be represented as a C structure: 61 We propose that an item of metadata be represented as a C structure with at least the following 62 fields: 62 63 \begin{verbatim} 63 64 /* … … 75 76 } val; // value of metadata 76 77 char *comment; // optional comment ("", not NULL) 77 78 } psMetaData; 78 } psMetaDataItem; 79 79 \end{verbatim} 80 80 … … 89 89 90 90 The 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: 92 92 \begin{verbatim} 93 93 /* … … 95 95 */ 96 96 typedef enum { // type of val is: 97 psMetaFloat = 0,// float (.f)97 psMetaFloat, // float (.f) 98 98 psMetaInt, // int (.i) 99 99 psMetaStr, // string (.v) … … 129 129 \section{Collections of Metadata} 130 130 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} 132 typedef struct { 133 psDlist *list; // list of psMetaDataItem 134 psHash *table; // hash table of the same metadata 135 } psMetaDataSet; 136 \end{verbatim} 137 138 The type \code{psMetaDataSet} is a container class for metadata. Note that there are 139 in fact \emph{two} representations of the metadata (each \code{psMetaDataItem} appears 140 on both). 141 142 We 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). 144 For 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 } 153 173 \end{verbatim} 154 174 155 175 \section{Naming convention for MetaData} 156 176 157 The \code{psMetaData } struct includes a name. This name should be of177 The \code{psMetaDataItem} struct includes a name. This name should be of 158 178 the form \code{name1.name2.name3$\cdots$}, e.g.\hfil\break 159 179 \null\qquad\qquad\code{IPP.phase1.ota12.biassec}. … … 163 183 all metadata names in use throughout the project. 164 184 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 203 It is an unfortunate fact that certain metadata keywords (such as \code{COMMENT} in a FITS header) 204 may be repeated with different values. The \code{psMetaDataAppend} routine is required 205 to check that all metadata names are unique unless the type is qualified as \code{PS_META_NON_UNIQUE}; 206 in this case a unique integer will be added to each name that you specify. In this case, 207 you may either delete individual element separately or as a complete set: 208 \begin{verbatim} 209 psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello.0")); 210 psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello")); 211 \end{verbatim} 212 213 \appendix 214 \section{MetaData APIs} 215 216 \begin{verbatim} 217 psMetaDataItem *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 226 void psMetaDataItemFree(psMetaDataItem *ms); // piece of metadata to destroy 227 228 psMetaDataSet *psMetaDataSetAlloc(void); // make a new set of metadata 229 void psMetaDataSetDel(psMetaDataSet *ms); // destroy a set of metadata 230 231 /*****************************************************************************/ 232 /* 233 * Utilities 234 */ 235 psMetaDataItem *psMetaDataAppend(psMetaDataSet *restrict ms, psMetaDataItem *restrict item); 236 psMetaDataItem *psMetaDataRemove(psMetaDataSet *restrict ms, const char *restrict key); 237 238 void psMetaDataSetIterator(psMetaDataSet *ms); 239 psMetaDataItem *psMetaDataGetNext(psMetaDataSet *ms); 240 psMetaDataItem *psMetaDataLookup(const psMetaDataSet *ms, const char *key); 241 242 void psMetaDataItemPrint(FILE *fd, // file descriptor to write to 243 const psMetaDataItem *ms); // item of metadata to print 244 \end{verbatim} 165 245 166 246 \bibliographystyle{plain} -
trunk/doc/draft/utils.tex
r139 r179 58 58 The \PS{} software system will need a level of memory management 59 59 placed between the operating system (malloc/free) and the high level 60 routines (e.g. \code{psMetaData New}).60 routines (e.g. \code{psMetaDataAlloc}). 61 61 62 62 This layer is in addition to the possibility that specific heavily 63 63 used data types may need their own special-purpose memory managers; 64 64 but as we have specified that all user-level objects be allocated via 65 \code{type New/typeDel} functions, we will easily be able to65 \code{typeAlloc/typeFree} functions, we will easily be able to 66 66 implement such functionality without impacting on the facilities 67 67 described here. … … 69 69 All of the memory management APIs should be provided in a header file 70 70 \file{psMemory.h} which is included by \file{psUtils.h}. 71 72 \textit{Do we want to rename \code{psAlloc} to \code{psNew} and73 \code{psFree} to \code{psDel}? Or is it too late? XXX}74 71 75 72 \subsection{Rationale} … … 92 89 We need to provide a mechanism for tracking and fixing memory 93 90 leaks. While it is possible to do this by linking with external 94 libraries ( XXX reference), it is convenient to do so within the91 libraries (\tbd{reference}), it is convenient to do so within the 95 92 \PS{} framework. 96 93 … … 376 373 } psSimple; 377 374 378 psSimple *psSimple New(const char *name, int val)375 psSimple *psSimpleAlloc(const char *name, int val) 379 376 { 380 377 psSimple *simp = psAlloc(sizeof(psSimple)); … … 385 382 } 386 383 387 void psSimple Del(psSimple *simp)384 void psSimpleFree(psSimple *simp) 388 385 { 389 386 if (simp == NULL) { return; } … … 411 408 \goodbreak 412 409 \begin{verbatim} 413 simp = psSimple New("RHL", 0);410 simp = psSimpleAlloc("RHL", 0); 414 411 psDlistAppend(list1, psMemIncrRefCounter(simp)); 415 412 psDlistAppend(list2, psMemIncrRefCounter(simp)); 416 psSimple Del(simp);413 psSimpleFree(simp); 417 414 \end{verbatim} 418 415 … … 447 444 int level); // desired trace level 448 445 int psGetTraceLevel(const char *name); // facilty of interest 446 447 void psTraceReset(void); // turn off all tracing, and free trace's allocated memory 449 448 450 449 void psPrintTraceLevels(void); // print trace levels … … 513 512 within the functions that implement \file{psTrace.h} 514 513 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. 515 519 \end{itemize} 516 520 … … 581 585 582 586 int psSetLogDestination(int dest); 587 void psSetLogFormat(const char *fmt); 588 583 589 int psSetLogLevel(int level); 584 590 \end{verbatim} … … 634 640 write to \code{stderr} and \code{stdout} respectively. 635 641 636 \section{The Pan-STARRS \texttt{psDlist} doubly-linked list type} 642 The fields included in the log message may be controlled using \code{psSetLogFormat} which 643 expects 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} 637 647 \hlabel{psDlist} 638 648 … … 667 677 668 678 \begin{verbatim} 669 psDlist *psDlist New(void *data); // initial data item; may be NULL670 671 void psDlist Del(psDlist *list, // list to destroy672 void (*elem Del)(void *)); // destructor for list data, or NULL679 psDlist *psDlistAlloc(void *data); // initial data item; may be NULL 680 681 void psDlistFree(psDlist *list, // list to destroy 682 void (*elemFree)(void *)); // destructor for list data, or NULL 673 683 674 684 /* … … 702 712 their reference counter. 703 713 704 If \code{psDlist Del}'s argument \code{elemDel} is NULL, the714 If \code{psDlistFree}'s argument \code{elemFree} is NULL, the 705 715 list should be deleted, but not the elements on it (although their 706 716 \code{refcounter}'s should be decremented). 707 717 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). 718 Iteration over all elements of the list is provided by the functions: 719 \begin{verbatim} 720 void psDlistSetIterator(psDlist *list, int where, int which); 721 void *psDlistGetNext(psDlist *list, int which); 722 void *psDlistGetPrev(psDlist *list, int which); 723 \end{verbatim} 724 in which the \code{where} argument must be \code{PS_DLIST_HEAD} or \code{PS_DLIST_TAIL}, 725 to start at the head or tail of the list, and \code{psDlistGetNext} and \code{psDlistGetPrev} 726 return the next/previous element. The argument \code{which} identifies which of potentially 727 many iteration cursors should be used; it must currently always be \code{0}. 714 728 715 729 Explicit traversal of the list using the \code{psDlistElem}'s … … 746 760 with associated constructors and a destructor: 747 761 \begin{verbatim} 748 psTypeArray *psType New(int n, int size);762 psTypeArray *psTypeAlloc(int n, int size); 749 763 psTypeArray *psTypeRealloc(psTypeArray *arr, int n); 750 void psType Del(psTypeArray *arr);764 void psTypeFree(psTypeArray *arr); 751 765 \end{verbatim} 752 766 … … 760 774 and declares the prototypes (and is thus suitable for use in a 761 775 header file); the latter generates the code for the three functions 762 \code{psType( New|Realloc|Del} (and should thus appear in exactly one776 \code{psType(Alloc|Realloc|Free} (and should thus appear in exactly one 763 777 source file for a given type). 764 778 … … 772 786 contains an array of \code{psType}s not 773 787 pointers to \code{psType}s; this means that the individual elements are 774 not allocated using \code{psType New}, are not correctly initialized,775 and shouldn't be individually deleted with \code{psType Del};788 not allocated using \code{psTypeAlloc}, are not correctly initialized, 789 and shouldn't be individually deleted with \code{psTypeFree}; 776 790 777 791 If you wish to use arrays of pointers, use the macros … … 788 802 with associated constructors and a destructor: 789 803 \begin{verbatim} 790 psTypePtrArray *psTypePtr New(int n, int size);804 psTypePtrArray *psTypePtrAlloc(int n, int size); 791 805 psTypePtrArray *psTypePtrRealloc(psTypePtrArray *arr, int n); 792 void psTypePtrArray Del(psTypePtrArray *arr);806 void psTypePtrArrayFree(psTypePtrArray *arr); 793 807 \end{verbatim} 794 808 795 809 These constructors create arrays of \code{psType *} and call 796 \code{psType New} and \code{psTypeDel} to allocate and free the810 \code{psTypeAlloc} and \code{psTypeFree} to allocate and free the 797 811 elements. As for the simple arrays, The former defines the typedef and 798 812 declares the prototypes (and is thus suitable for use in a header 799 813 file) and the latter generates the code for the three functions 800 \code{psType( New|Realloc|Del} (and should thus appear in exactly one814 \code{psType(Alloc|Realloc|Free} (and should thus appear in exactly one 801 815 source file for a given type). 802 816 … … 805 819 need to say something like: 806 820 \begin{verbatim} 807 psTypePtrArray *pt = psTypePtrArray New(10, 10);821 psTypePtrArray *pt = psTypePtrArrayAlloc(10, 10); 808 822 psType *xy = psMemDecrRefCounter(pt->arr[0]); 809 823 pt->arr[0] = NULL; 810 824 \end{verbatim} 811 825 812 \subsubsection{Arrays of \ texttt{void *}}826 \subsubsection{Arrays of \code{void *}} 813 827 \hlabel{secArrayVoidPtr} 814 828 … … 825 839 except that its destructor is specified as: 826 840 \begin{verbatim} 827 void psVoidPtrArray Del(psVoidPtrArray *arr, // array to destroy828 void (*elem Del)(void *)); // destructor for array data829 \end{verbatim} 830 831 The routine \code{psVoidPtrArray Del} assumes that all pointers841 void psVoidPtrArrayFree(psVoidPtrArray *arr, // array to destroy 842 void (*elemFree)(void *)); // destructor for array data 843 \end{verbatim} 844 845 The routine \code{psVoidPtrArrayFree} assumes that all pointers 832 846 had their reference counters incremented 833 847 when they were inserted onto the array.\footnote{% 834 848 \eg{} \code{va->arr[i] = psMemIncrRefCounter(ptr);}} 835 849 836 If \code{psVoidPtrArray Del}'s argument \code{elemDel} is NULL, the850 If \code{psVoidPtrArrayFree}'s argument \code{elemFree} is NULL, the 837 851 list should be deleted, but not the elements on it (although their 838 852 \code{refcounter}'s should be decremented). … … 849 863 } psXY; 850 864 851 psXY *psXY New(void)865 psXY *psXYAlloc(void) 852 866 { 853 867 return psAlloc(sizeof(psXY)); 854 868 } 855 869 856 void psXY Del(psXY *xy)870 void psXYFree(psXY *xy) 857 871 { 858 872 psFree(xy); … … 867 881 int main(void) 868 882 { 869 psXYArray *t = psXYArray New(10, 15);870 psXYPtrArray *pt = psXYPtrArray New(10, 10);883 psXYArray *t = psXYArrayAlloc(10, 15); 884 psXYPtrArray *pt = psXYPtrArrayAlloc(10, 10); 871 885 872 886 for (int i = 0; i < t->n; i++) { … … 883 897 printf("\n"); 884 898 885 psXYArray Del(t);899 psXYArrayFree(t); 886 900 887 901 psXY *xy = psMemDecrRefCounter(pt->arr[0]); 888 902 pt->arr[0] = NULL; 889 psXY Del(xy);903 psXYFree(xy); 890 904 891 psXYPtrArray Del(pt);905 psXYPtrArrayFree(pt); 892 906 893 907 psMemCheckLeaks(0, NULL, stderr); … … 904 918 typedef struct HashTable psHash; 905 919 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 920 psHash *psHashAlloc(int nbucket); // initial number of buckets 921 void psHashFree(psHash *table, // hash table to be freed 922 void (*itemFree)(void *item)); // how to free hashed data; 923 // or NULL 924 925 void *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 930 void *psHashLookup(psHash *table, // table to lookup key in 931 const char *key); // key to lookup 932 933 void *psHashRemove(psHash *table, // table to lookup key in 934 const char *key); // key to lookup 918 935 \end{verbatim} 919 936 \begin{caption}{The public API for hash tables from \file{psHash.h}} … … 926 943 is included by \file{psUtils.h}. 927 944 \footnote{ 928 We choose not to use the posix function \ texttt{hcreate},929 \ texttt{hdestroy}, and \code{hsearch} as they only support945 We choose not to use the posix function \code{hcreate}, 946 \code{hdestroy}, and \code{hsearch} as they only support 930 947 a single hash table at any one time.} 931 948 932 A hash table is an abstract type \ texttt{psHash}. The argument933 \ texttt{nbucket} to \texttt{psHashNew} is a non-binding suggestion949 A hash table is an abstract type \code{psHash}. The argument 950 \code{nbucket} to \code{psHashAlloc} is a non-binding suggestion 934 951 from the user for the initial size of the hash table. 935 952 936 If the \ texttt{itemDel} argument to \texttt{psHashDel} is non-NULL,953 If the \code{itemFree} argument to \code{psHashFree} is non-NULL, 937 954 it will be used to delete the data items that have been stored 938 955 in the hash table; if it is NULL this is the responsibility of 939 956 the caller. 940 957 941 The routine \ texttt{psHashInsert} must provide a non-NULL \texttt{itemDel}958 The routine \code{psHashInsert} must provide a non-NULL \code{itemFree} 942 959 argument if it wishes to change the value previously inserted keys; 943 if \ texttt{itemDel} is NULL attempting to insert a pre-existing key944 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 the960 if \code{itemFree} is NULL attempting to insert a pre-existing key 961 is an error, and the routine will return NULL. If \code{psHashInsert} 962 succeeds it returns \code{data}. 963 964 \code{psHashLookup} returns the \code{data} associated with the 948 965 key, or NULL if the key's invalid. 966 967 \code{psHashRemove} removes the entry associated with the 968 key from the table, and returns the \code{data}; if the key's invalid it returns NULL. 949 969 950 970 \section{Miscellaneous Utilities}
Note:
See TracChangeset
for help on using the changeset viewer.
