libdap++ Updated for version 3.8.2

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     // If only one part is being sent, it's clearly not a grid (it must be
00680     // the array part of the Grid that's being sent (given that the above
00681     // test passed and the array is being sent).
00682     if (components(true) == 1)
00683         return false;
00684 
00685     Array::Dim_iter d = a->dim_begin() ;
00686     Map_iter m = map_begin() ;
00687 
00688     while (valid && d != a->dim_end() && m != map_end()) {
00689         Array &map = dynamic_cast<Array&>(**m);
00690         if (a->dimension_size(d, true) && map.send_p()) {
00691             // Check the matching Map vector; the Map projection must equal
00692             // the Array dimension projection
00693             Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim!
00694             valid = map.dimension_start(fd, true) == a->dimension_start(d, true)
00695                     && map.dimension_stop(fd, true) == a->dimension_stop(d, true)
00696                     && map.dimension_stride(fd, true) == a->dimension_stride(d, true);
00697         }
00698         else {
00699            valid = false;
00700         }
00701 
00702         d++, m++;
00703     }
00704 
00705     return valid;
00706 }
00707 
00709 void
00710 Grid::clear_constraint()
00711 {
00712     dynamic_cast<Array&>(*_array_var).clear_constraint();
00713     for (Map_iter m = map_begin(); m != map_end(); ++m)
00714         dynamic_cast<Array&>(*(*m)).clear_constraint();
00715 }
00716 
00717 #if FILE_METHODS
00718 void
00719 Grid::print_decl(FILE *out, string space, bool print_semi,
00720                  bool constraint_info, bool constrained)
00721 {
00722     if (constrained && !send_p())
00723         return;
00724 
00725     // The problem with the above is that if two Grids are projected and each
00726     // contain one variable, say a map, and it happens to have the same name
00727     // in each Grid, then without the enclosing Structures, the returned dataset
00728     // has two variables with the same name at the same lexical level. So I'm
00729     // removing the code above.
00730     if (constrained && !projection_yields_grid()) {
00731         fprintf(out, "%sStructure {\n", space.c_str()) ;
00732 
00733         _array_var->print_decl(out, space + "    ", true, constraint_info,
00734                                constrained);
00735 
00736         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00737             (*i)->print_decl(out, space + "    ", true,
00738                              constraint_info, constrained);
00739         }
00740 
00741         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00742     }
00743     else {
00744         // The number of elements in the (projected) Grid must be such that
00745         // we have a valid Grid object; send it as such.
00746         fprintf(out, "%s%s {\n", space.c_str(), type_name().c_str()) ;
00747 
00748         fprintf(out, "%s  Array:\n", space.c_str()) ;
00749         _array_var->print_decl(out, space + "    ", true, constraint_info,
00750                                constrained);
00751 
00752         fprintf(out, "%s  Maps:\n", space.c_str()) ;
00753         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00754             (*i)->print_decl(out, space + "    ", true,
00755                              constraint_info, constrained);
00756         }
00757 
00758         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00759     }
00760 
00761     if (constraint_info) {
00762         if (send_p())
00763             fprintf( out, ": Send True");
00764         else
00765             fprintf( out, ": Send False");
00766     }
00767 
00768     if (print_semi)
00769         fprintf(out, ";\n") ;
00770 
00771     return;
00772 }
00773 #endif
00774 
00775 void
00776 Grid::print_decl(ostream &out, string space, bool print_semi,
00777                  bool constraint_info, bool constrained)
00778 {
00779     if (constrained && !send_p())
00780         return;
00781 
00782     // See comment for the FILE* version of this method.
00783     if (constrained && !projection_yields_grid()) {
00784         out << space << "Structure {\n" ;
00785 
00786         _array_var->print_decl(out, space + "    ", true, constraint_info,
00787                                constrained);
00788 
00789         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00790             (*i)->print_decl(out, space + "    ", true,
00791                              constraint_info, constrained);
00792         }
00793 
00794         out << space << "} " << id2www(name()) ;
00795     }
00796     else {
00797         // The number of elements in the (projected) Grid must be such that
00798         // we have a valid Grid object; send it as such.
00799         out << space << type_name() << " {\n" ;
00800 
00801         out << space << "  Array:\n" ;
00802         _array_var->print_decl(out, space + "    ", true, constraint_info,
00803                                constrained);
00804 
00805         out << space << "  Maps:\n" ;
00806         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00807             (*i)->print_decl(out, space + "    ", true,
00808                              constraint_info, constrained);
00809         }
00810 
00811         out << space << "} " << id2www(name()) ;
00812     }
00813 
00814     if (constraint_info) {
00815         if (send_p())
00816             out << ": Send True";
00817         else
00818             out << ": Send False";
00819     }
00820 
00821     if (print_semi)
00822         out << ";\n" ;
00823 
00824     return;
00825 }
00826 
00827 #if FILE_METHODS
00828 class PrintMapField : public unary_function<BaseType *, void>
00829 {
00830     FILE *d_out;
00831     string d_space;
00832     bool d_constrained;
00833     string d_tag;
00834 public:
00835     PrintMapField(FILE *o, string s, bool c, const string &t = "Map")
00836             : d_out(o), d_space(s), d_constrained(c), d_tag(t)
00837     {}
00838 
00839     void operator()(BaseType *btp)
00840     {
00841         Array *a = dynamic_cast<Array*>(btp);
00842         if (!a)
00843             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
00844         a->print_xml_core(d_out, d_space, d_constrained, d_tag);
00845     }
00846 };
00847 
00848 void
00849 Grid::print_xml(FILE *out, string space, bool constrained)
00850 {
00851     if (constrained && !send_p())
00852          return;
00853 
00854      if (constrained && !projection_yields_grid()) {
00855          fprintf(out, "%s<Structure", space.c_str());
00856          if (!name().empty())
00857              fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00858 
00859          fprintf(out, ">\n");
00860 
00861          get_attr_table().print_xml(out, space + "    ", constrained);
00862 
00863          get_array()->print_xml(out, space + "    ", constrained);
00864 
00865          for_each(map_begin(), map_end(),
00866                   PrintMapField(out, space + "    ", constrained, "Array"));
00867 
00868          fprintf(out, "%s</Structure>\n", space.c_str());
00869      }
00870      else {
00871          // The number of elements in the (projected) Grid must be such that
00872          // we have a valid Grid object; send it as such.
00873          fprintf(out, "%s<Grid", space.c_str());
00874          if (!name().empty())
00875              fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00876 
00877          fprintf(out, ">\n");
00878 
00879          get_attr_table().print_xml(out, space + "    ", constrained);
00880 
00881          get_array()->print_xml(out, space + "    ", constrained);
00882 
00883          for_each(map_begin(), map_end(),
00884                   PrintMapField(out, space + "    ", constrained));
00885 
00886          fprintf(out, "%s</Grid>\n", space.c_str());
00887      }
00888 }
00889 #endif
00890 
00891 class PrintMapFieldStrm : public unary_function<BaseType *, void>
00892 {
00893     ostream &d_out;
00894     string d_space;
00895     bool d_constrained;
00896     string d_tag;
00897 public:
00898     PrintMapFieldStrm(ostream &o, string s, bool c, const string &t = "Map")
00899             : d_out(o), d_space(s), d_constrained(c), d_tag(t)
00900     {}
00901 
00902     void operator()(BaseType *btp)
00903     {
00904         Array *a = dynamic_cast<Array*>(btp);
00905         if (!a)
00906             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
00907         a->print_xml_core(d_out, d_space, d_constrained, d_tag);
00908     }
00909 };
00910 
00911 void
00912 Grid::print_xml(ostream &out, string space, bool constrained)
00913 {
00914     if (constrained && !send_p())
00915         return;
00916 
00917     if (constrained && !projection_yields_grid()) {
00918         out << space << "<Structure" ;
00919         if (!name().empty())
00920             out << " name=\"" << id2xml(name()) << "\"" ;
00921 
00922         out << ">\n" ;
00923 
00924         get_attr_table().print_xml(out, space + "    ", constrained);
00925 
00926         get_array()->print_xml(out, space + "    ", constrained);
00927 
00928         for_each(map_begin(), map_end(),
00929                  PrintMapFieldStrm(out, space + "    ", constrained, "Array"));
00930 
00931         out << space << "</Structure>\n" ;
00932     }
00933     else {
00934         // The number of elements in the (projected) Grid must be such that
00935         // we have a valid Grid object; send it as such.
00936         out << space << "<Grid" ;
00937         if (!name().empty())
00938             out << " name=\"" << id2xml(name()) << "\"" ;
00939 
00940         out << ">\n" ;
00941 
00942         get_attr_table().print_xml(out, space + "    ", constrained);
00943 
00944         get_array()->print_xml(out, space + "    ", constrained);
00945 
00946         for_each(map_begin(), map_end(),
00947                  PrintMapFieldStrm(out, space + "    ", constrained));
00948 
00949         out << space << "</Grid>\n" ;
00950     }
00951 }
00952 
00953 #if FILE_METHODS
00954 void
00955 Grid::print_val(FILE *out, string space, bool print_decl_p)
00956 {
00957     if (print_decl_p) {
00958         print_decl(out, space, false);
00959         fprintf(out, " = ") ;
00960     }
00961 
00962     // If we are printing a value on the client-side, projection_yields_grid
00963     // should not be called since we don't *have* a projection without a
00964     // contraint. I think that if we are here and send_p() is not true, then
00965     // the value of this function should be ignored. 4/6/2000 jhrg
00966     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
00967     if (pyg || !send_p())
00968         fprintf(out, "{  Array: ") ;
00969     else
00970         fprintf(out, "{") ;
00971     _array_var->print_val(out, "", false);
00972     if (pyg || !send_p())
00973         fprintf(out, "  Maps: ") ;
00974     for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
00975          i++, (void)(i != _map_vars.end() && fprintf(out, ", "))) {
00976         (*i)->print_val(out, "", false);
00977     }
00978     fprintf(out, " }") ;
00979 
00980     if (print_decl_p)
00981         fprintf(out, ";\n") ;
00982 }
00983 #endif
00984 
00985 void
00986 Grid::print_val(ostream &out, string space, bool print_decl_p)
00987 {
00988     if (print_decl_p) {
00989         print_decl(out, space, false);
00990         out << " = " ;
00991     }
00992 
00993     // If we are printing a value on the client-side, projection_yields_grid
00994     // should not be called since we don't *have* a projection without a
00995     // Constraint. I think that if we are here and send_p() is not true, then
00996     // the value of this function should be ignored. 4/6/2000 jhrg
00997     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
00998     if (pyg || !send_p())
00999         out << "{  Array: " ;
01000     else
01001         out << "{" ;
01002     _array_var->print_val(out, "", false);
01003     if (pyg || !send_p())
01004         out << "  Maps: " ;
01005     for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
01006          i++, (void)(i != _map_vars.end() && out << ", ")) {
01007         (*i)->print_val(out, "", false);
01008     }
01009     out << " }" ;
01010 
01011     if (print_decl_p)
01012         out << ";\n" ;
01013 }
01014 
01015 // Grids have ugly semantics.
01016 
01021 bool
01022 Grid::check_semantics(string &msg, bool all)
01023 {
01024     if (!BaseType::check_semantics(msg))
01025         return false;
01026 
01027     msg = "";
01028 
01029     if (!_array_var) {
01030         msg += "Null grid base array in `" + name() + "'\n";
01031         return false;
01032     }
01033 
01034     // Is it an array?
01035     if (_array_var->type() != dods_array_c) {
01036         msg += "Grid `" + name() + "'s' member `" + _array_var->name() + "' must be an array\n";
01037         return false;
01038     }
01039 
01040     Array *av = (Array *)_array_var; // past test above, must be an array
01041 
01042     // Array must be of a simple_type.
01043     if (!av->var()->is_simple_type()) {
01044         msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
01045         return false;
01046     }
01047 
01048     // enough maps?
01049     if ((unsigned)_map_vars.size() != av->dimensions()) {
01050         msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
01051         msg += av->name() + "'\n";
01052         return false;
01053     }
01054 
01055     const string array_var_name = av->name();
01056     Array::Dim_iter asi = av->dim_begin() ;
01057     for (Map_iter mvi = _map_vars.begin();
01058          mvi != _map_vars.end(); mvi++, asi++) {
01059 
01060         BaseType *mv = *mvi;
01061 
01062         // check names
01063         if (array_var_name == mv->name()) {
01064             msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
01065             return false;
01066         }
01067         // check types
01068         if (mv->type() != dods_array_c) {
01069             msg += "Grid map variable  `" + mv->name() + "' is not an array\n";
01070             return false;
01071         }
01072 
01073         Array *mv_a = (Array *)mv; // downcast to (Array *)
01074 
01075         // Array must be of a simple_type.
01076         if (!mv_a->var()->is_simple_type()) {
01077             msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
01078             return false;
01079         }
01080 
01081         // check shape
01082         if (mv_a->dimensions() != 1) {// maps must have one dimension
01083             msg += "Grid map variable  `" + mv_a->name() + "' must be only one dimension\n";
01084             return false;
01085         }
01086         // size of map must match corresponding array dimension
01087         Array::Dim_iter mv_asi = mv_a->dim_begin() ;
01088         int mv_a_size = mv_a->dimension_size(mv_asi) ;
01089         int av_size = av->dimension_size(asi) ;
01090         if (mv_a_size != av_size) {
01091             msg += "Grid map variable  `" + mv_a->name() + "'s' size does not match the size of array variable '";
01092             msg += _array_var->name() + "'s' cooresponding dimension\n";
01093             return false;
01094         }
01095     }
01096 
01097     if (all) {
01098         if (!_array_var->check_semantics(msg, true))
01099             return false;
01100         for (Map_iter mvi = _map_vars.begin(); mvi != _map_vars.end(); mvi++) {
01101             if (!(*mvi)->check_semantics(msg, true)) {
01102                 return false;
01103             }
01104         }
01105     }
01106 
01107     return true;
01108 }
01109 
01118 void
01119 Grid::dump(ostream &strm) const
01120 {
01121     strm << DapIndent::LMarg << "Grid::dump - ("
01122     << (void *)this << ")" << endl ;
01123     DapIndent::Indent() ;
01124     Constructor::dump(strm) ;
01125     if (_array_var) {
01126         strm << DapIndent::LMarg << "array var: " << endl ;
01127         DapIndent::Indent() ;
01128         _array_var->dump(strm) ;
01129         DapIndent::UnIndent() ;
01130     }
01131     else {
01132         strm << DapIndent::LMarg << "array var: null" << endl ;
01133     }
01134     strm << DapIndent::LMarg << "map var: " << endl ;
01135     DapIndent::Indent() ;
01136     Map_citer i = _map_vars.begin() ;
01137     Map_citer ie = _map_vars.end() ;
01138     for (; i != ie; i++) {
01139         (*i)->dump(strm) ;
01140     }
01141     DapIndent::UnIndent() ;
01142     DapIndent::UnIndent() ;
01143 }
01144 
01145 } // namespace libdap
01146