libdap++
Updated for version 3.8.2
|
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 00222 unsigned int 00223 Grid::width(bool constrained) 00224 { 00225 unsigned int sz = 0; 00226 00227 if (constrained) { 00228 if (_array_var->send_p()) 00229 sz = _array_var->width(constrained); 00230 } 00231 else { 00232 sz = _array_var->width(constrained); 00233 } 00234 00235 for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) { 00236 if (constrained) { 00237 if ((*i)->send_p()) 00238 sz += (*i)->width(constrained); 00239 } 00240 else { 00241 sz += (*i)->width(constrained); 00242 } 00243 } 00244 00245 return sz; 00246 } 00247 00248 void 00249 Grid::intern_data(ConstraintEvaluator &eval, DDS &dds) 00250 { 00251 dds.timeout_on(); 00252 00253 if (!read_p()) 00254 read(); // read() throws Error and InternalErr 00255 00256 dds.timeout_off(); 00257 00258 if (_array_var->send_p()) 00259 _array_var->intern_data(eval, dds); 00260 00261 for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) { 00262 if ((*i)->send_p()) { 00263 (*i)->intern_data(eval, dds); 00264 } 00265 } 00266 } 00267 00268 bool 00269 Grid::serialize(ConstraintEvaluator &eval, DDS &dds, 00270 Marshaller &m, bool ce_eval) 00271 { 00272 dds.timeout_on(); 00273 00274 // Re ticket 560: Get an object from eval that describes how to sample 00275 // and rearrange the data, then perform those actions. Alternative: 00276 // implement this as a selection function. 00277 00278 if (!read_p()) 00279 read(); // read() throws Error and InternalErr 00280 00281 #if EVAL 00282 if (ce_eval && !eval.eval_selection(dds, dataset())) 00283 return true; 00284 #endif 00285 00286 dds.timeout_off(); 00287 00288 if (_array_var->send_p()) 00289 _array_var->serialize(eval, dds, m, false); 00290 00291 for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) { 00292 if ((*i)->send_p()) { 00293 (*i)->serialize(eval, dds, m, false); 00294 } 00295 } 00296 00297 return true; 00298 } 00299 00300 bool 00301 Grid::deserialize(UnMarshaller &um, DDS *dds, bool reuse) 00302 { 00303 _array_var->deserialize(um, dds, reuse); 00304 00305 for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) { 00306 (*i)->deserialize(um, dds, reuse); 00307 } 00308 00309 return false; 00310 } 00311 00319 unsigned int 00320 Grid::val2buf(void *, bool) 00321 { 00322 return sizeof(Grid); 00323 } 00324 00328 unsigned int 00329 Grid::buf2val(void **) 00330 { 00331 return sizeof(Grid); 00332 } 00333 00334 BaseType * 00335 Grid::var(const string &n, btp_stack &s) 00336 { 00337 return var(n, true, &s); 00338 } 00339 00344 BaseType * 00345 Grid::var(const string &n, bool, btp_stack *s) 00346 { 00347 string name = www2id(n); 00348 00349 if (_array_var->name() == name) { 00350 if (s) 00351 s->push(static_cast<BaseType *>(this)); 00352 return _array_var; 00353 } 00354 00355 for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) { 00356 if ((*i)->name() == name) { 00357 if (s) 00358 s->push(static_cast<BaseType *>(this)); 00359 return *i; 00360 } 00361 } 00362 00363 return 0; 00364 } 00365 00378 void 00379 Grid::add_var(BaseType *bt, Part part) 00380 { 00381 if (!bt) { 00382 throw InternalErr(__FILE__, __LINE__, 00383 "Passing NULL pointer as variable to be added."); 00384 } 00385 00386 if (part == array && _array_var) { 00387 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part. 00388 throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!"); 00389 } 00390 00391 // Set to the clone of bt if we get that far. 00392 BaseType* bt_clone = 0; 00393 00394 switch (part) { 00395 00396 case array: { 00397 // Refactored to use new set_array ([mjohnson 11 nov 2009]) 00398 Array* p_arr = dynamic_cast<Array*>(bt); 00399 // avoid obvious broken semantics 00400 if (!p_arr) { 00401 throw InternalErr(__FILE__, __LINE__, 00402 "Grid::add_var(): with Part==array: object is not an Array!"); 00403 } 00404 // Add it as a copy to preserve old semantics. This sets parent too. 00405 bt_clone = p_arr->ptr_duplicate(); 00406 set_array(static_cast<Array*>(bt_clone)); 00407 } 00408 break; 00409 00410 case maps: { 00411 bt_clone = bt->ptr_duplicate(); 00412 bt_clone->set_parent(this); 00413 _map_vars.push_back(bt_clone); 00414 } 00415 break; 00416 00417 default: { 00418 if (!_array_var) { 00419 // Refactored to use new set_array ([mjohnson 11 nov 2009]) 00420 Array* p_arr = dynamic_cast<Array*>(bt); 00421 // avoid obvious broken semantics 00422 if (!p_arr) { 00423 throw InternalErr(__FILE__, __LINE__, 00424 "Grid::add_var(): with Part==array: object is not an Array!"); 00425 } 00426 // Add it as a copy to preserve old semantics. This sets parent too. 00427 bt_clone = p_arr->ptr_duplicate(); 00428 set_array(static_cast<Array*>(bt_clone)); 00429 } 00430 else { 00431 bt_clone = bt->ptr_duplicate(); 00432 bt_clone->set_parent(this); 00433 _map_vars.push_back(bt_clone); 00434 } 00435 } 00436 break; 00437 }// switch 00438 00439 // if we get ehre without exception, add the cloned object to the superclass variable iterator 00440 // mjohnson 10 Sep 2009 00441 // Add it to the superclass _vars list so we can iterate on superclass vars 00442 if (bt_clone) { 00443 _vars.push_back(bt_clone); 00444 } 00445 } 00446 00462 void 00463 Grid::add_var_nocopy(BaseType *bt, Part part) 00464 { 00465 if (!bt) { 00466 throw InternalErr(__FILE__, __LINE__, 00467 "Passing NULL pointer as variable to be added."); 00468 } 00469 00470 if (part == array && _array_var) { 00471 // Avoid leaking memory... Function is add, not set, so it is an error to call again for the array part. 00472 throw InternalErr(__FILE__, __LINE__, "Error: Grid::add_var called with part==Array, but the array was already set!"); 00473 } 00474 00475 bt->set_parent(this); 00476 00477 switch (part) { 00478 00479 case array: { 00480 // Refactored to use new set_array ([mjohnson 11 nov 2009]) 00481 Array* p_arr = dynamic_cast<Array*>(bt); 00482 // avoid obvious broken semantics 00483 if (!p_arr) { 00484 throw InternalErr(__FILE__, __LINE__, 00485 "Grid::add_var(): with Part==array: object is not an Array!"); 00486 } 00487 set_array(static_cast<Array*>(bt)); 00488 } 00489 break; 00490 00491 case maps: { 00492 //bt->set_parent(this); 00493 _map_vars.push_back(bt); 00494 } 00495 break; 00496 00497 default: { 00498 if (!_array_var) { 00499 // Refactored to use new set_array ([mjohnson 11 nov 2009]) 00500 Array* p_arr = dynamic_cast<Array*>(bt); 00501 // avoid obvious broken semantics 00502 if (!p_arr) { 00503 throw InternalErr(__FILE__, __LINE__, 00504 "Grid::add_var(): with Part==array: object is not an Array!"); 00505 } 00506 set_array(static_cast<Array*>(bt)); 00507 } 00508 else { 00509 _map_vars.push_back(bt); 00510 } 00511 } 00512 break; 00513 }// switch 00514 00515 // if we get here without exception, add the cloned object to the superclass variable iterator 00516 // mjohnson 10 Sep 2009 00517 // Add it to the superclass _vars list so we can iterate on superclass vars 00518 if (bt) { 00519 _vars.push_back(bt); 00520 } 00521 } 00522 00532 void 00533 Grid::set_array(Array* p_new_arr) 00534 { 00535 if (!p_new_arr) { 00536 throw InternalErr(__FILE__, __LINE__, 00537 "Grid::set_array(): Cannot set to null!"); 00538 } 00539 // Make sure not same memory, this would be evil. 00540 if (p_new_arr == _array_var) { 00541 return; 00542 } 00543 // clean out any old array 00544 delete _array_var; _array_var = 0; 00545 // Set the new, with parent 00546 _array_var = p_new_arr; 00547 _array_var->set_parent(this); 00548 } 00549 00576 Array* 00577 Grid::add_map(Array* p_new_map, bool add_as_copy) 00578 { 00579 if (!p_new_map) { 00580 throw InternalErr(__FILE__, __LINE__, 00581 "Grid::add_map(): cannot have p_new_map null!"); 00582 } 00583 00584 if (add_as_copy) { 00585 p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate()); 00586 } 00587 00588 p_new_map->set_parent(this); 00589 _map_vars.push_back(p_new_map); 00590 _vars.push_back(p_new_map); // allow superclass iter to work as well. 00591 00592 // return the one that got put into the Grid. 00593 return p_new_map; 00594 } 00595 00608 Array* 00609 Grid::prepend_map(Array* p_new_map, bool add_copy) 00610 { 00611 if (add_copy) 00612 { 00613 p_new_map = static_cast<Array*>(p_new_map->ptr_duplicate()); 00614 } 00615 00616 p_new_map->set_parent(this); 00617 _map_vars.insert(_map_vars.begin(), p_new_map); 00618 _vars.insert(_vars.begin(), p_new_map); // allow superclass iter to work as well. 00619 00620 // return the one that got put into the Grid. 00621 return p_new_map; 00622 } 00623 00627 BaseType * 00628 Grid::array_var() 00629 { 00630 return _array_var; 00631 } 00632 00636 Array * 00637 Grid::get_array() 00638 { 00639 Array *a = dynamic_cast<Array*>(_array_var); 00640 if (a) 00641 return a; 00642 else 00643 throw InternalErr(__FILE__, __LINE__, "bad Cast"); 00644 } 00645 00647 Grid::Map_iter 00648 Grid::map_begin() 00649 { 00650 return _map_vars.begin() ; 00651 } 00652 00655 Grid::Map_iter 00656 Grid::map_end() 00657 { 00658 return _map_vars.end() ; 00659 } 00660 00662 Grid::Map_riter 00663 Grid::map_rbegin() 00664 { 00665 return _map_vars.rbegin() ; 00666 } 00667 00670 Grid::Map_riter 00671 Grid::map_rend() 00672 { 00673 return _map_vars.rend() ; 00674 } 00675 00679 Grid::Map_iter 00680 Grid::get_map_iter(int i) 00681 { 00682 return _map_vars.begin() + i; 00683 } 00684 00700 int 00701 Grid::components(bool constrained) 00702 { 00703 int comp; 00704 00705 if (constrained) { 00706 comp = _array_var->send_p() ? 1 : 0; 00707 00708 for (Map_iter i = _map_vars.begin(); i != _map_vars.end(); i++) { 00709 if ((*i)->send_p()) { 00710 comp++; 00711 } 00712 } 00713 } 00714 else { 00715 comp = 1 + _map_vars.size(); 00716 } 00717 00718 return comp; 00719 } 00720 00721 void Grid::transfer_attributes(AttrTable *at_container) 00722 { 00723 AttrTable *at = at_container->get_attr_table(name()); 00724 00725 if (at) { 00726 at->set_is_global_attribute(false); 00727 00728 array_var()->transfer_attributes(at); 00729 00730 Map_iter map = map_begin(); 00731 while (map != map_end()) { 00732 (*map)->transfer_attributes(at); 00733 map++; 00734 } 00735 00736 // Trick: If an attribute that's within the container 'at' still has its 00737 // is_global_attribute property set, then it's not really a global attr 00738 // but instead an attribute that belongs to this Grid. 00739 AttrTable::Attr_iter at_p = at->attr_begin(); 00740 while (at_p != at->attr_end()) { 00741 if (at->is_global_attribute(at_p)) { 00742 if (at->get_attr_type(at_p) == Attr_container) 00743 get_attr_table().append_container(new AttrTable( 00744 *at->get_attr_table(at_p)), at->get_name(at_p)); 00745 else 00746 get_attr_table().append_attr(at->get_name(at_p), 00747 at->get_type(at_p), at->get_attr_vector(at_p)); 00748 } 00749 00750 at_p++; 00751 } 00752 } 00753 } 00754 00755 // When projected (using whatever the current constraint provides in the way 00756 // of a projection), is the object still a Grid? 00757 00774 bool 00775 Grid::projection_yields_grid() 00776 { 00777 // For each dimension in the Array part, check the corresponding Map 00778 // vector to make sure it is present in the projected Grid. If for each 00779 // projected dimension in the Array component, there is a matching Map 00780 // vector, then the Grid is valid. 00781 bool valid = true; 00782 Array *a = (Array *)_array_var; 00783 00784 // Don't bother checking if the Array component is not included. 00785 if (!a->send_p()) 00786 return false; 00787 00788 // If only one part is being sent, it's clearly not a grid (it must be 00789 // the array part of the Grid that's being sent (given that the above 00790 // test passed and the array is being sent). 00791 if (components(true) == 1) 00792 return false; 00793 00794 Array::Dim_iter d = a->dim_begin() ; 00795 Map_iter m = map_begin() ; 00796 00797 while (valid && d != a->dim_end() && m != map_end()) { 00798 Array &map = dynamic_cast<Array&>(**m); 00799 if (a->dimension_size(d, true) && map.send_p()) { 00800 // Check the matching Map vector; the Map projection must equal 00801 // the Array dimension projection 00802 Array::Dim_iter fd = map.dim_begin(); // Maps have only one dim! 00803 valid = map.dimension_start(fd, true) == a->dimension_start(d, true) 00804 && map.dimension_stop(fd, true) == a->dimension_stop(d, true) 00805 && map.dimension_stride(fd, true) == a->dimension_stride(d, true); 00806 } 00807 else { 00808 valid = false; 00809 } 00810 00811 d++, m++; 00812 } 00813 00814 return valid; 00815 } 00816 00818 void 00819 Grid::clear_constraint() 00820 { 00821 dynamic_cast<Array&>(*_array_var).clear_constraint(); 00822 for (Map_iter m = map_begin(); m != map_end(); ++m) 00823 dynamic_cast<Array&>(*(*m)).clear_constraint(); 00824 } 00825 00826 #if FILE_METHODS 00827 void 00828 Grid::print_decl(FILE *out, string space, bool print_semi, 00829 bool constraint_info, bool constrained) 00830 { 00831 if (constrained && !send_p()) 00832 return; 00833 00834 // The problem with the above is that if two Grids are projected and each 00835 // contain one variable, say a map, and it happens to have the same name 00836 // in each Grid, then without the enclosing Structures, the returned dataset 00837 // has two variables with the same name at the same lexical level. So I'm 00838 // removing the code above. 00839 if (constrained && !projection_yields_grid()) { 00840 fprintf(out, "%sStructure {\n", space.c_str()) ; 00841 00842 _array_var->print_decl(out, space + " ", true, constraint_info, 00843 constrained); 00844 00845 for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) { 00846 (*i)->print_decl(out, space + " ", true, 00847 constraint_info, constrained); 00848 } 00849 00850 fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ; 00851 } 00852 else { 00853 // The number of elements in the (projected) Grid must be such that 00854 // we have a valid Grid object; send it as such. 00855 fprintf(out, "%s%s {\n", space.c_str(), type_name().c_str()) ; 00856 00857 fprintf(out, "%s Array:\n", space.c_str()) ; 00858 _array_var->print_decl(out, space + " ", true, constraint_info, 00859 constrained); 00860 00861 fprintf(out, "%s Maps:\n", space.c_str()) ; 00862 for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) { 00863 (*i)->print_decl(out, space + " ", true, 00864 constraint_info, constrained); 00865 } 00866 00867 fprintf(out, "%s} %s", space.c_str(), id2www(name()).c_str()) ; 00868 } 00869 00870 if (constraint_info) { 00871 if (send_p()) 00872 fprintf( out, ": Send True"); 00873 else 00874 fprintf( out, ": Send False"); 00875 } 00876 00877 if (print_semi) 00878 fprintf(out, ";\n") ; 00879 00880 return; 00881 } 00882 #endif 00883 00884 void 00885 Grid::print_decl(ostream &out, string space, bool print_semi, 00886 bool constraint_info, bool constrained) 00887 { 00888 if (constrained && !send_p()) 00889 return; 00890 00891 // See comment for the FILE* version of this method. 00892 if (constrained && !projection_yields_grid()) { 00893 out << space << "Structure {\n" ; 00894 00895 _array_var->print_decl(out, space + " ", true, constraint_info, 00896 constrained); 00897 00898 for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) { 00899 (*i)->print_decl(out, space + " ", true, 00900 constraint_info, constrained); 00901 } 00902 00903 out << space << "} " << id2www(name()) ; 00904 } 00905 else { 00906 // The number of elements in the (projected) Grid must be such that 00907 // we have a valid Grid object; send it as such. 00908 out << space << type_name() << " {\n" ; 00909 00910 out << space << " Array:\n" ; 00911 _array_var->print_decl(out, space + " ", true, constraint_info, 00912 constrained); 00913 00914 out << space << " Maps:\n" ; 00915 for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); i++) { 00916 (*i)->print_decl(out, space + " ", true, 00917 constraint_info, constrained); 00918 } 00919 00920 out << space << "} " << id2www(name()) ; 00921 } 00922 00923 if (constraint_info) { 00924 if (send_p()) 00925 out << ": Send True"; 00926 else 00927 out << ": Send False"; 00928 } 00929 00930 if (print_semi) 00931 out << ";\n" ; 00932 00933 return; 00934 } 00935 00936 #if FILE_METHODS 00937 class PrintMapField : public unary_function<BaseType *, void> 00938 { 00939 FILE *d_out; 00940 string d_space; 00941 bool d_constrained; 00942 string d_tag; 00943 public: 00944 PrintMapField(FILE *o, string s, bool c, const string &t = "Map") 00945 : d_out(o), d_space(s), d_constrained(c), d_tag(t) 00946 {} 00947 00948 void operator()(BaseType *btp) 00949 { 00950 Array *a = dynamic_cast<Array*>(btp); 00951 if (!a) 00952 throw InternalErr(__FILE__, __LINE__, "Expected an Array."); 00953 a->print_xml_core(d_out, d_space, d_constrained, d_tag); 00954 } 00955 }; 00956 00960 void 00961 Grid::print_xml(FILE *out, string space, bool constrained) 00962 { 00963 if (constrained && !send_p()) 00964 return; 00965 00966 if (constrained && !projection_yields_grid()) { 00967 fprintf(out, "%s<Structure", space.c_str()); 00968 if (!name().empty()) 00969 fprintf(out, " name=\"%s\"", id2xml(name()).c_str()); 00970 00971 fprintf(out, ">\n"); 00972 00973 get_attr_table().print_xml(out, space + " ", constrained); 00974 00975 get_array()->print_xml(out, space + " ", constrained); 00976 00977 for_each(map_begin(), map_end(), 00978 PrintMapField(out, space + " ", constrained, "Array")); 00979 00980 fprintf(out, "%s</Structure>\n", space.c_str()); 00981 } 00982 else { 00983 // The number of elements in the (projected) Grid must be such that 00984 // we have a valid Grid object; send it as such. 00985 fprintf(out, "%s<Grid", space.c_str()); 00986 if (!name().empty()) 00987 fprintf(out, " name=\"%s\"", id2xml(name()).c_str()); 00988 00989 fprintf(out, ">\n"); 00990 00991 get_attr_table().print_xml(out, space + " ", constrained); 00992 00993 get_array()->print_xml(out, space + " ", constrained); 00994 00995 for_each(map_begin(), map_end(), 00996 PrintMapField(out, space + " ", constrained)); 00997 00998 fprintf(out, "%s</Grid>\n", space.c_str()); 00999 } 01000 } 01001 #endif 01002 01003 class PrintMapFieldStrm : public unary_function<BaseType *, void> 01004 { 01005 ostream &d_out; 01006 string d_space; 01007 bool d_constrained; 01008 string d_tag; 01009 public: 01010 PrintMapFieldStrm(ostream &o, string s, bool c, const string &t = "Map") 01011 : d_out(o), d_space(s), d_constrained(c), d_tag(t) 01012 {} 01013 01014 void operator()(BaseType *btp) 01015 { 01016 Array *a = dynamic_cast<Array*>(btp); 01017 if (!a) 01018 throw InternalErr(__FILE__, __LINE__, "Expected an Array."); 01019 a->print_xml_core(d_out, d_space, d_constrained, d_tag); 01020 } 01021 }; 01022 01026 void 01027 Grid::print_xml(ostream &out, string space, bool constrained) 01028 { 01029 if (constrained && !send_p()) 01030 return; 01031 01032 if (constrained && !projection_yields_grid()) { 01033 out << space << "<Structure" ; 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, "Array")); 01045 01046 out << space << "</Structure>\n" ; 01047 } 01048 else { 01049 // The number of elements in the (projected) Grid must be such that 01050 // we have a valid Grid object; send it as such. 01051 out << space << "<Grid" ; 01052 if (!name().empty()) 01053 out << " name=\"" << id2xml(name()) << "\"" ; 01054 01055 out << ">\n" ; 01056 01057 get_attr_table().print_xml(out, space + " ", constrained); 01058 01059 get_array()->print_xml(out, space + " ", constrained); 01060 01061 for_each(map_begin(), map_end(), 01062 PrintMapFieldStrm(out, space + " ", constrained)); 01063 01064 out << space << "</Grid>\n" ; 01065 } 01066 } 01067 01068 01069 class PrintGridFieldXMLWriter : public unary_function<BaseType *, void> 01070 { 01071 XMLWriter &d_xml; 01072 bool d_constrained; 01073 string d_tag; 01074 public: 01075 PrintGridFieldXMLWriter(XMLWriter &x, bool c, const string &t = "Map") 01076 : d_xml(x), d_constrained(c), d_tag(t) 01077 {} 01078 01079 void operator()(BaseType *btp) 01080 { 01081 Array *a = dynamic_cast<Array*>(btp); 01082 if (!a) 01083 throw InternalErr(__FILE__, __LINE__, "Expected an Array."); 01084 a->print_xml_writer_core(d_xml, d_constrained, d_tag); 01085 } 01086 }; 01087 01088 void 01089 Grid::print_xml_writer(XMLWriter &xml, bool constrained) 01090 { 01091 if (constrained && !send_p()) 01092 return; 01093 01094 if (constrained && !projection_yields_grid()) { 01095 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Structure") < 0) 01096 throw InternalErr(__FILE__, __LINE__, "Could not write Structure element"); 01097 01098 if (!name().empty()) 01099 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0) 01100 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01101 01102 get_attr_table().print_xml_writer(xml); 01103 01104 get_array()->print_xml_writer(xml, constrained); 01105 01106 for_each(map_begin(), map_end(), 01107 PrintGridFieldXMLWriter(xml, constrained, "Array")); 01108 01109 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01110 throw InternalErr(__FILE__, __LINE__, "Could not end Structure element"); 01111 } 01112 else { 01113 // The number of elements in the (projected) Grid must be such that 01114 // we have a valid Grid object; send it as such. 01115 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"Grid") < 0) 01116 throw InternalErr(__FILE__, __LINE__, "Could not write Grid element"); 01117 01118 if (!name().empty()) 01119 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0) 01120 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 01121 01122 get_attr_table().print_xml_writer(xml); 01123 01124 get_array()->print_xml_writer(xml, constrained); 01125 01126 for_each(map_begin(), map_end(), 01127 PrintGridFieldXMLWriter(xml, constrained, "Map")); 01128 01129 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 01130 throw InternalErr(__FILE__, __LINE__, "Could not end Grid element"); 01131 } 01132 } 01133 01134 #if FILE_METHODS 01135 void 01136 Grid::print_val(FILE *out, string space, bool print_decl_p) 01137 { 01138 if (print_decl_p) { 01139 print_decl(out, space, false); 01140 fprintf(out, " = ") ; 01141 } 01142 01143 // If we are printing a value on the client-side, projection_yields_grid 01144 // should not be called since we don't *have* a projection without a 01145 // contraint. I think that if we are here and send_p() is not true, then 01146 // the value of this function should be ignored. 4/6/2000 jhrg 01147 bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg 01148 if (pyg || !send_p()) 01149 fprintf(out, "{ Array: ") ; 01150 else 01151 fprintf(out, "{") ; 01152 _array_var->print_val(out, "", false); 01153 if (pyg || !send_p()) 01154 fprintf(out, " Maps: ") ; 01155 for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); 01156 i++, (void)(i != _map_vars.end() && fprintf(out, ", "))) { 01157 (*i)->print_val(out, "", false); 01158 } 01159 fprintf(out, " }") ; 01160 01161 if (print_decl_p) 01162 fprintf(out, ";\n") ; 01163 } 01164 #endif 01165 01166 void 01167 Grid::print_val(ostream &out, string space, bool print_decl_p) 01168 { 01169 if (print_decl_p) { 01170 print_decl(out, space, false); 01171 out << " = " ; 01172 } 01173 01174 // If we are printing a value on the client-side, projection_yields_grid 01175 // should not be called since we don't *have* a projection without a 01176 // Constraint. I think that if we are here and send_p() is not true, then 01177 // the value of this function should be ignored. 4/6/2000 jhrg 01178 bool pyg = projection_yields_grid(); // hack 12/1/99 jhrg 01179 if (pyg || !send_p()) 01180 out << "{ Array: " ; 01181 else 01182 out << "{" ; 01183 _array_var->print_val(out, "", false); 01184 if (pyg || !send_p()) 01185 out << " Maps: " ; 01186 for (Map_citer i = _map_vars.begin(); i != _map_vars.end(); 01187 i++, (void)(i != _map_vars.end() && out << ", ")) { 01188 (*i)->print_val(out, "", false); 01189 } 01190 out << " }" ; 01191 01192 if (print_decl_p) 01193 out << ";\n" ; 01194 } 01195 01196 // Grids have ugly semantics. 01197 01202 bool 01203 Grid::check_semantics(string &msg, bool all) 01204 { 01205 if (!BaseType::check_semantics(msg)) 01206 return false; 01207 01208 msg = ""; 01209 01210 if (!_array_var) { 01211 msg += "Null grid base array in `" + name() + "'\n"; 01212 return false; 01213 } 01214 01215 // Is it an array? 01216 if (_array_var->type() != dods_array_c) { 01217 msg += "Grid `" + name() + "'s' member `" + _array_var->name() + "' must be an array\n"; 01218 return false; 01219 } 01220 01221 Array *av = (Array *)_array_var; // past test above, must be an array 01222 01223 // Array must be of a simple_type. 01224 if (!av->var()->is_simple_type()) { 01225 msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n"; 01226 return false; 01227 } 01228 01229 // enough maps? 01230 if ((unsigned)_map_vars.size() != av->dimensions()) { 01231 msg += "The number of map variables for grid `" + this->name() + "' does not match the number of dimensions of `"; 01232 msg += av->name() + "'\n"; 01233 return false; 01234 } 01235 01236 const string array_var_name = av->name(); 01237 Array::Dim_iter asi = av->dim_begin() ; 01238 for (Map_iter mvi = _map_vars.begin(); 01239 mvi != _map_vars.end(); mvi++, asi++) { 01240 01241 BaseType *mv = *mvi; 01242 01243 // check names 01244 if (array_var_name == mv->name()) { 01245 msg += "Grid map variable `" + mv->name() + "' conflicts with the grid array name in grid `" + name() + "'\n"; 01246 return false; 01247 } 01248 // check types 01249 if (mv->type() != dods_array_c) { 01250 msg += "Grid map variable `" + mv->name() + "' is not an array\n"; 01251 return false; 01252 } 01253 01254 Array *mv_a = (Array *)mv; // downcast to (Array *) 01255 01256 // Array must be of a simple_type. 01257 if (!mv_a->var()->is_simple_type()) { 01258 msg += "The field variable `" + this->name() + "' must be an array of simple type elements (e.g., int32, String)\n"; 01259 return false; 01260 } 01261 01262 // check shape 01263 if (mv_a->dimensions() != 1) {// maps must have one dimension 01264 msg += "Grid map variable `" + mv_a->name() + "' must be only one dimension\n"; 01265 return false; 01266 } 01267 // size of map must match corresponding array dimension 01268 Array::Dim_iter mv_asi = mv_a->dim_begin() ; 01269 int mv_a_size = mv_a->dimension_size(mv_asi) ; 01270 int av_size = av->dimension_size(asi) ; 01271 if (mv_a_size != av_size) { 01272 msg += "Grid map variable `" + mv_a->name() + "'s' size does not match the size of array variable '"; 01273 msg += _array_var->name() + "'s' cooresponding dimension\n"; 01274 return false; 01275 } 01276 } 01277 01278 if (all) { 01279 if (!_array_var->check_semantics(msg, true)) 01280 return false; 01281 for (Map_iter mvi = _map_vars.begin(); mvi != _map_vars.end(); mvi++) { 01282 if (!(*mvi)->check_semantics(msg, true)) { 01283 return false; 01284 } 01285 } 01286 } 01287 01288 return true; 01289 } 01290 01299 void 01300 Grid::dump(ostream &strm) const 01301 { 01302 strm << DapIndent::LMarg << "Grid::dump - (" 01303 << (void *)this << ")" << endl ; 01304 DapIndent::Indent() ; 01305 Constructor::dump(strm) ; 01306 if (_array_var) { 01307 strm << DapIndent::LMarg << "array var: " << endl ; 01308 DapIndent::Indent() ; 01309 _array_var->dump(strm) ; 01310 DapIndent::UnIndent() ; 01311 } 01312 else { 01313 strm << DapIndent::LMarg << "array var: null" << endl ; 01314 } 01315 strm << DapIndent::LMarg << "map var: " << endl ; 01316 DapIndent::Indent() ; 01317 Map_citer i = _map_vars.begin() ; 01318 Map_citer ie = _map_vars.end() ; 01319 for (; i != ie; i++) { 01320 (*i)->dump(strm) ; 01321 } 01322 DapIndent::UnIndent() ; 01323 DapIndent::UnIndent() ; 01324 } 01325 01326 } // namespace libdap 01327