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 #include <memory>
7 #include <utility>
8 
9 #include "axom/sidre.hpp"
10 #include "axom/fmt.hpp"
11 #include "axom/core/utilities/StringUtilities.hpp"
12 #include "axom/core/Path.hpp"
13 
14 #ifndef INLET_UTILS_HPP
15   #define INLET_UTILS_HPP
16 
17 namespace axom
18 {
19 namespace inlet
20 {
21 enum class ReaderResult
22 {
23   Success,         // Found with no issue
24   NotFound,        // Path does not exist in the input file
25   NotHomogeneous,  // Found, but elements of other type exist
26   WrongType  // Found, but item at specified path was not of requested type
27 };
28 
29 /*!
30  *****************************************************************************
31  * \brief Information on an Inlet verification error
32  *****************************************************************************
33  */
34 struct VerificationError
35 {
36   /// \brief The path to the container/field/function with the error
37   const axom::Path path;
38   /// \brief The error message
39   const std::string message;
40   /// \brief Returns whether a given substring is present in the error message
messageContainsaxom::inlet::VerificationError41   bool messageContains(const std::string substr) const
42   {
43     return message.find(substr) != std::string::npos;
44   }
45 };
46 
47 /*!
48  *****************************************************************************
49  * \brief Utility macro for selecting between logging to SLIC and logging
50  * to a list of errors
51  * \param path The path within the input file to warn on
52  * \param msg The warning message
53  * \param errs The list of errors, must be of type \p std::vector<VerificationError>*
54  *****************************************************************************
55  */
56   #define INLET_VERIFICATION_WARNING(path, msg, errs) \
57     if(errs)                                          \
58     {                                                 \
59       errs->push_back({axom::Path {path}, msg});      \
60     }                                                 \
61     else                                              \
62     {                                                 \
63       SLIC_WARNING(msg);                              \
64     }
65 
66 /*!
67 *****************************************************************************
68 * \brief This function is used to mark if anything went wrong during the
69 * defining phase of inlet so verify() will properly fail.
70 *
71 * \param [in] root Pointer to the Sidre Root Group where the warning flag
72 * will be set.
73 *****************************************************************************
74 */
75 void setWarningFlag(axom::sidre::Group* root);
76 
77 /*!
78 *****************************************************************************
79 * \brief This function is used to add a flag to the Inlet object
80 * corresponding to the provided Sidre group
81 *
82 * \param [in] target Reference to the Sidre group to set the required
83 * status of
84 * \param [in] root Reference to the Sidre Root Group where the warning flag
85 * will be set on failure
86 * \param [in] flag The name of the flag to set
87 * \param [in] value The value of the flag
88 *****************************************************************************
89 */
90 void setFlag(axom::sidre::Group& target,
91              axom::sidre::Group& root,
92              const std::string& flag,
93              bool value);
94 
95 /*!
96 *****************************************************************************
97 * \brief This function is used to determine the value of a flag for the
98 * Inlet object corresponding to the provided Sidre group
99 *
100 * \param [in] target Reference to the Sidre group to check the required
101 * status of
102 * \param [in] root Reference to the Sidre Root Group where the warning flag
103 * will be set on failure
104 * \param [in] flag The name of the flag to check
105 * \return The value of the flag
106 *****************************************************************************
107 */
108 bool checkFlag(const axom::sidre::Group& target,
109                axom::sidre::Group& root,
110                const std::string& flag);
111 
112 /*!
113 *****************************************************************************
114 * \brief This function is used to verify the required-ness of the Inlet object
115 * corresponding to the provided Sidre group
116 *
117 * \param [in] target Reference to the Sidre group to verify the required-ness of
118 * \param [in] condition The condition that must be true if the object is required
119 * \param [in] type The type of the object as a string, for use in the warning message
120 * \param [in] errors An optional vector of errors to append to in the case
121 * of verification failure
122 *
123 * \return False if the object was required but \p condition was false, True otherwise
124 * \post If the function returns False, a warning message will be emitted
125 *****************************************************************************
126 */
127 bool verifyRequired(const axom::sidre::Group& target,
128                     const bool condition,
129                     const std::string& type,
130                     std::vector<VerificationError>* errors = nullptr);
131 
132 namespace detail
133 {
134 /*!
135   *******************************************************************************
136   * Names of the internal collection data and collection index groups/fields
137   * used for managing arrays/dictionaries
138   *******************************************************************************
139   */
140 const std::string COLLECTION_GROUP_NAME = "_inlet_collection";
141 const std::string COLLECTION_INDICES_NAME = "_inlet_collection_indices";
142 const std::string STRUCT_COLLECTION_FLAG = "_inlet_struct_collection";
143 const std::string REQUIRED_FLAG = "required";
144 const std::string STRICT_FLAG = "strict";
145 }  // namespace detail
146 
147 /*!
148 *****************************************************************************
149 * \brief Determines whether a Container is a collection group
150 *
151 * \param [in] name The name of the container
152 *****************************************************************************
153 */
isCollectionGroup(const std::string & name)154 inline bool isCollectionGroup(const std::string& name)
155 {
156   return axom::utilities::string::endsWith(name, detail::COLLECTION_GROUP_NAME);
157 }
158 
159 /*!
160 *****************************************************************************
161 * \brief Marks the sidre::Group as a "struct collection" by adding a
162 * corresponding flag to the group
163 *
164 * \param [inout] target The group to tag
165 *****************************************************************************
166 */
167 void markAsStructCollection(axom::sidre::Group& target);
168 
169 /*!
170 *****************************************************************************
171 * \brief Adds a ReaderResult to a sidre::Group corresponding to an inlet
172 * object
173 *
174 * \param [inout] target The group to tag
175 * \param [in] result The retrieval result
176 *****************************************************************************
177 */
178 void markRetrievalStatus(axom::sidre::Group& target, const ReaderResult result);
179 
180 /*!
181 *****************************************************************************
182 * \brief Returns the corresponding retrieval result for a collection depending
183 * on whether the collection contained any elements of the requested or of
184 * other type
185 *
186 * \param [in] contains_other_type Whether any collection elements were of type
187 * other than the requested type
188 * \param [in] contains_requested_type Whether the collection of requested type
189 * was not empty, i.e., if any elements of the requested type were present
190 *****************************************************************************
191 */
192 ReaderResult collectionRetrievalResult(const bool contains_other_type,
193                                        const bool contains_requested_type);
194 
195 namespace cpp11_compat
196 {
197 /*!
198 *****************************************************************************
199 * \brief This function provides backwards compatibility for std::make_unique,
200 * which is not implemented until C++14.  It should be removed when either
201 * Axom or the Inlet component is no longer required to support C++11
202 *
203 * \tparam T The type to construct
204 * \tparam Args The variadic argument list to forward to T's constructor
205 *
206 * \return A unique ptr constructed with the given arguments
207 *****************************************************************************
208 */
209 template <typename T, typename... Args>
make_unique(Args &&...args)210 std::unique_ptr<T> make_unique(Args&&... args)
211 {
212   return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
213 }
214 
215 }  // namespace cpp11_compat
216 
217 }  // namespace inlet
218 }  // namespace axom
219 
220 #endif
221