Skip to content

Commit c657a41

Browse files
committed
Add CSV Exporter
1 parent edb7bf5 commit c657a41

File tree

3 files changed

+185
-3
lines changed

3 files changed

+185
-3
lines changed

include/oi/exporters/CSV.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#ifndef INCLUDED_OI_EXPORTERS_CSV_H
17+
#define INCLUDED_OI_EXPORTERS_CSV_H 1
18+
19+
#include <oi/IntrospectionResult.h>
20+
21+
#include <ostream>
22+
23+
namespace oi::exporters {
24+
25+
// CSV exporter following [RFC 4180](https://www.rfc-editor.org/rfc/rfc4180).
26+
class CSV {
27+
public:
28+
CSV(std::ostream& out) : out_(out) {
29+
}
30+
31+
void print(const IntrospectionResult&);
32+
void print(IntrospectionResult::const_iterator& begin,
33+
IntrospectionResult::const_iterator end);
34+
35+
private:
36+
static constexpr std::string_view kCRLF = "\r\n";
37+
static constexpr std::string_view kDelimiter = ",";
38+
static constexpr std::string_view kQuote = "\"";
39+
static constexpr std::string_view kEscapedQuote = "\\\"";
40+
static constexpr std::string_view kListDelimiter = ";";
41+
42+
static constexpr std::string_view kColumns[] = {
43+
"id", "name", "typePath", "typeNames",
44+
"staticSize", "exclusiveSize", "pointer", "length",
45+
"capacity", "is_set", "parent_id"};
46+
47+
size_t id_ = 0;
48+
std::vector<size_t> parentIdStack_ = {0};
49+
50+
std::ostream& out_;
51+
52+
void printHeader();
53+
54+
template <typename Seq>
55+
static std::string escapeField(const Seq&);
56+
57+
static std::string escapeField(std::string_view);
58+
static std::string escapeField(std::string);
59+
};
60+
61+
} // namespace oi::exporters
62+
63+
#endif

oi/CMakeLists.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,12 @@ target_link_libraries(codegen
5252
glog::glog
5353
)
5454

55-
add_library(exporters_json
56-
exporters/Json.cpp
57-
)
55+
add_library(exporters_json exporters/Json.cpp)
5856
target_include_directories(exporters_json PUBLIC ${CMAKE_SOURCE_DIR}/include)
5957
target_link_libraries(exporters_json oil)
6058

59+
add_library(exporters_csv exporters/CSV.cpp)
60+
target_include_directories(exporters_csv PUBLIC ${CMAKE_SOURCE_DIR}/include)
61+
target_link_libraries(exporters_csv oil)
62+
6163
add_subdirectory(type_graph)

oi/exporters/CSV.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include <oi/exporters/CSV.h>
17+
18+
#include <algorithm>
19+
#include <ranges>
20+
#include <stdexcept>
21+
22+
namespace oi::exporters {
23+
24+
void CSV::print(const IntrospectionResult& result) {
25+
auto begin = result.cbegin();
26+
return print(begin, result.cend());
27+
}
28+
29+
template <typename Seq>
30+
std::string CSV::escapeField(const Seq& seq) {
31+
std::string field;
32+
size_t index = 0;
33+
for (const auto item : seq) {
34+
if (index++ > 0) {
35+
field += kListDelimiter;
36+
}
37+
38+
field += item;
39+
}
40+
41+
return escapeField(field);
42+
}
43+
44+
std::string CSV::escapeField(std::string_view field) {
45+
return escapeField(std::string(field));
46+
}
47+
48+
std::string CSV::escapeField(std::string field) {
49+
// Escape every instance of double quotes.
50+
auto it = field.find(kQuote);
51+
while (it != std::string::npos) {
52+
field.replace(it, 1, kEscapedQuote);
53+
it = field.find(kQuote, it + kEscapedQuote.size());
54+
}
55+
56+
field.insert(0, kQuote);
57+
field.append(kQuote);
58+
return field;
59+
}
60+
61+
void CSV::print(IntrospectionResult::const_iterator& it,
62+
IntrospectionResult::const_iterator end) {
63+
printHeader();
64+
65+
parentIdStack_.resize(1); // Reset to parentIdStack_ = {0}
66+
for (/* it */; it != end; ++it) {
67+
out_ << ++id_ << kDelimiter;
68+
out_ << escapeField(it->name) << kDelimiter;
69+
out_ << escapeField(it->type_path) << kDelimiter;
70+
out_ << escapeField(it->type_names) << kDelimiter;
71+
out_ << it->static_size << kDelimiter;
72+
out_ << it->exclusive_size << kDelimiter;
73+
74+
if (!it->pointer.has_value()) {
75+
out_ << kDelimiter;
76+
} else {
77+
out_ << it->pointer.value() << kDelimiter;
78+
}
79+
80+
if (!it->container_stats.has_value()) {
81+
out_ << kDelimiter << kDelimiter;
82+
} else {
83+
out_ << it->container_stats->length << kDelimiter;
84+
out_ << it->container_stats->capacity << kDelimiter;
85+
}
86+
87+
if (!it->is_set_stats.has_value()) {
88+
out_ << kDelimiter;
89+
} else {
90+
out_ << it->is_set_stats->is_set << kDelimiter;
91+
}
92+
93+
while (parentIdStack_.size() > it->type_path.size()) {
94+
parentIdStack_.pop_back();
95+
}
96+
97+
out_ << parentIdStack_.back();
98+
99+
parentIdStack_.push_back(id_);
100+
101+
out_ << kCRLF;
102+
}
103+
}
104+
105+
void CSV::printHeader() {
106+
size_t index = 0;
107+
for (const auto column : kColumns) {
108+
if (index++ > 0) {
109+
out_ << kDelimiter;
110+
}
111+
112+
out_ << column;
113+
}
114+
out_ << kCRLF;
115+
}
116+
117+
} // namespace oi::exporters

0 commit comments

Comments
 (0)