Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
csvreport.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
23
24#include <ql/errors.hpp>
25#include <ql/math/comparison.hpp>
26#include <ql/math/rounding.hpp>
27
28#include <boost/filesystem/operations.hpp>
29#include <boost/filesystem/path.hpp>
30#include <boost/variant/static_visitor.hpp>
31#include <boost/algorithm/string/join.hpp>
32
33using std::string;
34
35namespace ore {
36namespace data {
37
38// Local class for printing each report type via fprintf
39class ReportTypePrinter : public boost::static_visitor<> {
40public:
41 ReportTypePrinter(FILE* fp, int prec, char quoteChar = '\0', const string& nullString = "#N/A")
42 : fp_(fp), rounding_(prec, QuantLib::Rounding::Closest), quoteChar_(quoteChar), null_(nullString) {}
43
44 void operator()(const Size i) const {
45 if (i == QuantLib::Null<Size>()) {
46 fprintNull();
47 } else {
48 fprintf(fp_, "%zu", i);
49 }
50 }
51 void operator()(const Real d) const {
52 if (d == QuantLib::Null<Real>() || !std::isfinite(d)) {
53 fprintNull();
54 } else {
55 Real r = rounding_(d);
56 fprintf(fp_, "%.*f", rounding_.precision(), QuantLib::close_enough(r, 0.0) ? 0.0 : r);
57 }
58 }
59 void operator()(const string& s) const { fprintString(s); }
60 void operator()(const Date& d) const {
61 if (d == QuantLib::Null<Date>()) {
62 fprintNull();
63 } else {
64 string s = to_string(d);
65 fprintString(s);
66 }
67 }
68 void operator()(const Period& p) const {
69 string s = to_string(p);
70 fprintString(s);
71 }
72
73 void updateFile(FILE* fp) { fp_ = fp; }
74
75private:
76 void fprintNull() const { fprintf(fp_, "%s", null_.c_str()); }
77
78 // Shared implementation to include the quote character.
79 void fprintString(const string& s) const {
80 bool quoted = s.size() > 1 && s[0] == quoteChar_ && s[s.size() - 1] == quoteChar_;
81 if (!quoted && quoteChar_ != '\0')
82 fputc(quoteChar_, fp_);
83 fprintf(fp_, "%s", s.c_str());
84 if (!quoted && quoteChar_ != '\0')
85 fputc(quoteChar_, fp_);
86 }
87
88 FILE* fp_;
89 QuantLib::Rounding rounding_;
90 char quoteChar_;
91 string null_;
92};
93
94CSVFileReport::CSVFileReport(const string& filename, const char sep, const bool commentCharacter, char quoteChar,
95 const string& nullString, bool lowerHeader, QuantLib::Size rolloverSize)
96 : filename_(filename), sep_(sep), commentCharacter_(commentCharacter), quoteChar_(quoteChar),
97 nullString_(nullString), lowerHeader_(lowerHeader), rolloverSize_(rolloverSize), i_(0), fp_(NULL) {
99 open();
100}
101
103 if (!finalized_) {
104 WLOG("CSV file report '" << filename_ << "' was not finalized, call end() on the report instance.");
105 end();
106 }
107}
108
110 LOG("Opening CSV file report '" << filename_ << "'");
111 fp_ = FileIO::fopen(filename_.c_str(), "w");
112 QL_REQUIRE(fp_, "Error opening file '" << filename_ << "'");
113 for (auto& p : printers_)
114 p.updateFile(fp_);
115 finalized_ = false;
116}
117
119 checkIsOpen("rollover()");
120 end();
121 version_++;
122 boost::filesystem::path p(baseFilename_);
123 boost::filesystem::path newFilepath =
124 p.parent_path() /
125 boost::filesystem::path(p.stem().string() + "_" + to_string(version_) + p.extension().string());
126 filename_ = newFilepath.string();
127 open();
128}
129
131 checkIsOpen("flush()");
132 LOG("CVS file report '" << filename_ << "' is flushed");
133 fflush(fp_);
134}
135
136Report& CSVFileReport::addColumn(const string& name, const ReportType& rt, Size precision) {
137 checkIsOpen("addColumn(" + name + ")");
138 columnTypes_.push_back(rt);
139 headers_.push_back(name);
140 printers_.push_back(ReportTypePrinter(fp_, precision, quoteChar_, nullString_));
141 if (i_ == 0 && commentCharacter_)
142 fprintf(fp_, "#");
143 if (i_ > 0)
144 fprintf(fp_, "%c", sep_);
145 string cpName = name;
146 if (lowerHeader_ && !cpName.empty())
147 cpName[0] = std::tolower(static_cast<unsigned char>(cpName[0]));
148 fprintf(fp_, "%s", cpName.c_str());
149 i_++;
150 return *this;
151}
152
154 // check the filesize every for every 1000 rows, and roll if necessary
155 if (rolloverSize_ != QuantLib::Null<Size>()) {
156 if (j_ >= 10000) {
157 auto fileSize = boost::filesystem::file_size(filename_);
158 TLOG("CSV size of " << filename_ << " is " << fileSize);
159 if (fileSize > rolloverSize_ * 1024 * 1024)
160 rollover();
161 j_ = 0;
162 } else
163 j_++;
164 }
165
166 checkIsOpen("next()");
167 QL_REQUIRE(i_ == columnTypes_.size(), "Cannot go to next line, only "
168 << i_
169 << " entries filled, report headers are: " << boost::join(headers_, ","));
170 fprintf(fp_, "\n");
171 i_ = 0;
172 return *this;
173}
174
176 checkIsOpen("add()");
177 QL_REQUIRE(i_ < columnTypes_.size(),
178 "No column to add [" << rt << "] to, report headers are: " << boost::join(headers_, ","));
179 QL_REQUIRE(rt.which() == columnTypes_[i_].which(), "Cannot add value "
180 << rt << " of type " << rt.which() << " to column " << i_
181 << " of type " << columnTypes_[i_].which()
182 << ", report headers are: " << boost::join(headers_, ","));
183
184 if (i_ != 0)
185 fprintf(fp_, "%c", sep_);
186 boost::apply_visitor(printers_[i_], rt);
187 i_++;
188 return *this;
189}
190
192 checkIsOpen("end()");
193
194 if (fp_) {
195 fprintf(fp_, "\n");
196 if (int rc = fclose(fp_)) {
197 ALOG("CSV file report '" << filename_ << "' can not be closed (return code " << rc << ")");
198 } else {
199 LOG("CSV file report '" << filename_ << "' closed.");
200 }
201 } else {
202 ALOG("CSV file report '" << filename_ << "' can not be closed (file handle is null).");
203 }
204
205 QL_REQUIRE(i_ == columnTypes_.size() || i_ == 0, "csv report is finalized with incomplete row, got data for "
206 << i_ << " columns out of " << columnTypes_.size()
207 << ", report headers are: " << boost::join(headers_, ","));
208 finalized_ = true;
209}
210
211void CSVFileReport::checkIsOpen(const std::string& op) const {
212 QL_REQUIRE(!finalized_, "CSV file report '" << filename_ << "' is already finalized, can not process operation "
213 << op << ", report headers are: " << boost::join(headers_, ","));
214}
215
216} // namespace data
217} // namespace ore
std::string baseFilename_
Definition: csvreport.hpp:68
void flush() override
Definition: csvreport.cpp:130
Report & add(const ReportType &rt) override
Definition: csvreport.cpp:175
std::vector< ReportTypePrinter > printers_
Definition: csvreport.hpp:67
std::vector< std::string > headers_
Definition: csvreport.hpp:79
CSVFileReport(const string &filename, const char sep=',', const bool commentCharacter=true, char quoteChar='\0', const std::string &nullString="#N/A", bool lowerHeader=false, QuantLib::Size rolloverSize=QuantLib::Null< QuantLib::Size >())
Definition: csvreport.cpp:94
void end() override
Definition: csvreport.cpp:191
Report & next() override
Definition: csvreport.cpp:153
void checkIsOpen(const std::string &op) const
Definition: csvreport.cpp:211
QuantLib::Size rolloverSize_
Definition: csvreport.hpp:74
Report & addColumn(const string &name, const ReportType &rt, Size precision=0) override
Definition: csvreport.cpp:136
std::vector< ReportType > columnTypes_
Definition: csvreport.hpp:66
static FILE * fopen(const char *, const char *)
Retry wrapper for std::fopen.
Definition: fileio.cpp:64
boost::variant< Size, Real, string, Date, Period > ReportType
Definition: report.hpp:66
CSV Report class.
Wrapper class for retrying file IO operations.
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
#define ALOG(text)
Logging Macro (Level = Alert)
Definition: log.hpp:544
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
#define TLOG(text)
Logging Macro (Level = Data)
Definition: log.hpp:556
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
string conversion utilities
string name