Grid.cc

Go to the documentation of this file.
00001 
00002 // -*- mode: c++; c-basic-offset:4 -*-
00003 
00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00005 // Access Protocol.
00006 
00007 // Copyright (c) 2002,2003 OPeNDAP, Inc.
00008 // Author: James Gallagher <jgallagher@opendap.org>
00009 //
00010 // This library is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU Lesser General Public
00012 // License as published by the Free Software Foundation; either
00013 // version 2.1 of the License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 //
00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00025 
00026 // (c) COPYRIGHT URI/MIT 1994-1999
00027 // Please read the full copyright statement in the file COPYRIGHT_URI.
00028 //
00029 // Authors:
00030 //      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
00031 
00032 // implementation for Grid.
00033 //
00034 // jhrg 9/15/94
00035 
00036 #include "config.h"
00037 
00038 //#define DODS_DEBUG
00039 
00040 #include <functional>
00041 #include <algorithm>
00042 
00043 #include "Grid.h"
00044 #include "DDS.h"
00045 #include "Array.h"  // for downcasts
00046 #include "util.h"
00047 #include "InternalErr.h"
00048 #include "escaping.h"
00049 
00050 #include "debug.h"
00051 
00052 using namespace std;
00053 
00054 namespace libdap {
00055 
00056 void
00057 Grid::_duplicate(const Grid &s)
00058 {
00059     // Clear out any spurious vars in Constructor::_vars
00060     _vars.clear(); // [mjohnson 10 Sep 2009]
00061 
00062     _array_var = s._array_var->ptr_duplicate();
00063     _array_var->set_parent(this);
00064     _vars.push_back(_array_var); // so the Constructor::Vars_Iter sees it [mjohnson 10 Sep 2009]
00065 
00066     Grid &cs = const_cast<Grid &>(s);
00067 
00068     for (Map_iter i = cs._map_vars.begin(); i != cs._map_vars.end(); i++) {
00069         BaseType *btp = (*i)->ptr_duplicate();
00070         btp->set_parent(this);
00071         _map_vars.push_back(btp);
00072         _vars.push_back(btp); // push all map vectors as weak refs into super::_vars which won't delete them [mjohnson 10 Sep 2009]
00073     }
00074 
00075 }
00076 
00086 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), _array_var(0)
00087 {}
00088 
00100 Grid::Grid(const string &n, const string &d)
00101     : Constructor(n, d, dods_grid_c), _array_var(0)
00102 {}
00103 
00105 Grid::Grid(const Grid &rhs) : Constructor(rhs)
00106 {
00107     _duplicate(rhs);
00108 }
00109 
00110 Grid::~Grid()
00111 {
00112     delete _array_var; _array_var = 0;
00113 
00114     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00115         BaseType *btp = *i ;
00116         delete btp ; btp = 0;
00117     }
00118 }
00119 
00120 BaseType *
00121 Grid::ptr_duplicate()
00122 {
00123     return new Grid(*this);
00124 }
00125 
00126 Grid &
00127 Grid::operator=(const Grid &rhs)
00128 {
00129     if (this == &rhs)
00130         return *this;
00131 
00132     delete _array_var; _array_var = 0;
00133 
00134     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00135         BaseType *btp = *i ;
00136         delete btp ;
00137     }
00138 
00139     // this doesn't copy Constructor::_vars so...
00140     dynamic_cast<Constructor &>(*this) = rhs;
00141 
00142     // we do it in here...
00143     _duplicate(rhs);
00144 
00145     return *this;
00146 }
00147 
00148 int
00149 Grid::element_count(bool leaves)
00150 {
00151     if (!leaves)
00152         return _map_vars.size() + 1;
00153     else {
00154         int i = 0;
00155         for (Map_iter j = _map_vars.begin(); j != _map_vars.end(); j++) {
00156             j += (*j)->element_count(leaves);
00157         }
00158 
00159                 if (!get_array())
00160                         throw InternalErr(__FILE__, __LINE__, "No Grid arry!");
00161 
00162         i += get_array()->element_count(leaves);
00163         return i;
00164     }
00165 }
00166 
00167 void
00168 Grid::set_send_p(bool state)
00169 {
00170     _array_var->set_send_p(state);
00171 
00172     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00173         (*i)->set_send_p(state);
00174     }
00175 
00176     BaseType::set_send_p(state);
00177 }
00178 
00179 void
00180 Grid::set_read_p(bool state)
00181 {
00182     _array_var->set_read_p(state);
00183 
00184     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00185         (*i)->set_read_p(state);
00186     }
00187 
00188     BaseType::set_read_p(state);
00189 }
00190 
00191 void
00192 Grid::set_in_selection(bool state)
00193 {
00194     _array_var->set_in_selection(state);
00195 
00196     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00197         (*i)->set_in_selection(state);
00198     }
00199 
00200     BaseType::set_in_selection(state);
00201 }
00202 
00203 unsigned int
00204 Grid::width()
00205 {
00206     unsigned int sz = _array_var->width();
00207 
00208     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00209         sz += (*i)->width();
00210     }
00211 
00212     return sz;
00213 }
00214 
00215 void
00216 Grid::intern_data(ConstraintEvaluator &eval, DDS &dds)
00217 {
00218     dds.timeout_on();
00219 
00220     if (!read_p())
00221         read();  // read() throws Error and InternalErr
00222 
00223     dds.timeout_off();
00224 
00225     if (_array_var->send_p())
00226         _array_var->intern_data(eval, dds);
00227 
00228     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00229         if ((*i)->send_p()) {
00230             (*i)->intern_data(eval, dds);
00231         }
00232     }
00233 }
00234 
00235 bool
00236 Grid::serialize(ConstraintEvaluator &eval, DDS &dds,
00237                 Marshaller &m, bool ce_eval)
00238 {
00239     dds.timeout_on();
00240 
00241     // Re ticket 560: Get an object from eval that describes how to sample
00242     // and rearrange the data, then perform those actions. Alternative:
00243     // implement this as a selection function.
00244 
00245     if (!read_p())
00246         read();  // read() throws Error and InternalErr
00247 
00248 #if EVAL
00249     if (ce_eval && !eval.eval_selection(dds, dataset()))
00250         return true;
00251 #endif
00252 
00253     dds.timeout_off();
00254 
00255     if (_array_var->send_p())
00256         _array_var->serialize(eval, dds, m, false);
00257 
00258     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00259         if ((*i)->send_p()) {
00260             (*i)->serialize(eval, dds, m, false);
00261         }
00262     }
00263 
00264     return true;
00265 }
00266 
00267 bool
00268 Grid::deserialize(UnMarshaller &um, DDS *dds, bool reuse)
00269 {
00270     _array_var->deserialize(um, dds, reuse);
00271 
00272     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00273         (*i)->deserialize(um, dds, reuse);
00274     }
00275 
00276     return false;
00277 }
00278 
00286 unsigned int
00287 Grid::val2buf(void *, bool)
00288 {
00289     return sizeof(Grid);
00290 }
00291 
00295 unsigned int
00296 Grid::buf2val(void **)
00297 {
00298     return sizeof(Grid);
00299 }
00300 
00301 BaseType *
00302 Grid::var(const string &n, btp_stack &s)
00303 {
00304     return var(n, true, &s);
00305 }
00306 
00311 BaseType *
00312 Grid::var(const string &n, bool, btp_stack *s)
00313 {
00314     string name = www2id(n);
00315 
00316     if (_array_var->name() == name) {
00317         if (s)
00318             s->push(static_cast<BaseType *>(this));
00319         return _array_var;
00320     }
00321 
00322     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00323         if ((*i)->name() == name) {
00324             if (s)
00325                 s->push(static_cast<BaseType *>(this));
00326             return *i;
00327         }
00328     }
00329 
00330     return 0;
00331 }
00332 
00345 void
00346 Grid::add_var(BaseType *bt, Part part)
00347 {
00348     if (!bt) {
00349         throw InternalErr(__FILE__, __LINE__,
00350                           "Passing NULL pointer as variable to be added.");
00351     }
00352 
00353     if (part == array && _array_var) {
00354       // Avoid leaking memory...  Function is add, not set, so it is an error to call again for the array part.
00355       throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
00356     }
00357 
00358     // Set to the clone of bt if we get that far.
00359     BaseType* bt_clone = 0;
00360 
00361     switch (part) {
00362 
00363     case array: {
00364         // Refactored to use new set_array ([mjohnson 11 nov 2009])
00365         Array* p_arr = dynamic_cast<Array*>(bt);
00366         // avoid obvious broken semantics
00367         if (!p_arr) {
00368           throw InternalErr(__FILE__, __LINE__,
00369               "Grid::add_var(): with Part==array: object is not an Array!");
00370         }
00371         // Add it as a copy to preserve old semantics.  This sets parent too.
00372         bt_clone = p_arr->ptr_duplicate();
00373         set_array(static_cast<Array*>(bt_clone));
00374     }
00375     break;
00376 
00377     case maps: {
00378             bt_clone = bt->ptr_duplicate();
00379             bt_clone->set_parent(this);
00380             _map_vars.push_back(bt_clone);
00381         }
00382     break;
00383 
00384     default: {
00385         if (!_array_var) {
00386             // Refactored to use new set_array ([mjohnson 11 nov 2009])
00387             Array* p_arr = dynamic_cast<Array*>(bt);
00388             // avoid obvious broken semantics
00389             if (!p_arr) {
00390               throw InternalErr(__FILE__, __LINE__,
00391                   "Grid::add_var(): with Part==array: object is not an Array!");
00392             }
00393             // Add it as a copy to preserve old semantics.  This sets parent too.
00394             bt_clone = p_arr->ptr_duplicate();
00395             set_array(static_cast<Array*>(bt_clone));
00396         }
00397         else {
00398             bt_clone = bt->ptr_duplicate();
00399             bt_clone->set_parent(this);
00400             _map_vars.push_back(bt_clone);
00401         }
00402     }
00403     break;
00404   }// switch
00405 
00406   // if we get ehre without exception, add the cloned object to the superclass variable iterator
00407   // mjohnson 10 Sep 2009
00408   // Add it to the superclass _vars list so we can iterate on superclass vars
00409   if (bt_clone) {
00410     _vars.push_back(bt_clone);
00411   }
00412 }
00413 
00423 void
00424 Grid::set_array(Array* p_new_arr)
00425 {
00426   if (!p_new_arr) {
00427     throw InternalErr(__FILE__, __LINE__,
00428         "Grid::set_array(): Cannot set to null!");
00429   }
00430   // Make sure not same memory, this would be evil.
00431   if (p_new_arr == _array_var) {
00432       return;
00433    }
00434   // clean out any old array
00435   delete _array_var; _array_var = 0;
00436   // Set the new, with parent
00437   _array_var = p_new_arr;
00438   _array_var->set_parent(this);
00439 }
00440 
00467 Array*
00468 Grid::add_map(Array* p_new_map, bool add_as_copy)
00469 {
00470   if (!p_new_map) {
00471     throw InternalErr(__FILE__, __LINE__,
00472         "Grid::add_map(): cannot have p_new_map null!");
00473   }
00474 
00475   if (add_as_copy) {
00476     p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
00477   }
00478 
00479   p_new_map->set_parent(this);
00480   _map_vars.push_back(p_new_map);
00481   _vars.push_back(p_new_map); // allow superclass iter to work as well.
00482 
00483   // return the one that got put into the Grid.
00484   return p_new_map;
00485 }
00486 
00499 Array*
00500 Grid::prepend_map(Array* p_new_map, bool add_copy)
00501 {
00502   if (add_copy)
00503     {
00504       p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
00505     }
00506 
00507   p_new_map->set_parent(this);
00508   _map_vars.insert(_map_vars.begin(), p_new_map);
00509   _vars.insert(_vars.begin(), p_new_map); // allow superclass iter to work as well.
00510 
00511    // return the one that got put into the Grid.
00512    return p_new_map;
00513 }
00514 
00518 BaseType *
00519 Grid::array_var()
00520 {
00521     return _array_var;
00522 }
00523 
00527 Array *
00528 Grid::get_array()
00529 {
00530     Array *a = dynamic_cast<Array*>(_array_var);
00531     if (a)
00532         return a;
00533     else
00534         throw InternalErr(__FILE__, __LINE__, "bad Cast");
00535 }
00536 
00538 Grid::Map_iter
00539 Grid::map_begin()
00540 {
00541     return _map_vars.begin() ;
00542 }
00543 
00546 Grid::Map_iter
00547 Grid::map_end()
00548 {
00549     return _map_vars.end() ;
00550 }
00551 
00553 Grid::Map_riter
00554 Grid::map_rbegin()
00555 {
00556     return _map_vars.rbegin() ;
00557 }
00558 
00561 Grid::Map_riter
00562 Grid::map_rend()
00563 {
00564     return _map_vars.rend() ;
00565 }
00566 
00570 Grid::Map_iter
00571 Grid::get_map_iter(int i)
00572 {
00573     return _map_vars.begin() + i;
00574 }
00575 
00591 int
00592 Grid::components(bool constrained)
00593 {
00594     int comp;
00595 
00596     if (constrained) {
00597         comp = _array_var->send_p() ? 1 : 0;
00598 
00599         for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00600             if ((*i)->send_p()) {
00601                 comp++;
00602             }
00603         }
00604     }
00605     else {
00606         comp = 1 + _map_vars.size();
00607     }
00608 
00609     return comp;
00610 }
00611 
00612 void Grid::transfer_attributes(AttrTable *at_container)
00613 {
00614     AttrTable *at = at_container->get_attr_table(name());
00615 
00616     if (at) {
00617         at->set_is_global_attribute(false);
00618 
00619         array_var()->transfer_attributes(at);
00620 
00621         Map_iter map = map_begin();
00622         while (map != map_end()) {
00623             (*map)->transfer_attributes(at);
00624             map++;
00625         }
00626 
00627         // Trick: If an attribute that's within the container 'at' still has its
00628         // is_global_attribute property set, then it's not really a global attr
00629         // but instead an attribute that belongs to this Grid.
00630         AttrTable::Attr_iter at_p = at->attr_begin();
00631         while (at_p != at->attr_end()) {
00632             if (at->is_global_attribute(at_p)) {
00633                 if (at->get_attr_type(at_p) == Attr_container)
00634                     get_attr_table().append_container(new AttrTable(
00635                             *at->get_attr_table(at_p)), at->get_name(at_p));
00636                 else
00637                     get_attr_table().append_attr(at->get_name(at_p),
00638                             at->get_type(at_p), at->get_attr_vector(at_p));
00639             }
00640 
00641             at_p++;
00642         }
00643     }
00644 }
00645 
00646 // When projected (using whatever the current constraint provides in the way
00647 // of a projection), is the object still a Grid?
00648 
00665 bool
00666 Grid::projection_yields_grid()
00667 {
00668     // For each dimension in the Array part, check the corresponding Map
00669     // vector to make sure it is present in the projected Grid. If for each
00670     // projected dimension in the Array component, there is a matching Map
00671     // vector, then the Grid is valid.
00672     bool valid = true;
00673     Array *a = (Array *)_array_var;
00674 
00675     // Don't bother checking if the Array component is not included.
00676     if (!a->send_p())
00677         return false;
00678 
00679     Array::Dim_iter i = a->dim_begin() ;
00680     Map_iter m = map_begin() ;
00681     for (; valid && i != a->dim_end() && m != map_end(); i++, m++) {
00682         if (a->dimension_size(i, true)) {
00683             // Check the matching Map vector; the Map projection must equal
00684             // the Array dimension projection
00685             Array *map = (Array *)(*m);
00686             Array::Dim_iter fd = map->dim_begin(); // Maps have only one dim!
00687             valid = map->dimension_start(fd, true)
00688                     == a->dimension_start(i, true)
00689                     && map->dimension_stop(fd, true)
00690                     == a->dimension_stop(i, true)
00691                     && map->dimension_stride(fd, true)
00692                     == a->dimension_stride(i, true);
00693         }
00694         else {
00695             // Corresponding Map vector must be excluded from the projection.
00696             Array *map = (Array *)(*m);
00697             valid = !map->send_p();
00698         }
00699     }
00700 
00701     return valid;
00702 }
00703 
00705 void
00706 Grid::clear_constraint()
00707 {
00708     dynamic_cast<Array&>(*_array_var).clear_constraint();
00709     for (Map_iter m = map_begin(); m != map_end(); ++m)
00710         dynamic_cast<Array&>(*(*m)).clear_constraint();
00711 }
00712 
00713 #if FILE_METHODS
00714 void
00715 Grid::print_decl(FILE *out, string space, bool print_semi,
00716                  bool constraint_info, bool constrained)
00717 {
00718     if (constrained && !send_p())
00719         return;
00720 
00721 #if 0
00722     // If we are printing the declaration of a constrained Grid then check for
00723     // the case where the projection removes all but one component; the
00724     // resulting object is a simple array.
00725     int projection = components(true);
00726     if (constrained && projection == 1) {
00727         _array_var->print_decl(out, space, print_semi /*true*/, constraint_info,
00728                                constrained);
00729         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00730             (*i)->print_decl(out, space, print_semi /*true*/, constraint_info, constrained);
00731         }
00732 
00733         goto exit;  // Skip end material.
00734     }
00735     // If there are M (< N) componets (Array and Maps combined) in a N
00736     // component Grid, send the M components as elements of a Struture.
00737     // This will preserve the grouping without violating the rules for a
00738     // Grid.
00739     // else
00740 #endif
00741     // The problem with the above is that if two Grids are projected and each
00742     // contain one variable, say a map, and it happens to have the same name
00743     // in each Grid, then without the enclosing Structures, the returned dataset
00744     // has two variables with the same name at the same lexical level. So I'm
00745     // removing the code above.
00746     if (constrained && !projection_yields_grid()) {
00747         fprintf(out, "%sStructure {\n", space.c_str()) ;
00748 
00749         _array_var->print_decl(out, space + "    ", true, constraint_info,
00750                                constrained);
00751 
00752         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00753             (*i)->print_decl(out, space + "    ", true,
00754                              constraint_info, constrained);
00755         }
00756 
00757         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00758     }
00759     else {
00760         // The number of elements in the (projected) Grid must be such that
00761         // we have a valid Grid object; send it as such.
00762         fprintf(out, "%s%s {\n", space.c_str(), type_name().c_str()) ;
00763 
00764         fprintf(out, "%s  Array:\n", space.c_str()) ;
00765         _array_var->print_decl(out, space + "    ", true, constraint_info,
00766                                constrained);
00767 
00768         fprintf(out, "%s  Maps:\n", space.c_str()) ;
00769         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00770             (*i)->print_decl(out, space + "    ", true,
00771                              constraint_info, constrained);
00772         }
00773 
00774         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00775     }
00776 
00777     if (constraint_info) {
00778         if (send_p())
00779             fprintf( out, ": Send True");
00780         else
00781             fprintf( out, ": Send False");
00782     }
00783 
00784     if (print_semi)
00785         fprintf(out, ";\n") ;
00786 #if 0
00787     // If sending just one comp, skip sending the terminal semicolon, etc.
00788 exit:
00789 #endif
00790 
00791     return;
00792 }
00793 #endif
00794 
00795 void
00796 Grid::print_decl(ostream &out, string space, bool print_semi,
00797                  bool constraint_info, bool constrained)
00798 {
00799     if (constrained && !send_p())
00800         return;
00801 
00802     // If we are printing the declaration of a constrained Grid then check for
00803     // the case where the projection removes all but one component; the
00804     // resulting object is a simple array.
00805     //
00806     // I replaced the 'true' with the value of 'print_semi' passed in by the
00807     // caller. This fixes an issue with the intern_data tests and does not
00808     // seem to break anything else. jhrg 11/9/07
00809 #if 0
00810     int projection = components(true);
00811     if (constrained && projection == 1) {
00812         _array_var->print_decl(out, space, print_semi /*true*/, constraint_info,
00813                                constrained);
00814         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00815             (*i)->print_decl(out, space, print_semi /*true*/, constraint_info, constrained);
00816         }
00817 
00818         goto exit;  // Skip end material.
00819     }
00820     // If there are M (< N) components (Array and Maps combined) in a N
00821     // component Grid, send the M components as elements of a Structure.
00822     // This will preserve the grouping without violating the rules for a
00823     // Grid.
00824     // else
00825 #endif
00826 
00827     // See comment for the FILE* version of this method.
00828     if (constrained && !projection_yields_grid()) {
00829         out << space << "Structure {\n" ;
00830 
00831         _array_var->print_decl(out, space + "    ", true, constraint_info,
00832                                constrained);
00833 
00834         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00835             (*i)->print_decl(out, space + "    ", true,
00836                              constraint_info, constrained);
00837         }
00838 
00839         out << space << "} " << id2www(name()) ;
00840     }
00841     else {
00842         // The number of elements in the (projected) Grid must be such that
00843         // we have a valid Grid object; send it as such.
00844         out << space << type_name() << " {\n" ;
00845 
00846         out << space << "  Array:\n" ;
00847         _array_var->print_decl(out, space + "    ", true, constraint_info,
00848                                constrained);
00849 
00850         out << space << "  Maps:\n" ;
00851         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00852             (*i)->print_decl(out, space + "    ", true,
00853                              constraint_info, constrained);
00854         }
00855 
00856         out << space << "} " << id2www(name()) ;
00857     }
00858 
00859     if (constraint_info) {
00860         if (send_p())
00861             out << ": Send True";
00862         else
00863             out << ": Send False";
00864     }
00865 
00866     if (print_semi)
00867         out << ";\n" ;
00868 #if 0
00869     // If sending just one comp, skip sending the terminal semicolon, etc.
00870 exit:
00871 #endif
00872 
00873     return;
00874 }
00875 
00876 #if FILE_METHODS
00877 class PrintMapField : public unary_function<BaseType *, void>
00878 {
00879     FILE *d_out;
00880     string d_space;
00881     bool d_constrained;
00882     string d_tag;
00883 public:
00884     PrintMapField(FILE *o, string s, bool c, const string &t = "Map")
00885             : d_out(o), d_space(s), d_constrained(c), d_tag(t)
00886     {}
00887 
00888     void operator()(BaseType *btp)
00889     {
00890         Array *a = dynamic_cast<Array*>(btp);
00891         if (!a)
00892             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
00893         a->print_xml_core(d_out, d_space, d_constrained, d_tag);
00894     }
00895 };
00896 
00897 void
00898 Grid::print_xml(FILE *out, string space, bool constrained)
00899 {
00900     if (constrained && !send_p())
00901          return;
00902 
00903      // If we are printing the declaration of a constrained Grid then check for
00904      // the case where the projection removes all but one component; the
00905      // resulting object is a simple array.
00906      //
00907      // I replaced the 'true' with the value of 'print_semi' passed in by the
00908      // caller. This fixes an issue with the intern_data tests and does not
00909      // seem to break anything else. jhrg 11/9/07
00910 #if 0
00911      int projection = components(true);
00912      if (constrained && projection == 1) {
00913          get_attr_table().print_xml(out, space + "    ", constrained);
00914 
00915          get_array()->print_xml(out, space + "    ", constrained);
00916 
00917          for_each(map_begin(), map_end(),
00918                   PrintMapField(out, space + "    ", constrained, "Array"));
00919      }
00920      // If there are M (< N) components (Array and Maps combined) in a N
00921      // component Grid, send the M components as elements of a Structure.
00922      // This will preserve the grouping without violating the rules for a
00923      // Grid.
00924      // else
00925 #endif
00926 
00927      if (constrained && !projection_yields_grid()) {
00928          fprintf(out, "%s<Structure", space.c_str());
00929          if (!name().empty())
00930              fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00931 
00932          fprintf(out, ">\n");
00933 
00934          get_attr_table().print_xml(out, space + "    ", constrained);
00935 
00936          get_array()->print_xml(out, space + "    ", constrained);
00937 
00938          for_each(map_begin(), map_end(),
00939                   PrintMapField(out, space + "    ", constrained, "Array"));
00940 
00941          fprintf(out, "%s</Structure>\n", space.c_str());
00942      }
00943      else {
00944          // The number of elements in the (projected) Grid must be such that
00945          // we have a valid Grid object; send it as such.
00946          fprintf(out, "%s<Grid", space.c_str());
00947          if (!name().empty())
00948              fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00949 
00950          fprintf(out, ">\n");
00951 
00952          get_attr_table().print_xml(out, space + "    ", constrained);
00953 
00954          get_array()->print_xml(out, space + "    ", constrained);
00955 
00956          for_each(map_begin(), map_end(),
00957                   PrintMapField(out, space + "    ", constrained));
00958 
00959          fprintf(out, "%s</Grid>\n", space.c_str());
00960      }
00961 }
00962 #endif
00963 
00964 class PrintMapFieldStrm : public unary_function<BaseType *, void>
00965 {
00966     ostream &d_out;
00967     string d_space;
00968     bool d_constrained;
00969     string d_tag;
00970 public:
00971     PrintMapFieldStrm(ostream &o, string s, bool c, const string &t = "Map")
00972             : d_out(o), d_space(s), d_constrained(c), d_tag(t)
00973     {}
00974 
00975     void operator()(BaseType *btp)
00976     {
00977         Array *a = dynamic_cast<Array*>(btp);
00978         if (!a)
00979             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
00980         a->print_xml_core(d_out, d_space, d_constrained, d_tag);
00981     }
00982 };
00983 
00984 void
00985 Grid::print_xml(ostream &out, string space, bool constrained)
00986 {
00987     if (constrained && !send_p())
00988         return;
00989 
00990     // If we are printing the declaration of a constrained Grid then check for
00991     // the case where the projection removes all but one component; the
00992     // resulting object is a simple array.
00993     //
00994     // I replaced the 'true' with the value of 'print_semi' passed in by the
00995     // caller. This fixes an issue with the intern_data tests and does not
00996     // seem to break anything else. jhrg 11/9/07
00997 #if 0
00998     int projection = components(true);
00999     if (constrained && projection == 1) {
01000         get_attr_table().print_xml(out, space + "    ", constrained);
01001 
01002         get_array()->print_xml(out, space + "    ", constrained);
01003 
01004         for_each(map_begin(), map_end(),
01005                  PrintMapFieldStrm(out, space + "    ", constrained, "Array"));
01006     }
01007     // If there are M (< N) components (Array and Maps combined) in a N
01008     // component Grid, send the M components as elements of a Structure.
01009     // This will preserve the grouping without violating the rules for a
01010     // Grid.
01011     //else
01012 #endif
01013 
01014     if (constrained && !projection_yields_grid()) {
01015         out << space << "<Structure" ;
01016         if (!name().empty())
01017             out << " name=\"" << id2xml(name()) << "\"" ;
01018 
01019         out << ">\n" ;
01020 
01021         get_attr_table().print_xml(out, space + "    ", constrained);
01022 
01023         get_array()->print_xml(out, space + "    ", constrained);
01024 
01025         for_each(map_begin(), map_end(),
01026                  PrintMapFieldStrm(out, space + "    ", constrained, "Array"));
01027 
01028         out << space << "</Structure>\n" ;
01029     }
01030     else {
01031         // The number of elements in the (projected) Grid must be such that
01032         // we have a valid Grid object; send it as such.
01033         out << space << "<Grid" ;
01034         if (!name().empty())
01035             out << " name=\"" << id2xml(name()) << "\"" ;
01036 
01037         out << ">\n" ;
01038 
01039         get_attr_table().print_xml(out, space + "    ", constrained);
01040 
01041         get_array()->print_xml(out, space + "    ", constrained);
01042 
01043         for_each(map_begin(), map_end(),
01044                  PrintMapFieldStrm(out, space + "    ", constrained));
01045 
01046         out << space << "</Grid>\n" ;
01047     }
01048 }
01049 
01050 #if FILE_METHODS
01051 void
01052 Grid::print_val(FILE *out, string space, bool print_decl_p)
01053 {
01054     if (print_decl_p) {
01055         print_decl(out, space, false);
01056         fprintf(out, " = ") ;
01057     }
01058 
01059     // If we are printing a value on the client-side, projection_yields_grid
01060     // should not be called since we don't *have* a projection without a
01061     // contraint. I think that if we are here and send_p() is not true, then
01062     // the value of this function should be ignored. 4/6/2000 jhrg
01063     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
01064     if (pyg || !send_p())
01065         fprintf(out, "{  Array: ") ;
01066     else
01067         fprintf(out, "{") ;
01068     _array_var->print_val(out, "", false);
01069     if (pyg || !send_p())
01070         fprintf(out, "  Maps: ") ;
01071     for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
01072          i++, (void)(i != _map_vars.end() && fprintf(out, ", "))) {
01073         (*i)->print_val(out, "", false);
01074     }
01075     fprintf(out, " }") ;
01076 
01077     if (print_decl_p)
01078         fprintf(out, ";\n") ;
01079 }
01080 #endif
01081 
01082 void
01083 Grid::print_val(ostream &out, string space, bool print_decl_p)
01084 {
01085     if (print_decl_p) {
01086         print_decl(out, space, false);
01087         out << " = " ;
01088     }
01089 
01090     // If we are printing a value on the client-side, projection_yields_grid
01091     // should not be called since we don't *have* a projection without a
01092     // Constraint. I think that if we are here and send_p() is not true, then
01093     // the value of this function should be ignored. 4/6/2000 jhrg
01094     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
01095     if (pyg || !send_p())
01096         out << "{  Array: " ;
01097     else
01098         out << "{" ;
01099     _array_var->print_val(out, "", false);
01100     if (pyg || !send_p())
01101         out << "  Maps: " ;
01102     for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
01103          i++, (void)(i != _map_vars.end() && out << ", ")) {
01104         (*i)->print_val(out, "", false);
01105     }
01106     out << " }" ;
01107 
01108     if (print_decl_p)
01109         out << ";\n" ;
01110 }
01111 
01112 // Grids have ugly semantics.
01113 
01118 bool
01119 Grid::check_semantics(string &msg, bool all)
01120 {
01121     if (!BaseType::check_semantics(msg))
01122         return false;
01123 
01124     msg = "";
01125 
01126     if (!_array_var) {
01127         msg += "Null grid base array in `" + name() + "'\n";
01128         return false;
01129     }
01130 
01131     // Is it an array?
01132     if (_array_var->type() != dods_array_c) {
01133         msg += "Grid `" + name() + "'s' member `" + _array_var->name() + "' must be an array\n";
01134         return false;
01135     }
01136 
01137     Array *av = (Array *)_array_var; // past test above, must be an array
01138 
01139     // Array must be of a simple_type.
01140     if (!av->var()->is_simple_type()) {
01141         msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
01142         return false;
01143     }
01144 
01145     // enough maps?
01146     if ((unsigned)_map_vars.size() != av->dimensions()) {
01147         msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
01148         msg += av->name() + "'\n";
01149         return false;
01150     }
01151 
01152     const string array_var_name = av->name();
01153     Array::Dim_iter asi = av->dim_begin() ;
01154     for (Map_iter mvi = _map_vars.begin();
01155          mvi != _map_vars.end(); mvi++, asi++) {
01156 
01157         BaseType *mv = *mvi;
01158 
01159         // check names
01160         if (array_var_name == mv->name()) {
01161             msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
01162             return false;
01163         }
01164         // check types
01165         if (mv->type() != dods_array_c) {
01166             msg += "Grid map variable  `" + mv->name() + "' is not an array\n";
01167             return false;
01168         }
01169 
01170         Array *mv_a = (Array *)mv; // downcast to (Array *)
01171 
01172         // Array must be of a simple_type.
01173         if (!mv_a->var()->is_simple_type()) {
01174             msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
01175             return false;
01176         }
01177 
01178         // check shape
01179         if (mv_a->dimensions() != 1) {// maps must have one dimension
01180             msg += "Grid map variable  `" + mv_a->name() + "' must be only one dimension\n";
01181             return false;
01182         }
01183         // size of map must match corresponding array dimension
01184         Array::Dim_iter mv_asi = mv_a->dim_begin() ;
01185         int mv_a_size = mv_a->dimension_size(mv_asi) ;
01186         int av_size = av->dimension_size(asi) ;
01187         if (mv_a_size != av_size) {
01188             msg += "Grid map variable  `" + mv_a->name() + "'s' size does not match the size of array variable '";
01189             msg += _array_var->name() + "'s' cooresponding dimension\n";
01190             return false;
01191         }
01192     }
01193 
01194     if (all) {
01195         if (!_array_var->check_semantics(msg, true))
01196             return false;
01197         for (Map_iter mvi = _map_vars.begin(); mvi != _map_vars.end(); mvi++) {
01198             if (!(*mvi)->check_semantics(msg, true)) {
01199                 return false;
01200             }
01201         }
01202     }
01203 
01204     return true;
01205 }
01206 
01215 void
01216 Grid::dump(ostream &strm) const
01217 {
01218     strm << DapIndent::LMarg << "Grid::dump - ("
01219     << (void *)this << ")" << endl ;
01220     DapIndent::Indent() ;
01221     Constructor::dump(strm) ;
01222     if (_array_var) {
01223         strm << DapIndent::LMarg << "array var: " << endl ;
01224         DapIndent::Indent() ;
01225         _array_var->dump(strm) ;
01226         DapIndent::UnIndent() ;
01227     }
01228     else {
01229         strm << DapIndent::LMarg << "array var: null" << endl ;
01230     }
01231     strm << DapIndent::LMarg << "map var: " << endl ;
01232     DapIndent::Indent() ;
01233     Map_citer i = _map_vars.begin() ;
01234     Map_citer ie = _map_vars.end() ;
01235     for (; i != ie; i++) {
01236         (*i)->dump(strm) ;
01237     }
01238     DapIndent::UnIndent() ;
01239     DapIndent::UnIndent() ;
01240 }
01241 
01242 } // namespace libdap
01243 

Generated on Tue Jun 1 17:27:42 2010 for libdap++ by  doxygen 1.4.7