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 //#include "BTIterAdapter.h"
00048 
00049 
00050 using namespace std;
00051 
00052 void
00053 Grid::_duplicate(const Grid &s)
00054 {
00055     _array_var = s._array_var->ptr_duplicate();
00056     _array_var->set_parent(this);
00057 
00058     Grid &cs = const_cast<Grid &>(s);
00059 
00060     for (Map_iter i = cs._map_vars.begin(); i != cs._map_vars.end(); i++) {
00061         BaseType *btp = (*i)->ptr_duplicate();
00062         btp->set_parent(this);
00063         _map_vars.push_back(btp);
00064     }
00065 }
00066 
00076 Grid::Grid(const string &n) : Constructor(n, dods_grid_c), _array_var(0)
00077 {}
00078 
00080 Grid::Grid(const Grid &rhs) : Constructor(rhs)
00081 {
00082     _duplicate(rhs);
00083 }
00084 
00085 Grid::~Grid()
00086 {
00087     delete _array_var; _array_var = 0;
00088 
00089     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00090         BaseType *btp = *i ;
00091         delete btp ; btp = 0;
00092     }
00093 }
00094 
00095 BaseType *
00096 Grid::ptr_duplicate()
00097 {
00098     return new Grid(*this);
00099 }
00100 
00101 Grid &
00102 Grid::operator=(const Grid &rhs)
00103 {
00104     if (this == &rhs)
00105         return *this;
00106 
00107     delete _array_var; _array_var = 0;
00108 
00109     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00110         BaseType *btp = *i ;
00111         delete btp ;
00112     }
00113 
00114     dynamic_cast<Constructor &>(*this) = rhs;
00115 
00116     _duplicate(rhs);
00117 
00118     return *this;
00119 }
00120 
00121 int
00122 Grid::element_count(bool leaves)
00123 {
00124     if (!leaves)
00125         return _map_vars.size() + 1;
00126     else {
00127         int i = 0;
00128         for (Map_iter j = _map_vars.begin(); j != _map_vars.end(); j++) {
00129             j += (*j)->element_count(leaves);
00130         }
00131 
00132         i += get_array()->element_count(leaves);
00133         return i;
00134     }
00135 }
00136 
00137 void
00138 Grid::set_send_p(bool state)
00139 {
00140     _array_var->set_send_p(state);
00141 
00142     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00143         (*i)->set_send_p(state);
00144     }
00145 
00146     BaseType::set_send_p(state);
00147 }
00148 
00149 void
00150 Grid::set_read_p(bool state)
00151 {
00152     _array_var->set_read_p(state);
00153 
00154     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00155         (*i)->set_read_p(state);
00156     }
00157 
00158     BaseType::set_read_p(state);
00159 }
00160 
00161 void
00162 Grid::set_in_selection(bool state)
00163 {
00164     _array_var->set_in_selection(state);
00165 
00166     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00167         (*i)->set_in_selection(state);
00168     }
00169 
00170     BaseType::set_in_selection(state);
00171 }
00172 
00173 unsigned int
00174 Grid::width()
00175 {
00176     unsigned int sz = _array_var->width();
00177 
00178     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00179         sz += (*i)->width();
00180     }
00181 
00182     return sz;
00183 }
00184 
00185 bool
00186 Grid::serialize(const string &dataset, ConstraintEvaluator &eval, DDS &dds,
00187                 XDR *sink, bool ce_eval)
00188 {
00189     dds.timeout_on();
00190 
00191     // Re ticket 560: Get an object from eval that describes how to sample
00192     // and rearrange the data, then perform those actions. Alternative:
00193     // implement this as a selection function.
00194 
00195     if (!read_p())
00196         read(dataset);  // read() throws Error and InternalErr
00197 
00198 #if EVAL
00199     if (ce_eval && !eval.eval_selection(dds, dataset))
00200         return true;
00201 #endif
00202 
00203     dds.timeout_off();
00204 
00205     if (_array_var->send_p())
00206         _array_var->serialize(dataset, eval, dds, sink, false);
00207 
00208     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00209         if ((*i)->send_p()) {
00210             (*i)->serialize(dataset, eval, dds, sink, false);
00211         }
00212     }
00213 
00214     return true;
00215 }
00216 
00217 bool
00218 Grid::deserialize(XDR *source, DDS *dds, bool reuse)
00219 {
00220     _array_var->deserialize(source, dds, reuse);
00221 
00222     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00223         (*i)->deserialize(source, dds, reuse);
00224     }
00225 
00226     return false;
00227 }
00228 
00236 unsigned int
00237 Grid::val2buf(void *, bool)
00238 {
00239     return sizeof(Grid);
00240 }
00241 
00245 unsigned int
00246 Grid::buf2val(void **)
00247 {
00248     return sizeof(Grid);
00249 }
00250 
00251 BaseType *
00252 Grid::var(const string &n, btp_stack &s)
00253 {
00254     return var(n, true, &s);
00255 }
00256 
00261 BaseType *
00262 Grid::var(const string &n, bool, btp_stack *s)
00263 {
00264     string name = www2id(n);
00265 
00266     if (_array_var->name() == name) {
00267         if (s)
00268             s->push(static_cast<BaseType *>(this));
00269         return _array_var;
00270     }
00271 
00272     for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00273         if ((*i)->name() == name) {
00274             if (s)
00275                 s->push(static_cast<BaseType *>(this));
00276             return *i;
00277         }
00278     }
00279 
00280     return 0;
00281 }
00282 
00295 void
00296 Grid::add_var(BaseType *bt, Part part)
00297 {
00298     if (!bt)
00299         throw InternalErr(__FILE__, __LINE__,
00300                           "Passing NULL pointer as variable to be added.");
00301 
00302     // Jose Garcia
00303     // Now we get a copy of the maps or of the array
00304     // so the owner of bt which is external to libdap++
00305     // is free to deallocate its object.
00306     switch (part) {
00307     case array:
00308         _array_var = bt->ptr_duplicate();
00309         _array_var->set_parent(this);
00310         return;
00311     case maps: {
00312             BaseType *btp = bt->ptr_duplicate();
00313             btp->set_parent(this);
00314             _map_vars.push_back(btp);
00315             return;
00316         }
00317     default:
00318         if (!_array_var) {
00319             _array_var = bt->ptr_duplicate();
00320             _array_var->set_parent(this);
00321         }
00322         else {
00323             BaseType *btp = bt->ptr_duplicate();
00324             btp->set_parent(this);
00325             _map_vars.push_back(btp);
00326         }
00327         return;
00328     }
00329 }
00330 
00334 BaseType *
00335 Grid::array_var()
00336 {
00337     return _array_var;
00338 }
00339 
00343 Array *
00344 Grid::get_array()
00345 {
00346     return dynamic_cast<Array*>(_array_var);
00347 }
00348 
00350 Grid::Map_iter
00351 Grid::map_begin()
00352 {
00353     return _map_vars.begin() ;
00354 }
00355 
00358 Grid::Map_iter
00359 Grid::map_end()
00360 {
00361     return _map_vars.end() ;
00362 }
00363 
00365 Grid::Map_riter
00366 Grid::map_rbegin()
00367 {
00368     return _map_vars.rbegin() ;
00369 }
00370 
00373 Grid::Map_riter
00374 Grid::map_rend()
00375 {
00376     return _map_vars.rend() ;
00377 }
00378 
00382 Grid::Map_iter
00383 Grid::get_map_iter(int i)
00384 {
00385     return _map_vars.begin() + i;
00386 }
00387 
00403 int
00404 Grid::components(bool constrained)
00405 {
00406     int comp;
00407 
00408     if (constrained) {
00409         comp = _array_var->send_p() ? 1 : 0;
00410 
00411         for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) {
00412             if ((*i)->send_p()) {
00413                 comp++;
00414             }
00415         }
00416     }
00417     else {
00418         comp = 1 + _map_vars.size();
00419     }
00420 
00421     return comp;
00422 }
00423 
00424 // When projected (using whatever the current constraint provides in the way
00425 // of a projection), is the object still a Grid?
00426 
00443 bool
00444 Grid::projection_yields_grid()
00445 {
00446     // For each dimension in the Array part, check the corresponding Map
00447     // vector to make sure it is present in the projected Grid. If for each
00448     // projected dimension in the Array component, there is a matching Map
00449     // vector, then the Grid is valid.
00450     bool valid = true;
00451     Array *a = (Array *)_array_var;
00452 
00453     // Don't bother checking if the Array component is not included.
00454     if (!a->send_p())
00455         return false;
00456 
00457     Array::Dim_iter i = a->dim_begin() ;
00458     Map_iter m = map_begin() ;
00459     for (; valid && i != a->dim_end() && m != map_end(); i++, m++) {
00460         if (a->dimension_size(i, true)) {
00461             // Check the matching Map vector; the Map projection must equal
00462             // the Array dimension projection
00463             Array *map = (Array *)(*m);
00464             Array::Dim_iter fd = map->dim_begin(); // Maps have only one dim!
00465             valid = map->dimension_start(fd, true)
00466                     == a->dimension_start(i, true)
00467                     && map->dimension_stop(fd, true)
00468                     == a->dimension_stop(i, true)
00469                     && map->dimension_stride(fd, true)
00470                     == a->dimension_stride(i, true);
00471         }
00472         else {
00473             // Corresponding Map vector must be excluded from the projection.
00474             Array *map = (Array *)(*m);
00475             valid = !map->send_p();
00476         }
00477     }
00478 
00479     return valid;
00480 }
00481 
00483 void
00484 Grid::clear_constraint()
00485 {
00486     dynamic_cast<Array&>(*_array_var).clear_constraint();
00487     for (Map_iter m = map_begin(); m != map_end(); ++m)
00488         dynamic_cast<Array&>(*(*m)).clear_constraint();
00489 }
00490 
00491 void
00492 Grid::print_decl(FILE *out, string space, bool print_semi,
00493                  bool constraint_info, bool constrained)
00494 {
00495     if (constrained && !send_p())
00496         return;
00497 
00498     // If we are printing the declaration of a constrained Grid then check for
00499     // the case where the projection removes all but one component; the
00500     // resulting object is a simple array.
00501     int projection = components(true);
00502     if (constrained && projection == 1) {
00503         _array_var->print_decl(out, space, true, constraint_info,
00504                                constrained);
00505         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00506             (*i)->print_decl(out, space, true, constraint_info, constrained);
00507         }
00508         goto exit;  // Skip end material.
00509     }
00510     // If there are M (< N) componets (Array and Maps combined) in a N
00511     // component Grid, send the M components as elements of a Struture.
00512     // This will preserve the grouping without violating the rules for a
00513     // Grid.
00514     else if (constrained && !projection_yields_grid()) {
00515         fprintf(out, "%sStructure {\n", space.c_str()) ;
00516 
00517         _array_var->print_decl(out, space + "    ", true, constraint_info,
00518                                constrained);
00519 
00520         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00521             (*i)->print_decl(out, space + "    ", true,
00522                              constraint_info, constrained);
00523         }
00524 
00525         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00526     }
00527     else {
00528         // The number of elements in the (projected) Grid must be such that
00529         // we have a valid Grid object; send it as such.
00530         fprintf(out, "%s%s {\n", space.c_str(), type_name().c_str()) ;
00531 
00532         fprintf(out, "%s  Array:\n", space.c_str()) ;
00533         _array_var->print_decl(out, space + "    ", true, constraint_info,
00534                                constrained);
00535 
00536         fprintf(out, "%s  Maps:\n", space.c_str()) ;
00537         for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) {
00538             (*i)->print_decl(out, space + "    ", true,
00539                              constraint_info, constrained);
00540         }
00541 
00542         fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ;
00543     }
00544 
00545     if (constraint_info) {
00546         if (send_p())
00547             cout << ": Send True";
00548         else
00549             cout << ": Send False";
00550     }
00551 
00552     if (print_semi)
00553         fprintf(out, ";\n") ;
00554 
00555     // If sending just one comp, skip sending the terminal semicolon, etc.
00556 exit:
00557     return;
00558 }
00559 
00560 class PrintMapField : public unary_function<BaseType *, void>
00561 {
00562     FILE *d_out;
00563     string d_space;
00564     bool d_constrained;
00565 public:
00566     PrintMapField(FILE *o, string s, bool c)
00567             : d_out(o), d_space(s), d_constrained(c)
00568     {}
00569 
00570     void operator()(BaseType *btp)
00571     {
00572         Array *a = dynamic_cast<Array*>(btp);
00573         if (!a)
00574             throw InternalErr(__FILE__, __LINE__, "Expected an Array.");
00575         a->print_as_map_xml(d_out, d_space, d_constrained);
00576     }
00577 };
00578 
00579 void
00580 Grid::print_xml(FILE *out, string space, bool constrained)
00581 {
00582     if (constrained && !send_p())
00583         return;
00584 
00585     fprintf(out, "%s<Grid", space.c_str());
00586     if (!name().empty())
00587         fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00588 
00589     fprintf(out, ">\n");
00590 
00591     get_attr_table().print_xml(out, space + "    ", constrained);
00592 
00593     get_array()->print_xml(out, space + "    ", constrained);
00594 
00595     for_each(map_begin(), map_end(),
00596              PrintMapField(out, space + "    ", constrained));
00597 
00598     fprintf(out, "%s</Grid>\n", space.c_str());
00599 }
00600 
00601 void
00602 Grid::print_val(FILE *out, string space, bool print_decl_p)
00603 {
00604     if (print_decl_p) {
00605         print_decl(out, space, false);
00606         fprintf(out, " = ") ;
00607     }
00608 
00609     // If we are printing a value on the client-side, projection_yields_grid
00610     // should not be called since we don't *have* a projection without a
00611     // contraint. I think that if we are here and send_p() is not true, then
00612     // the value of this function should be ignored. 4/6/2000 jhrg
00613     bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg
00614     if (pyg || !send_p())
00615         fprintf(out, "{  Array: ") ;
00616     else
00617         fprintf(out, "{") ;
00618     _array_var->print_val(out, "", false);
00619     if (pyg || !send_p())
00620         fprintf(out, "  Maps: ") ;
00621     for (Map_citer i = _map_vars.begin(); i != _map_vars.end();
00622          i++, (void)(i != _map_vars.end() && fprintf(out, ", "))) {
00623         (*i)->print_val(out, "", false);
00624     }
00625     fprintf(out, " }") ;
00626 
00627     if (print_decl_p)
00628         fprintf(out, ";\n") ;
00629 }
00630 
00631 // Grids have ugly semantics.
00632 
00637 bool
00638 Grid::check_semantics(string &msg, bool all)
00639 {
00640     if (!BaseType::check_semantics(msg))
00641         return false;
00642 #if 0
00643     // Actually, the spec doesn't say this. jhrg 2/13/06
00644     if (!unique_names(_map_vars, name(), type_name(), msg))
00645         return false;
00646 #endif
00647 
00648     msg = "";
00649 
00650     if (!_array_var) {
00651         msg += "Null grid base array in `" + name() + "'\n";
00652         return false;
00653     }
00654 
00655     // Is it an array?
00656     if (_array_var->type() != dods_array_c) {
00657         msg += "Grid `" + name() + "'s' member `" + _array_var->name() + "' must be an array\n";
00658         return false;
00659     }
00660 
00661     Array *av = (Array *)_array_var; // past test above, must be an array
00662 
00663     // Array must be of a simple_type.
00664     if (!av->var()->is_simple_type()) {
00665         msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
00666         return false;
00667     }
00668 
00669     // enough maps?
00670     if ((unsigned)_map_vars.size() != av->dimensions()) {
00671         msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `";
00672         msg += av->name() + "'\n";
00673         return false;
00674     }
00675 
00676     const string array_var_name = av->name();
00677     Array::Dim_iter asi = av->dim_begin() ;
00678     for (Map_iter mvi = _map_vars.begin();
00679          mvi != _map_vars.end(); mvi++, asi++) {
00680 
00681         BaseType *mv = *mvi;
00682 
00683         // check names
00684         if (array_var_name == mv->name()) {
00685             msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n";
00686             return false;
00687         }
00688         // check types
00689         if (mv->type() != dods_array_c) {
00690             msg += "Grid map variable  `" + mv->name() + "' is not an array\n";
00691             return false;
00692         }
00693 
00694         Array *mv_a = (Array *)mv; // downcast to (Array *)
00695 
00696         // Array must be of a simple_type.
00697         if (!mv_a->var()->is_simple_type()) {
00698             msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n";
00699             return false;
00700         }
00701 
00702         // check shape
00703         if (mv_a->dimensions() != 1) {// maps must have one dimension
00704             msg += "Grid map variable  `" + mv_a->name() + "' must be only one dimension\n";
00705             return false;
00706         }
00707         // size of map must match corresponding array dimension
00708         Array::Dim_iter mv_asi = mv_a->dim_begin() ;
00709         int mv_a_size = mv_a->dimension_size(mv_asi) ;
00710         int av_size = av->dimension_size(asi) ;
00711         if (mv_a_size != av_size) {
00712             msg += "Grid map variable  `" + mv_a->name() + "'s' size does not match the size of array variable '";
00713             msg += _array_var->name() + "'s' cooresponding dimension\n";
00714             return false;
00715         }
00716     }
00717 
00718     if (all) {
00719         if (!_array_var->check_semantics(msg, true))
00720             return false;
00721         for (Map_iter mvi = _map_vars.begin(); mvi != _map_vars.end(); mvi++) {
00722             if (!(*mvi)->check_semantics(msg, true)) {
00723                 return false;
00724             }
00725         }
00726     }
00727 
00728     return true;
00729 }
00730 
00739 void
00740 Grid::dump(ostream &strm) const
00741 {
00742     strm << DapIndent::LMarg << "Grid::dump - ("
00743     << (void *)this << ")" << endl ;
00744     DapIndent::Indent() ;
00745     Constructor::dump(strm) ;
00746     if (_array_var) {
00747         strm << DapIndent::LMarg << "array var: " << endl ;
00748         DapIndent::Indent() ;
00749         _array_var->dump(strm) ;
00750         DapIndent::UnIndent() ;
00751     }
00752     else {
00753         strm << DapIndent::LMarg << "array var: null" << endl ;
00754     }
00755     strm << DapIndent::LMarg << "map var: " << endl ;
00756     DapIndent::Indent() ;
00757     Map_citer i = _map_vars.begin() ;
00758     Map_citer ie = _map_vars.end() ;
00759     for (; i != ie; i++) {
00760         (*i)->dump(strm) ;
00761     }
00762     DapIndent::UnIndent() ;
00763     DapIndent::UnIndent() ;
00764 }
00765 

Generated on Wed Jun 27 12:56:39 2007 for libdap++ by  doxygen 1.4.7