FLAME  devel
 All Classes Functions Variables Typedefs Enumerations Pages
util.cpp
1 
2 #include <fstream>
3 
4 #include <ctime>
5 
6 #include <boost/numeric/ublas/vector.hpp>
7 #include <boost/thread/mutex.hpp>
8 #define BOOST_FILESYSTEM_DYN_LINK
9 #include <boost/filesystem.hpp>
10 
11 #include "flame/util.h"
12 
13 void numeric_table::read(std::istream &strm)
14 {
15  typedef boost::numeric::ublas::vector<double> vector_t;
16 
17  std::string rawline;
18 
19  std::vector<double> values;
20 
21  std::vector<vector_t> table;
22 
23  unsigned line = 0;
24  while(std::getline(strm, rawline)) {
25  line++;
26  values.clear();
27 
28  size_t cpos = rawline.find_first_not_of(" \t");
29  if(cpos==rawline.npos)
30  continue; // skip blank and comment lines
31 
32  cpos = rawline.find_last_not_of("\r\n");
33  if(cpos!=rawline.npos)
34  rawline = rawline.substr(0, cpos+1);
35 
36  if(rawline[0]=='%') {
37  // headers
38  size_t P = rawline.find_first_not_of(" \t", 1);
39 
40  colnames_t cols;
41 
42  unsigned col=0;
43  while(P!=rawline.npos) {
44  size_t E = rawline.find_first_of(" \t", P);
45 
46  const std::string& ent = rawline.substr(P, E==rawline.npos ? E : E-P);
47  cols[ent] = col++;
48 
49  P = rawline.find_first_not_of(" \t", E);
50  }
51 
52  colnames.swap(cols);
53 
54  } else {
55  // data
56 
57  std::istringstream lstrm(rawline);
58 
59  while(lstrm.good()) {
60  double val;
61  lstrm>>val;
62  if(!lstrm.fail())
63  values.push_back(val);
64  }
65 
66  if(!lstrm.eof() && lstrm.fail())
67  throw std::runtime_error(SB()<<"Error parsing data line "<<line<<" '"<<rawline<<"'");
68 
69  if(!table.empty() && table.back().size()!=values.size())
70  throw std::runtime_error(SB()<<"Line "<<line<<" w/ different # of elements");
71 
72  table.push_back(vector_t(values.size()));
73 
74  std::copy(values.begin(),
75  values.end(),
76  table.back().begin());
77  }
78  }
79 
80  if(!strm.eof() && strm.fail())
81  throw std::runtime_error(SB()<<"Error parsing line "<<line<<" '"<<rawline<<"'");
82  else if(table.empty()) {
83  this->table.clear();
84  } else {
85  value_t result(table.size(), table.front().size());
86 
87  for(size_t r=0; r<result.size1(); r++) {
88  const vector_t& R=table[r];
89  for(size_t c=0; c<result.size2(); c++) {
90  std::copy(R.begin(),
91  R.end(),
92  result.find2(2, r,0));
93  }
94  }
95 
96  this->table.swap(result);
97  }
98 }
99 
100 struct numeric_table_cache::Pvt {
101  boost::mutex lock;
102 
103  struct Value {
104  std::time_t lastmod;
105  typedef boost::shared_ptr<numeric_table> table_pointer;
106  table_pointer table;
107  };
108 
109  typedef std::map<std::string, Value> cache_t;
110  cache_t cache;
111 };
112 
113 numeric_table_cache::numeric_table_cache()
114  :pvt(new Pvt)
115 {}
116 
117 numeric_table_cache::~numeric_table_cache() {}
118 
119 numeric_table_cache::table_pointer numeric_table_cache::fetch(const std::string& path)
120 {
121  Pvt::Value::table_pointer ret;
122 
123  boost::filesystem::path P(path);
124  if(!P.is_absolute())
125  throw std::logic_error("numeric_table_cache want's absolute paths");
126 
127  std::time_t mtime = boost::filesystem::last_write_time(P);
128 
129  boost::mutex::scoped_lock L(pvt->lock);
130 
131  Pvt::cache_t::const_iterator it = pvt->cache.find(path);
132  if(it==pvt->cache.end() || mtime>it->second.lastmod) {
133  // miss
134 
135  ret.reset(new numeric_table);
136 
137  std::ifstream strm(path.c_str());
138 
139  ret->read(strm);
140 
141  Pvt::Value v;
142  v.lastmod = boost::filesystem::last_write_time(P); // fetch again to avoid some, but not all, races
143  v.table = ret;
144 
145  pvt->cache[path] = v;
146  } else {
147  ret = it->second.table;
148  }
149 
150  return ret;
151 }
152 
153 void numeric_table_cache::clear()
154 {
155  boost::mutex::scoped_lock L(pvt->lock);
156  pvt->cache.clear();
157 }
158 
159  //TODO: worry about global ctor order or calls before main() ???
160 static numeric_table_cache ntc_single;
161 
162 numeric_table_cache* numeric_table_cache::get()
163 {
164  return &ntc_single;
165 }