//# TableDesc.cc: Description of a table //# Copyright (C) 1994,1995,1996,1997,1999,2000,2001,2002 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id$ #include #include #include #include #include #include #include #include #include namespace casacore { //# NAMESPACE CASACORE - BEGIN //# This is the implementation of the class TableDesc. //# //# It uses the class TabPath to find which directory contains //# the table description file. //# Define the prefix to use for keywords representing hypercolumns. static const String theHyperPrefix ("Hypercolumn_"); TableDesc::TableDesc() : option_p (Scratch) { init (TabPath()); // use default search path } TableDesc::TableDesc (const String& nam, TDOption opt) : name_p (nam), option_p (opt) { init (TabPath()); // use default search path } TableDesc::TableDesc (const String& nam, const String& version, TDOption opt) : name_p (nam), vers_p (version), option_p (opt) { init (TabPath()); // use default search path } TableDesc::TableDesc (const String& nam, const String& version, const TabPath& tdpath, TDOption opt) : name_p (nam), vers_p (version), option_p (opt) { init (tdpath); // use given search path } TableDesc::TableDesc (const TableDesc& td, const String& nam, const String& version, TDOption opt, Bool copyColumns) : name_p (nam), vers_p (version), option_p (opt) { copy (td, TabPath(), copyColumns); // use default search path } TableDesc::TableDesc (const TableDesc& td, const String& nam, const String& version, const TabPath& tdpath, TDOption opt, Bool copyColumns) : name_p (nam), vers_p (version), option_p (opt) { copy (td, tdpath, copyColumns); // use given search path } TableDesc::TableDesc (const TableDesc& td, TDOption opt) : option_p (opt) { copy (td, TabPath(), True); // use default search path } TableDesc::~TableDesc () { //# Write if the description if opened for output and if the //# description can be written. //# Delete will be done by destructor of AipsIO. if (swwrite_p) { if (option_p == Update || option_p == New || option_p == NewNoReplace) { putFile (iofil_p, TableAttr()); // write the description } } iofil_p.close (); delete key_p; delete privKey_p; } // //
  • TableDescNoName //
  • TableDuplFile //
  • TableNoFile //
  • TableInvOpt // void TableDesc::init (const TabPath& tdpath) { //# Initialize some variables. swwrite_p = False; // writing is not possible yet //# If non-scratch, check if name is not blank and look if the //# description already exists. if (option_p == Scratch) { dir_p = "**SCRATCH**"; }else{ if (name_p.empty()) { throw TableDescNoName(); } Bool exsw = tdpath.found (name_p + ".tabdsc", dir_p); if (option_p == NewNoReplace) { if (exsw) { throw (TableDuplFile("desc. " + name_p));// table already exists } }else{ if (option_p != New && !exsw) { throw (TableNoFile("desc." + name_p)); // table does not exist } } } //# Determine the AipsIO option for this file. ByteIO::OpenOption fopt = ByteIO::Old; switch (option_p) { case TableDesc::Old: fopt = ByteIO::Old; break; case TableDesc::New: fopt = ByteIO::New; break; case TableDesc::NewNoReplace: fopt = ByteIO::NewNoReplace; break; case TableDesc::Scratch: fopt = ByteIO::Scratch; break; case TableDesc::Update: fopt = ByteIO::Update; break; case TableDesc::Delete: fopt = ByteIO::Delete; break; default: throw (TableInvOpt ("TableDesc", "must be Old, New, NewNoReplace, Scratch, Update or Delete")); } //# Allocate the keyword sets. key_p = new TableRecord(); privKey_p = new TableRecord(); //# If non-scratch, open the file. Read it for new, update and delete. //# It can be closed immediately when old (i.e readonly). if (option_p != Scratch) { iofil_p.open (dir_p + name_p + ".tabdsc", fopt); if (option_p == Old || option_p == Update || option_p == Delete) { getFile (iofil_p, TableAttr()); // read file } if (option_p == Old || option_p == Update) { iofil_p.close (); if (option_p == Update) { iofil_p.open (dir_p + name_p + ".tabdsc", fopt); // reposition } } } swwrite_p = True; // writing is possible now } // //
  • TableInvOpt // void TableDesc::copy (const TableDesc& td, const TabPath& tdpath, Bool copyColumns) { //# Check the options; it has to be a new description. if (option_p != New && option_p != NewNoReplace && option_p != Scratch) { throw (TableInvOpt ("TableDesc", "must be New, NewNoReplace or Scratch")); } init (tdpath); if (name_p.empty()) { name_p = td.name_p; } if (vers_p.empty()) { vers_p = td.vers_p; } comm_p = td.comm_p; *key_p = *(td.key_p); *privKey_p = *(td.privKey_p); if (copyColumns) { col_p = td.col_p; } } // Test if a description exists. Bool TableDesc::isReadable (const String& tableDescName) { File file(tableDescName + ".tabdsc"); return file.isReadable(); } // Get a vector with all column names. Vector TableDesc::columnNames() const { Vector names(ncolumn()); for (uInt i=0; idescription().isDisjoint (that.privKey_p->description())){ throw (TableInvOper ("TableDesc::add; hypercolumns not disjoint")); } if (addKeywordSet) { if (! key_p->description().isDisjoint (that.key_p->description())) { throw (TableInvOper ("TableDesc::add; keywords not disjoint")); } } col_p.add (that.col_p); privKey_p->merge (*that.privKey_p, RecordInterface::ThrowOnDuplicates); if (addKeywordSet) { key_p->merge (*that.key_p, RecordInterface::ThrowOnDuplicates); } } //# Show the table. void TableDesc::show () const { show (cout); } void TableDesc::show (ostream& os) const { os << endl; os << "TableDesc " << name_p; os << " version " << vers_p; os << " (Directory " << dir_p << ")"; os << endl; os << "---------" << endl; os << " Comment: " << comm_p << endl; os << " #Keywords = " << key_p->nfields() << endl;; os << key_p->description(); os << " #Columns = " << ncolumn() << endl;; os << privKey_p->description(); col_p.show (os); } void TableDesc::putFile (AipsIO& ios, const TableAttr& parentAttr) const { ios.putstart ("TableDesc", 2); ios << name_p; ios << vers_p; ios << comm_p; key_p->putRecord (ios, parentAttr); ios << *privKey_p; col_p.putFile (ios, parentAttr); ios.putend (); } void TableDesc::getFile (AipsIO& ios, const TableAttr& parentAttr) { uInt tvers = ios.getstart ("TableDesc"); ios >> name_p; ios >> vers_p; ios >> comm_p; key_p->getRecord (ios, parentAttr); // Version 1 does not contain privKey_p. if (tvers != 1) { ios >> *privKey_p; } col_p.getFile (ios, parentAttr); ios.getend (); } //# Rename a column. void TableDesc::renameColumn (const String& newname, const String& oldname) { // First rename the column itself. col_p.rename (newname, oldname); // Now adjust the hypercolumn descriptions. std::map old2new; // First fill the map with all columns and replace it for the new name. for (uInt i=0; i& dataColumnNames) { Vector columnNames; defineHypercolumn (hypercolumnName, ndim, dataColumnNames, columnNames, columnNames); } void TableDesc::defineHypercolumn (const String& hypercolumnName, uInt ndim, const Vector& dataColumnNames, const Vector& coordColumnNames) { Vector columnNames; defineHypercolumn (hypercolumnName, ndim, dataColumnNames, coordColumnNames, columnNames); } void TableDesc::defineHypercolumn (const String& hypercolumnName, uInt ndim, const Vector& dataColumnNames, const Vector& coordColumnNames, const Vector& idColumnNames) { // Check if data and coordinate columns have been given. if (dataColumnNames.nelements() < 1) { throwHypercolumn (hypercolumnName, "dataColumnNames is empty"); } if (ndim < 1) { throwHypercolumn (hypercolumnName, "ndim < 1"); } uInt ncoord = coordColumnNames.nelements(); if (ncoord != 0 && ncoord != ndim) { throwHypercolumn (hypercolumnName, "#coordColumnNames mismatches ndim"); } uInt i, j; // Check if the coordinate columns exist and are numeric // scalars or vectors. An empty coordinate name is allowed meaning // that the axis has no coordinate. // Get the number of vectors. uInt firstCoordSca = 0; uInt lastCoordVec = 0; for (i=0; i 0 && lastCoordVec > firstCoordSca) { throwHypercolumn (hypercolumnName, "coordinate vectors have to describe the first axes"); } // Check if the data columns exist and have fixed length // (i.e. no String, Table or Other type). // Also check if their dimensionality matches the number of // coordinate vectors (if coordinates are defined). // Find out if all data columns have FixedShape. Bool fixedShape = True; uInt cellNdim = 0; for (i=0; i 0 && firstCoordSca <= cellNdim) || lastCoordVec > cellNdim) { throwHypercolumn (hypercolumnName, "the dimensionality of the data columns" " mismatches nr of coordinate columns with a" " vector value"); } // Check if the ID columns exist and are scalars (not type Other). // Type (u)Char and (u)Short are not possible. for (i=0; i names(nr); names(Slice(0,dataColumnNames.nelements())) = dataColumnNames; nr = dataColumnNames.nelements(); names(Slice(nr,coordColumnNames.nelements())) = coordColumnNames; nr += coordColumnNames.nelements(); names(Slice(nr,idColumnNames.nelements())) = idColumnNames; nr += idColumnNames.nelements(); for (i=0; idefineRecord (keyName, set); // Set the default data manager to TiledShapeStMan or TiledColumnStMan. // (use TiledColumnStMan if all data columns have FixedShape). // Set default data manager group to hypercolumn name. String dmName = (fixedShape ? "TiledColumnStMan" : "TiledShapeStMan"); for (i=0; iisDefined (theHyperPrefix + name); } Vector TableDesc::hypercolumnNames() const { uInt i; uInt nhyp = 0; uInt nkey = privKey_p->nfields(); for (i=0; itype(i) == TpRecord) { const String& key = privKey_p->description().name (i); if (key.index (theHyperPrefix) == 0) { nhyp++; } } } Vector result(nhyp); if (nhyp > 0) { nhyp = 0; for (i=0; itype(i) == TpRecord) { const String& key = privKey_p->description().name (i); if (key.index (theHyperPrefix) == 0) { result(nhyp) = String(key).from (int(theHyperPrefix.length())); nhyp++; } } } } return result; } uInt TableDesc::hypercolumnDesc (const String& name, Vector& dataColumnNames, Vector& coordColumnNames, Vector& idColumnNames) const { const TableRecord& set = privKey_p->subRecord (theHyperPrefix + name); // Make vectors empty, so assignment will be possible. dataColumnNames.resize (0); coordColumnNames.resize (0); idColumnNames.resize (0); dataColumnNames = set.asArrayString ("data"); coordColumnNames = set.asArrayString ("coord"); idColumnNames = set.asArrayString ("id"); return set.asuInt ("ndim"); } void TableDesc::adjustHypercolumns (const std::map& old2new, Bool keepUnknownData, Bool keepUnknownCoord, Bool keepUnknownId) { Vector hcNames = hypercolumnNames(); Vector dataNames, coordNames, idNames; for (uInt i=0; iremoveField (theHyperPrefix + hcNames(i)); // Rename/remove columns in the hypercolumn description. uInt nr = 0; for (uInt j=0; j::const_iterator iter = old2new.find (dataNames(j)); if (iter != old2new.end()) { dataNames(nr++) = iter->second; } else if (keepUnknownData) { nr++; } } // If no data columns left, there is no need to recreate the hypercolumn. if (nr > 0) { dataNames.resize (nr, True); nr = 0; for (uInt j=0; j::const_iterator iter = old2new.find (dataNames(j)); if (iter != old2new.end()) { coordNames(nr++) = iter->second; } else if (keepUnknownCoord) { nr++; } } // All coordinate columns are needed, so removal of one means // that they cannot be used anymore. // That also means their default storage manager has to be reset. if (nr != ndim) { for (uInt j=0; j::const_iterator iter = old2new.find (dataNames(j)); if (iter != old2new.end()) { idNames(nr++) = iter->second; } else if (keepUnknownId) { nr++; } } idNames.resize (nr, True); // Add the hypercolumn again. defineHypercolumn (hcNames(i), ndim, dataNames, coordNames, idNames); } } } void TableDesc::removeIDhypercolumns (const Vector& hcNames) { Vector dataNames, coordNames, idNames; for (uInt i=0; i 0) { for (uInt j=0; jremoveField (theHyperPrefix + hcNames(i)); defineHypercolumn (hcNames(i), ndim, dataNames, coordNames); } } } void TableDesc::removeHypercolumnDesc (const String& hypercolumnName) { if (! isHypercolumn(hypercolumnName)) { throw TableError ("Hypercolumn " + hypercolumnName + " does not exist, thus cannot be removed"); } // Remove all hypercolumns; start at the end to avoid invalid indices. privKey_p->removeField (theHyperPrefix + hypercolumnName); } void TableDesc::renameHypercolumn (const String& newHypercolumnName, const String& hypercolumnName) { if (! isHypercolumn(hypercolumnName)) { throw TableError ("Hypercolumn " + hypercolumnName + " does not exist, thus cannot be renamed"); } if (newHypercolumnName == "") { throw TableError ("New hypercolumn name must be non-empty"); } // Get hypercolumn description Vector dataNames, coordNames, idNames; uInt ndim = hypercolumnDesc (hypercolumnName, dataNames, coordNames, idNames); // delete the hypercolumn privKey_p->removeField (theHyperPrefix + hypercolumnName); // recreate it under new name (will also change the column descriptions) defineHypercolumn (newHypercolumnName, ndim, dataNames, coordNames, idNames); } } //# NAMESPACE CASACORE - END