metric_format.h
Go to the documentation of this file.
1 
9 #pragma once
10 #ifdef _MSC_VER
11 #pragma warning(disable:4702) // MSVC warns that there is unreachable code
12 #endif
13 
14 
15 #include "interop/util/exception.h"
19 
20 namespace illumina { namespace interop { namespace io
21 {
30  template<class Metric, class Layout>
31  struct metric_format : public abstract_metric_format<Metric>
32  {
33  private:
34  typedef typename Metric::id_t id_t;
36  typedef typename metric_set_t::offset_map_t offset_map_t;
37  public:
39  typedef Metric metric_t;
41  typedef typename Metric::header_type header_t;
43  typedef typename Layout::metric_id_t metric_id_t;
45  typedef typename Layout::record_size_t record_size_t;
46 
52  void write_metric_header(std::ostream &out, const header_t &header)
53  {
54  const ::uint8_t version = static_cast< ::uint8_t >(Layout::VERSION);
55  write_binary(out, version);
56  Layout::map_stream_record_size(out, Layout::compute_size(header));
57  Layout::map_stream_for_header(out, header);
58  }
59 
66  void write_metric(std::ostream &out, const metric_t &metric, const header_t &header)
67  {
68  metric_id_t metric_id;
69  metric_id.set(metric);
70  write_binary(out, metric_id);
71  Layout::map_stream(out, metric, header, false);
72  }
79  size_t read_header(std::istream& in, model::metric_base::metric_set<Metric>& metric_set)
80  {
81  const size_t version_byte_size = 1;
82  const std::streampos beg = in.tellg();
83  read_header_impl(in, metric_set);
84  return static_cast<size_t>(in.tellg()-beg)+version_byte_size;
85  }
86 
93  void read_metrics(std::istream& in, metric_set_t& metric_set, const size_t file_size)
94  {
95  const std::streamsize record_size = read_header_impl(in, metric_set);
96  offset_map_t& metric_offset_map = metric_set.offset_map();
97  metric_t metric(metric_set);
98  if(file_size > 0 && !Layout::MULTI_RECORD)
99  {
100  const size_t record_count = static_cast<size_t>((file_size-header_size(metric_set))/record_size);
101  metric_set.resize(metric_set.size()+record_count);
102  std::vector<char> buffer(static_cast<size_t>(record_size));
103  INTEROP_ASSERT(!buffer.empty());
104  while (in)
105  {
106  char *in_ptr = &buffer.front();
107  in.read(in_ptr, record_size);
108  const std::streamsize count = in.gcount();
109  try
110  {
111  if (!test_stream(in, metric_offset_map, count, record_size)) break;
112  read_record(in_ptr, metric_set, metric_offset_map, metric, record_size);
113  }
114  catch(const incomplete_file_exception& ex)
115  {
116  metric_set.trim(metric_offset_map.size());
117  throw ex;
118  }
119  }
120  }
121  else
122  {
123  while (in)
124  {
125  read_record(in, metric_set, metric_offset_map, metric, record_size);
126  }
127  }
128  metric_set.trim(metric_offset_map.size());
129  }
136  std::streamsize read_header_impl(std::istream &in, header_t &header)
137  {
138  // TODO: optimize header reading with block read
139  if (in.fail())
140  INTEROP_THROW(incomplete_file_exception, "Insufficient header data read from the file"
141  << " for "
142  << Metric::prefix() << " " << Metric::suffix() << " v" << Layout::VERSION);
143 
144  //if we're not actually reading the record size from the stream
145  // (the stream position is the same before and after),
146  // then don't compare the layout size against the record size
147  const ::int64_t stream_position_pre_record_check = in.tellg();
148  const std::streamsize record_size = Layout::map_stream_record_size(in,
149  static_cast<record_size_t>(0));
150  if(in.fail())
151  {
152  INTEROP_THROW(incomplete_file_exception, "Insufficient header data read from the file"
153  << " for "
154  << Metric::prefix() << " " << Metric::suffix() << " v" << Layout::VERSION);
155  }
156  if(record_size==0)
157  {
158  INTEROP_THROW(bad_format_exception, "Record size cannot be 0");
159  }
160  const ::int64_t stream_position_post_record_check = in.tellg();
161  Layout::map_stream_for_header(in, header);
162 
163  if (in.fail())
164  INTEROP_THROW(incomplete_file_exception, "Insufficient extended header data read from the file");
165  const std::streamsize layout_size = Layout::compute_size(header);
166  if (stream_position_pre_record_check != stream_position_post_record_check && record_size != layout_size)
167  INTEROP_THROW(bad_format_exception, "Record size does not match layout size, record size: " <<
168  record_size << " != layout size: " <<
169  layout_size << " for " <<
170  Metric::prefix() << " " << Metric::suffix() << " v" <<
171  Layout::VERSION);
172  return layout_size;
173  }
179  size_t buffer_size(const model::metric_base::metric_set<Metric>& metric_set) const
180  {
182  }
183 
189  size_t record_size(const header_t &header) const
190  {
191  return static_cast<size_t>(Layout::compute_size(header));
192  }
193 
199  size_t header_size(const header_t &header) const
200  {
201  return static_cast<size_t>(Layout::compute_header_size(header));
202  }
203 
208  ::int16_t version() const
209  {
210  return static_cast< ::int16_t >(Layout::VERSION);
211  }
216  bool is_multi_record() const
217  {
218  return Layout::MULTI_RECORD > 0;
219  }
224  bool is_deprecated() const
225  {
226  return Layout::IS_DEPRECATED > 0;
227  }
228 
229  private:
230  typedef typename int_constant_type<0>::pointer_t is_single_record_t;
231  typedef typename int_constant_type<1>::pointer_t is_multi_record_t;
232  size_t buffer_size(const model::metric_base::metric_set<Metric>& metric_set, is_single_record_t)const
233  {
234  return header_size(metric_set) + record_size(metric_set)*metric_set.size();
235  }
236  size_t buffer_size(const model::metric_base::metric_set<Metric>& metric_set, is_multi_record_t)const
237  {
238  return Layout::compute_buffer_size(metric_set);
239  }
240 
241  private:
242  static bool test_stream(std::istream& in,
243  const offset_map_t& metric_offset_map,
244  const std::streamsize count,
245  const std::streamsize record_size)
246  {
247  if (in.fail())
248  {
249  if (count == 0 && !metric_offset_map.empty()) return false;
250  INTEROP_THROW(incomplete_file_exception, "Insufficient data read from the file, got: " << count
251  << " != expected: " << record_size << " for "
252  << Metric::prefix() << " " << Metric::suffix() << " v"
253  << Layout::VERSION);
254  }
255  return true;
256  }
257  static bool test_stream(const char*, const offset_map_t&, const std::streamsize, const std::streamsize)
258  {return true;}
259  template<typename InputStream>
260  static void read_record(InputStream& in,
261  model::metric_base::metric_set<Metric>& metric_set,
262  offset_map_t& metric_offset_map,
263  metric_t& metric,
264  const std::streamsize record_size)
265  {
266  metric_id_t id;
267  const std::streamsize read_byte_count = read_binary_with_count (in, id);
268  if(!test_stream(in, metric_offset_map, read_byte_count, record_size)) return;
269  std::streamsize count=read_byte_count;
270  if (Layout::is_valid(id))
271  // TODO: Refactor tile metrics to move record type into layout id, then we can remove skip_metric,
272  // simplifiy all this logic
273  {
274  metric.set_base(id);// TODO replace with static call
275  if (metric_offset_map.find(metric.id()) == metric_offset_map.end())
276  {
277  const size_t offset = metric_offset_map.size();
278  if(offset>= metric_set.size()) metric_set.resize(offset+1);
279  metric_set[offset].set_base(id);
280  count += Layout::map_stream(in, metric_set[offset], metric_set, true);
281  if(!test_stream(in, metric_offset_map, count, record_size)) return;
282  if(Layout::skip_metric(metric_set[offset]))//Avoid adding control lanes in tile metrics
283  {
284  metric_set.resize(offset);
285  }
286  else metric_offset_map[metric.id()] = offset;
287  }
288  else
289  {
290  const size_t offset = metric_offset_map[metric.id()];
291  count += Layout::map_stream(in, metric_set[offset], metric_set, false);
292  INTEROP_ASSERT(metric_set[offset].id()>0);
293  }
294  }
295  else
296  {
297  count += Layout::map_stream(in, metric, metric_set, true);
298  //TODO: replace with skip function, simplify code, required for index metrics
299  }
300  if(!test_stream(in, metric_offset_map, count, record_size)) return;
301  if (count != record_size)
302  {
303  INTEROP_THROW(bad_format_exception, "Record does not match expected size! for "
304  << Metric::prefix() << " " << Metric::suffix() << " v"
305  << Layout::VERSION << " count=" << count << " != "
306  << " record_size: " << record_size
307  << " n= " << metric_offset_map.size());
308  }
309  }
310  };
311 }}}
312 
313 
::int16_t version() const
Definition: metric_format.h:208
metric_t::id_t id_t
Definition: abstract_metric_format.h:31
Definition: enum_description.h:15
Metric::header_type header_t
Definition: metric_format.h:41
Definition: abstract_metric_format.h:24
void trim(const size_t n)
Definition: metric_set.h:258
size_t buffer_size(const model::metric_base::metric_set< Metric > &metric_set) const
Definition: metric_format.h:179
#define INTEROP_THROW(EXCEPTION, MESSAGE)
Definition: exception.h:18
size_t size() const
Definition: metric_set.h:519
std::streamsize read_header_impl(std::istream &in, header_t &header)
Definition: metric_format.h:136
Definition: metric_format.h:31
#define INTEROP_ASSERT(TST)
Definition: assert.h:21
std::map< id_t, size_t > offset_map_t
Definition: metric_set.h:70
Definition: type_traits.h:161
Layout::record_size_t record_size_t
Definition: metric_format.h:45
void write_binary(std::ostream &out, const T *buffer, const size_t n)
Definition: stream_util.h:158
Layout::metric_id_t metric_id_t
Definition: metric_format.h:43
void read_metrics(std::istream &in, metric_set_t &metric_set, const size_t file_size)
Definition: metric_format.h:93
size_t header_size(const header_t &header) const
Definition: metric_format.h:199
Metric metric_t
Definition: metric_format.h:39
void write_metric(std::ostream &out, const metric_t &metric, const header_t &header)
Definition: metric_format.h:66
void write_metric_header(std::ostream &out, const header_t &header)
Definition: metric_format.h:52
size_t record_size(const header_t &header) const
Definition: metric_format.h:189
std::streamsize read_binary_with_count(std::istream &in, T &buffer)
Definition: stream_util.h:76
offset_map_t & offset_map()
Definition: metric_set.h:580
Definition: stream_exceptions.h:59
void resize(const size_t n)
Definition: metric_set.h:242
Definition: stream_exceptions.h:73
bool is_multi_record() const
Definition: metric_format.h:216
size_t read_header(std::istream &in, model::metric_base::metric_set< Metric > &metric_set)
Definition: metric_format.h:79
size_t compute_buffer_size(const MetricSet &metrics) INTEROP_THROW_SPEC((io
Definition: metric_file_stream.h:32
::int64_t file_size(const std::string &path)
Definition: filesystem.cpp:156
bool is_deprecated() const
Definition: metric_format.h:224