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 
00106 Array::Array(const Array &rhs) : Vector(rhs)
00107 {
00108     _duplicate(rhs);
00109 }
00110 
00112 Array::~Array()
00113 {
00114     DBG(cerr << "Entering ~Array (" << this << ")" << endl);
00115     DBG(cerr << "Exiting ~Array" << endl);
00116 }
00117 
00118 BaseType *
00119 Array::ptr_duplicate()
00120 {
00121     return new Array(*this);
00122 }
00123 
00124 Array &
00125 Array::operator=(const Array &rhs)
00126 {
00127     if (this == &rhs)
00128         return *this;
00129 
00130     dynamic_cast<Vector &>(*this) = rhs;
00131 
00132     _duplicate(rhs);
00133 
00134     return *this;
00135 }
00136 
00156 void
00157 Array::add_var(BaseType *v, Part)
00158 {
00159     if (v && v->type() == dods_array_c) {
00160         Array &a = dynamic_cast<Array&>(*v);
00161         Vector::add_var(a.var());
00162         Dim_iter i = a.dim_begin();
00163         Dim_iter i_end = a.dim_end();
00164         while (i != i_end) {
00165             append_dim(a.dimension_size(i), a.dimension_name(i));
00166             ++i;
00167         }
00168     }
00169     else {
00170         Vector::add_var(v);
00171     }
00172 }
00173 
00185 void
00186 Array::append_dim(int size, string name)
00187 {
00188     dimension d;
00189 
00190     // This is invariant
00191     d.size = size;
00192     d.name = www2id(name);
00193 
00194     // this information changes with each constraint expression
00195     d.start = 0;
00196     d.stop = size - 1;
00197     d.stride = 1;
00198     d.c_size = size;
00199 #if 0
00200     d.selected = true;  // assume all dims selected.
00201 #endif
00202     _shape.push_back(d);
00203 
00204     update_length(size);
00205 }
00206 
00213 void
00214 Array::reset_constraint()
00215 {
00216     set_length(-1);
00217 
00218     for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
00219         (*i).start = 0;
00220         (*i).stop = (*i).size - 1;
00221         (*i).stride = 1;
00222         (*i).c_size = (*i).size;
00223 #if 0
00224         (*i).selected = true;
00225 #endif
00226         update_length((*i).size);
00227     }
00228 }
00229 
00230 
00240 void
00241 Array::clear_constraint()
00242 {
00243     reset_constraint();
00244 #if 0
00245     for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
00246         (*i).start = 0;
00247         (*i).stop = 0;
00248         (*i).stride = 0;
00249         (*i).c_size = 0;
00250         (*i).selected = false;
00251     }
00252 
00253     set_length(-1);
00254 #endif
00255 }
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 #if 0
00305     d.selected = true;
00306 #endif
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         dim++;
00339 #if 0
00340         if (constrained) {
00341             if ((*i).selected)
00342                 dim++;
00343         }
00344         else {
00345             dim++;
00346         }
00347 #endif
00348     }
00349 
00350     return dim;
00351 }
00352 
00370 int
00371 Array::dimension_size(Dim_iter i, bool constrained)
00372 {
00373     int size = 0;
00374 
00375     if (!_shape.empty()) {
00376         if (constrained)
00377             size = (*i).c_size;
00378         else
00379             size = (*i).size;
00380     }
00381     
00382 #if 0    
00383         if (constrained) {
00384             if ((*i).selected)
00385                 size = (*i).c_size;
00386             else
00387                 size = 0;
00388         }
00389         else
00390             size = (*i).size;
00391 #endif
00392 
00393     return size;
00394 }
00395 
00414 int
00415 Array::dimension_start(Dim_iter i, bool /*constrained*/)
00416 {
00417     return (!_shape.empty()) ? (*i).start : 0;
00418     
00419 #if 0
00420     int start = 0;
00421 
00422     if (!_shape.empty())
00423         start = (*i).start;
00424         
00425 #if array_selected
00426         if (constrained) {
00427             if ((*i).selected)
00428                 start = (*i).start;
00429             else
00430                 start = 0;
00431         }
00432         else
00433             start = (*i).start;
00434 #endif
00435 
00436     return start;
00437 #endif
00438 }
00439 
00458 int
00459 Array::dimension_stop(Dim_iter i, bool /*constrained*/)
00460 {
00461     return (!_shape.empty()) ? (*i).stop : 0;
00462     
00463 #if 0
00464     int stop = 0;
00465 
00466     if (!_shape.empty())
00467         stop = (*i).stop;
00468     
00469 #if array_selected
00470         if (constrained) {
00471             if ((*i).selected)
00472                 stop = (*i).stop;
00473             else
00474                 stop = 0;
00475         }
00476         else
00477             stop = (*i).stop;
00478 #endif
00479 
00480     return stop;
00481 #endif
00482 }
00483 
00503 int
00504 Array::dimension_stride(Dim_iter i, bool /*constrained*/)
00505 {
00506     return (!_shape.empty()) ? (*i).stride : 0;
00507     
00508 #if 0
00509     int stride = 0;
00510 
00511     if (!_shape.empty())
00512         stride = (*i).stride;
00513     
00514 #if array_selected
00515         if (constrained) {
00516             if ((*i).selected)
00517                 stride = (*i).stride;
00518             else
00519                 stride = 0;
00520         }
00521         else
00522             stride = (*i).stride;
00523 #endif
00524 
00525     return stride;
00526 #endif
00527 }
00528 
00539 string
00540 Array::dimension_name(Dim_iter i)
00541 {
00542     // Jose Garcia
00543     // Since this method is public, it is possible for a user
00544     // to call it before the Array object has been properly set
00545     // this will cause an exception which is the user's fault.
00546     // (User in this context is the developer of the surrogate library.)
00547     if (_shape.empty())
00548         throw  InternalErr(__FILE__, __LINE__,
00549                            "*This* array has no dimensions.");
00550     return (*i).name;
00551 }
00552 
00570 void
00571 Array::print_decl(FILE *out, string space, bool print_semi,
00572                   bool constraint_info, bool constrained)
00573 {
00574     if (constrained && !send_p())
00575         return;
00576 
00577     // print it, but w/o semicolon
00578     var()->print_decl(out, space, false, constraint_info, constrained);
00579 
00580     for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
00581 #if 0
00582         if (constrained && !((*i).selected))
00583             continue;
00584 #endif
00585         fprintf(out, "[") ;
00586         if ((*i).name != "") {
00587             fprintf(out, "%s = ", id2www((*i).name).c_str()) ;
00588         }
00589         if (constrained) {
00590             fprintf(out, "%d]", (*i).c_size) ;
00591         }
00592         else {
00593             fprintf(out, "%d]", (*i).size) ;
00594         }
00595     }
00596 
00597     if (print_semi) {
00598         fprintf(out, ";\n") ;
00599     }
00600 }
00601 
00619 void
00620 Array::print_decl(ostream &out, string space, bool print_semi,
00621                   bool constraint_info, bool constrained)
00622 {
00623     if (constrained && !send_p())
00624         return;
00625 
00626     // print it, but w/o semicolon
00627     var()->print_decl(out, space, false, constraint_info, constrained);
00628 
00629     for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
00630 #if 0
00631         if (constrained && !((*i).selected))
00632             continue;
00633 #endif
00634         out << "[" ;
00635         if ((*i).name != "") {
00636             out << id2www((*i).name) << " = " ;
00637         }
00638         if (constrained) {
00639             out << (*i).c_size << "]" ;
00640         }
00641         else {
00642             out << (*i).size << "]" ;
00643         }
00644     }
00645 
00646     if (print_semi) {
00647         out << ";\n" ;
00648     }
00649 }
00650 
00651 void
00652 Array::print_xml(FILE *out, string space, bool constrained)
00653 {
00654     print_xml_core(out, space, constrained, "Array");
00655 }
00656 
00657 void
00658 Array::print_xml(ostream &out, string space, bool constrained)
00659 {
00660     print_xml_core(out, space, constrained, "Array");
00661 }
00662 
00663 void
00664 Array::print_as_map_xml(FILE *out, string space, bool constrained)
00665 {
00666     print_xml_core(out, space, constrained, "Map");
00667 }
00668 
00669 void
00670 Array::print_as_map_xml(ostream &out, string space, bool constrained)
00671 {
00672     print_xml_core(out, space, constrained, "Map");
00673 }
00674 
00675 class PrintArrayDim : public unary_function<Array::dimension&, void>
00676 {
00677     FILE *d_out;
00678     string d_space;
00679     bool d_constrained;
00680 public:
00681     PrintArrayDim(FILE *o, string s, bool c)
00682             : d_out(o), d_space(s), d_constrained(c)
00683     {}
00684 
00685     void operator()(Array::dimension &d)
00686     {
00687         int size = d_constrained ? d.c_size : d.size;
00688         if (d.name.empty())
00689             fprintf(d_out, "%s<dimension size=\"%d\"/>\n", d_space.c_str(),
00690                     size);
00691         else
00692             fprintf(d_out, "%s<dimension name=\"%s\" size=\"%d\"/>\n",
00693                     d_space.c_str(), id2xml(d.name).c_str(), size);
00694     }
00695 };
00696 
00697 void
00698 Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
00699 {
00700     if (constrained && !send_p())
00701         return;
00702 
00703     fprintf(out, "%s<%s", space.c_str(), tag.c_str());
00704     if (!name().empty())
00705         fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00706     fprintf(out , ">\n");
00707 
00708     get_attr_table().print_xml(out, space + "    ", constrained);
00709 
00710     BaseType *btp = var();
00711     string tmp_name = btp->name();
00712     btp->set_name("");
00713     btp->print_xml(out, space + "    ", constrained);
00714     btp->set_name(tmp_name);
00715 
00716     for_each(dim_begin(), dim_end(),
00717              PrintArrayDim(out, space + "    ", constrained));
00718 
00719     fprintf(out, "%s</%s>\n", space.c_str(), tag.c_str());
00720 }
00721 
00722 class PrintArrayDimStrm : public unary_function<Array::dimension&, void>
00723 {
00724     ostream &d_out;
00725     string d_space;
00726     bool d_constrained;
00727 public:
00728     PrintArrayDimStrm(ostream &o, string s, bool c)
00729             : d_out(o), d_space(s), d_constrained(c)
00730     {}
00731 
00732     void operator()(Array::dimension &d)
00733     {
00734         int size = d_constrained ? d.c_size : d.size;
00735         if (d.name.empty())
00736             d_out << d_space << "<dimension size=\"" << size << "\"/>\n" ;
00737         else
00738             d_out << d_space << "<dimension name=\"" << id2xml(d.name)
00739                   << "\" size=\"" << size << "\"/>\n" ;
00740     }
00741 };
00742 
00743 void
00744 Array::print_xml_core(ostream &out, string space, bool constrained, string tag)
00745 {
00746     if (constrained && !send_p())
00747         return;
00748 
00749     out << space << "<" << tag ;
00750     if (!name().empty())
00751         out << " name=\"" << id2xml(name()) << "\"" ;
00752     out << ">\n" ;
00753 
00754     get_attr_table().print_xml(out, space + "    ", constrained);
00755 
00756     BaseType *btp = var();
00757     string tmp_name = btp->name();
00758     btp->set_name("");
00759     btp->print_xml(out, space + "    ", constrained);
00760     btp->set_name(tmp_name);
00761 
00762     for_each(dim_begin(), dim_end(),
00763              PrintArrayDimStrm(out, space + "    ", constrained));
00764 
00765     out << space << "</" << tag << ">\n" ;
00766 }
00767 
00778 unsigned int
00779 Array::print_array(FILE *out, unsigned int index, unsigned int dims,
00780                    unsigned int shape[])
00781 {
00782     if (dims == 1) {
00783         fprintf(out, "{") ;
00784         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00785             var(index++)->print_val(out, "", false);
00786             fprintf(out, ", ") ;
00787         }
00788         var(index++)->print_val(out, "", false);
00789         fprintf(out, "}") ;
00790 
00791         return index;
00792     }
00793     else {
00794         fprintf(out, "{") ;
00795         // Fixed an off-by-one error in the following loop. Since the array
00796         // length is shape[dims-1]-1 *and* since we want one less dimension
00797         // than that, the correct limit on this loop is shape[dims-2]-1. From
00798         // Todd Karakasian.
00799         // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
00800         // 9/12/96.
00801         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00802             index = print_array(out, index, dims - 1, shape + 1);
00803             fprintf(out, ",") ;   // Removed the extra `}'. Also from Todd
00804         }
00805         index = print_array(out, index, dims - 1, shape + 1);
00806         fprintf(out, "}") ;
00807 
00808         return index;
00809     }
00810 }
00811 
00822 unsigned int
00823 Array::print_array(ostream &out, unsigned int index, unsigned int dims,
00824                    unsigned int shape[])
00825 {
00826     if (dims == 1) {
00827         out << "{" ;
00828         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00829             var(index++)->print_val(out, "", false);
00830             out << ", " ;
00831         }
00832         var(index++)->print_val(out, "", false);
00833         out << "}" ;
00834 
00835         return index;
00836     }
00837     else {
00838         out << "{" ;
00839         // Fixed an off-by-one error in the following loop. Since the array
00840         // length is shape[dims-1]-1 *and* since we want one less dimension
00841         // than that, the correct limit on this loop is shape[dims-2]-1. From
00842         // Todd Karakasian.
00843         // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
00844         // 9/12/96.
00845         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00846             index = print_array(out, index, dims - 1, shape + 1);
00847             out << "," ;
00848         }
00849         index = print_array(out, index, dims - 1, shape + 1);
00850         out << "}" ;
00851 
00852         return index;
00853     }
00854 }
00855 
00856 void
00857 Array::print_val(FILE *out, string space, bool print_decl_p)
00858 {
00859     // print the declaration if print decl is true.
00860     // for each dimension,
00861     //   for each element,
00862     //     print the array given its shape, number of dimensions.
00863     // Add the `;'
00864 
00865     if (print_decl_p) {
00866         print_decl(out, space, false, false, false);
00867         fprintf(out, " = ") ;
00868     }
00869 
00870     unsigned int *shape = new unsigned int[_shape.size()];
00871     unsigned int index = 0;
00872     for (Dim_iter i = _shape.begin(); i != _shape.end() && index < _shape.size(); i++)
00873         shape[index++] = dimension_size(i, true);
00874 
00875     print_array(out, 0, _shape.size(), shape);
00876     
00877     delete [] shape; shape = 0;
00878 
00879     if (print_decl_p) {
00880         fprintf(out, ";\n") ;
00881     }
00882 }
00883 
00884 void
00885 Array::print_val(ostream &out, string space, bool print_decl_p)
00886 {
00887     // print the declaration if print decl is true.
00888     // for each dimension,
00889     //   for each element,
00890     //     print the array given its shape, number of dimensions.
00891     // Add the `;'
00892 
00893     if (print_decl_p) {
00894         print_decl(out, space, false, false, false);
00895             out << " = " ;
00896     }
00897 
00898     unsigned int *shape = new unsigned int[dimensions(true)];
00899     unsigned int index = 0;
00900     for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i)
00901         shape[index++] = dimension_size(i, true);
00902 
00903     print_array(out, 0, dimensions(true), shape);
00904     
00905     delete [] shape; shape = 0;
00906 
00907     if (print_decl_p) {
00908             out << ";\n" ;
00909     }
00910 }
00911 
00921 bool
00922 Array::check_semantics(string &msg, bool)
00923 {
00924     bool sem = BaseType::check_semantics(msg) && !_shape.empty();
00925 
00926     if (!sem)
00927         msg = "An array variable must have dimensions";
00928 
00929     return sem;
00930 }
00931 
00940 void
00941 Array::dump(ostream &strm) const
00942 {
00943     strm << DapIndent::LMarg << "Array::dump - ("
00944     << (void *)this << ")" << endl ;
00945     DapIndent::Indent() ;
00946     Vector::dump(strm) ;
00947     strm << DapIndent::LMarg << "shape:" << endl ;
00948     DapIndent::Indent() ;
00949     Dim_citer i = _shape.begin() ;
00950     Dim_citer ie = _shape.end() ;
00951     unsigned int dim_num = 0 ;
00952     for (; i != ie; i++) {
00953         strm << DapIndent::LMarg << "dimension " << dim_num++ << ":"
00954              << endl ;
00955         DapIndent::Indent() ;
00956         strm << DapIndent::LMarg << "name: " << (*i).name << endl ;
00957         strm << DapIndent::LMarg << "size: " << (*i).size << endl ;
00958         strm << DapIndent::LMarg << "start: " << (*i).start << endl ;
00959         strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ;
00960         strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ;
00961         strm << DapIndent::LMarg << "constrained size: " << (*i).c_size
00962              << endl ;
00963 #if 0
00964         strm << DapIndent::LMarg << "selected: " << (*i).selected << endl ;
00965 #endif
00966         DapIndent::UnIndent() ;
00967     }
00968     DapIndent::UnIndent() ;
00969     DapIndent::UnIndent() ;
00970 }
00971 
00972 } // namespace libdap
00973 

Generated on Tue Jun 10 18:00:29 2008 for libdap++ by  doxygen 1.5.4