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 <algorithm> 00040 #include <functional> 00041 #include <sstream> 00042 00043 #include "Array.h" 00044 #include "util.h" 00045 #include "debug.h" 00046 #include "InternalErr.h" 00047 #include "escaping.h" 00048 00049 using namespace std; 00050 00051 namespace libdap { 00052 00053 void 00054 Array::_duplicate(const Array &a) 00055 { 00056 _shape = a._shape; 00057 } 00058 00059 // The first method of calculating length works when only one dimension is 00060 // constrained and you want the others to appear in total. This is important 00061 // when selecting from grids since users may not select from all dimensions 00062 // in which case that means they want the whole thing. Array projection 00063 // should probably work this way too, but it doesn't. 9/21/2001 jhrg 00064 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 00229 void 00230 Array::prepend_dim(int size, const string& name/* = "" */) 00231 { 00232 dimension d; 00233 00234 // This is invariant 00235 d.size = size; 00236 d.name = www2id(name); 00237 00238 // this information changes with each constraint expression 00239 d.start = 0; 00240 d.stop = size - 1; 00241 d.stride = 1; 00242 d.c_size = size; 00243 00244 // Shifts the whole array, but it's tiny in general 00245 _shape.insert(_shape.begin(), d); 00246 00247 update_length(size); // the number is ignored... 00248 } 00249 00256 void 00257 Array::reset_constraint() 00258 { 00259 set_length(-1); 00260 00261 for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) { 00262 (*i).start = 0; 00263 (*i).stop = (*i).size - 1; 00264 (*i).stride = 1; 00265 (*i).c_size = (*i).size; 00266 00267 update_length((*i).size); 00268 } 00269 } 00270 00271 00281 void 00282 Array::clear_constraint() 00283 { 00284 reset_constraint(); 00285 } 00286 00287 // Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n 00288 // is explicit. 00289 static const char *array_sss = \ 00290 "Invalid constraint parameters: At least one of the start, stride or stop \n\ 00291 specified do not match the array variable."; 00292 00312 void 00313 Array::add_constraint(Dim_iter i, int start, int stride, int stop) 00314 { 00315 dimension &d = *i ; 00316 00317 // Check for bad constraints. 00318 // Jose Garcia 00319 // Usually invalid data for a constraint is the user's mistake 00320 // because they build a wrong URL in the client side. 00321 if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0) 00322 throw Error(malformed_expr, array_sss); 00323 00324 if (((stop - start) / stride + 1) > d.size) 00325 throw Error(malformed_expr, array_sss); 00326 00327 d.start = start; 00328 d.stop = stop; 00329 d.stride = stride; 00330 00331 d.c_size = (stop - start) / stride + 1; 00332 00333 DBG(cerr << "add_constraint: c_size = " << d.c_size << endl); 00334 00335 update_length(d.c_size); 00336 } 00337 00339 Array::Dim_iter 00340 Array::dim_begin() 00341 { 00342 return _shape.begin() ; 00343 } 00344 00346 Array::Dim_iter 00347 Array::dim_end() 00348 { 00349 return _shape.end() ; 00350 } 00351 00361 unsigned int 00362 Array::dimensions(bool /*constrained*/) 00363 { 00364 unsigned int dim = 0; 00365 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00366 dim++; 00367 } 00368 00369 return dim; 00370 } 00371 00389 int 00390 Array::dimension_size(Dim_iter i, bool constrained) 00391 { 00392 int size = 0; 00393 00394 if (!_shape.empty()) { 00395 if (constrained) 00396 size = (*i).c_size; 00397 else 00398 size = (*i).size; 00399 } 00400 00401 return size; 00402 } 00403 00422 int 00423 Array::dimension_start(Dim_iter i, bool /*constrained*/) 00424 { 00425 return (!_shape.empty()) ? (*i).start : 0; 00426 } 00427 00446 int 00447 Array::dimension_stop(Dim_iter i, bool /*constrained*/) 00448 { 00449 return (!_shape.empty()) ? (*i).stop : 0; 00450 } 00451 00471 int 00472 Array::dimension_stride(Dim_iter i, bool /*constrained*/) 00473 { 00474 return (!_shape.empty()) ? (*i).stride : 0; 00475 } 00476 00487 string 00488 Array::dimension_name(Dim_iter i) 00489 { 00490 // Jose Garcia 00491 // Since this method is public, it is possible for a user 00492 // to call it before the Array object has been properly set 00493 // this will cause an exception which is the user's fault. 00494 // (User in this context is the developer of the surrogate library.) 00495 if (_shape.empty()) 00496 throw InternalErr(__FILE__, __LINE__, 00497 "*This* array has no dimensions."); 00498 return (*i).name; 00499 } 00500 00504 unsigned int Array::width(bool constrained) 00505 { 00506 00507 if (constrained) { 00508 // This preserves the original method's semantics when we ask for the 00509 // size of the constrained array but no constraint has been applied. 00510 // In this case, length will be -1. Wrong, I know... 00511 return length() * var()->width(constrained); 00512 } 00513 else { 00514 int length = 1; 00515 for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) { 00516 length *= dimension_size(i, false); 00517 } 00518 return length * var()->width(false); 00519 } 00520 } 00521 00522 00523 #if FILE_METHODS 00524 00541 void 00542 Array::print_decl(FILE *out, string space, bool print_semi, 00543 bool constraint_info, bool constrained) 00544 { 00545 if (constrained && !send_p()) 00546 return; 00547 00548 // print it, but w/o semicolon 00549 var()->print_decl(out, space, false, constraint_info, constrained); 00550 00551 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00552 fprintf(out, "[") ; 00553 if ((*i).name != "") { 00554 fprintf(out, "%s = ", id2www((*i).name).c_str()) ; 00555 } 00556 if (constrained) { 00557 fprintf(out, "%d]", (*i).c_size) ; 00558 } 00559 else { 00560 fprintf(out, "%d]", (*i).size) ; 00561 } 00562 } 00563 00564 if (print_semi) { 00565 fprintf(out, ";\n") ; 00566 } 00567 } 00568 #endif 00569 00587 void 00588 Array::print_decl(ostream &out, string space, bool print_semi, 00589 bool constraint_info, bool constrained) 00590 { 00591 if (constrained && !send_p()) 00592 return; 00593 00594 // print it, but w/o semicolon 00595 var()->print_decl(out, space, false, constraint_info, constrained); 00596 00597 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00598 out << "[" ; 00599 if ((*i).name != "") { 00600 out << id2www((*i).name) << " = " ; 00601 } 00602 if (constrained) { 00603 out << (*i).c_size << "]" ; 00604 } 00605 else { 00606 out << (*i).size << "]" ; 00607 } 00608 } 00609 00610 if (print_semi) { 00611 out << ";\n" ; 00612 } 00613 } 00614 #if FILE_METHODS 00615 00618 void 00619 Array::print_xml(FILE *out, string space, bool constrained) 00620 { 00621 print_xml_core(out, space, constrained, "Array"); 00622 } 00623 #endif 00624 00628 void 00629 Array::print_xml(ostream &out, string space, bool constrained) 00630 { 00631 print_xml_core(out, space, constrained, "Array"); 00632 } 00633 00634 #if FILE_METHODS 00635 00638 void 00639 Array::print_as_map_xml(FILE *out, string space, bool constrained) 00640 { 00641 print_xml_core(out, space, constrained, "Map"); 00642 } 00643 #endif 00644 00648 void 00649 Array::print_as_map_xml(ostream &out, string space, bool constrained) 00650 { 00651 print_xml_core(out, space, constrained, "Map"); 00652 } 00653 00654 #if FILE_METHODS 00655 class PrintArrayDim : public unary_function<Array::dimension&, void> 00656 { 00657 FILE *d_out; 00658 string d_space; 00659 bool d_constrained; 00660 public: 00661 PrintArrayDim(FILE *o, string s, bool c) 00662 : d_out(o), d_space(s), d_constrained(c) 00663 {} 00664 00665 void operator()(Array::dimension &d) 00666 { 00667 int size = d_constrained ? d.c_size : d.size; 00668 if (d.name.empty()) 00669 fprintf(d_out, "%s<dimension size=\"%d\"/>\n", d_space.c_str(), 00670 size); 00671 else 00672 fprintf(d_out, "%s<dimension name=\"%s\" size=\"%d\"/>\n", 00673 d_space.c_str(), id2xml(d.name).c_str(), size); 00674 } 00675 }; 00676 00680 void 00681 Array::print_xml_core(FILE *out, string space, bool constrained, string tag) 00682 { 00683 if (constrained && !send_p()) 00684 return; 00685 00686 fprintf(out, "%s<%s", space.c_str(), tag.c_str()); 00687 if (!name().empty()) 00688 fprintf(out, " name=\"%s\"", id2xml(name()).c_str()); 00689 fprintf(out , ">\n"); 00690 00691 get_attr_table().print_xml(out, space + " ", constrained); 00692 00693 BaseType *btp = var(); 00694 string tmp_name = btp->name(); 00695 btp->set_name(""); 00696 btp->print_xml(out, space + " ", constrained); 00697 btp->set_name(tmp_name); 00698 00699 for_each(dim_begin(), dim_end(), 00700 PrintArrayDim(out, space + " ", constrained)); 00701 00702 fprintf(out, "%s</%s>\n", space.c_str(), tag.c_str()); 00703 } 00704 #endif 00705 00706 class PrintArrayDimStrm : public unary_function<Array::dimension&, void> 00707 { 00708 ostream &d_out; 00709 string d_space; 00710 bool d_constrained; 00711 public: 00712 PrintArrayDimStrm(ostream &o, string s, bool c) 00713 : d_out(o), d_space(s), d_constrained(c) 00714 {} 00715 00716 void operator()(Array::dimension &d) 00717 { 00718 int size = d_constrained ? d.c_size : d.size; 00719 if (d.name.empty()) 00720 d_out << d_space << "<dimension size=\"" << size << "\"/>\n" ; 00721 else 00722 d_out << d_space << "<dimension name=\"" << id2xml(d.name) 00723 << "\" size=\"" << size << "\"/>\n" ; 00724 } 00725 }; 00726 00730 void 00731 Array::print_xml_core(ostream &out, string space, bool constrained, string tag) 00732 { 00733 if (constrained && !send_p()) 00734 return; 00735 00736 out << space << "<" << tag; 00737 if (!name().empty()) 00738 out << " name=\"" << id2xml(name()) << "\""; 00739 out << ">\n"; 00740 00741 get_attr_table().print_xml(out, space + " ", constrained); 00742 00743 BaseType *btp = var(); 00744 string tmp_name = btp->name(); 00745 btp->set_name(""); 00746 btp->print_xml(out, space + " ", constrained); 00747 btp->set_name(tmp_name); 00748 00749 for_each(dim_begin(), dim_end(), PrintArrayDimStrm(out, space + " ", constrained)); 00750 00751 out << space << "</" << tag << ">\n"; 00752 } 00753 00754 void 00755 Array::print_xml_writer(XMLWriter &xml, bool constrained) 00756 { 00757 print_xml_writer_core(xml, constrained, "Array"); 00758 } 00759 00760 void 00761 Array::print_as_map_xml_writer(XMLWriter &xml, bool constrained) 00762 { 00763 print_xml_writer_core(xml, constrained, "Map"); 00764 } 00765 00766 class PrintArrayDimXMLWriter : public unary_function<Array::dimension&, void> 00767 { 00768 XMLWriter &xml; 00769 bool d_constrained; 00770 public: 00771 PrintArrayDimXMLWriter(XMLWriter &xml, bool c) : xml(xml), d_constrained(c) {} 00772 00773 void operator()(Array::dimension &d) 00774 { 00775 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)"dimension") < 0) 00776 throw InternalErr(__FILE__, __LINE__, "Could not write dimension element"); 00777 00778 if (!d.name.empty()) 00779 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d.name.c_str()) < 0) 00780 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 00781 00782 ostringstream size; 00783 size << (d_constrained ? d.c_size : d.size); 00784 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "size", (const xmlChar*)size.str().c_str()) < 0) 00785 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 00786 00787 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 00788 throw InternalErr(__FILE__, __LINE__, "Could not end dimension element"); 00789 } 00790 }; 00791 00792 void 00793 Array::print_xml_writer_core(XMLWriter &xml, bool constrained, string tag) 00794 { 00795 if (constrained && !send_p()) 00796 return; 00797 00798 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*)tag.c_str()) < 0) 00799 throw InternalErr(__FILE__, __LINE__, "Could not write " + tag + " element"); 00800 00801 if (!name().empty()) 00802 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0) 00803 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name"); 00804 00805 get_attr_table().print_xml_writer(xml); 00806 00807 BaseType *btp = var(); 00808 string tmp_name = btp->name(); 00809 btp->set_name(""); 00810 btp->print_xml_writer(xml, constrained); 00811 btp->set_name(tmp_name); 00812 00813 for_each(dim_begin(), dim_end(), PrintArrayDimXMLWriter(xml, constrained)); 00814 00815 if (xmlTextWriterEndElement(xml.get_writer()) < 0) 00816 throw InternalErr(__FILE__, __LINE__, "Could not end " + tag + " element"); 00817 } 00818 00819 #if FILE_METHODS 00820 00831 unsigned int 00832 Array::print_array(FILE *out, unsigned int index, unsigned int dims, 00833 unsigned int shape[]) 00834 { 00835 if (dims == 1) { 00836 fprintf(out, "{") ; 00837 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00838 var(index++)->print_val(out, "", false); 00839 fprintf(out, ", ") ; 00840 } 00841 var(index++)->print_val(out, "", false); 00842 fprintf(out, "}") ; 00843 00844 return index; 00845 } 00846 else { 00847 fprintf(out, "{") ; 00848 // Fixed an off-by-one error in the following loop. Since the array 00849 // length is shape[dims-1]-1 *and* since we want one less dimension 00850 // than that, the correct limit on this loop is shape[dims-2]-1. From 00851 // Todd Karakasian. 00852 // The saga continues; the loop test should be `i < shape[0]-1'. jhrg 00853 // 9/12/96. 00854 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00855 index = print_array(out, index, dims - 1, shape + 1); 00856 fprintf(out, ",") ; // Removed the extra `}'. Also from Todd 00857 } 00858 index = print_array(out, index, dims - 1, shape + 1); 00859 fprintf(out, "}") ; 00860 00861 return index; 00862 } 00863 } 00864 #endif 00865 00877 unsigned int 00878 Array::print_array(ostream &out, unsigned int index, unsigned int dims, 00879 unsigned int shape[]) 00880 { 00881 if (dims == 1) { 00882 out << "{" ; 00883 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00884 var(index++)->print_val(out, "", false); 00885 out << ", " ; 00886 } 00887 var(index++)->print_val(out, "", false); 00888 out << "}" ; 00889 00890 return index; 00891 } 00892 else { 00893 out << "{" ; 00894 // Fixed an off-by-one error in the following loop. Since the array 00895 // length is shape[dims-1]-1 *and* since we want one less dimension 00896 // than that, the correct limit on this loop is shape[dims-2]-1. From 00897 // Todd Karakasian. 00898 // The saga continues; the loop test should be `i < shape[0]-1'. jhrg 00899 // 9/12/96. 00900 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00901 index = print_array(out, index, dims - 1, shape + 1); 00902 out << "," ; 00903 } 00904 index = print_array(out, index, dims - 1, shape + 1); 00905 out << "}" ; 00906 00907 return index; 00908 } 00909 } 00910 00911 #if FILE_METHODS 00912 void 00913 Array::print_val(FILE *out, string space, bool print_decl_p) 00914 { 00915 // print the declaration if print decl is true. 00916 // for each dimension, 00917 // for each element, 00918 // print the array given its shape, number of dimensions. 00919 // Add the `;' 00920 00921 if (print_decl_p) { 00922 print_decl(out, space, false, false, false); 00923 fprintf(out, " = ") ; 00924 } 00925 00926 unsigned int *shape = new unsigned int[_shape.size()]; 00927 unsigned int index = 0; 00928 for (Dim_iter i = _shape.begin(); i != _shape.end() && index < _shape.size(); i++) 00929 shape[index++] = dimension_size(i, true); 00930 00931 print_array(out, 0, _shape.size(), shape); 00932 00933 delete [] shape; shape = 0; 00934 00935 if (print_decl_p) { 00936 fprintf(out, ";\n") ; 00937 } 00938 } 00939 #endif 00940 00941 void 00942 Array::print_val(ostream &out, string space, bool print_decl_p) 00943 { 00944 // print the declaration if print decl is true. 00945 // for each dimension, 00946 // for each element, 00947 // print the array given its shape, number of dimensions. 00948 // Add the `;' 00949 00950 if (print_decl_p) { 00951 print_decl(out, space, false, false, false); 00952 out << " = " ; 00953 } 00954 00955 unsigned int *shape = new unsigned int[dimensions(true)]; 00956 unsigned int index = 0; 00957 for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i) 00958 shape[index++] = dimension_size(i, true); 00959 00960 print_array(out, 0, dimensions(true), shape); 00961 00962 delete [] shape; shape = 0; 00963 00964 if (print_decl_p) { 00965 out << ";\n" ; 00966 } 00967 } 00968 00978 bool 00979 Array::check_semantics(string &msg, bool) 00980 { 00981 bool sem = BaseType::check_semantics(msg) && !_shape.empty(); 00982 00983 if (!sem) 00984 msg = "An array variable must have dimensions"; 00985 00986 return sem; 00987 } 00988 00997 void 00998 Array::dump(ostream &strm) const 00999 { 01000 strm << DapIndent::LMarg << "Array::dump - (" 01001 << (void *)this << ")" << endl ; 01002 DapIndent::Indent() ; 01003 Vector::dump(strm) ; 01004 strm << DapIndent::LMarg << "shape:" << endl ; 01005 DapIndent::Indent() ; 01006 Dim_citer i = _shape.begin() ; 01007 Dim_citer ie = _shape.end() ; 01008 unsigned int dim_num = 0 ; 01009 for (; i != ie; i++) { 01010 strm << DapIndent::LMarg << "dimension " << dim_num++ << ":" 01011 << endl ; 01012 DapIndent::Indent() ; 01013 strm << DapIndent::LMarg << "name: " << (*i).name << endl ; 01014 strm << DapIndent::LMarg << "size: " << (*i).size << endl ; 01015 strm << DapIndent::LMarg << "start: " << (*i).start << endl ; 01016 strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ; 01017 strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ; 01018 strm << DapIndent::LMarg << "constrained size: " << (*i).c_size 01019 << endl ; 01020 DapIndent::UnIndent() ; 01021 } 01022 DapIndent::UnIndent() ; 01023 DapIndent::UnIndent() ; 01024 } 01025 01026 } // namespace libdap 01027