#579 closed enhancement (fixed)
New function: psMetadataCopy
| Reported by: | Paul Price | Owned by: | |
|---|---|---|---|
| Priority: | high | Milestone: | |
| Component: | types | Version: | unspecified |
| Severity: | minor | Keywords: | |
| Cc: | robert.desonia@…, rhl@… |
Description
Adding a new function, at RHL's request. I could put together a prototype, if
desired, but I think it's fairly straightforward.
There will be occasions when we want to perform a deep copy of a
\code{psMetadata}, for example, to generate a new and independent FITS
header.
\begin{prototype}
psMetadata *psMetadataCopy(psMetadata *out, const psMetadata *in);
\end{prototype}
\code{psMetadataCopy} shall create a new copy of all
\code{psMetadataItem}s in the \code{in} metadata, and place them in
the \code{out} metadata, or a new \code{psMetadata} if \code{out} is
\code{NULL}. Now, it is not feasible (at this time) to be able to
copy every type that we might put on a \code{psMetadata}. Therefore,
\code{psMetadataCopy} shall copy only the numerical types and strings.
Other pointer types may simply have the pointer copied (with the
reference counter incremented appropriately), with the total number of
such copies (if positive) reported in a warning at the end of the
function.
Change History (10)
comment:1 by , 21 years ago
| Status: | new → assigned |
|---|
comment:2 by , 21 years ago
| Cc: | added |
|---|---|
| Owner: | changed from to |
| Status: | assigned → new |
comment:3 by , 21 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
comment:4 by , 21 years ago
| Resolution: | fixed |
|---|---|
| Status: | closed → reopened |
The implementation in 0.9.0 simply puts the psMetadataItems that are on one
psMetadata onto a new psMetadata. What we really want is a new copy of the data
that is on the psMetadata, so that we can change it without changing the
original. One example is FITS headers --- we might read in an image with the
header, manipulate the image, and want to write it out with an altered header
without altering the original header.
Here's an implementation that's more in keeping with what I had in mind (also in
psAdditionals.c in psModule branch pap_branch_051214):
psMetadata *pap_psMetadataCopy(psMetadata *out,
const psMetadata *in)
{
PS_ASSERT_PTR_NON_NULL(in,NULL);
if (out == NULL) {
out = psMetadataAlloc();
}
psMetadataItem *inItem = NULL;
psMetadataIterator *iter = psMetadataIteratorAlloc(*(psMetadata)&in,
PS_LIST_HEAD, NULL);
unsigned long numPointers = 0; Number of pointers we were forced to copy
while ((inItem = psMetadataGetAndIncrement(iter))) {
Need to look for MULTI, which won't be picked up using the iterator.
psMetadataItem *multiCheckItem = psMetadataLookup(in, inItem->name);
unsigned int flag = PS_META_REPLACE; Flag to indicate MULTI;
otherwise, replace
if (multiCheckItem->type == PS_DATA_METADATA_MULTI) {
psTrace(func, 10, "MULTI: %s (%s)\n", inItem->name,
inItem->comment);
flag = PS_DATA_METADATA_MULTI;
}
psTrace(func, 5, "Copying %s (%s)...\n", inItem->name, inItem->comment);
#define PS_METADATA_COPY_CASE(NAME,TYPE) \
case PS_TYPE_##NAME: \
if (! psMetadataAdd(out, PS_LIST_TAIL, inItem->name, PS_TYPE_##NAME
| flag, inItem->comment, \
inItem->data.TYPE)) { \
psErrorStackPrint(stderr, "Error copying %s (%s) in the
metadata\n", inItem->name, \
inItem->comment); \
} \
break;
switch (inItem->type) {
Numerical types
PS_METADATA_COPY_CASE(BOOL,B);
PS_METADATA_COPY_CASE(S8,S8);
PS_METADATA_COPY_CASE(S16,S16);
PS_METADATA_COPY_CASE(S32,S32);
PS_METADATA_COPY_CASE(U8,U8);
PS_METADATA_COPY_CASE(U16,U16);
PS_METADATA_COPY_CASE(U32,U32);
PS_METADATA_COPY_CASE(F32,F32);
PS_METADATA_COPY_CASE(F64,F64);
String: relying on the fact that this will copy the string, not
point at it.
case PS_DATA_STRING:
psMetadataAdd(out, PS_LIST_TAIL, inItem->name, PS_DATA_STRING |
flag, inItem->comment,
inItem->data.V);
break;
Metadata: copy the next level and stuff that in too
case PS_DATA_METADATA:
{
psMetadata *metadata = pap_psMetadataCopy(NULL, inItem->data.md);
psMetadataAdd(out, PS_LIST_TAIL, inItem->name, PS_DATA_METADATA
| flag, inItem->comment,
metadata);
break;
}
Other kinds of pointers
default:
numPointers++;
psTrace(func, 10, "Copying a pointer in the metadata: %x\n",
inItem->type);
psMetadataAdd(out, PS_LIST_TAIL, inItem->name, inItem->type | flag,
inItem->comment,
inItem->data.V);
break;
}
}
psFree(iter);
if (numPointers > 0) {
psLogMsg(func, PS_LOG_WARN, "Forced to copy %d pointers when copying
metadata. Updating the "
"copied psMetadata will affect the original!\n", numPointers);
}
return out;
}
comment:5 by , 20 years ago
| Resolution: | → fixed |
|---|---|
| Status: | reopened → closed |
Ok, I see your point. I've incorporated your changes into psMetadataCopy.
However, I've expanded the cases to include vectors and times. This will create
new copies of those vectors and times as desired. I've also commented out the
cases S8, S16, U8, U16, U32 because these types currently are not present in
psDataType.
comment:6 by , 20 years ago
S8, S16, U8, U16, U32 are included in psMetadata.data, so we should include them
in psMetadataCopy. We should upgrade psDataType to match the current range of
psMetadata.data:
typedef enum { /< type of item.data is:
PS_TYPE_S8 = PS_TYPE_S8, /< psS8
PS_TYPE_S16 = PS_TYPE_S16, /< psS16
PS_DATA_S32 = PS_TYPE_S32, /< psS32
PS_TYPE_U8 = PS_TYPE_U8, /< psU8
PS_TYPE_U16 = PS_TYPE_U16, /< psU16
PS_TYPE_U32 = PS_TYPE_U32, /< psU32
PS_DATA_F32 = PS_TYPE_F32, /< psF32
PS_DATA_F64 = PS_TYPE_F64, /< psF64
PS_DATA_BOOL = PS_TYPE_BOOL, /< psBool
PS_DATA_STRING = 0x10000, /< String (char *)
....
} psDataType;
comment:7 by , 20 years ago
ok, updated psDataType. Also updated Metadata to use these types. What about
S64, U64, C32, and C64? If you want these too, please let me know.
comment:8 by , 20 years ago
I don't think we're supporting those in psMetadata.... or at least, not yet. We
may in the future, but not now.

Done.