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 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 00501 #if FILE_METHODS 00502 00519 void 00520 Array::print_decl(FILE *out, string space, bool print_semi, 00521 bool constraint_info, bool constrained) 00522 { 00523 if (constrained && !send_p()) 00524 return; 00525 00526 // print it, but w/o semicolon 00527 var()->print_decl(out, space, false, constraint_info, constrained); 00528 00529 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00530 fprintf(out, "[") ; 00531 if ((*i).name != "") { 00532 fprintf(out, "%s = ", id2www((*i).name).c_str()) ; 00533 } 00534 if (constrained) { 00535 fprintf(out, "%d]", (*i).c_size) ; 00536 } 00537 else { 00538 fprintf(out, "%d]", (*i).size) ; 00539 } 00540 } 00541 00542 if (print_semi) { 00543 fprintf(out, ";\n") ; 00544 } 00545 } 00546 #endif 00547 00565 void 00566 Array::print_decl(ostream &out, string space, bool print_semi, 00567 bool constraint_info, bool constrained) 00568 { 00569 if (constrained && !send_p()) 00570 return; 00571 00572 // print it, but w/o semicolon 00573 var()->print_decl(out, space, false, constraint_info, constrained); 00574 00575 for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) { 00576 out << "[" ; 00577 if ((*i).name != "") { 00578 out << id2www((*i).name) << " = " ; 00579 } 00580 if (constrained) { 00581 out << (*i).c_size << "]" ; 00582 } 00583 else { 00584 out << (*i).size << "]" ; 00585 } 00586 } 00587 00588 if (print_semi) { 00589 out << ";\n" ; 00590 } 00591 } 00592 #if FILE_METHODS 00593 void 00594 Array::print_xml(FILE *out, string space, bool constrained) 00595 { 00596 print_xml_core(out, space, constrained, "Array"); 00597 } 00598 #endif 00599 void 00600 Array::print_xml(ostream &out, string space, bool constrained) 00601 { 00602 print_xml_core(out, space, constrained, "Array"); 00603 } 00604 #if FILE_METHODS 00605 void 00606 Array::print_as_map_xml(FILE *out, string space, bool constrained) 00607 { 00608 print_xml_core(out, space, constrained, "Map"); 00609 } 00610 #endif 00611 void 00612 Array::print_as_map_xml(ostream &out, string space, bool constrained) 00613 { 00614 print_xml_core(out, space, constrained, "Map"); 00615 } 00616 #if FILE_METHODS 00617 class PrintArrayDim : public unary_function<Array::dimension&, void> 00618 { 00619 FILE *d_out; 00620 string d_space; 00621 bool d_constrained; 00622 public: 00623 PrintArrayDim(FILE *o, string s, bool c) 00624 : d_out(o), d_space(s), d_constrained(c) 00625 {} 00626 00627 void operator()(Array::dimension &d) 00628 { 00629 int size = d_constrained ? d.c_size : d.size; 00630 if (d.name.empty()) 00631 fprintf(d_out, "%s<dimension size=\"%d\"/>\n", d_space.c_str(), 00632 size); 00633 else 00634 fprintf(d_out, "%s<dimension name=\"%s\" size=\"%d\"/>\n", 00635 d_space.c_str(), id2xml(d.name).c_str(), size); 00636 } 00637 }; 00638 00639 void 00640 Array::print_xml_core(FILE *out, string space, bool constrained, string tag) 00641 { 00642 if (constrained && !send_p()) 00643 return; 00644 00645 fprintf(out, "%s<%s", space.c_str(), tag.c_str()); 00646 if (!name().empty()) 00647 fprintf(out, " name=\"%s\"", id2xml(name()).c_str()); 00648 fprintf(out , ">\n"); 00649 00650 get_attr_table().print_xml(out, space + " ", constrained); 00651 00652 BaseType *btp = var(); 00653 string tmp_name = btp->name(); 00654 btp->set_name(""); 00655 btp->print_xml(out, space + " ", constrained); 00656 btp->set_name(tmp_name); 00657 00658 for_each(dim_begin(), dim_end(), 00659 PrintArrayDim(out, space + " ", constrained)); 00660 00661 fprintf(out, "%s</%s>\n", space.c_str(), tag.c_str()); 00662 } 00663 #endif 00664 00665 class PrintArrayDimStrm : public unary_function<Array::dimension&, void> 00666 { 00667 ostream &d_out; 00668 string d_space; 00669 bool d_constrained; 00670 public: 00671 PrintArrayDimStrm(ostream &o, string s, bool c) 00672 : d_out(o), d_space(s), d_constrained(c) 00673 {} 00674 00675 void operator()(Array::dimension &d) 00676 { 00677 int size = d_constrained ? d.c_size : d.size; 00678 if (d.name.empty()) 00679 d_out << d_space << "<dimension size=\"" << size << "\"/>\n" ; 00680 else 00681 d_out << d_space << "<dimension name=\"" << id2xml(d.name) 00682 << "\" size=\"" << size << "\"/>\n" ; 00683 } 00684 }; 00685 00686 void 00687 Array::print_xml_core(ostream &out, string space, bool constrained, string tag) 00688 { 00689 if (constrained && !send_p()) 00690 return; 00691 00692 out << space << "<" << tag ; 00693 if (!name().empty()) 00694 out << " name=\"" << id2xml(name()) << "\"" ; 00695 out << ">\n" ; 00696 00697 get_attr_table().print_xml(out, space + " ", constrained); 00698 00699 BaseType *btp = var(); 00700 string tmp_name = btp->name(); 00701 btp->set_name(""); 00702 btp->print_xml(out, space + " ", constrained); 00703 btp->set_name(tmp_name); 00704 00705 for_each(dim_begin(), dim_end(), 00706 PrintArrayDimStrm(out, space + " ", constrained)); 00707 00708 out << space << "</" << tag << ">\n" ; 00709 } 00710 00711 #if FILE_METHODS 00712 00722 unsigned int 00723 Array::print_array(FILE *out, unsigned int index, unsigned int dims, 00724 unsigned int shape[]) 00725 { 00726 if (dims == 1) { 00727 fprintf(out, "{") ; 00728 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00729 var(index++)->print_val(out, "", false); 00730 fprintf(out, ", ") ; 00731 } 00732 var(index++)->print_val(out, "", false); 00733 fprintf(out, "}") ; 00734 00735 return index; 00736 } 00737 else { 00738 fprintf(out, "{") ; 00739 // Fixed an off-by-one error in the following loop. Since the array 00740 // length is shape[dims-1]-1 *and* since we want one less dimension 00741 // than that, the correct limit on this loop is shape[dims-2]-1. From 00742 // Todd Karakasian. 00743 // The saga continues; the loop test should be `i < shape[0]-1'. jhrg 00744 // 9/12/96. 00745 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00746 index = print_array(out, index, dims - 1, shape + 1); 00747 fprintf(out, ",") ; // Removed the extra `}'. Also from Todd 00748 } 00749 index = print_array(out, index, dims - 1, shape + 1); 00750 fprintf(out, "}") ; 00751 00752 return index; 00753 } 00754 } 00755 #endif 00756 00767 unsigned int 00768 Array::print_array(ostream &out, unsigned int index, unsigned int dims, 00769 unsigned int shape[]) 00770 { 00771 if (dims == 1) { 00772 out << "{" ; 00773 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00774 var(index++)->print_val(out, "", false); 00775 out << ", " ; 00776 } 00777 var(index++)->print_val(out, "", false); 00778 out << "}" ; 00779 00780 return index; 00781 } 00782 else { 00783 out << "{" ; 00784 // Fixed an off-by-one error in the following loop. Since the array 00785 // length is shape[dims-1]-1 *and* since we want one less dimension 00786 // than that, the correct limit on this loop is shape[dims-2]-1. From 00787 // Todd Karakasian. 00788 // The saga continues; the loop test should be `i < shape[0]-1'. jhrg 00789 // 9/12/96. 00790 for (unsigned i = 0; i < shape[0] - 1; ++i) { 00791 index = print_array(out, index, dims - 1, shape + 1); 00792 out << "," ; 00793 } 00794 index = print_array(out, index, dims - 1, shape + 1); 00795 out << "}" ; 00796 00797 return index; 00798 } 00799 } 00800 00801 #if FILE_METHODS 00802 void 00803 Array::print_val(FILE *out, string space, bool print_decl_p) 00804 { 00805 // print the declaration if print decl is true. 00806 // for each dimension, 00807 // for each element, 00808 // print the array given its shape, number of dimensions. 00809 // Add the `;' 00810 00811 if (print_decl_p) { 00812 print_decl(out, space, false, false, false); 00813 fprintf(out, " = ") ; 00814 } 00815 00816 unsigned int *shape = new unsigned int[_shape.size()]; 00817 unsigned int index = 0; 00818 for (Dim_iter i = _shape.begin(); i != _shape.end() && index < _shape.size(); i++) 00819 shape[index++] = dimension_size(i, true); 00820 00821 print_array(out, 0, _shape.size(), shape); 00822 00823 delete [] shape; shape = 0; 00824 00825 if (print_decl_p) { 00826 fprintf(out, ";\n") ; 00827 } 00828 } 00829 #endif 00830 00831 void 00832 Array::print_val(ostream &out, string space, bool print_decl_p) 00833 { 00834 // print the declaration if print decl is true. 00835 // for each dimension, 00836 // for each element, 00837 // print the array given its shape, number of dimensions. 00838 // Add the `;' 00839 00840 if (print_decl_p) { 00841 print_decl(out, space, false, false, false); 00842 out << " = " ; 00843 } 00844 00845 unsigned int *shape = new unsigned int[dimensions(true)]; 00846 unsigned int index = 0; 00847 for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i) 00848 shape[index++] = dimension_size(i, true); 00849 00850 print_array(out, 0, dimensions(true), shape); 00851 00852 delete [] shape; shape = 0; 00853 00854 if (print_decl_p) { 00855 out << ";\n" ; 00856 } 00857 } 00858 00868 bool 00869 Array::check_semantics(string &msg, bool) 00870 { 00871 bool sem = BaseType::check_semantics(msg) && !_shape.empty(); 00872 00873 if (!sem) 00874 msg = "An array variable must have dimensions"; 00875 00876 return sem; 00877 } 00878 00887 void 00888 Array::dump(ostream &strm) const 00889 { 00890 strm << DapIndent::LMarg << "Array::dump - (" 00891 << (void *)this << ")" << endl ; 00892 DapIndent::Indent() ; 00893 Vector::dump(strm) ; 00894 strm << DapIndent::LMarg << "shape:" << endl ; 00895 DapIndent::Indent() ; 00896 Dim_citer i = _shape.begin() ; 00897 Dim_citer ie = _shape.end() ; 00898 unsigned int dim_num = 0 ; 00899 for (; i != ie; i++) { 00900 strm << DapIndent::LMarg << "dimension " << dim_num++ << ":" 00901 << endl ; 00902 DapIndent::Indent() ; 00903 strm << DapIndent::LMarg << "name: " << (*i).name << endl ; 00904 strm << DapIndent::LMarg << "size: " << (*i).size << endl ; 00905 strm << DapIndent::LMarg << "start: " << (*i).start << endl ; 00906 strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ; 00907 strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ; 00908 strm << DapIndent::LMarg << "constrained size: " << (*i).c_size 00909 << endl ; 00910 DapIndent::UnIndent() ; 00911 } 00912 DapIndent::UnIndent() ; 00913 DapIndent::UnIndent() ; 00914 } 00915 00916 } // namespace libdap 00917