1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2013 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 #ifndef D4DIMENSIONS_H_
26 #define D4DIMENSIONS_H_
27 
28 #include <string>
29 #include <vector>
30 
31 // #include "XMLWriter.h"
32 
33 using namespace std;
34 
35 namespace libdap {
36 
37 class D4Group;
38 class D4Dimensions;
39 class XMLWriter;
40 
41 class D4Dimension {
42     string d_name;
43     unsigned long long d_size;
44 
45     D4Dimensions *d_parent;	// This is used to get the Dimensions and then the Group object
46 
47     bool d_constrained;
48     unsigned long long d_c_start, d_c_stride, d_c_stop;
49 
50     bool d_used_by_projected_var;
51 
52 public:
D4Dimension()53     D4Dimension() : d_name(""), d_size(0),  d_parent(0), d_constrained(false), d_c_start(0), d_c_stride(0),
54             d_c_stop(0), d_used_by_projected_var(false) {}
d_name(name)55     D4Dimension(const string &name, unsigned long long size, D4Dimensions *d = 0) : d_name(name), d_size(size), d_parent(d),
56             d_constrained(false), d_c_start(0), d_c_stride(0), d_c_stop(0), d_used_by_projected_var(false) {}
57 
name()58     string name() const {return d_name;}
set_name(const string & name)59     void set_name(const string &name) { d_name = name; }
60     string fully_qualified_name() const;
61 
size()62     unsigned long long size() const { return d_size; }
set_size(unsigned long long size)63     void set_size(unsigned long long size) { d_size = size; }
64     // Because we build these in the XML parser and it's all text...
65     void set_size(const string &size);
66 
parent()67     D4Dimensions *parent() const { return d_parent; }
set_parent(D4Dimensions * d)68     void set_parent(D4Dimensions *d) { d_parent = d; }
69 
constrained()70     bool constrained() const { return d_constrained; }
c_start()71     unsigned long long c_start() const { return d_c_start; }
c_stride()72     unsigned long long c_stride() const { return d_c_stride; }
c_stop()73     unsigned long long c_stop() const { return d_c_stop; }
74 
used_by_projected_var()75     bool used_by_projected_var() const { return d_used_by_projected_var; }
set_used_by_projected_var(bool state)76     void set_used_by_projected_var(bool state) { d_used_by_projected_var = state; }
77 
78     /**
79      * Set this Shared Diemension's constraint. While an Array Dimension object uses a
80      * stop value of -1 to indicate the end of the dimension, this method does not support
81      * that; the caller will have to sort out the correct end value for 'stop'.
82      * @param start Starting index (zero-based)
83      * @param stride The stride for the slice
84      * @param stop The stopping index (never greater than size -1)
85      */
set_constraint(unsigned long long start,unsigned long long stride,unsigned long long stop)86     void set_constraint(unsigned long long start, unsigned long long stride, unsigned long long stop) {
87         d_c_start = start;
88         d_c_stride = stride;
89         d_c_stop = stop;
90         d_constrained = true;
91     }
92 
93     void print_dap4(XMLWriter &xml) const;
94 };
95 
96 /**
97  * This class holds information about dimensions. This can be used to store
98  * actual dimension information in an instance of BaseType and it can be
99  * used to store the definition of a dimension in an instance of Group.
100  */
101 class D4Dimensions {
102     vector<D4Dimension*> d_dims;
103 
104     D4Group *d_parent;		// the group that holds this set of D4Dimensions; weak pointer, don't delete
105 
106 protected:
107     // Note Code in Array depends on the order of these 'new' dimensions
108     // matching the 'old' dimensions they are derived from. See
109     // Array::update_dimension_pointers. jhrg 8/25/14
m_duplicate(const D4Dimensions & rhs)110     void m_duplicate(const D4Dimensions &rhs) {
111         D4DimensionsCIter i = rhs.d_dims.begin();
112         while (i != rhs.d_dims.end()) {
113             d_dims.push_back(new D4Dimension(**i++));    // deep copy
114             d_dims.back()->set_parent(this);			// Set the Dimension's parent
115         }
116 
117         d_parent = rhs.d_parent;
118     }
119 
120 public:
121     /// Iterator used for D4Dimensions
122     typedef vector<D4Dimension*>::iterator D4DimensionsIter;
123     typedef vector<D4Dimension*>::const_iterator D4DimensionsCIter;
124 
D4Dimensions()125     D4Dimensions() : d_parent(0) {}
D4Dimensions(D4Group * g)126     D4Dimensions(D4Group *g) : d_parent(g) {}
D4Dimensions(const D4Dimensions & rhs)127     D4Dimensions(const D4Dimensions &rhs) : d_parent(0) { m_duplicate(rhs); }
128 
~D4Dimensions()129     virtual ~D4Dimensions() {
130         D4DimensionsIter i = d_dims.begin();
131         while (i != d_dims.end())
132             delete *i++;
133     }
134 
135     D4Dimensions &operator=(const D4Dimensions &rhs) {
136         if (this == &rhs) return *this;
137         m_duplicate(rhs);
138         return *this;
139     }
140 
141     /// Does this D4Dimensions object actually have dimensions?
empty()142     bool empty() const { return d_dims.empty(); }
143 
parent()144     D4Group *parent() const { return d_parent;}
set_parent(D4Group * g)145     void set_parent(D4Group *g) { d_parent = g; }
146 
147     /** Append a new dimension.
148      * In DAP4 dimensions are either of a known size or are varying. For
149      * fixed-size dimensions, the value of varying should be false. For varying
150      * dimensions the value of 'size' will be ignored - any value can be used
151      * when called this method.
152      *
153      * @param dim Pointer to the D4Dimension object to add; deep copy
154      */
add_dim(D4Dimension * dim)155     void add_dim(D4Dimension *dim) { add_dim_nocopy(new D4Dimension(*dim)); }
156 
157     /** Append a new dimension.
158      * @param dim Pointer to the D4Dimension object to add; copies the pointer
159      */
add_dim_nocopy(D4Dimension * dim)160     void add_dim_nocopy(D4Dimension *dim) { dim->set_parent(this); d_dims.push_back(dim); }
161 
162     /// Get an iterator to the start of the dimensions
dim_begin()163     D4DimensionsIter dim_begin() { return d_dims.begin(); }
164 
165     /// Get an iterator to the end of the dimensions
dim_end()166     D4DimensionsIter dim_end() { return d_dims.end(); }
167 
168     D4Dimension *find_dim(const string &name);
169 
170     /** Insert a dimension.
171      * Insert a dimension before the position specified by the iterator.
172      * @note Calling this method invalidates all iterators that reference this
173      * D4Dimension object.
174      * @param dim Inserted before i; deep copy
175      * @param i iterator
176      */
insert_dim(D4Dimension * dim,D4DimensionsIter i)177     void insert_dim(D4Dimension *dim, D4DimensionsIter i) {
178     	insert_dim_nocopy(new D4Dimension(*dim), i);
179     }
180 
181     /** Insert a dimension.
182      * @param dim Inserted before i; pointer copy
183      * @param i iterator
184      */
insert_dim_nocopy(D4Dimension * dim,D4DimensionsIter i)185     void insert_dim_nocopy(D4Dimension *dim, D4DimensionsIter i) {
186     	dim->set_parent(this);
187         d_dims.insert(i, dim);
188     }
189 
190     void print_dap4(XMLWriter &xml, bool constrained = false) const;
191 };
192 
193 } /* namespace libdap */
194 #endif /* D4DIMENSIONS_H_ */
195