1 // Copyright (c) Lawrence Livermore National Security, LLC and other Conduit
2 // Project developers. See top-level LICENSE AND COPYRIGHT files for dates and
3 // other details. No copyright assignment is required to contribute to Conduit.
4
5 //-----------------------------------------------------------------------------
6 ///
7 /// file: conduit_blueprint_table.cpp
8 ///
9 //-----------------------------------------------------------------------------
10
11 //-----------------------------------------------------------------------------
12 // std lib includes
13 //-----------------------------------------------------------------------------
14 // std lib includes will go here
15
16 //-----------------------------------------------------------------------------
17 // conduit includes
18 //-----------------------------------------------------------------------------
19 #include "conduit_blueprint_table.hpp"
20 #include "conduit_log.hpp"
21 #include "conduit_blueprint_mcarray.hpp"
22
23 using namespace conduit;
24
25 //-----------------------------------------------------------------------------
26 // -- begin internal helper functions --
27 //-----------------------------------------------------------------------------
28 static const std::string PROTOCOL = "table";
29
30 //-----------------------------------------------------------------------------
31 static bool
verify_table_values(const Node & n,Node & info)32 verify_table_values(const Node &n, Node &info)
33 {
34 bool res = true;
35
36 // Each entry in n represents a column in the table.
37 // All columns must have the same length.
38 auto columns = n.children();
39 index_t num_rows = 0;
40 index_t num_cols = 0;
41 bool first_column = true;
42 while(columns.has_next())
43 {
44 const Node &n_col = columns.next();
45 Node &i_col = info[n_col.name()];
46 index_t this_num_elems = 0;
47 bool this_res = true;
48
49 // Each entry must be a data array or a valid mlarray
50 if(n_col.dtype().is_list() || n_col.dtype().is_object())
51 {
52 this_res = blueprint::mcarray::verify(n_col, i_col);
53 this_num_elems = (res) ? n_col[0].dtype().number_of_elements() : 0;
54 }
55 else if(n_col.dtype().is_empty())
56 {
57 this_res = false;
58 }
59 else
60 {
61 this_num_elems = n_col.dtype().number_of_elements();
62 }
63
64 // Record the error if we have one
65 if(!this_res)
66 {
67 utils::log::error(info, PROTOCOL, "child " + utils::log::quote(n_col.name()) + " is not a data_array or valid mcarray.");
68 }
69 else
70 {
71 // Check that number of elements matches for each column
72 // If this is the first column, set num_rows first.
73 num_rows = (first_column) ? this_num_elems : num_rows;
74 i_col["elements"] = this_num_elems;
75 if(num_rows != this_num_elems)
76 {
77 utils::log::error(info, PROTOCOL, "child " + utils::log::quote(n_col.name()) + " does not contain the correct number of elements.");
78 this_res = false;
79 }
80 }
81
82 utils::log::validation(i_col, this_res);
83 res &= this_res;
84 first_column = false;
85 num_cols++;
86 }
87
88 // Add some extra info for a valid table.
89 if(res)
90 {
91 info["columns"] = num_cols;
92 info["rows"] = num_rows;
93 }
94 utils::log::validation(info, res);
95 return res;
96 }
97
98 //-----------------------------------------------------------------------------
99 static bool
verify_single_table(const Node & n,Node & info)100 verify_single_table(const Node &n, Node &info)
101 {
102 bool res = true;
103
104 // "values" child must exist
105 if(!n.has_child("values"))
106 {
107 res = false;
108 utils::log::error(info, PROTOCOL, "missing child" + utils::log::quote("values", 1));
109 }
110
111 if(res)
112 {
113 // "values" child must be a list or an object
114 const Node &n_values = n["values"];
115 Node &i_values = info["values"];
116 if(!n_values.dtype().is_object() && !n_values.dtype().is_list())
117 {
118 res = false;
119 utils::log::error(i_values, PROTOCOL, utils::log::quote("values", 0) + " must be an object or a list.");
120 }
121
122 if(res)
123 {
124 res = verify_table_values(n_values, i_values);
125 }
126 }
127
128 utils::log::validation(info, res);
129 return res;
130 }
131
132 //-----------------------------------------------------------------------------
133 static bool
verify_many_tables(const conduit::Node & n,conduit::Node & info)134 verify_many_tables(const conduit::Node &n, conduit::Node &info)
135 {
136 bool res = true;
137
138 // Check if each child is a table
139 auto children = n.children();
140 index_t num_tables = 0;
141 while(children.has_next())
142 {
143 const Node &child = children.next();
144 Node &info_child = info[child.name()];
145 res &= verify_single_table(child, info_child);
146 num_tables++;
147 }
148
149 // Check if there were actually any children
150 res &= num_tables > 0;
151
152 if(res)
153 {
154 info["tables"] = num_tables;
155 }
156 utils::log::validation(info, res);
157 return res;
158 }
159
160 //-----------------------------------------------------------------------------
161 // -- end internal helper functions --
162 //-----------------------------------------------------------------------------
163
164 //-----------------------------------------------------------------------------
165 // -- begin conduit:: --
166 //-----------------------------------------------------------------------------
167 namespace conduit
168 {
169
170 //-----------------------------------------------------------------------------
171 // -- begin conduit::blueprint --
172 //-----------------------------------------------------------------------------
173 namespace blueprint
174 {
175
176 //-----------------------------------------------------------------------------
177 // -- begin conduit::table --
178 //-----------------------------------------------------------------------------
179 namespace table
180 {
181
182 //-----------------------------------------------------------------------------
verify(const conduit::Node & n,conduit::Node & info)183 bool verify(const conduit::Node &n,
184 conduit::Node &info)
185 {
186 bool res = true;
187 info.reset();
188
189 if(n.has_child("values"))
190 {
191 res = verify_single_table(n, info);
192 }
193 else
194 {
195 res = verify_many_tables(n, info);
196 }
197 return res;
198 }
199
200 //-----------------------------------------------------------------------------
verify(const std::string &,const conduit::Node &,conduit::Node & info)201 bool verify(const std::string &,
202 const conduit::Node &,
203 conduit::Node &info)
204 {
205 // Table doesn't currently provide any nested protocols
206
207 info.reset();
208 utils::log::validation(info,false);
209 return false;
210 }
211
212 }
213 //-----------------------------------------------------------------------------
214 // -- end conduit::table --
215 //-----------------------------------------------------------------------------
216
217 }
218 //-----------------------------------------------------------------------------
219 // -- end conduit::blueprint --
220 //-----------------------------------------------------------------------------
221
222 }
223 //-----------------------------------------------------------------------------
224 // -- end conduit:: --
225 //-----------------------------------------------------------------------------
226