OpenStructure
star_writer.hh
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // This file is part of the OpenStructure project <www.openstructure.org>
3 //
4 // Copyright (C) 2008-2023 by the OpenStructure authors
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License as published by the Free
8 // Software Foundation; either version 3.0 of the License, or (at your option)
9 // any later version.
10 // This library is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this library; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 //------------------------------------------------------------------------------
19 #ifndef OST_IO_STAR_WRITER_HH
20 #define OST_IO_STAR_WRITER_HH
21 
22 #include <map>
23 #include <fstream>
24 #include <boost/iostreams/filtering_stream.hpp>
25 #include <boost/iostreams/filter/gzip.hpp>
26 #include <boost/shared_ptr.hpp>
27 #include <ost/string_ref.hh>
28 #include <ost/io/io_exception.hh>
29 
30 namespace{
31  // float to string with specified number of decimals
32  void fts(Real f, int decimals, String& s) {
33  char data[20];
34  size_t len;
35  switch(decimals){
36  case 0:
37  len = std::snprintf(data, sizeof(data), "%.0f", f);
38  break;
39  case 1:
40  len = std::snprintf(data, sizeof(data), "%.1f", f);
41  break;
42  case 2:
43  len = std::snprintf(data, sizeof(data), "%.2f", f);
44  break;
45  case 3:
46  len = std::snprintf(data, sizeof(data), "%.3f", f);
47  break;
48  case 4:
49  len = std::snprintf(data, sizeof(data), "%.4f", f);
50  break;
51  case 5:
52  len = std::snprintf(data, sizeof(data), "%.5f", f);
53  break;
54  case 6:
55  len = std::snprintf(data, sizeof(data), "%.6f", f);
56  break;
57  default:
58  throw ost::io::IOException("Max decimals in float conversion: 6");
59  }
60 
61  if(len < 0 || len > 20) {
62  throw ost::io::IOException("float conversion failed");
63  }
64  s.assign(data, len);
65  }
66 }
67 
68 namespace ost { namespace io {
69 
70 class StarWriterObject;
71 class StarWriterValue;
72 class StarWriterDataItem;
73 class StarWriterLoopDesc;
74 class StarWriterLoop;
75 typedef boost::shared_ptr<StarWriterObject> StarWriterObjectPtr;
76 typedef boost::shared_ptr<StarWriterValue> StarWriterValuePtr;
77 typedef boost::shared_ptr<StarWriterDataItem> StarWriterDataItemPtr;
78 typedef boost::shared_ptr<StarWriterLoopDesc> StarWriterLoopDescPtr;
79 typedef boost::shared_ptr<StarWriterLoop> StarWriterLoopPtr;
80 
81 
82 class DLLEXPORT_OST_IO StarWriterObject {
83 public:
84  virtual ~StarWriterObject() { }
85  virtual void ToStream(std::ostream& s) = 0;
86 };
87 
88 
90 public:
91 
93 
94  static StarWriterValue FromInt(int int_value) {
95  StarWriterValue value;
96  value.value_ = std::to_string(int_value);
97  return value;
98  }
99  static StarWriterValue FromFloat(Real float_value, int decimals) {
100  StarWriterValue value;
101  fts(float_value, decimals, value.value_);
102  return value;
103  }
104  static StarWriterValue FromString(const String& string_value) {
105  StarWriterValue value;
106 
107  if(string_value == "") {
108  value.value_ = "?";
109  } else {
110  // string requires quotes if any of the following is True
111  // information from https://www.iucr.org/resources/cif/spec/version1.1/cifsyntax
112  // * space in string
113  // * any string that starts with any of the following strings
114  // * _
115  // * #
116  // * $
117  // * '
118  // * "
119  // * [
120  // * ]
121  // * ;
122  // * data_ (case insensitive)
123  // * save_ (case insensitive)
124  // * any string that is equal to any of the following reserved words
125  // * loop_ (case insensitive)
126  // * stop_ (case insensitive)
127  // * global_ (case insensitive)
128  bool needs_quotes = false;
129 
130  // space in string
131  for(char c: string_value) {
132  if(isspace(c)) {
133  needs_quotes = true;
134  break;
135  }
136  }
137 
138  // any string that starts with any of the special single characters
139  if(!needs_quotes) {
140  switch(string_value[0]) {
141  case '_': {
142  needs_quotes = true;
143  break;
144  }
145  case '#': {
146  needs_quotes = true;
147  break;
148  }
149  case '$': {
150  needs_quotes = true;
151  break;
152  }
153  case '\'': {
154  needs_quotes = true;
155  break;
156  }
157  case '\"': {
158  needs_quotes = true;
159  break;
160  }
161  case '[': {
162  needs_quotes = true;
163  break;
164  }
165  case ']': {
166  needs_quotes = true;
167  break;
168  }
169  case ';': {
170  needs_quotes = true;
171  break;
172  }
173  }
174  }
175 
176  // any string that starts with any of the special multi character thingies
177  if(!needs_quotes && string_value.size() >= 5 && string_value[4] == '_') {
178  // need to do case insensitive checking
179  if((string_value[0] == 'd' || string_value[0] == 'D') &&
180  (string_value[1] == 'a' || string_value[1] == 'A') &&
181  (string_value[2] == 't' || string_value[2] == 'T') &&
182  (string_value[3] == 'a' || string_value[3] == 'A')) {
183  needs_quotes = true;
184  }
185  if((string_value[0] == 's' || string_value[0] == 'S') &&
186  (string_value[1] == 'a' || string_value[1] == 'A') &&
187  (string_value[2] == 'v' || string_value[2] == 'V') &&
188  (string_value[3] == 'e' || string_value[3] == 'E')) {
189  needs_quotes = true;
190  }
191  }
192 
193  // any string that is exactly one of the reserved words
194  if(!needs_quotes && string_value.size() == 5 && string_value[4] == '_') {
195  // need to do case insensitive checking
196  if((string_value[0] == 'l' || string_value[0] == 'L') &&
197  (string_value[1] == 'o' || string_value[1] == 'O') &&
198  (string_value[2] == 'o' || string_value[2] == 'O') &&
199  (string_value[3] == 'p' || string_value[3] == 'P')) {
200  needs_quotes = true;
201  }
202  if((string_value[0] == 's' || string_value[0] == 'S') &&
203  (string_value[1] == 't' || string_value[1] == 'T') &&
204  (string_value[2] == 'o' || string_value[2] == 'O') &&
205  (string_value[3] == 'p' || string_value[3] == 'P')) {
206  needs_quotes = true;
207  }
208  }
209 
210  if(!needs_quotes && string_value.size() == 7 && string_value[6] == '_') {
211  // need to do case insensitive checking
212  if((string_value[0] == 'g' || string_value[0] == 'G') &&
213  (string_value[1] == 'l' || string_value[1] == 'L') &&
214  (string_value[2] == 'o' || string_value[2] == 'O') &&
215  (string_value[3] == 'b' || string_value[3] == 'B') &&
216  (string_value[4] == 'a' || string_value[4] == 'A') &&
217  (string_value[5] == 'l' || string_value[5] == 'L')) {
218  needs_quotes = true;
219  }
220  }
221 
222  if(needs_quotes) {
223  value.value_ = "\"" + string_value + "\"";
224  } else {
225  value.value_ = string_value;
226  }
227  }
228  return value;
229  }
230  const String& GetValue() const { return value_; }
231 private:
232  String value_;
233 };
234 
235 
236 class DLLEXPORT_OST_IO StarWriterDataItem : public StarWriterObject {
237 public:
238  StarWriterDataItem(const String& category, const String& attribute,
239  const StarWriterValue& value): category_(category),
240  attribute_(attribute),
241  value_(value) { }
242  virtual void ToStream(std::ostream& s) {
243  s << category_ << '.' << attribute_ << ' ' << value_.GetValue() << std::endl;
244  }
245  const String& GetCategory() const { return category_; }
246  const String& GetAttribute() const { return attribute_; }
247  const StarWriterValue& GetValue() const { return value_; }
248 private:
249  String category_;
250  String attribute_;
251  StarWriterValue value_;
252 };
253 
254 
255 class DLLEXPORT_OST_IO StarWriterLoopDesc : public StarWriterObject {
256 public:
257  StarWriterLoopDesc(const String& category): category_(category) { }
258 
259  int GetIndex(const String& attribute) const {
260  std::map<String, int>::const_iterator i=index_map_.find(attribute);
261  return i==index_map_.end() ? -1 : i->second;
262  }
263 
264  void Add(const String& attribute) {
265  index_map_.insert(std::make_pair(attribute, index_map_.size()));
266  }
267 
268  size_t GetSize() const {
269  return index_map_.size();
270  }
271 
272  virtual void ToStream(std::ostream& s) {
273  std::vector<std::pair<int, String> > tmp;
274  for(auto it = index_map_.begin(); it != index_map_.end(); ++it) {
275  tmp.push_back(std::make_pair(it->second, it->first));
276  }
277  std::sort(tmp.begin(), tmp.end());
278  for(auto it = tmp.begin(); it != tmp.end(); ++it) {
279  s << category_ << "." << it->second << std::endl;
280  }
281  }
282 
283  const String& GetCategory() const { return category_; }
284 private:
285  String category_;
286  std::map<String, int> index_map_;
287 };
288 
289 
290 class DLLEXPORT_OST_IO StarWriterLoop: public StarWriterObject {
291 public:
292 
293  StarWriterLoop(const StarWriterLoopDesc& desc): desc_(desc) { }
294 
295  const StarWriterLoopDesc& GetDesc() { return desc_; }
296 
297  void AddData(const std::vector<StarWriterValue>& data) {
298  if(data.size() != desc_.GetSize()) {
299  throw ost::io::IOException("Invalid data size when adding to StarLoop");
300  }
301  data_.insert(data_.end(), data.begin(), data.end());
302  }
303 
304  const std::vector<StarWriterValue>& GetData() { return data_; }
305 
306  int GetN() {
307  return data_.size() / desc_.GetSize();
308  }
309 
310  virtual void ToStream(std::ostream& s) {
311  if(data_.empty()) {
312  return; // skip loop, including header
313  }
314  s << "loop_" << std::endl;
315  desc_.ToStream(s);
316  int desc_size = desc_.GetSize();
317  for(size_t i = 0; i < data_.size(); ++i) {
318  s << data_[i].GetValue();
319  if((i+1) % desc_size == 0) {
320  s << std::endl;
321  } else {
322  s << ' ';
323  }
324  }
325  }
326 
327 private:
328  StarWriterLoopDesc desc_;
329  std::vector<StarWriterValue> data_;
330 };
331 
332 
333 class DLLEXPORT_OST_IO StarWriter {
334 public:
336  virtual ~StarWriter() { }
337 
338  void Push(StarWriterObjectPtr obj) { categories_to_write_.push_back(obj); }
339 
340  void Write(const String& data_name, const String& filename);
341  void Write(const String& data_name, std::ostream& stream);
342 
343 private:
344  std::vector<StarWriterObjectPtr> categories_to_write_;
345 };
346 
347 }} // ns
348 
349 #endif
const String & GetAttribute() const
Definition: star_writer.hh:246
virtual void ToStream(std::ostream &s)
Definition: star_writer.hh:242
StarWriterDataItem(const String &category, const String &attribute, const StarWriterValue &value)
Definition: star_writer.hh:238
const StarWriterValue & GetValue() const
Definition: star_writer.hh:247
const String & GetCategory() const
Definition: star_writer.hh:245
void Write(const String &data_name, std::ostream &stream)
void Push(StarWriterObjectPtr obj)
Definition: star_writer.hh:338
void Write(const String &data_name, const String &filename)
StarWriterLoopDesc(const String &category)
Definition: star_writer.hh:257
void Add(const String &attribute)
Definition: star_writer.hh:264
int GetIndex(const String &attribute) const
Definition: star_writer.hh:259
virtual void ToStream(std::ostream &s)
Definition: star_writer.hh:272
const String & GetCategory() const
Definition: star_writer.hh:283
StarWriterLoop(const StarWriterLoopDesc &desc)
Definition: star_writer.hh:293
const std::vector< StarWriterValue > & GetData()
Definition: star_writer.hh:304
const StarWriterLoopDesc & GetDesc()
Definition: star_writer.hh:295
void AddData(const std::vector< StarWriterValue > &data)
Definition: star_writer.hh:297
virtual void ToStream(std::ostream &s)
Definition: star_writer.hh:310
virtual void ToStream(std::ostream &s)=0
const String & GetValue() const
Definition: star_writer.hh:230
static StarWriterValue FromInt(int int_value)
Definition: star_writer.hh:94
static StarWriterValue FromFloat(Real float_value, int decimals)
Definition: star_writer.hh:99
static StarWriterValue FromString(const String &string_value)
Definition: star_writer.hh:104
#define DLLEXPORT_OST_IO
float Real
Definition: base.hh:44
std::string String
Definition: base.hh:54
boost::shared_ptr< StarWriterLoop > StarWriterLoopPtr
Definition: star_writer.hh:79
boost::shared_ptr< StarWriterDataItem > StarWriterDataItemPtr
Definition: star_writer.hh:77
boost::shared_ptr< StarWriterLoopDesc > StarWriterLoopDescPtr
Definition: star_writer.hh:78
boost::shared_ptr< StarWriterObject > StarWriterObjectPtr
Definition: star_writer.hh:74
boost::shared_ptr< StarWriterValue > StarWriterValuePtr
Definition: star_writer.hh:76
Definition: base.dox:1