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

Generated on Mon May 18 10:25:02 2009 for libdap++ by  doxygen 1.4.7