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 #include <functional>
00039 #include <algorithm>
00040 
00041 #include "Grid.h"
00042 #include "DDS.h"
00043 #include "Array.h"  // for downcasts
00044 #include "util.h"
00045 #include "InternalErr.h"
00046 #include "escaping.h"
00047 
00048 using namespace std;
00049 
00050 namespace libdap {
00051 
00052 void
00053 Grid::_duplicate(const Grid &s)
00054 {
00055     // Clear out any spurious vars in Constructor::_vars
00056     _vars.clear(); // [mjohnson 10 Sep 2009]
00057 
00058     _array_var = s._array_var->ptr_duplicate();
00059     _array_var->set_parent(this);
00060     _vars.push_back(_array_var); // so the Constructor::Vars_Iter sees it [mjohnson 10 Sep 2009]
00061 
00062     Grid &cs = const_cast<Grid &>(s);
00063 
00064     for (Map_iter i = cs._map_vars.begin(); i != cs._map_vars.end(); i++) {
00065         BaseType *btp = (*i)->ptr_duplicate();
00066         btp->set_parent(this);
00067         _map_vars.push_back(btp);
00068         _vars.push_back(btp); // push all map vectors as weak refs into super::_vars which won't delete them [mjohnson 10 Sep 2009]
00069     }
00070 
00071 }
00072 
00082 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), _array_var(0)
00083 {}
00084 
00096 Grid::Grid(const string &n, const string &d)
00097     : Constructor(n, d, dods_grid_c), _array_var(0)
00098 {}
00099 
00101 Grid::Grid(const Grid &rhs) : Constructor(rhs)
00102 {
00103     _duplicate(rhs);
00104 }
00105 
00106 Grid::~Grid()
00107 {
00108     delete _array_var; _array_var = 0;
00109 
00110     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00111         BaseType *btp = *i ;
00112         delete btp ; btp = 0;
00113     }
00114 }
00115 
00116 BaseType *
00117 Grid::ptr_duplicate()
00118 {
00119     return new Grid(*this);
00120 }
00121 
00122 Grid &
00123 Grid::operator=(const Grid &rhs)
00124 {
00125     if (this == &rhs)
00126         return *this;
00127 
00128     delete _array_var; _array_var = 0;
00129 
00130     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00131         BaseType *btp = *i ;
00132         delete btp ;
00133     }
00134 
00135     // this doesn't copy Constructor::_vars so...
00136     dynamic_cast<Constructor &>(*this) = rhs;
00137 
00138     // we do it in here...
00139     _duplicate(rhs);
00140 
00141     return *this;
00142 }
00143 
00144 int
00145 Grid::element_count(bool leaves)
00146 {
00147     if (!leaves)
00148         return _map_vars.size() + 1;
00149     else {
00150         int i = 0;
00151         for (Map_iter j = _map_vars.begin(); j != _map_vars.end(); j++) {
00152             j += (*j)->element_count(leaves);
00153         }
00154 
00155                 if (!get_array())
00156                         throw InternalErr(__FILE__, __LINE__, "No Grid arry!");
00157 
00158         i += get_array()->element_count(leaves);
00159         return i;
00160     }
00161 }
00162 
00163 void
00164 Grid::set_send_p(bool state)
00165 {
00166     _array_var->set_send_p(state);
00167 
00168     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00169         (*i)->set_send_p(state);
00170     }
00171 
00172     BaseType::set_send_p(state);
00173 }
00174 
00175 void
00176 Grid::set_read_p(bool state)
00177 {
00178     _array_var->set_read_p(state);
00179 
00180     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00181         (*i)->set_read_p(state);
00182     }
00183 
00184     BaseType::set_read_p(state);
00185 }
00186 
00187 void
00188 Grid::set_in_selection(bool state)
00189 {
00190     _array_var->set_in_selection(state);
00191 
00192     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00193         (*i)->set_in_selection(state);
00194     }
00195 
00196     BaseType::set_in_selection(state);
00197 }
00198 
00199 unsigned int
00200 Grid::width()
00201 {
00202     unsigned int sz = _array_var->width();
00203 
00204     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00205         sz += (*i)->width();
00206     }
00207 
00208     return sz;
00209 }
00210 
00211 void
00212 Grid::intern_data(ConstraintEvaluator &eval, DDS &dds)
00213 {
00214     dds.timeout_on();
00215 
00216     if (!read_p())
00217         read();  // read() throws Error and InternalErr
00218 
00219     dds.timeout_off();
00220 
00221     if (_array_var->send_p())
00222         _array_var->intern_data(eval, dds);
00223 
00224     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00225         if ((*i)->send_p()) {
00226             (*i)->intern_data(eval, dds);
00227         }
00228     }
00229 }
00230 
00231 bool
00232 Grid::serialize(ConstraintEvaluator &eval, DDS &dds,
00233                 Marshaller &m, bool ce_eval)
00234 {
00235     dds.timeout_on();
00236 
00237     // Re ticket 560: Get an object from eval that describes how to sample
00238     // and rearrange the data, then perform those actions. Alternative:
00239     // implement this as a selection function.
00240 
00241     if (!read_p())
00242         read();  // read() throws Error and InternalErr
00243 
00244 #if EVAL
00245     if (ce_eval && !eval.eval_selection(dds, dataset()))
00246         return true;
00247 #endif
00248 
00249     dds.timeout_off();
00250 
00251     if (_array_var->send_p())
00252         _array_var->serialize(eval, dds, m, false);
00253 
00254     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00255         if ((*i)->send_p()) {
00256             (*i)->serialize(eval, dds, m, false);
00257         }
00258     }
00259 
00260     return true;
00261 }
00262 
00263 bool
00264 Grid::deserialize(UnMarshaller &um, DDS *dds, bool reuse)
00265 {
00266     _array_var->deserialize(um, dds, reuse);
00267 
00268     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00269         (*i)->deserialize(um, dds, reuse);
00270     }
00271 
00272     return false;
00273 }
00274 
00282 unsigned int
00283 Grid::val2buf(void *, bool)
00284 {
00285     return sizeof(Grid);
00286 }
00287 
00291 unsigned int
00292 Grid::buf2val(void **)
00293 {
00294     return sizeof(Grid);
00295 }
00296 
00297 BaseType *
00298 Grid::var(const string &n, btp_stack &s)
00299 {
00300     return var(n, true, &s);
00301 }
00302 
00307 BaseType *
00308 Grid::var(const string &n, bool, btp_stack *s)
00309 {
00310     string name = www2id(n);
00311 
00312     if (_array_var->name() == name) {
00313         if (s)
00314             s->push(static_cast<BaseType *>(this));
00315         return _array_var;
00316     }
00317 
00318     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00319         if ((*i)->name() == name) {
00320             if (s)
00321                 s->push(static_cast<BaseType *>(this));
00322             return *i;
00323         }
00324     }
00325 
00326     return 0;
00327 }
00328 
00341 void
00342 Grid::add_var(BaseType *bt, Part part)
00343 {
00344     if (!bt)
00345         throw InternalErr(__FILE__, __LINE__,
00346                           "Passing NULL pointer as variable to be added.");
00347 
00348     if (part == array && _array_var) {
00349       // Avoid leaking memory...  Function is add, not set, so it is an error to call again for the array part.
00350       throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!");
00351     }
00352 
00353     // mjohnson 10 Sep 2009
00354     // Add it to the superclass _vars list so we can iterate on superclass vars
00355     _vars.push_back(bt);
00356 
00357     // Jose Garcia
00358     // Now we get a copy of the maps or of the array
00359     // so the owner of bt which is external to libdap++
00360     // is free to deallocate its object.
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         set_array(static_cast<Array*>(p_arr->ptr_duplicate()));
00373         return;
00374     }
00375     break;
00376 
00377     case maps: {
00378             BaseType *btp = bt->ptr_duplicate();
00379             btp->set_parent(this);
00380             _map_vars.push_back(btp);
00381             return;
00382         }
00383     break;
00384 
00385     default: {
00386         if (!_array_var) {
00387             // Refactored to use new set_array ([mjohnson 11 nov 2009])
00388             Array* p_arr = dynamic_cast<Array*>(bt);
00389             // avoid obvious broken semantics
00390             if (!p_arr) {
00391               throw InternalErr(__FILE__, __LINE__,
00392                   "Grid::add_var(): with Part==array: object is not an Array!");
00393             }
00394             // Add it as a copy to preserve old semantics.  This sets parent too.
00395             set_array(static_cast<Array*>(p_arr->ptr_duplicate()));
00396         }
00397         else {
00398             BaseType *btp = bt->ptr_duplicate();
00399             btp->set_parent(this);
00400             _map_vars.push_back(btp);
00401         }
00402         return;
00403     }
00404     break;
00405   }// switch
00406 }
00407 
00417 void
00418 Grid::set_array(Array* p_new_arr)
00419 {
00420   if (!p_new_arr) {
00421     throw InternalErr(__FILE__, __LINE__,
00422         "Grid::set_array(): Cannot set to null!");
00423   }
00424   // Make sure not same memory, this would be evil.
00425   if (p_new_arr == _array_var) {
00426       return;
00427    }
00428   // clean out any old array
00429   delete _array_var; _array_var = 0;
00430   // Set the new, with parent
00431   _array_var = p_new_arr;
00432   _array_var->set_parent(this);
00433 }
00434 
00461 Array*
00462 Grid::add_map(Array* p_new_map, bool add_as_copy)
00463 {
00464   if (!p_new_map) {
00465     throw InternalErr(__FILE__, __LINE__,
00466         "Grid::add_map(): cannot have p_new_map null!");
00467   }
00468 
00469   if (add_as_copy) {
00470     p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
00471   }
00472 
00473   p_new_map->set_parent(this);
00474   _map_vars.push_back(p_new_map);
00475   _vars.push_back(p_new_map); // allow superclass iter to work as well.
00476 
00477   // return the one that got put into the Grid.
00478   return p_new_map;
00479 }
00480 
00493 Array*
00494 Grid::prepend_map(Array* p_new_map, bool add_copy)
00495 {
00496   if (add_copy)
00497     {
00498       p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate());
00499     }
00500 
00501   p_new_map->set_parent(this);
00502   _map_vars.insert(_map_vars.begin(), p_new_map);
00503   _vars.insert(_vars.begin(), p_new_map); // allow superclass iter to work as well.
00504 
00505    // return the one that got put into the Grid.
00506    return p_new_map;
00507 }
00508 
00512 BaseType *
00513 Grid::array_var()
00514 {
00515     return _array_var;
00516 }
00517 
00521 Array *
00522 Grid::get_array()
00523 {
00524     Array *a = dynamic_cast<Array*>(_array_var);
00525     if (a)
00526         return a;
00527     else
00528         throw InternalErr(__FILE__, __LINE__, "bad Cast");
00529 }
00530 
00532 Grid::Map_iter
00533 Grid::map_begin()
00534 {
00535     return _map_vars.begin() ;
00536 }
00537 
00540 Grid::Map_iter
00541 Grid::map_end()
00542 {
00543     return _map_vars.end() ;
00544 }
00545 
00547 Grid::Map_riter
00548 Grid::map_rbegin()
00549 {
00550     return _map_vars.rbegin() ;
00551 }
00552 
00555 Grid::Map_riter
00556 Grid::map_rend()
00557 {
00558     return _map_vars.rend() ;
00559 }
00560 
00564 Grid::Map_iter
00565 Grid::get_map_iter(int i)
00566 {
00567     return _map_vars.begin() + i;
00568 }
00569 
00585 int
00586 Grid::components(bool constrained)
00587 {
00588     int comp;
00589 
00590     if (constrained) {
00591         comp = _array_var->send_p() ? 1 : 0;
00592 
00593         for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00594             if ((*i)->send_p()) {
00595                 comp++;
00596             }
00597         }
00598     }
00599     else {
00600         comp = 1 + _map_vars.size();
00601     }
00602 
00603     return comp;
00604 }
00605 
00606 // When projected (using whatever the current constraint provides in the way
00607 // of a projection), is the object still a Grid?
00608 
00625 bool
00626 Grid::projection_yields_grid()
00627 {
00628     // For each dimension in the Array part, check the corresponding Map
00629     // vector to make sure it is present in the projected Grid. If for each
00630     // projected dimension in the Array component, there is a matching Map
00631     // vector, then the Grid is valid.
00632     bool valid = true;
00633     Array *a = (Array *)_array_var;
00634 
00635     // Don't bother checking if the Array component is not included.
00636     if (!a->send_p())
00637         return false;
00638 
00639     Array::Dim_iter i = a->dim_begin() ;
00640     Map_iter m = map_begin() ;
00641     for (; valid && i != a->dim_end() && m != map_end(); i++, m++) {
00642         if (a->dimension_size(i, true)) {
00643             // Check the matching Map vector; the Map projection must equal
00644             // the Array dimension projection
00645             Array *map = (Array *)(*m);
00646             Array::Dim_iter fd = map->dim_begin(); // Maps have only one dim!
00647             valid = map->dimension_start(fd, true)
00648                     == a->dimension_start(i, true)
00649                     && map->dimension_stop(fd, true)
00650                     == a->dimension_stop(i, true)
00651                     && map->dimension_stride(fd, true)
00652                     == a->dimension_stride(i, true);
00653         }
00654         else {
00655             // Corresponding Map vector must be excluded from the projection.
00656             Array *map = (Array *)(*m);
00657             valid = !map->send_p();
00658         }
00659     }
00660 
00661     return valid;
00662 }
00663 
00665 void
00666 Grid::clear_constraint()
00667 {
00668     dynamic_cast<Array&>(*_array_var).clear_constraint();
00669     for (Map_iter m = map_begin(); m != map_end(); ++m)
00670         dynamic_cast<Array&>(*(*m)).clear_constraint();
00671 }
00672 
00673 #if FILE_METHODS
00674 void
00675 Grid::print_decl(FILE *out, string space, bool print_semi,
00676                  bool constraint_info, bool constrained)
00677 {
00678     if (constrained && !send_p())
00679         return;
00680 
00681 #if 0
00682     // If we are printing the declaration of a constrained Grid then check for
00683     // the case where the projection removes all but one component; the
00684     // resulting object is a simple array.
00685     int projection = components(true);
00686     if (constrained && projection == 1) {
00687         _array_var->print_decl(out, space, print_semi /*true*/, constraint_info,
00688                                constrained);
00689         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00690             (*i)->print_decl(out, space, print_semi /*true*/, constraint_info, constrained);
00691         }
00692 
00693         goto exit;  // Skip end material.
00694     }
00695     // If there are M (< N) componets (Array and Maps combined) in a N
00696     // component Grid, send the M components as elements of a Struture.
00697     // This will preserve the grouping without violating the rules for a
00698     // Grid.
00699     // else
00700 #endif
00701     // The problem with the above is that if two Grids are projected and each
00702     // contain one variable, say a map, and it happens to have the same name
00703     // in each Grid, then without the enclosing Structures, the returned dataset
00704     // has two variables with the same name at the same lexical level. So I'm
00705     // removing the code above.
00706     if (constrained && !projection_yields_grid()) {
00707         fprintf(out, "%sStructure {\n", space.c_str()) ;
00708 
00709         _array_var->print_decl(out, space + "    ", true, constraint_info,
00710                                constrained);
00711 
00712         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00713             (*i)->print_decl(out, space + "    ", true,
00714                              constraint_info, constrained);
00715         }
00716 
00717         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00718     }
00719     else {
00720         // The number of elements in the (projected) Grid must be such that
00721         // we have a valid Grid object; send it as such.
00722         fprintf(out, "%s%s {\n", space.c_str(), type_name().c_str()) ;
00723 
00724         fprintf(out, "%s  Array:\n", space.c_str()) ;
00725         _array_var->print_decl(out, space + "    ", true, constraint_info,
00726                                constrained);
00727 
00728         fprintf(out, "%s  Maps:\n", space.c_str()) ;
00729         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00730             (*i)->print_decl(out, space + "    ", true,
00731                              constraint_info, constrained);
00732         }
00733 
00734         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00735     }
00736 
00737     if (constraint_info) {
00738         if (send_p())
00739             fprintf( out, ": Send True");
00740         else
00741             fprintf( out, ": Send False");
00742     }
00743 
00744     if (print_semi)
00745         fprintf(out, ";\n") ;
00746 #if 0
00747     // If sending just one comp, skip sending the terminal semicolon, etc.
00748 exit:
00749 #endif
00750 
00751     return;
00752 }
00753 #endif
00754 
00755 void
00756 Grid::print_decl(ostream &out, string space, bool print_semi,
00757                  bool constraint_info, bool constrained)
00758 {
00759     if (constrained && !send_p())
00760         return;
00761 
00762     // If we are printing the declaration of a constrained Grid then check for
00763     // the case where the projection removes all but one component; the
00764     // resulting object is a simple array.
00765     //
00766     // I replaced the 'true' with the value of 'print_semi' passed in by the
00767     // caller. This fixes an issue with the intern_data tests and does not
00768     // seem to break anything else. jhrg 11/9/07
00769 #if 0
00770     int projection = components(true);
00771     if (constrained && projection == 1) {
00772         _array_var->print_decl(out, space, print_semi /*true*/, constraint_info,
00773                                constrained);
00774         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00775             (*i)->print_decl(out, space, print_semi /*true*/, constraint_info, constrained);
00776         }
00777 
00778         goto exit;  // Skip end material.
00779     }
00780     // If there are M (< N) components (Array and Maps combined) in a N
00781     // component Grid, send the M components as elements of a Structure.
00782     // This will preserve the grouping without violating the rules for a
00783     // Grid.
00784     // else
00785 #endif
00786 
00787     // See comment for the FILE* version of this method.
00788     if (constrained && !projection_yields_grid()) {
00789         out << space << "Structure {\n" ;
00790 
00791         _array_var->print_decl(out, space + "    ", true, constraint_info,
00792                                constrained);
00793 
00794         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00795             (*i)->print_decl(out, space + "    ", true,
00796                              constraint_info, constrained);
00797         }
00798 
00799         out << space << "} " << id2www(name()) ;
00800     }
00801     else {
00802         // The number of elements in the (projected) Grid must be such that
00803         // we have a valid Grid object; send it as such.
00804         out << space << type_name() << " {\n" ;
00805 
00806         out << space << "  Array:\n" ;
00807         _array_var->print_decl(out, space + "    ", true, constraint_info,
00808                                constrained);
00809 
00810         out << space << "  Maps:\n" ;
00811         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00812             (*i)->print_decl(out, space + "    ", true,
00813                              constraint_info, constrained);
00814         }
00815 
00816         out << space << "} " << id2www(name()) ;
00817     }
00818 
00819     if (constraint_info) {
00820         if (send_p())
00821             out << ": Send True";
00822         else
00823             out << ": Send False";
00824     }
00825 
00826     if (print_semi)
00827         out << ";\n" ;
00828 #if 0
00829     // If sending just one comp, skip sending the terminal semicolon, etc.
00830 exit:
00831 #endif
00832 
00833     return;
00834 }
00835 
00836 #if FILE_METHODS
00837 class PrintMapField : public unary_function<BaseType *, void>
00838 {
00839     FILE *d_out;
00840     string d_space;
00841     bool d_constrained;
00842     string d_tag;
00843 public:
00844     PrintMapField(FILE *o, string s, bool c, const string &t = "Map")
00845             : d_out(o), d_space(s), d_constrained(c), d_tag(t)
00846     {}
00847 
00848     void operator()(BaseType *btp)
00849     {
00850         Array *a = dynamic_cast<Array*>(btp);
00851         if (!a)
00852             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
00853         a->print_xml_core(d_out, d_space, d_constrained, d_tag);
00854     }
00855 };
00856 
00857 void
00858 Grid::print_xml(FILE *out, string space, bool constrained)
00859 {
00860     if (constrained && !send_p())
00861          return;
00862 
00863      // If we are printing the declaration of a constrained Grid then check for
00864      // the case where the projection removes all but one component; the
00865      // resulting object is a simple array.
00866      //
00867      // I replaced the 'true' with the value of 'print_semi' passed in by the
00868      // caller. This fixes an issue with the intern_data tests and does not
00869      // seem to break anything else. jhrg 11/9/07
00870 #if 0
00871      int projection = components(true);
00872      if (constrained && projection == 1) {
00873          get_attr_table().print_xml(out, space + "    ", constrained);
00874 
00875          get_array()->print_xml(out, space + "    ", constrained);
00876 
00877          for_each(map_begin(), map_end(),
00878                   PrintMapField(out, space + "    ", constrained, "Array"));
00879      }
00880      // If there are M (< N) components (Array and Maps combined) in a N
00881      // component Grid, send the M components as elements of a Structure.
00882      // This will preserve the grouping without violating the rules for a
00883      // Grid.
00884      // else
00885 #endif
00886 
00887      if (constrained && !projection_yields_grid()) {
00888          fprintf(out, "%s<Structure", space.c_str());
00889          if (!name().empty())
00890              fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00891 
00892          fprintf(out, ">\n");
00893 
00894          get_attr_table().print_xml(out, space + "    ", constrained);
00895 
00896          get_array()->print_xml(out, space + "    ", constrained);
00897 
00898          for_each(map_begin(), map_end(),
00899                   PrintMapField(out, space + "    ", constrained, "Array"));
00900 
00901          fprintf(out, "%s</Structure>\n", space.c_str());
00902      }
00903      else {
00904          // The number of elements in the (projected) Grid must be such that
00905          // we have a valid Grid object; send it as such.
00906          fprintf(out, "%s<Grid", space.c_str());
00907          if (!name().empty())
00908              fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00909 
00910          fprintf(out, ">\n");
00911 
00912          get_attr_table().print_xml(out, space + "    ", constrained);
00913 
00914          get_array()->print_xml(out, space + "    ", constrained);
00915 
00916          for_each(map_begin(), map_end(),
00917                   PrintMapField(out, space + "    ", constrained));
00918 
00919          fprintf(out, "%s</Grid>\n", space.c_str());
00920      }
00921 }
00922 #endif
00923 
00924 class PrintMapFieldStrm : public unary_function<BaseType *, void>
00925 {
00926     ostream &d_out;
00927     string d_space;
00928     bool d_constrained;
00929     string d_tag;
00930 public:
00931     PrintMapFieldStrm(ostream &o, string s, bool c, const string &t = "Map")
00932             : d_out(o), d_space(s), d_constrained(c), d_tag(t)
00933     {}
00934 
00935     void operator()(BaseType *btp)
00936     {
00937         Array *a = dynamic_cast<Array*>(btp);
00938         if (!a)
00939             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
00940         a->print_xml_core(d_out, d_space, d_constrained, d_tag);
00941     }
00942 };
00943 
00944 void
00945 Grid::print_xml(ostream &out, string space, bool constrained)
00946 {
00947     if (constrained && !send_p())
00948         return;
00949 
00950     // If we are printing the declaration of a constrained Grid then check for
00951     // the case where the projection removes all but one component; the
00952     // resulting object is a simple array.
00953     //
00954     // I replaced the 'true' with the value of 'print_semi' passed in by the
00955     // caller. This fixes an issue with the intern_data tests and does not
00956     // seem to break anything else. jhrg 11/9/07
00957 #if 0
00958     int projection = components(true);
00959     if (constrained && projection == 1) {
00960         get_attr_table().print_xml(out, space + "    ", constrained);
00961 
00962         get_array()->print_xml(out, space + "    ", constrained);
00963 
00964         for_each(map_begin(), map_end(),
00965                  PrintMapFieldStrm(out, space + "    ", constrained, "Array"));
00966     }
00967     // If there are M (< N) components (Array and Maps combined) in a N
00968     // component Grid, send the M components as elements of a Structure.
00969     // This will preserve the grouping without violating the rules for a
00970     // Grid.
00971     //else
00972 #endif
00973 
00974     if (constrained && !projection_yields_grid()) {
00975         out << space << "<Structure" ;
00976         if (!name().empty())
00977             out << " name=\"" << id2xml(name()) << "\"" ;
00978 
00979         out << ">\n" ;
00980 
00981         get_attr_table().print_xml(out, space + "    ", constrained);
00982 
00983         get_array()->print_xml(out, space + "    ", constrained);
00984 
00985         for_each(map_begin(), map_end(),
00986                  PrintMapFieldStrm(out, space + "    ", constrained, "Array"));
00987 
00988         out << space << "</Structure>\n" ;
00989     }
00990     else {
00991         // The number of elements in the (projected) Grid must be such that
00992         // we have a valid Grid object; send it as such.
00993         out << space << "<Grid" ;
00994         if (!name().empty())
00995             out << " name=\"" << id2xml(name()) << "\"" ;
00996 
00997         out << ">\n" ;
00998 
00999         get_attr_table().print_xml(out, space + "    ", constrained);
01000 
01001         get_array()->print_xml(out, space + "    ", constrained);
01002 
01003         for_each(map_begin(), map_end(),
01004                  PrintMapFieldStrm(out, space + "    ", constrained));
01005 
01006         out << space << "</Grid>\n" ;
01007     }
01008 }
01009 
01010 #if FILE_METHODS
01011 void
01012 Grid::print_val(FILE *out, string space, bool print_decl_p)
01013 {
01014     if (print_decl_p) {
01015         print_decl(out, space, false);
01016         fprintf(out, " = ") ;
01017     }
01018 
01019     // If we are printing a value on the client-side, projection_yields_grid
01020     // should not be called since we don't *have* a projection without a
01021     // contraint. I think that if we are here and send_p() is not true, then
01022     // the value of this function should be ignored. 4/6/2000 jhrg
01023     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
01024     if (pyg || !send_p())
01025         fprintf(out, "{  Array: ") ;
01026     else
01027         fprintf(out, "{") ;
01028     _array_var->print_val(out, "", false);
01029     if (pyg || !send_p())
01030         fprintf(out, "  Maps: ") ;
01031     for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
01032          i++, (void)(i != _map_vars.end() && fprintf(out, ", "))) {
01033         (*i)->print_val(out, "", false);
01034     }
01035     fprintf(out, " }") ;
01036 
01037     if (print_decl_p)
01038         fprintf(out, ";\n") ;
01039 }
01040 #endif
01041 
01042 void
01043 Grid::print_val(ostream &out, string space, bool print_decl_p)
01044 {
01045     if (print_decl_p) {
01046         print_decl(out, space, false);
01047         out << " = " ;
01048     }
01049 
01050     // If we are printing a value on the client-side, projection_yields_grid
01051     // should not be called since we don't *have* a projection without a
01052     // Constraint. I think that if we are here and send_p() is not true, then
01053     // the value of this function should be ignored. 4/6/2000 jhrg
01054     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
01055     if (pyg || !send_p())
01056         out << "{  Array: " ;
01057     else
01058         out << "{" ;
01059     _array_var->print_val(out, "", false);
01060     if (pyg || !send_p())
01061         out << "  Maps: " ;
01062     for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
01063          i++, (void)(i != _map_vars.end() && out << ", ")) {
01064         (*i)->print_val(out, "", false);
01065     }
01066     out << " }" ;
01067 
01068     if (print_decl_p)
01069         out << ";\n" ;
01070 }
01071 
01072 // Grids have ugly semantics.
01073 
01078 bool
01079 Grid::check_semantics(string &msg, bool all)
01080 {
01081     if (!BaseType::check_semantics(msg))
01082         return false;
01083 
01084     msg = "";
01085 
01086     if (!_array_var) {
01087         msg += "Null grid base array in `" + name() + "'\n";
01088         return false;
01089     }
01090 
01091     // Is it an array?
01092     if (_array_var->type() != dods_array_c) {
01093         msg += "Grid `" + name() + "'s' member `" + _array_var->name() + "' must be an array\n";
01094         return false;
01095     }
01096 
01097     Array *av = (Array *)_array_var; // past test above, must be an array
01098 
01099     // Array must be of a simple_type.
01100     if (!av->var()->is_simple_type()) {
01101         msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
01102         return false;
01103     }
01104 
01105     // enough maps?
01106     if ((unsigned)_map_vars.size() != av->dimensions()) {
01107         msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
01108         msg += av->name() + "'\n";
01109         return false;
01110     }
01111 
01112     const string array_var_name = av->name();
01113     Array::Dim_iter asi = av->dim_begin() ;
01114     for (Map_iter mvi = _map_vars.begin();
01115          mvi != _map_vars.end(); mvi++, asi++) {
01116 
01117         BaseType *mv = *mvi;
01118 
01119         // check names
01120         if (array_var_name == mv->name()) {
01121             msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
01122             return false;
01123         }
01124         // check types
01125         if (mv->type() != dods_array_c) {
01126             msg += "Grid map variable  `" + mv->name() + "' is not an array\n";
01127             return false;
01128         }
01129 
01130         Array *mv_a = (Array *)mv; // downcast to (Array *)
01131 
01132         // Array must be of a simple_type.
01133         if (!mv_a->var()->is_simple_type()) {
01134             msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
01135             return false;
01136         }
01137 
01138         // check shape
01139         if (mv_a->dimensions() != 1) {// maps must have one dimension
01140             msg += "Grid map variable  `" + mv_a->name() + "' must be only one dimension\n";
01141             return false;
01142         }
01143         // size of map must match corresponding array dimension
01144         Array::Dim_iter mv_asi = mv_a->dim_begin() ;
01145         int mv_a_size = mv_a->dimension_size(mv_asi) ;
01146         int av_size = av->dimension_size(asi) ;
01147         if (mv_a_size != av_size) {
01148             msg += "Grid map variable  `" + mv_a->name() + "'s' size does not match the size of array variable '";
01149             msg += _array_var->name() + "'s' cooresponding dimension\n";
01150             return false;
01151         }
01152     }
01153 
01154     if (all) {
01155         if (!_array_var->check_semantics(msg, true))
01156             return false;
01157         for (Map_iter mvi = _map_vars.begin(); mvi != _map_vars.end(); mvi++) {
01158             if (!(*mvi)->check_semantics(msg, true)) {
01159                 return false;
01160             }
01161         }
01162     }
01163 
01164     return true;
01165 }
01166 
01175 void
01176 Grid::dump(ostream &strm) const
01177 {
01178     strm << DapIndent::LMarg << "Grid::dump - ("
01179     << (void *)this << ")" << endl ;
01180     DapIndent::Indent() ;
01181     Constructor::dump(strm) ;
01182     if (_array_var) {
01183         strm << DapIndent::LMarg << "array var: " << endl ;
01184         DapIndent::Indent() ;
01185         _array_var->dump(strm) ;
01186         DapIndent::UnIndent() ;
01187     }
01188     else {
01189         strm << DapIndent::LMarg << "array var: null" << endl ;
01190     }
01191     strm << DapIndent::LMarg << "map var: " << endl ;
01192     DapIndent::Indent() ;
01193     Map_citer i = _map_vars.begin() ;
01194     Map_citer ie = _map_vars.end() ;
01195     for (; i != ie; i++) {
01196         (*i)->dump(strm) ;
01197     }
01198     DapIndent::UnIndent() ;
01199     DapIndent::UnIndent() ;
01200 }
01201 
01202 } // namespace libdap
01203 

Generated on Wed Feb 10 16:08:02 2010 for libdap++ by  doxygen 1.4.7