libdap++  Updated for version 3.8.2
Array.cc
Go to the documentation of this file.
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
5 // Access Protocol.
6 
7 // Copyright (c) 2002,2003 OPeNDAP, Inc.
8 // Author: James Gallagher <jgallagher@opendap.org>
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 //
24 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25 
26 // (c) COPYRIGHT URI/MIT 1994-1999
27 // Please read the full copyright statement in the file COPYRIGHT_URI.
28 //
29 // Authors:
30 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31 
32 // Implementation for Array.
33 //
34 // jhrg 9/13/94
35 
36 
37 #include "config.h"
38 
39 #include "Array.h"
40 #include "util.h"
41 #include "debug.h"
42 #include "InternalErr.h"
43 #include "escaping.h"
44 
45 #include <algorithm>
46 #include <functional>
47 
48 using namespace std;
49 
50 namespace libdap {
51 
52 void
53 Array::_duplicate(const Array &a)
54 {
55  _shape = a._shape;
56 }
57 
58 // The first method of calculating length works when only one dimension is
59 // constrained and you want the others to appear in total. This is important
60 // when selecting from grids since users may not select from all dimensions
61 // in which case that means they want the whole thing. Array projection
62 // should probably work this way too, but it doesn't. 9/21/2001 jhrg
63 
71 void
72 Array::update_length(int)
73 {
74  int length = 1;
75  for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
76  length *= (*i).c_size > 0 ? (*i).c_size : 1;
77  }
78 
79  set_length(length);
80 }
81 
82 // Construct an instance of Array. The (BaseType *) is assumed to be
83 // allocated using new - The dtor for Vector will delete this object.
84 
100 Array::Array(const string &n, BaseType *v) : Vector(n, 0, dods_array_c)
101 {
102  add_var(v); // Vector::add_var() stores null is v is null
103 }
104 
118 Array::Array(const string &n, const string &d, BaseType *v)
119  : Vector(n, d, 0, dods_array_c)
120 {
121  add_var(v); // Vector::add_var() stores null is v is null
122 }
123 
125 Array::Array(const Array &rhs) : Vector(rhs)
126 {
127  _duplicate(rhs);
128 }
129 
132 {
133  DBG(cerr << "Entering ~Array (" << this << ")" << endl);
134  DBG(cerr << "Exiting ~Array" << endl);
135 }
136 
137 BaseType *
139 {
140  return new Array(*this);
141 }
142 
143 Array &
145 {
146  if (this == &rhs)
147  return *this;
148 
149  dynamic_cast<Vector &>(*this) = rhs;
150 
151  _duplicate(rhs);
152 
153  return *this;
154 }
155 
175 void
177 {
178  if (v && v->type() == dods_array_c) {
179  Array &a = dynamic_cast<Array&>(*v);
180  Vector::add_var(a.var());
181  Dim_iter i = a.dim_begin();
182  Dim_iter i_end = a.dim_end();
183  while (i != i_end) {
185  ++i;
186  }
187  }
188  else {
189  Vector::add_var(v);
190  }
191 }
192 
204 void
205 Array::append_dim(int size, string name)
206 {
207  dimension d;
208 
209  // This is invariant
210  d.size = size;
211  d.name = www2id(name);
212 
213  // this information changes with each constraint expression
214  d.start = 0;
215  d.stop = size - 1;
216  d.stride = 1;
217  d.c_size = size;
218 
219  _shape.push_back(d);
220 
221  update_length(size);
222 }
223 
229 void
230 Array::prepend_dim(int size, const string& name/* = "" */)
231 {
232  dimension d;
233 
234  // This is invariant
235  d.size = size;
236  d.name = www2id(name);
237 
238  // this information changes with each constraint expression
239  d.start = 0;
240  d.stop = size - 1;
241  d.stride = 1;
242  d.c_size = size;
243 
244  // Shifts the whole array, but it's tiny in general
245  _shape.insert(_shape.begin(), d);
246 
247  update_length(size); // the number is ignored...
248 }
249 
256 void
258 {
259  set_length(-1);
260 
261  for (Dim_iter i = _shape.begin(); i != _shape.end(); i++) {
262  (*i).start = 0;
263  (*i).stop = (*i).size - 1;
264  (*i).stride = 1;
265  (*i).c_size = (*i).size;
266 
267  update_length((*i).size);
268  }
269 }
270 
271 
281 void
283 {
285 }
286 
287 // Note: MS VC++ won't tolerate embedded newlines in strings, hence the \n
288 // is explicit.
289 static const char *array_sss = \
290 "Invalid constraint parameters: At least one of the start, stride or stop \n\
291 specified do not match the array variable.";
292 
312 void
313 Array::add_constraint(Dim_iter i, int start, int stride, int stop)
314 {
315  dimension &d = *i ;
316 
317  // Check for bad constraints.
318  // Jose Garcia
319  // Usually invalid data for a constraint is the user's mistake
320  // because they build a wrong URL in the client side.
321  if (start >= d.size || stop >= d.size || stride > d.size || stride <= 0)
322  throw Error(malformed_expr, array_sss);
323 
324  if (((stop - start) / stride + 1) > d.size)
325  throw Error(malformed_expr, array_sss);
326 
327  d.start = start;
328  d.stop = stop;
329  d.stride = stride;
330 
331  d.c_size = (stop - start) / stride + 1;
332 
333  DBG(cerr << "add_constraint: c_size = " << d.c_size << endl);
334 
336 }
337 
341 {
342  return _shape.begin() ;
343 }
344 
348 {
349  return _shape.end() ;
350 }
351 
361 unsigned int
362 Array::dimensions(bool /*constrained*/)
363 {
364  unsigned int dim = 0;
365  for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
366  dim++;
367  }
368 
369  return dim;
370 }
371 
389 int
390 Array::dimension_size(Dim_iter i, bool constrained)
391 {
392  int size = 0;
393 
394  if (!_shape.empty()) {
395  if (constrained)
396  size = (*i).c_size;
397  else
398  size = (*i).size;
399  }
400 
401  return size;
402 }
403 
422 int
423 Array::dimension_start(Dim_iter i, bool /*constrained*/)
424 {
425  return (!_shape.empty()) ? (*i).start : 0;
426 }
427 
446 int
447 Array::dimension_stop(Dim_iter i, bool /*constrained*/)
448 {
449  return (!_shape.empty()) ? (*i).stop : 0;
450 }
451 
471 int
472 Array::dimension_stride(Dim_iter i, bool /*constrained*/)
473 {
474  return (!_shape.empty()) ? (*i).stride : 0;
475 }
476 
487 string
489 {
490  // Jose Garcia
491  // Since this method is public, it is possible for a user
492  // to call it before the Array object has been properly set
493  // this will cause an exception which is the user's fault.
494  // (User in this context is the developer of the surrogate library.)
495  if (_shape.empty())
496  throw InternalErr(__FILE__, __LINE__,
497  "*This* array has no dimensions.");
498  return (*i).name;
499 }
500 
501 #if FILE_METHODS
502 
519 void
520 Array::print_decl(FILE *out, string space, bool print_semi,
521  bool constraint_info, bool constrained)
522 {
523  if (constrained && !send_p())
524  return;
525 
526  // print it, but w/o semicolon
527  var()->print_decl(out, space, false, constraint_info, constrained);
528 
529  for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
530  fprintf(out, "[") ;
531  if ((*i).name != "") {
532  fprintf(out, "%s = ", id2www((*i).name).c_str()) ;
533  }
534  if (constrained) {
535  fprintf(out, "%d]", (*i).c_size) ;
536  }
537  else {
538  fprintf(out, "%d]", (*i).size) ;
539  }
540  }
541 
542  if (print_semi) {
543  fprintf(out, ";\n") ;
544  }
545 }
546 #endif
547 
565 void
566 Array::print_decl(ostream &out, string space, bool print_semi,
567  bool constraint_info, bool constrained)
568 {
569  if (constrained && !send_p())
570  return;
571 
572  // print it, but w/o semicolon
573  var()->print_decl(out, space, false, constraint_info, constrained);
574 
575  for (Dim_citer i = _shape.begin(); i != _shape.end(); i++) {
576  out << "[" ;
577  if ((*i).name != "") {
578  out << id2www((*i).name) << " = " ;
579  }
580  if (constrained) {
581  out << (*i).c_size << "]" ;
582  }
583  else {
584  out << (*i).size << "]" ;
585  }
586  }
587 
588  if (print_semi) {
589  out << ";\n" ;
590  }
591 }
592 #if FILE_METHODS
593 void
594 Array::print_xml(FILE *out, string space, bool constrained)
595 {
596  print_xml_core(out, space, constrained, "Array");
597 }
598 #endif
599 void
600 Array::print_xml(ostream &out, string space, bool constrained)
601 {
602  print_xml_core(out, space, constrained, "Array");
603 }
604 #if FILE_METHODS
605 void
606 Array::print_as_map_xml(FILE *out, string space, bool constrained)
607 {
608  print_xml_core(out, space, constrained, "Map");
609 }
610 #endif
611 void
612 Array::print_as_map_xml(ostream &out, string space, bool constrained)
613 {
614  print_xml_core(out, space, constrained, "Map");
615 }
616 #if FILE_METHODS
617 class PrintArrayDim : public unary_function<Array::dimension&, void>
618 {
619  FILE *d_out;
620  string d_space;
621  bool d_constrained;
622 public:
623  PrintArrayDim(FILE *o, string s, bool c)
624  : d_out(o), d_space(s), d_constrained(c)
625  {}
626 
627  void operator()(Array::dimension &d)
628  {
629  int size = d_constrained ? d.c_size : d.size;
630  if (d.name.empty())
631  fprintf(d_out, "%s<dimension size=\"%d\"/>\n", d_space.c_str(),
632  size);
633  else
634  fprintf(d_out, "%s<dimension name=\"%s\" size=\"%d\"/>\n",
635  d_space.c_str(), id2xml(d.name).c_str(), size);
636  }
637 };
638 
639 void
640 Array::print_xml_core(FILE *out, string space, bool constrained, string tag)
641 {
642  if (constrained && !send_p())
643  return;
644 
645  fprintf(out, "%s<%s", space.c_str(), tag.c_str());
646  if (!name().empty())
647  fprintf(out, " name=\"%s\"", id2xml(name()).c_str());
648  fprintf(out , ">\n");
649 
650  get_attr_table().print_xml(out, space + " ", constrained);
651 
652  BaseType *btp = var();
653  string tmp_name = btp->name();
654  btp->set_name("");
655  btp->print_xml(out, space + " ", constrained);
656  btp->set_name(tmp_name);
657 
658  for_each(dim_begin(), dim_end(),
659  PrintArrayDim(out, space + " ", constrained));
660 
661  fprintf(out, "%s</%s>\n", space.c_str(), tag.c_str());
662 }
663 #endif
664 
665 class PrintArrayDimStrm : public unary_function<Array::dimension&, void>
666 {
667  ostream &d_out;
668  string d_space;
669  bool d_constrained;
670 public:
671  PrintArrayDimStrm(ostream &o, string s, bool c)
672  : d_out(o), d_space(s), d_constrained(c)
673  {}
674 
675  void operator()(Array::dimension &d)
676  {
677  int size = d_constrained ? d.c_size : d.size;
678  if (d.name.empty())
679  d_out << d_space << "<dimension size=\"" << size << "\"/>\n" ;
680  else
681  d_out << d_space << "<dimension name=\"" << id2xml(d.name)
682  << "\" size=\"" << size << "\"/>\n" ;
683  }
684 };
685 
686 void
687 Array::print_xml_core(ostream &out, string space, bool constrained, string tag)
688 {
689  if (constrained && !send_p())
690  return;
691 
692  out << space << "<" << tag ;
693  if (!name().empty())
694  out << " name=\"" << id2xml(name()) << "\"" ;
695  out << ">\n" ;
696 
697  get_attr_table().print_xml(out, space + " ", constrained);
698 
699  BaseType *btp = var();
700  string tmp_name = btp->name();
701  btp->set_name("");
702  btp->print_xml(out, space + " ", constrained);
703  btp->set_name(tmp_name);
704 
705  for_each(dim_begin(), dim_end(),
706  PrintArrayDimStrm(out, space + " ", constrained));
707 
708  out << space << "</" << tag << ">\n" ;
709 }
710 
711 #if FILE_METHODS
712 
723 unsigned int
724 Array::print_array(FILE *out, unsigned int index, unsigned int dims,
725  unsigned int shape[])
726 {
727  if (dims == 1) {
728  fprintf(out, "{") ;
729  for (unsigned i = 0; i < shape[0] - 1; ++i) {
730  var(index++)->print_val(out, "", false);
731  fprintf(out, ", ") ;
732  }
733  var(index++)->print_val(out, "", false);
734  fprintf(out, "}") ;
735 
736  return index;
737  }
738  else {
739  fprintf(out, "{") ;
740  // Fixed an off-by-one error in the following loop. Since the array
741  // length is shape[dims-1]-1 *and* since we want one less dimension
742  // than that, the correct limit on this loop is shape[dims-2]-1. From
743  // Todd Karakasian.
744  // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
745  // 9/12/96.
746  for (unsigned i = 0; i < shape[0] - 1; ++i) {
747  index = print_array(out, index, dims - 1, shape + 1);
748  fprintf(out, ",") ; // Removed the extra `}'. Also from Todd
749  }
750  index = print_array(out, index, dims - 1, shape + 1);
751  fprintf(out, "}") ;
752 
753  return index;
754  }
755 }
756 #endif
757 
769 unsigned int
770 Array::print_array(ostream &out, unsigned int index, unsigned int dims,
771  unsigned int shape[])
772 {
773  if (dims == 1) {
774  out << "{" ;
775  for (unsigned i = 0; i < shape[0] - 1; ++i) {
776  var(index++)->print_val(out, "", false);
777  out << ", " ;
778  }
779  var(index++)->print_val(out, "", false);
780  out << "}" ;
781 
782  return index;
783  }
784  else {
785  out << "{" ;
786  // Fixed an off-by-one error in the following loop. Since the array
787  // length is shape[dims-1]-1 *and* since we want one less dimension
788  // than that, the correct limit on this loop is shape[dims-2]-1. From
789  // Todd Karakasian.
790  // The saga continues; the loop test should be `i < shape[0]-1'. jhrg
791  // 9/12/96.
792  for (unsigned i = 0; i < shape[0] - 1; ++i) {
793  index = print_array(out, index, dims - 1, shape + 1);
794  out << "," ;
795  }
796  index = print_array(out, index, dims - 1, shape + 1);
797  out << "}" ;
798 
799  return index;
800  }
801 }
802 
803 #if FILE_METHODS
804 void
805 Array::print_val(FILE *out, string space, bool print_decl_p)
806 {
807  // print the declaration if print decl is true.
808  // for each dimension,
809  // for each element,
810  // print the array given its shape, number of dimensions.
811  // Add the `;'
812 
813  if (print_decl_p) {
814  print_decl(out, space, false, false, false);
815  fprintf(out, " = ") ;
816  }
817 
818  unsigned int *shape = new unsigned int[_shape.size()];
819  unsigned int index = 0;
820  for (Dim_iter i = _shape.begin(); i != _shape.end() && index < _shape.size(); i++)
821  shape[index++] = dimension_size(i, true);
822 
823  print_array(out, 0, _shape.size(), shape);
824 
825  delete [] shape; shape = 0;
826 
827  if (print_decl_p) {
828  fprintf(out, ";\n") ;
829  }
830 }
831 #endif
832 
833 void
834 Array::print_val(ostream &out, string space, bool print_decl_p)
835 {
836  // print the declaration if print decl is true.
837  // for each dimension,
838  // for each element,
839  // print the array given its shape, number of dimensions.
840  // Add the `;'
841 
842  if (print_decl_p) {
843  print_decl(out, space, false, false, false);
844  out << " = " ;
845  }
846 
847  unsigned int *shape = new unsigned int[dimensions(true)];
848  unsigned int index = 0;
849  for (Dim_iter i = _shape.begin(); i != _shape.end() && index < dimensions(true); ++i)
850  shape[index++] = dimension_size(i, true);
851 
852  print_array(out, 0, dimensions(true), shape);
853 
854  delete [] shape; shape = 0;
855 
856  if (print_decl_p) {
857  out << ";\n" ;
858  }
859 }
860 
870 bool
871 Array::check_semantics(string &msg, bool)
872 {
873  bool sem = BaseType::check_semantics(msg) && !_shape.empty();
874 
875  if (!sem)
876  msg = "An array variable must have dimensions";
877 
878  return sem;
879 }
880 
889 void
890 Array::dump(ostream &strm) const
891 {
892  strm << DapIndent::LMarg << "Array::dump - ("
893  << (void *)this << ")" << endl ;
895  Vector::dump(strm) ;
896  strm << DapIndent::LMarg << "shape:" << endl ;
898  Dim_citer i = _shape.begin() ;
899  Dim_citer ie = _shape.end() ;
900  unsigned int dim_num = 0 ;
901  for (; i != ie; i++) {
902  strm << DapIndent::LMarg << "dimension " << dim_num++ << ":"
903  << endl ;
905  strm << DapIndent::LMarg << "name: " << (*i).name << endl ;
906  strm << DapIndent::LMarg << "size: " << (*i).size << endl ;
907  strm << DapIndent::LMarg << "start: " << (*i).start << endl ;
908  strm << DapIndent::LMarg << "stop: " << (*i).stop << endl ;
909  strm << DapIndent::LMarg << "stride: " << (*i).stride << endl ;
910  strm << DapIndent::LMarg << "constrained size: " << (*i).c_size
911  << endl ;
913  }
916 }
917 
918 } // namespace libdap
919