libdap++ Updated for version 3.8.2

Array.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 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