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 Array. 00033 // 00034 // jhrg 9/13/94 00035 00036 00037 #include "config.h" 00038 00039 #include "Array.h" 00040 #include "util.h" 00041 #include "debug.h" 00042 #include "InternalErr.h" 00043 #include "escaping.h" 00044 00045 #include <algorithm> 00046 #include <functional> 00047 00048 using namespace std; 00049 00050 namespace libdap { 00051 00052 void 00053 Array::_duplicate(const Array &a) 00054 { 00055 _shape = a._shape; 00056 } 00057 00058 // The first method of calculating length works when only one dimension is 00059 // constrained and you want the others to appear in total. This is important 00060 // when selecting from grids since users may not select from all dimensions 00061 // in which case that means they want the whole thing. Array projection 00062 // should probably work this way too, but it doesn't. 9/21/2001 jhrg 00063 00071 void 00072 Array::update_length(int) 00073 { 00074 int length = 1; 00075 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00076 length *= (*i).c_size > 0 ? (*i).c_size : 1; 00077 } 00078 00079 set_length(length); 00080 } 00081 00082 // Construct an instance of Array. The (BaseType *) is assumed to be 00083 // allocated using new - The dtor for Vector will delete this object. 00084 00100 Array::Array(const string &n, BaseType *v) : Vector(n, 0, dods_array_c) 00101 { 00102 add_var(v); // Vector::add_var() stores null is v is null 00103 } 00104 00118 Array::Array(const string &n, const string &d, BaseType *v) 00119 : Vector(n, d, 0, dods_array_c) 00120 { 00121 add_var(v); // Vector::add_var() stores null is v is null 00122 } 00123 00125 Array::Array(const Array &rhs) : Vector(rhs) 00126 { 00127 _duplicate(rhs); 00128 } 00129 00131 Array::~Array() 00132 { 00133 DBG(cerr << "Entering ~Array (" << this << ")" << endl); 00134 DBG(cerr << "Exiting ~Array" << endl); 00135 } 00136 00137 BaseType * 00138 Array::ptr_duplicate() 00139 { 00140 return new Array(*this); 00141 } 00142 00143 Array & 00144 Array::operator=(const Array &rhs) 00145 { 00146 if (this == &rhs) 00147 return *this; 00148 00149 dynamic_cast<Vector &>(*this) = rhs; 00150 00151 _duplicate(rhs); 00152 00153 return *this; 00154 } 00155 00175 void 00176 Array::add_var(BaseType *v, Part) 00177 { 00178 if (v && v->type() == dods_array_c) { 00179 Array &a = dynamic_cast<Array&>(*v); 00180 Vector::add_var(a.var()); 00181 Dim_iter i = a.dim_begin(); 00182 Dim_iter i_end = a.dim_end(); 00183 while (i != i_end) { 00184 append_dim(a.dimension_size(i), a.dimension_name(i)); 00185 ++i; 00186 } 00187 } 00188 else { 00189 Vector::add_var(v); 00190 } 00191 } 00192 00204 void 00205 Array::append_dim(int size, string name) 00206 { 00207 dimension d; 00208 00209 // This is invariant 00210 d.size = size; 00211 d.name = www2id(name); 00212 00213 // this information changes with each constraint expression 00214 d.start = 0; 00215 d.stop = size - 1; 00216 d.stride = 1; 00217 d.c_size = size; 00218 00219 _shape.push_back(d); 00220 00221 update_length(size); 00222 } 00223 00230 void 00231 Array::reset_constraint() 00232 { 00233 set_length(-1); 00234 00235 for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) { 00236 (*i).start = 0; 00237 (*i).stop = (*i).size - 1; 00238 (*i).stride = 1; 00239 (*i).c_size = (*i).size; 00240 00241 update_length((*i).size); 00242 } 00243 } 00244 00245 00255 void 00256 Array::clear_constraint() 00257 { 00258 reset_constraint(); 00259 } 00260 00261 // Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n 00262 // is explicit. 00263 static const char *array_sss = \ 00264 "Invalid constraint parameters: At least one of the start, stride or stop \n\ 00265 specified do not match the array variable."; 00266 00286 void 00287 Array::add_constraint(Dim_iter i, int start, int stride, int stop) 00288 { 00289 dimension &d = *i ; 00290 00291 // Check for bad constraints. 00292 // Jose Garcia 00293 // Usually invalid data for a constraint is the user's mistake 00294 // because they build a wrong URL in the client side. 00295 if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0) 00296 throw Error(malformed_expr, array_sss); 00297 00298 if (((stop - start) / stride + 1) > d.size) 00299 throw Error(malformed_expr, array_sss); 00300 00301 d.start = start; 00302 d.stop = stop; 00303 d.stride = stride; 00304 00305 d.c_size = (stop - start) / stride + 1; 00306 00307 DBG(cerr << "add_constraint: c_size = " << d.c_size << endl); 00308 00309 update_length(d.c_size); 00310 } 00311 00313 Array::Dim_iter 00314 Array::dim_begin() 00315 { 00316 return _shape.begin() ; 00317 } 00318 00320 Array::Dim_iter 00321 Array::dim_end() 00322 { 00323 return _shape.end() ; 00324 } 00325 00335 unsigned int 00336 Array::dimensions(bool /*constrained*/) 00337 { 00338 unsigned int dim = 0; 00339 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00340 dim++; 00341 } 00342 00343 return dim; 00344 } 00345 00363 int 00364 Array::dimension_size(Dim_iter i, bool constrained) 00365 { 00366 int size = 0; 00367 00368 if (!_shape.empty()) { 00369 if (constrained) 00370 size = (*i).c_size; 00371 else 00372 size = (*i).size; 00373 } 00374 00375 return size; 00376 } 00377 00396 int 00397 Array::dimension_start(Dim_iter i, bool /*constrained*/) 00398 { 00399 return (!_shape.empty()) ? (*i).start : 0; 00400 } 00401 00420 int 00421 Array::dimension_stop(Dim_iter i, bool /*constrained*/) 00422 { 00423 return (!_shape.empty()) ? (*i).stop : 0; 00424 } 00425 00445 int 00446 Array::dimension_stride(Dim_iter i, bool /*constrained*/) 00447 { 00448 return (!_shape.empty()) ? (*i).stride : 0; 00449 } 00450 00461 string 00462 Array::dimension_name(Dim_iter i) 00463 { 00464 // Jose Garcia 00465 // Since this method is public, it is possible for a user 00466 // to call it before the Array object has been properly set 00467 // this will cause an exception which is the user's fault. 00468 // (User in this context is the developer of the surrogate library.) 00469 if (_shape.empty()) 00470 throw InternalErr(__FILE__, __LINE__, 00471 "*This* array has no dimensions."); 00472 return (*i).name; 00473 } 00474 //#if FILE_METHODS 00492 void 00493 Array::print_decl(FILE *out, string space, bool print_semi, 00494 bool constraint_info, bool constrained) 00495 { 00496 if (constrained && !send_p()) 00497 return; 00498 00499 // print it, but w/o semicolon 00500 var()->print_decl(out, space, false, constraint_info, constrained); 00501 00502 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00503 fprintf(out, "[") ; 00504 if ((*i).name != "") { 00505 fprintf(out, "%s = ", id2www((*i).name).c_str()) ; 00506 } 00507 if (constrained) { 00508 fprintf(out, "%d]", (*i).c_size) ; 00509 } 00510 else { 00511 fprintf(out, "%d]", (*i).size) ; 00512 } 00513 } 00514 00515 if (print_semi) { 00516 fprintf(out, ";\n") ; 00517 } 00518 } 00519 //#endif 00537 void 00538 Array::print_decl(ostream &out, string space, bool print_semi, 00539 bool constraint_info, bool constrained) 00540 { 00541 if (constrained && !send_p()) 00542 return; 00543 00544 // print it, but w/o semicolon 00545 var()->print_decl(out, space, false, constraint_info, constrained); 00546 00547 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00548 out << "[" ; 00549 if ((*i).name != "") { 00550 out << id2www((*i).name) << " = " ; 00551 } 00552 if (constrained) { 00553 out << (*i).c_size << "]" ; 00554 } 00555 else { 00556 out << (*i).size << "]" ; 00557 } 00558 } 00559 00560 if (print_semi) { 00561 out << ";\n" ; 00562 } 00563 } 00564 //#if FILE_METHODS 00565 void 00566 Array::print_xml(FILE *out, string space, bool constrained) 00567 { 00568 print_xml_core(out, space, constrained, "Array"); 00569 } 00570 //#endif 00571 void 00572 Array::print_xml(ostream &out, string space, bool constrained) 00573 { 00574 print_xml_core(out, space, constrained, "Array"); 00575 } 00576 //#if FILE_METHODS 00577 void 00578 Array::print_as_map_xml(FILE *out, string space, bool constrained) 00579 { 00580 print_xml_core(out, space, constrained, "Map"); 00581 } 00582 //#endif 00583 void 00584 Array::print_as_map_xml(ostream &out, string space, bool constrained) 00585 { 00586 print_xml_core(out, space, constrained, "Map"); 00587 } 00588 //#if FILE_METHODS 00589 class PrintArrayDim : public unary_function<Array::dimension&, void> 00590 { 00591 FILE *d_out; 00592 string d_space; 00593 bool d_constrained; 00594 public: 00595 PrintArrayDim(FILE *o, string s, bool c) 00596 : d_out(o), d_space(s), d_constrained(c) 00597 {} 00598 00599 void operator()(Array::dimension &d) 00600 { 00601 int size = d_constrained ? d.c_size : d.size; 00602 if (d.name.empty()) 00603 fprintf(d_out, "%s<dimension size=\"%d\"/>\n", d_space.c_str(), 00604 size); 00605 else 00606 fprintf(d_out, "%s<dimension name=\"%s\" size=\"%d\"/>\n", 00607 d_space.c_str(), id2xml(d.name).c_str(), size); 00608 } 00609 }; 00610 00611 void 00612 Array::print_xml_core(FILE *out, string space, bool constrained, string tag) 00613 { 00614 if (constrained && !send_p()) 00615 return; 00616 00617 fprintf(out, "%s<%s", space.c_str(), tag.c_str()); 00618 if (!name().empty()) 00619 fprintf(out, " name=\"%s\"", id2xml(name()).c_str()); 00620 fprintf(out , ">\n"); 00621 00622 get_attr_table().print_xml(out, space + " ", constrained); 00623 00624 BaseType *btp = var(); 00625 string tmp_name = btp->name(); 00626 btp->set_name(""); 00627 btp->print_xml(out, space + " ", constrained); 00628 btp->set_name(tmp_name); 00629 00630 for_each(dim_begin(), dim_end(), 00631 PrintArrayDim(out, space + " ", constrained)); 00632 00633 fprintf(out, "%s</%s>\n", space.c_str(), tag.c_str()); 00634 } 00635 //#endif 00636 class PrintArrayDimStrm : public unary_function<Array::dimension&, void> 00637 { 00638 ostream &d_out; 00639 string d_space; 00640 bool d_constrained; 00641 public: 00642 PrintArrayDimStrm(ostream &o, string s, bool c) 00643 : d_out(o), d_space(s), d_constrained(c) 00644 {} 00645 00646 void operator()(Array::dimension &d) 00647 { 00648 int size = d_constrained ? d.c_size : d.size; 00649 if (d.name.empty()) 00650 d_out << d_space << "<dimension size=\"" << size << "\"/>\n" ; 00651 else 00652 d_out << d_space << "<dimension name=\"" << id2xml(d.name) 00653 << "\" size=\"" << size << "\"/>\n" ; 00654 } 00655 }; 00656 00657 void 00658 Array::print_xml_core(ostream &out, string space, bool constrained, string tag) 00659 { 00660 if (constrained && !send_p()) 00661 return; 00662 00663 out << space << "<" << tag ; 00664 if (!name().empty()) 00665 out << " name=\"" << id2xml(name()) << "\"" ; 00666 out << ">\n" ; 00667 00668 get_attr_table().print_xml(out, space + " ", constrained); 00669 00670 BaseType *btp = var(); 00671 string tmp_name = btp->name(); 00672 btp->set_name(""); 00673 btp->print_xml(out, space + " ", constrained); 00674 btp->set_name(tmp_name); 00675 00676 for_each(dim_begin(), dim_end(), 00677 PrintArrayDimStrm(out, space + " ", constrained)); 00678 00679 out << space << "</" << tag << ">\n" ; 00680 } 00681 //#if FILE_METHODS 00692 unsigned int 00693 Array::print_array(FILE *out, unsigned int index, unsigned int dims, 00694 unsigned int shape[]) 00695 { 00696 if (dims == 1) { 00697 fprintf(out, "{") ; 00698 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00699 var(index++)->print_val(out, "", false); 00700 fprintf(out, ", ") ; 00701 } 00702 var(index++)->print_val(out, "", false); 00703 fprintf(out, "}") ; 00704 00705 return index; 00706 } 00707 else { 00708 fprintf(out, "{") ; 00709 // Fixed an off-by-one error in the following loop. Since the array 00710 // length is shape[dims-1]-1 *and* since we want one less dimension 00711 // than that, the correct limit on this loop is shape[dims-2]-1. From 00712 // Todd Karakasian. 00713 // The saga continues; the loop test should be `i < shape[0]-1'. jhrg 00714 // 9/12/96. 00715 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00716 index = print_array(out, index, dims - 1, shape + 1); 00717 fprintf(out, ",") ; // Removed the extra `}'. Also from Todd 00718 } 00719 index = print_array(out, index, dims - 1, shape + 1); 00720 fprintf(out, "}") ; 00721 00722 return index; 00723 } 00724 } 00725 //#endif 00736 unsigned int 00737 Array::print_array(ostream &out, unsigned int index, unsigned int dims, 00738 unsigned int shape[]) 00739 { 00740 if (dims == 1) { 00741 out << "{" ; 00742 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00743 var(index++)->print_val(out, "", false); 00744 out << ", " ; 00745 } 00746 var(index++)->print_val(out, "", false); 00747 out << "}" ; 00748 00749 return index; 00750 } 00751 else { 00752 out << "{" ; 00753 // Fixed an off-by-one error in the following loop. Since the array 00754 // length is shape[dims-1]-1 *and* since we want one less dimension 00755 // than that, the correct limit on this loop is shape[dims-2]-1. From 00756 // Todd Karakasian. 00757 // The saga continues; the loop test should be `i < shape[0]-1'. jhrg 00758 // 9/12/96. 00759 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00760 index = print_array(out, index, dims - 1, shape + 1); 00761 out << "," ; 00762 } 00763 index = print_array(out, index, dims - 1, shape + 1); 00764 out << "}" ; 00765 00766 return index; 00767 } 00768 } 00769 //#if FILE_METHODS 00770 void 00771 Array::print_val(FILE *out, string space, bool print_decl_p) 00772 { 00773 // print the declaration if print decl is true. 00774 // for each dimension, 00775 // for each element, 00776 // print the array given its shape, number of dimensions. 00777 // Add the `;' 00778 00779 if (print_decl_p) { 00780 print_decl(out, space, false, false, false); 00781 fprintf(out, " = ") ; 00782 } 00783 00784 unsigned int *shape = new unsigned int[_shape.size()]; 00785 unsigned int index = 0; 00786 for (Dim_iter i = _shape.begin(); i != _shape.end() && index < _shape.size(); i++) 00787 shape[index++] = dimension_size(i, true); 00788 00789 print_array(out, 0, _shape.size(), shape); 00790 00791 delete [] shape; shape = 0; 00792 00793 if (print_decl_p) { 00794 fprintf(out, ";\n") ; 00795 } 00796 } 00797 //#endif 00798 void 00799 Array::print_val(ostream &out, string space, bool print_decl_p) 00800 { 00801 // print the declaration if print decl is true. 00802 // for each dimension, 00803 // for each element, 00804 // print the array given its shape, number of dimensions. 00805 // Add the `;' 00806 00807 if (print_decl_p) { 00808 print_decl(out, space, false, false, false); 00809 out << " = " ; 00810 } 00811 00812 unsigned int *shape = new unsigned int[dimensions(true)]; 00813 unsigned int index = 0; 00814 for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i) 00815 shape[index++] = dimension_size(i, true); 00816 00817 print_array(out, 0, dimensions(true), shape); 00818 00819 delete [] shape; shape = 0; 00820 00821 if (print_decl_p) { 00822 out << ";\n" ; 00823 } 00824 } 00825 00835 bool 00836 Array::check_semantics(string &msg, bool) 00837 { 00838 bool sem = BaseType::check_semantics(msg) && !_shape.empty(); 00839 00840 if (!sem) 00841 msg = "An array variable must have dimensions"; 00842 00843 return sem; 00844 } 00845 00854 void 00855 Array::dump(ostream &strm) const 00856 { 00857 strm << DapIndent::LMarg << "Array::dump - (" 00858 << (void *)this << ")" << endl ; 00859 DapIndent::Indent() ; 00860 Vector::dump(strm) ; 00861 strm << DapIndent::LMarg << "shape:" << endl ; 00862 DapIndent::Indent() ; 00863 Dim_citer i = _shape.begin() ; 00864 Dim_citer ie = _shape.end() ; 00865 unsigned int dim_num = 0 ; 00866 for (; i != ie; i++) { 00867 strm << DapIndent::LMarg << "dimension " << dim_num++ << ":" 00868 << endl ; 00869 DapIndent::Indent() ; 00870 strm << DapIndent::LMarg << "name: " << (*i).name << endl ; 00871 strm << DapIndent::LMarg << "size: " << (*i).size << endl ; 00872 strm << DapIndent::LMarg << "start: " << (*i).start << endl ; 00873 strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ; 00874 strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ; 00875 strm << DapIndent::LMarg << "constrained size: " << (*i).c_size 00876 << endl ; 00877 DapIndent::UnIndent() ; 00878 } 00879 DapIndent::UnIndent() ; 00880 DapIndent::UnIndent() ; 00881 } 00882 00883 } // namespace libdap 00884