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 void
00051 Array::_duplicate(const Array &a)
00052 {
00053     _shape = a._shape;
00054 }
00055 
00056 // The first method of calculating length works when only one dimension is
00057 // constrained and you want the others to appear in total. This is important
00058 // when selecting from grids since users may not select from all dimensions
00059 // in which case that means they want the whole thing. Array projection
00060 // should probably work this way too, but it doesn't. 9/21/2001 jhrg
00061 
00069 void
00070 Array::update_length(int)
00071 {
00072     int length = 1;
00073     for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
00074         length *= (*i).c_size > 0 ? (*i).c_size : 1;
00075     }
00076 
00077     set_length(length);
00078 }
00079 
00080 // Construct an instance of Array. The (BaseType *) is assumed to be
00081 // allocated using new - The dtor for Vector will delete this object.
00082 
00098 Array::Array(const string &n, BaseType *v) : Vector(n, 0, dods_array_c)
00099 {
00100     add_var(v); // Vector::add_var() stores null is v is null
00101 }
00102 
00104 Array::Array(const Array &rhs) : Vector(rhs)
00105 {
00106     _duplicate(rhs);
00107 }
00108 
00110 Array::~Array()
00111 {
00112     DBG(cerr << "Entering ~Array (" << this << ")" << endl);
00113     DBG(cerr << "Exiting ~Array" << endl);
00114 }
00115 
00116 BaseType *
00117 Array::ptr_duplicate()
00118 {
00119     return new Array(*this);
00120 }
00121 
00122 Array &
00123 Array::operator=(const Array &rhs)
00124 {
00125     if (this == &rhs)
00126         return *this;
00127 
00128     dynamic_cast<Vector &>(*this) = rhs;
00129 
00130     _duplicate(rhs);
00131 
00132     return *this;
00133 }
00134 
00154 void
00155 Array::add_var(BaseType *v, Part)
00156 {
00157     if (v && v->type() == dods_array_c) {
00158         Array &a = dynamic_cast<Array&>(*v);
00159         Vector::add_var(a.var());
00160         Dim_iter i = a.dim_begin();
00161         Dim_iter i_end = a.dim_end();
00162         while (i != i_end) {
00163             append_dim(a.dimension_size(i), a.dimension_name(i));
00164             ++i;
00165         }
00166     }
00167     else {
00168         Vector::add_var(v);
00169     }
00170 }
00171 
00183 void
00184 Array::append_dim(int size, string name)
00185 {
00186     dimension d;
00187 
00188     // This is invariant
00189     d.size = size;
00190     d.name = www2id(name);
00191 
00192     // this information changes with each constraint expression
00193     d.start = 0;
00194     d.stop = size - 1;
00195     d.stride = 1;
00196     d.c_size = size;
00197 #if 0
00198     d.selected = true;  // assume all dims selected.
00199 #endif
00200     _shape.push_back(d);
00201 
00202     update_length(size);
00203 }
00204 
00211 void
00212 Array::reset_constraint()
00213 {
00214     set_length(-1);
00215 
00216     for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
00217         (*i).start = 0;
00218         (*i).stop = (*i).size - 1;
00219         (*i).stride = 1;
00220         (*i).c_size = (*i).size;
00221 #if 0
00222         (*i).selected = true;
00223 #endif
00224         update_length((*i).size);
00225     }
00226 }
00227 
00228 
00238 void
00239 Array::clear_constraint()
00240 {
00241     reset_constraint();
00242 #if 0
00243     for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
00244         (*i).start = 0;
00245         (*i).stop = 0;
00246         (*i).stride = 0;
00247         (*i).c_size = 0;
00248         (*i).selected = false;
00249     }
00250 
00251     set_length(-1);
00252 #endif
00253 }
00254 
00255 // Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
00256 // is explicit.
00257 static const char *array_sss = \
00258 "Invalid constraint parameters: At least one of the start, stride or stop \n\
00259 specified do not match the array variable.";
00260 
00280 void
00281 Array::add_constraint(Dim_iter i, int start, int stride, int stop)
00282 {
00283     dimension &d = *i ;
00284 
00285     // Check for bad constraints.
00286     // Jose Garcia
00287     // Usually invalid data for a constraint is the user's mistake
00288     // because they build a wrong URL in the client side.
00289     if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0)
00290         throw Error(malformed_expr, array_sss);
00291 
00292     if (((stop - start) / stride + 1) > d.size)
00293         throw Error(malformed_expr, array_sss);
00294 
00295     d.start = start;
00296     d.stop = stop;
00297     d.stride = stride;
00298 
00299     d.c_size = (stop - start) / stride + 1;
00300 
00301     DBG(cerr << "add_constraint: c_size = " << d.c_size << endl);
00302 #if 0
00303     d.selected = true;
00304 #endif
00305     update_length(d.c_size);
00306 }
00307 
00309 Array::Dim_iter
00310 Array::dim_begin()
00311 {
00312     return _shape.begin() ;
00313 }
00314 
00316 Array::Dim_iter
00317 Array::dim_end()
00318 {
00319     return _shape.end() ;
00320 }
00321 
00331 unsigned int
00332 Array::dimensions(bool /*constrained*/)
00333 {
00334     unsigned int dim = 0;
00335     for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
00336         dim++;
00337 #if 0
00338         if (constrained) {
00339             if ((*i).selected)
00340                 dim++;
00341         }
00342         else {
00343             dim++;
00344         }
00345 #endif
00346     }
00347 
00348     return dim;
00349 }
00350 
00368 int
00369 Array::dimension_size(Dim_iter i, bool constrained)
00370 {
00371     int size = 0;
00372 
00373     if (!_shape.empty()) {
00374         if (constrained)
00375             size = (*i).c_size;
00376         else
00377             size = (*i).size;
00378     }
00379     
00380 #if 0    
00381         if (constrained) {
00382             if ((*i).selected)
00383                 size = (*i).c_size;
00384             else
00385                 size = 0;
00386         }
00387         else
00388             size = (*i).size;
00389 #endif
00390 
00391     return size;
00392 }
00393 
00412 int
00413 Array::dimension_start(Dim_iter i, bool /*constrained*/)
00414 {
00415     return (!_shape.empty()) ? (*i).start : 0;
00416     
00417 #if 0
00418     int start = 0;
00419 
00420     if (!_shape.empty())
00421         start = (*i).start;
00422         
00423 #if array_selected
00424         if (constrained) {
00425             if ((*i).selected)
00426                 start = (*i).start;
00427             else
00428                 start = 0;
00429         }
00430         else
00431             start = (*i).start;
00432 #endif
00433 
00434     return start;
00435 #endif
00436 }
00437 
00456 int
00457 Array::dimension_stop(Dim_iter i, bool /*constrained*/)
00458 {
00459     return (!_shape.empty()) ? (*i).stop : 0;
00460     
00461 #if 0
00462     int stop = 0;
00463 
00464     if (!_shape.empty())
00465         stop = (*i).stop;
00466     
00467 #if array_selected
00468         if (constrained) {
00469             if ((*i).selected)
00470                 stop = (*i).stop;
00471             else
00472                 stop = 0;
00473         }
00474         else
00475             stop = (*i).stop;
00476 #endif
00477 
00478     return stop;
00479 #endif
00480 }
00481 
00501 int
00502 Array::dimension_stride(Dim_iter i, bool /*constrained*/)
00503 {
00504     return (!_shape.empty()) ? (*i).stride : 0;
00505     
00506 #if 0
00507     int stride = 0;
00508 
00509     if (!_shape.empty())
00510         stride = (*i).stride;
00511     
00512 #if array_selected
00513         if (constrained) {
00514             if ((*i).selected)
00515                 stride = (*i).stride;
00516             else
00517                 stride = 0;
00518         }
00519         else
00520             stride = (*i).stride;
00521 #endif
00522 
00523     return stride;
00524 #endif
00525 }
00526 
00537 string
00538 Array::dimension_name(Dim_iter i)
00539 {
00540     // Jose Garcia
00541     // Since this method is public, it is possible for a user
00542     // to call it before the Array object has been properly set
00543     // this will cause an exception which is the user's fault.
00544     // (User in this context is the developer of the surrogate library.)
00545     if (_shape.empty())
00546         throw  InternalErr(__FILE__, __LINE__,
00547                            "*This* array has no dimensions.");
00548     return (*i).name;
00549 }
00550 
00568 void
00569 Array::print_decl(FILE *out, string space, bool print_semi,
00570                   bool constraint_info, bool constrained)
00571 {
00572     if (constrained && !send_p())
00573         return;
00574 
00575     // print it, but w/o semicolon
00576     var()->print_decl(out, space, false, constraint_info, constrained);
00577 
00578     for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
00579 #if 0
00580         if (constrained && !((*i).selected))
00581             continue;
00582 #endif
00583         fprintf(out, "[") ;
00584         if ((*i).name != "") {
00585             fprintf(out, "%s = ", id2www((*i).name).c_str()) ;
00586         }
00587         if (constrained) {
00588             fprintf(out, "%d]", (*i).c_size) ;
00589         }
00590         else {
00591             fprintf(out, "%d]", (*i).size) ;
00592         }
00593     }
00594 
00595     if (print_semi) {
00596         fprintf(out, ";\n") ;
00597     }
00598 }
00599 
00617 void
00618 Array::print_decl(ostream &out, string space, bool print_semi,
00619                   bool constraint_info, bool constrained)
00620 {
00621     if (constrained && !send_p())
00622         return;
00623 
00624     // print it, but w/o semicolon
00625     var()->print_decl(out, space, false, constraint_info, constrained);
00626 
00627     for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
00628 #if 0
00629         if (constrained && !((*i).selected))
00630             continue;
00631 #endif
00632         out << "[" ;
00633         if ((*i).name != "") {
00634             out << id2www((*i).name) << " = " ;
00635         }
00636         if (constrained) {
00637             out << (*i).c_size << "]" ;
00638         }
00639         else {
00640             out << (*i).size << "]" ;
00641         }
00642     }
00643 
00644     if (print_semi) {
00645         out << ";\n" ;
00646     }
00647 }
00648 
00649 void
00650 Array::print_xml(FILE *out, string space, bool constrained)
00651 {
00652     print_xml_core(out, space, constrained, "Array");
00653 }
00654 
00655 void
00656 Array::print_xml(ostream &out, string space, bool constrained)
00657 {
00658     print_xml_core(out, space, constrained, "Array");
00659 }
00660 
00661 void
00662 Array::print_as_map_xml(FILE *out, string space, bool constrained)
00663 {
00664     print_xml_core(out, space, constrained, "Map");
00665 }
00666 
00667 void
00668 Array::print_as_map_xml(ostream &out, string space, bool constrained)
00669 {
00670     print_xml_core(out, space, constrained, "Map");
00671 }
00672 
00673 class PrintArrayDim : public unary_function<Array::dimension&, void>
00674 {
00675     FILE *d_out;
00676     string d_space;
00677     bool d_constrained;
00678 public:
00679     PrintArrayDim(FILE *o, string s, bool c)
00680             : d_out(o), d_space(s), d_constrained(c)
00681     {}
00682 
00683     void operator()(Array::dimension &d)
00684     {
00685         int size = d_constrained ? d.c_size : d.size;
00686         if (d.name.empty())
00687             fprintf(d_out, "%s<dimension size=\"%d\"/>\n", d_space.c_str(),
00688                     size);
00689         else
00690             fprintf(d_out, "%s<dimension name=\"%s\" size=\"%d\"/>\n",
00691                     d_space.c_str(), id2xml(d.name).c_str(), size);
00692     }
00693 };
00694 
00695 void
00696 Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
00697 {
00698     if (constrained && !send_p())
00699         return;
00700 
00701     fprintf(out, "%s<%s", space.c_str(), tag.c_str());
00702     if (!name().empty())
00703         fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
00704     fprintf(out , ">\n");
00705 
00706     get_attr_table().print_xml(out, space + "    ", constrained);
00707 
00708     BaseType *btp = var();
00709     string tmp_name = btp->name();
00710     btp->set_name("");
00711     btp->print_xml(out, space + "    ", constrained);
00712     btp->set_name(tmp_name);
00713 
00714     for_each(dim_begin(), dim_end(),
00715              PrintArrayDim(out, space + "    ", constrained));
00716 
00717     fprintf(out, "%s</%s>\n", space.c_str(), tag.c_str());
00718 }
00719 
00720 class PrintArrayDimStrm : public unary_function<Array::dimension&, void>
00721 {
00722     ostream &d_out;
00723     string d_space;
00724     bool d_constrained;
00725 public:
00726     PrintArrayDimStrm(ostream &o, string s, bool c)
00727             : d_out(o), d_space(s), d_constrained(c)
00728     {}
00729 
00730     void operator()(Array::dimension &d)
00731     {
00732         int size = d_constrained ? d.c_size : d.size;
00733         if (d.name.empty())
00734             d_out << d_space << "<dimension size=\"" << size << "\"/>\n" ;
00735         else
00736             d_out << d_space << "<dimension name=\"" << id2xml(d.name)
00737                   << "\" size=\"" << size << "\"/>\n" ;
00738     }
00739 };
00740 
00741 void
00742 Array::print_xml_core(ostream &out, string space, bool constrained, string tag)
00743 {
00744     if (constrained && !send_p())
00745         return;
00746 
00747     out << space << "<" << tag ;
00748     if (!name().empty())
00749         out << " name=\"" << id2xml(name()) << "\"" ;
00750     out << ">\n" ;
00751 
00752     get_attr_table().print_xml(out, space + "    ", constrained);
00753 
00754     BaseType *btp = var();
00755     string tmp_name = btp->name();
00756     btp->set_name("");
00757     btp->print_xml(out, space + "    ", constrained);
00758     btp->set_name(tmp_name);
00759 
00760     for_each(dim_begin(), dim_end(),
00761              PrintArrayDimStrm(out, space + "    ", constrained));
00762 
00763     out << space << "</" << tag << ">\n" ;
00764 }
00765 
00776 unsigned int
00777 Array::print_array(FILE *out, unsigned int index, unsigned int dims,
00778                    unsigned int shape[])
00779 {
00780     if (dims == 1) {
00781         fprintf(out, "{") ;
00782         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00783             var(index++)->print_val(out, "", false);
00784             fprintf(out, ", ") ;
00785         }
00786         var(index++)->print_val(out, "", false);
00787         fprintf(out, "}") ;
00788 
00789         return index;
00790     }
00791     else {
00792         fprintf(out, "{") ;
00793         // Fixed an off-by-one error in the following loop. Since the array
00794         // length is shape[dims-1]-1 *and* since we want one less dimension
00795         // than that, the correct limit on this loop is shape[dims-2]-1. From
00796         // Todd Karakasian.
00797         // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
00798         // 9/12/96.
00799         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00800             index = print_array(out, index, dims - 1, shape + 1);
00801             fprintf(out, ",") ;   // Removed the extra `}'. Also from Todd
00802         }
00803         index = print_array(out, index, dims - 1, shape + 1);
00804         fprintf(out, "}") ;
00805 
00806         return index;
00807     }
00808 }
00809 
00820 unsigned int
00821 Array::print_array(ostream &out, unsigned int index, unsigned int dims,
00822                    unsigned int shape[])
00823 {
00824     if (dims == 1) {
00825         out << "{" ;
00826         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00827             var(index++)->print_val(out, "", false);
00828             out << ", " ;
00829         }
00830         var(index++)->print_val(out, "", false);
00831         out << "}" ;
00832 
00833         return index;
00834     }
00835     else {
00836         out << "{" ;
00837         // Fixed an off-by-one error in the following loop. Since the array
00838         // length is shape[dims-1]-1 *and* since we want one less dimension
00839         // than that, the correct limit on this loop is shape[dims-2]-1. From
00840         // Todd Karakasian.
00841         // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
00842         // 9/12/96.
00843         for (unsigned i = 0; i < shape[0] - 1; ++i) {
00844             index = print_array(out, index, dims - 1, shape + 1);
00845             out << "," ;
00846         }
00847         index = print_array(out, index, dims - 1, shape + 1);
00848         out << "}" ;
00849 
00850         return index;
00851     }
00852 }
00853 
00854 void
00855 Array::print_val(FILE *out, string space, bool print_decl_p)
00856 {
00857     // print the declaration if print decl is true.
00858     // for each dimension,
00859     //   for each element,
00860     //     print the array given its shape, number of dimensions.
00861     // Add the `;'
00862 
00863     if (print_decl_p) {
00864         print_decl(out, space, false, false, false);
00865         fprintf(out, " = ") ;
00866     }
00867 
00868     unsigned int *shape = new unsigned int[_shape.size()];
00869     unsigned int index = 0;
00870     for (Dim_iter i = _shape.begin(); i != _shape.end() && index < _shape.size(); i++)
00871         shape[index++] = dimension_size(i, true);
00872 
00873     print_array(out, 0, _shape.size(), shape);
00874     
00875     delete [] shape; shape = 0;
00876 
00877     if (print_decl_p) {
00878         fprintf(out, ";\n") ;
00879     }
00880 }
00881 
00882 void
00883 Array::print_val(ostream &out, string space, bool print_decl_p)
00884 {
00885     // print the declaration if print decl is true.
00886     // for each dimension,
00887     //   for each element,
00888     //     print the array given its shape, number of dimensions.
00889     // Add the `;'
00890 
00891     if (print_decl_p) {
00892         print_decl(out, space, false, false, false);
00893             out << " = " ;
00894     }
00895 
00896     unsigned int *shape = new unsigned int[dimensions(true)];
00897     unsigned int index = 0;
00898     for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i)
00899         shape[index++] = dimension_size(i, true);
00900 
00901     print_array(out, 0, dimensions(true), shape);
00902     
00903     delete [] shape; shape = 0;
00904 
00905     if (print_decl_p) {
00906             out << ";\n" ;
00907     }
00908 }
00909 
00919 bool
00920 Array::check_semantics(string &msg, bool)
00921 {
00922     bool sem = BaseType::check_semantics(msg) && !_shape.empty();
00923 
00924     if (!sem)
00925         msg = "An array variable must have dimensions";
00926 
00927     return sem;
00928 }
00929 
00938 void
00939 Array::dump(ostream &strm) const
00940 {
00941     strm << DapIndent::LMarg << "Array::dump - ("
00942     << (void *)this << ")" << endl ;
00943     DapIndent::Indent() ;
00944     Vector::dump(strm) ;
00945     strm << DapIndent::LMarg << "shape:" << endl ;
00946     DapIndent::Indent() ;
00947     Dim_citer i = _shape.begin() ;
00948     Dim_citer ie = _shape.end() ;
00949     unsigned int dim_num = 0 ;
00950     for (; i != ie; i++) {
00951         strm << DapIndent::LMarg << "dimension " << dim_num++ << ":"
00952              << endl ;
00953         DapIndent::Indent() ;
00954         strm << DapIndent::LMarg << "name: " << (*i).name << endl ;
00955         strm << DapIndent::LMarg << "size: " << (*i).size << endl ;
00956         strm << DapIndent::LMarg << "start: " << (*i).start << endl ;
00957         strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ;
00958         strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ;
00959         strm << DapIndent::LMarg << "constrained size: " << (*i).c_size
00960              << endl ;
00961 #if 0
00962         strm << DapIndent::LMarg << "selected: " << (*i).selected << endl ;
00963 #endif
00964         DapIndent::UnIndent() ;
00965     }
00966     DapIndent::UnIndent() ;
00967     DapIndent::UnIndent() ;
00968 }
00969 

Generated on Wed Jan 2 04:13:15 2008 for libdap++ by  doxygen 1.5.4