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 //#include "ArrayIterAdapter.h"
00045 
00046 #include <algorithm>
00047 #include <functional>
00048 
00049 
00050 using namespace std;
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 
00102 Array::Array(const string &n, BaseType *v) : Vector(n, 0, dods_array_c)
00103 {
00104     add_var(v);
00105 }
00106 
00108 Array::Array(const Array &rhs) : Vector(rhs)
00109 {
00110     _duplicate(rhs);
00111 }
00112 
00114 Array::~Array()
00115 {
00116     DBG(cerr << "Entering ~Array (" << this << ")" << endl);
00117     DBG(cerr << "Exiting ~Array" << endl);
00118 }
00119 
00120 BaseType *
00121 Array::ptr_duplicate()
00122 {
00123     return new Array(*this);
00124 }
00125 
00126 Array &
00127 Array::operator=(const Array &rhs)
00128 {
00129     if (this == &rhs)
00130         return *this;
00131 
00132     dynamic_cast<Vector &>(*this) = rhs;
00133 
00134     _duplicate(rhs);
00135 
00136     return *this;
00137 }
00138 
00158 void
00159 Array::add_var(BaseType *v, Part)
00160 {
00161     if (v && v->type() == dods_array_c) {
00162         Array &a = dynamic_cast<Array&>(*v);
00163         Vector::add_var(a.var());
00164         Dim_iter i = a.dim_begin();
00165         Dim_iter i_end = a.dim_end();
00166         while (i != i_end) {
00167             append_dim(a.dimension_size(i), a.dimension_name(i));
00168             ++i;
00169         }
00170     }
00171     else {
00172         Vector::add_var(v);
00173     }
00174 }
00175 
00187 void
00188 Array::append_dim(int size, string name)
00189 {
00190     dimension d;
00191 
00192     // This is invariant
00193     d.size = size;
00194     d.name = www2id(name);
00195 
00196     // this information changes with each constraint expression
00197     d.start = 0;
00198     d.stop = size - 1;
00199     d.stride = 1;
00200     d.c_size = size;
00201     d.selected = true;  // assume all dims selected.
00202 
00203     _shape.push_back(d);
00204 
00205     update_length(size);
00206 }
00207 
00214 void
00215 Array::reset_constraint()
00216 {
00217     set_length(-1);
00218 
00219     for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
00220         (*i).start = 0;
00221         (*i).stop = (*i).size - 1;
00222         (*i).stride = 1;
00223         (*i).c_size = (*i).size;
00224 
00225         (*i).selected = true;
00226 
00227         update_length((*i).size);
00228     }
00229 }
00230 
00231 
00241 void
00242 Array::clear_constraint()
00243 {
00244     for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
00245         (*i).start = 0;
00246         (*i).stop = 0;
00247         (*i).stride = 0;
00248         (*i).c_size = 0;
00249         (*i).selected = false;
00250     }
00251 
00252     set_length(-1);
00253 }
00254 
00255 // the start and stop indexes are inclusive.
00256 
00257 // Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
00258 // is explicit.
00259 static const char *array_sss = \
00260                                "Invalid constraint parameters: At least one of the start, stride or stop \n\
00261                                specified do not match the array variable.";
00262 
00282 void
00283 Array::add_constraint(Dim_iter i, int start, int stride, int stop)
00284 {
00285     dimension &d = *i ;
00286 
00287     // Check for bad constraints.
00288     // Jose Garcia
00289     // Usually invalid data for a constraint is the user's mistake
00290     // because they build a wrong URL in the client side.
00291     if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0)
00292         throw Error(malformed_expr, array_sss);
00293 
00294     if (((stop - start) / stride + 1) > d.size)
00295         throw Error(malformed_expr, array_sss);
00296 
00297     d.start = start;
00298     d.stop = stop;
00299     d.stride = stride;
00300 
00301     d.c_size = (stop - start) / stride + 1;
00302 
00303     DBG(cerr << "add_constraint: c_size = " << d.c_size << endl);
00304 
00305     d.selected = true;
00306 
00307     update_length(d.c_size);
00308 }
00309 
00311 Array::Dim_iter
00312 Array::dim_begin()
00313 {
00314     return _shape.begin() ;
00315 }
00316 
00318 Array::Dim_iter
00319 Array::dim_end()
00320 {
00321     return _shape.end() ;
00322 }
00323 
00333 unsigned int
00334 Array::dimensions(bool constrained)
00335 {
00336     unsigned int dim = 0;
00337     for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
00338         if (constrained) {
00339             if ((*i).selected)
00340                 dim++;
00341         }
00342         else {
00343             dim++;
00344         }
00345     }
00346 
00347     return dim;
00348 }
00349 
00367 int
00368 Array::dimension_size(Dim_iter i, bool constrained)
00369 {
00370     int size = 0;
00371 
00372     if (!_shape.empty())
00373         if (constrained) {
00374             if ((*i).selected)
00375                 size = (*i).c_size;
00376             else
00377                 size = 0;
00378         }
00379         else
00380             size = (*i).size;
00381 
00382     return size;
00383 }
00384 
00403 int
00404 Array::dimension_start(Dim_iter i, bool constrained)
00405 {
00406     int start = 0;
00407 
00408     if (!_shape.empty())
00409         if (constrained) {
00410             if ((*i).selected)
00411                 start = (*i).start;
00412             else
00413                 start = 0;
00414         }
00415         else
00416             start = (*i).start;
00417 
00418     return start;
00419 }
00420 
00439 int
00440 Array::dimension_stop(Dim_iter i, bool constrained)
00441 {
00442     int stop = 0;
00443 
00444     if (!_shape.empty())
00445         if (constrained) {
00446             if ((*i).selected)
00447                 stop = (*i).stop;
00448             else
00449                 stop = 0;
00450         }
00451         else
00452             stop = (*i).stop;
00453 
00454     return stop;
00455 }
00456 
00476 int
00477 Array::dimension_stride(Dim_iter i, bool constrained)
00478 {
00479     int stride = 0;
00480 
00481     if (!_shape.empty())
00482         if (constrained) {
00483             if ((*i).selected)
00484                 stride = (*i).stride;
00485             else
00486                 stride = 0;
00487         }
00488         else
00489             stride = (*i).stride;
00490 
00491     return stride;
00492 }
00493 
00504 string
00505 Array::dimension_name(Dim_iter i)
00506 {
00507     // Jose Garcia
00508     // Since this method is public, it is possible for a user
00509     // to call it before the Array object has been properly set
00510     // this will cause an exception which is the user's fault.
00511     // (User in this context is the developer of the surrogate library.)
00512     if (_shape.empty())
00513         throw  InternalErr(__FILE__, __LINE__,
00514                            "*This* array has no dimensions.");
00515     return (*i).name;
00516 }
00517 
00535 void
00536 Array::print_decl(FILE *out, string space, bool print_semi,
00537                   bool constraint_info, bool constrained)
00538 {
00539     if (constrained && !send_p())
00540         return;
00541 
00542     // print it, but w/o semicolon
00543     var()->print_decl(out, space, false, constraint_info, constrained);
00544 
00545     for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
00546         if (constrained && !((*i).selected))
00547             continue;
00548         fprintf(out, "[") ;
00549         if ((*i).name != "") {
00550             fprintf(out, "%s = ", id2www((*i).name).c_str()) ;
00551         }
00552         if (constrained) {
00553             fprintf(out, "%d]", (*i).c_size) ;
00554         }
00555         else {
00556             fprintf(out, "%d]", (*i).size) ;
00557         }
00558     }
00559 
00560     if (print_semi) {
00561         fprintf(out, ";\n") ;
00562     }
00563 }
00564 
00565 void
00566 Array::print_xml(FILE *out, string space, bool constrained)
00567 {
00568     print_xml_core(out, space, constrained, "Array");
00569 }
00570 
00571 void
00572 Array::print_as_map_xml(FILE *out, string space, bool constrained)
00573 {
00574     print_xml_core(out, space, constrained, "Map");
00575 }
00576 
00577 class PrintArrayDim : public unary_function<Array::dimension&, void>
00578 {
00579     FILE *d_out;
00580     string d_space;
00581     bool d_constrained;
00582 public:
00583     PrintArrayDim(FILE *o, string s, bool c)
00584             : d_out(o), d_space(s), d_constrained(c)
00585     {}
00586 
00587     void operator()(Array::dimension &d)
00588     {
00589         int size = d_constrained ? d.c_size : d.size;
00590         if (d.name.empty())
00591             fprintf(d_out, "%s<dimension size=\"%d\"/>\n", d_space.c_str(),
00592                     size);
00593         else
00594             fprintf(d_out, "%s<dimension name=\"%s\" size=\"%d\"/>\n",
00595                     d_space.c_str(), id2xml(d.name).c_str(), size);
00596     }
00597 };
00598 
00599 void
00600 Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
00601 {
00602     if (constrained && !send_p())
00603         return;
00604 
00605     fprintf(out, "%s<%s", space.c_str(), tag.c_str());
00606     if (!name().empty())
00607         fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00608     fprintf(out , ">\n");
00609 
00610     get_attr_table().print_xml(out, space + "    ", constrained);
00611 
00612     BaseType *btp = var();
00613     string tmp_name = btp->name();
00614     btp->set_name("");
00615     btp->print_xml(out, space + "    ", constrained);
00616     btp->set_name(tmp_name);
00617 
00618     for_each(dim_begin(), dim_end(),
00619              PrintArrayDim(out, space + "    ", constrained));
00620 
00621     fprintf(out, "%s</%s>\n", space.c_str(), tag.c_str());
00622 }
00623 
00634 unsigned int
00635 Array::print_array(FILE *out, unsigned int index, unsigned int dims,
00636                    unsigned int shape[])
00637 {
00638     if (dims == 1) {
00639         fprintf(out, "{") ;
00640         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00641             var(index++)->print_val(out, "", false);
00642             fprintf(out, ", ") ;
00643         }
00644         var(index++)->print_val(out, "", false);
00645         fprintf(out, "}") ;
00646 
00647         return index;
00648     }
00649     else {
00650         fprintf(out, "{") ;
00651         // Fixed an off-by-one error in the following loop. Since the array
00652         // length is shape[dims-1]-1 *and* since we want one less dimension
00653         // than that, the correct limit on this loop is shape[dims-2]-1. From
00654         // Todd Karakasian.
00655         // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
00656         // 9/12/96.
00657         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00658             index = print_array(out, index, dims - 1, shape + 1);
00659             fprintf(out, ",") ;   // Removed the extra `}'. Also from Todd
00660         }
00661         index = print_array(out, index, dims - 1, shape + 1);
00662         fprintf(out, "}") ;
00663 
00664         return index;
00665     }
00666 }
00667 
00668 void
00669 Array::print_val(FILE *out, string space, bool print_decl_p)
00670 {
00671     // print the declaration if print decl is true.
00672     // for each dimension,
00673     //   for each element,
00674     //     print the array given its shape, number of dimensions.
00675     // Add the `;'
00676 
00677     if (print_decl_p) {
00678         print_decl(out, space, false, false, false);
00679         fprintf(out, " = ") ;
00680     }
00681 
00682     unsigned int dims = dimensions(true);
00683     unsigned int *shape = new unsigned int[dims];
00684     unsigned int index = 0;
00685     for (Dim_iter i = _shape.begin(); i != _shape.end(); i++)
00686         shape[index++] = dimension_size(i, true);
00687 
00688     print_array(out, 0, dims, shape);
00689     delete [] shape; shape = 0;
00690 
00691     if (print_decl_p) {
00692         fprintf(out, ";\n") ;
00693     }
00694 }
00695 
00705 bool
00706 Array::check_semantics(string &msg, bool)
00707 {
00708     bool sem = BaseType::check_semantics(msg) && !_shape.empty();
00709 
00710     if (!sem)
00711         msg = "An array variable must have dimensions";
00712 
00713     return sem;
00714 }
00715 
00724 void
00725 Array::dump(ostream &strm) const
00726 {
00727     strm << DapIndent::LMarg << "Array::dump - ("
00728     << (void *)this << ")" << endl ;
00729     DapIndent::Indent() ;
00730     Vector::dump(strm) ;
00731     strm << DapIndent::LMarg << "shape:" << endl ;
00732     DapIndent::Indent() ;
00733     Dim_citer i = _shape.begin() ;
00734     Dim_citer ie = _shape.end() ;
00735     unsigned int dim_num = 0 ;
00736     for (; i != ie; i++) {
00737         strm << DapIndent::LMarg << "dimension " << dim_num++ << ":" << endl ;
00738         DapIndent::Indent() ;
00739         strm << DapIndent::LMarg << "name: " << (*i).name << endl ;
00740         strm << DapIndent::LMarg << "size: " << (*i).size << endl ;
00741         strm << DapIndent::LMarg << "start: " << (*i).start << endl ;
00742         strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ;
00743         strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ;
00744         strm << DapIndent::LMarg << "constrained size: " << (*i).c_size
00745         << endl ;
00746         strm << DapIndent::LMarg << "selected: " << (*i).selected << endl ;
00747         DapIndent::UnIndent() ;
00748     }
00749     DapIndent::UnIndent() ;
00750     DapIndent::UnIndent() ;
00751 }
00752 

Generated on Wed Jun 27 12:56:38 2007 for libdap++ by  doxygen 1.4.7