1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5 
6 /*!
7  ******************************************************************************
8  *
9  * \file AttrValue.hpp
10  *
11  * \brief   Header file containing definition of AttrValue class.
12  *
13  ******************************************************************************
14  */
15 
16 // Standard C++ headers
17 #include <string>
18 #include <vector>
19 
20 // Other axom headers
21 #include "axom/config.hpp"
22 #include "axom/core/Macros.hpp"
23 #include "axom/slic/interface/slic.hpp"
24 
25 // Sidre project headers
26 #include "axom/sidre/core/Attribute.hpp"
27 #include "axom/sidre/core/SidreTypes.hpp"
28 
29 #ifndef SIDRE_ATTRVALUES_HPP_
30   #define SIDRE_ATTRVALUES_HPP_
31 
32 namespace axom
33 {
34 namespace sidre
35 {
36 class View;
37 
38 /*!
39  * \class AttrValue
40  *
41  * \brief Store Attribute values.
42  *
43  * Each attribute is defined by an instance of Attribute in the DataStore.
44  * The attribute has an associated type and index.
45  *
46  * The assumption is made that attributes will be looked up more often than
47  * set.  So getAttribute should be optimized over setAttribute.
48  *
49  * Another assumption is that the View should not pay for attributes if they
50  * are not being used.
51  *
52  * Space can be minimized by creating more common Attribute first so that they
53  * will have a lower index.
54  *
55  * Methods which accept a Attribute pointer will check for
56  * nullptr but will not print a message.  The calling routines in
57  * the View class are expected to print any error message.  This will
58  * avoid multiple messages for the same error.  For example, if the
59  * index cannot be converted to an Attribute pointer in the View
60  * class, an error message will be printing and then a NULL pointer
61  * passed to the AttrValues class which will not print another
62  * message.
63  */
64 class AttrValues
65 {
66 public:
67   /*!
68    * Friend declarations to constrain usage via controlled access to
69    * private members.
70    */
71   friend class View;
72 
73 private:
74   //DISABLE_DEFAULT_CTOR(AttrValues);
75   DISABLE_MOVE_AND_ASSIGNMENT(AttrValues);
76 
77   /*!
78    * \brief Return true if attribute is set in value.
79    */
isEmpty(Node & value)80   static bool isEmpty(Node& value) { return value.schema().dtype().is_empty(); }
81 
82   /*!
83    * \brief Return true if the attribute has been explicitly set; else false.
84    */
85   bool hasValue(const Attribute* attr) const;
86 
87   /*!
88    * \brief Create a Conduit Node to store an attribute.
89    *
90    * Create vector of Nodes and push empty nodes up to attr's index.
91    * Called as part of View::createAttributeScalar and
92    * View::createAttributeString.
93    */
94   bool createNode(IndexType idx);
95 
96   /*!
97    * \brief Set attribute to its default value.
98    */
99   bool setToDefault(const Attribute* attr);
100 
101   /*!
102    * \brief Set attribute value from a scalar.
103    */
104   template <typename ScalarType>
setScalar(const Attribute * attr,ScalarType value)105   bool setScalar(const Attribute* attr, ScalarType value)
106   {
107     DataTypeId arg_id = detail::SidreTT<ScalarType>::id;
108     if(arg_id != attr->getTypeID())
109     {
110       SLIC_CHECK_MSG(arg_id == attr->getTypeID(),
111                      "setScalar: Incorrect type for attribute '"
112                        << attr->getName() << "' of type "
113                        << attr->getDefaultNodeRef().dtype().name() << ": "
114                        << DataType::id_to_name(arg_id) << ".");
115       return false;
116     }
117 
118     IndexType iattr = attr->getIndex();
119     bool ok = createNode(iattr);
120     if(ok)
121     {
122       (*m_values)[iattr] = value;
123     }
124     return ok;
125   }
126 
127   /*!
128    * \brief Set attribute value from a string.
129    */
setString(const Attribute * attr,const std::string & value)130   bool setString(const Attribute* attr, const std::string& value)
131   {
132     DataTypeId arg_id = CHAR8_STR_ID;
133     if(arg_id != attr->getTypeID())
134     {
135       SLIC_CHECK_MSG(arg_id == attr->getTypeID(),
136                      "setString: Incorrect type for attribute '"
137                        << attr->getName() << "' of type "
138                        << attr->getDefaultNodeRef().dtype().name() << ": "
139                        << DataType::id_to_name(arg_id) << ".");
140       return false;
141     }
142 
143     IndexType iattr = attr->getIndex();
144     bool ok = createNode(iattr);
145     if(ok)
146     {
147       (*m_values)[iattr] = value;
148     }
149     return ok;
150   }
151 
152   /*!
153    * \brief Set attribute value from a Node.
154    *
155    * Used when restoring attributes from a file.
156    * The type of node is not check.
157    */
setNode(const Attribute * attr,const Node & node)158   bool setNode(const Attribute* attr, const Node& node)
159   {
160     IndexType iattr = attr->getIndex();
161     bool ok = createNode(iattr);
162     if(ok)
163     {
164       (*m_values)[iattr] = node;
165     }
166     return ok;
167   }
168 
169   /*!
170    * \brief Remove all attribute values.
171    */
clear()172   void clear()
173   {
174     if(m_values != nullptr)
175     {
176       delete m_values;
177       m_values = nullptr;
178     }
179   }
180 
181   /*!
182    * \brief Return a scalar attribute value.
183    */
184   Node::ConstValue getScalar(const Attribute* attr) const;
185 
186   /*!
187    * \brief Return a string attribute value.
188    */
189   const char* getString(const Attribute* attr) const;
190 
191   /*!
192    * \brief Return reference to value Node.
193    */
194   const Node& getValueNodeRef(const Attribute* attr) const;
195 
196   /*!
197    * \brief Return a reference to an empty Node.
198    *
199    * Used as error return value from getValueNodeRef.
200    */
getEmptyNodeRef() const201   const Node& getEmptyNodeRef() const
202   {
203     static const Node empty;
204     return empty;
205   }
206 
207   /*!
208    * \brief Return first valid Attribute index for a set Attribute.
209    *        (i.e., smallest index over all Attributes).
210    *
211    * sidre::InvalidIndex is returned if AttrValue has no Attributes.
212    */
213   IndexType getFirstValidAttrValueIndex() const;
214 
215   /*!
216    * \brief Return next valid Attribute index for a set Attribute
217    *        after given index (i.e., smallest index over all Attribute
218    *        indices larger than given one).
219    *
220    * sidre::InvalidIndex is returned if there is no valid index greater
221    * than given one.
222    * getNextAttrValueIndex(InvalidIndex) returns InvalidIndex.
223    */
224   IndexType getNextValidAttrValueIndex(IndexType idx) const;
225 
226   //@{
227   //!  @name Private AttrValues ctor and dtor
228   //!        (callable only by DataStore methods).
229 
230   /*!
231    *  \brief Private ctor.
232    */
233   AttrValues();
234 
235   /*!
236    * \brief Private copy ctor.
237    */
238   AttrValues(const AttrValues& source);
239 
240   /*!
241    * \brief Private dtor.
242    */
243   ~AttrValues();
244 
245   //@}
246 
247   ///////////////////////////////////////////////////////////////////
248   //
249   using Values = std::vector<Node>;
250   ///////////////////////////////////////////////////////////////////
251 
252   /// Attributes values.
253   Values* m_values;
254 };
255 
256 } /* end namespace sidre */
257 } /* end namespace axom */
258 
259 #endif /* SIDRE_ATTRVALUES_HPP_ */
260