Skip to content

Commit 2bfe6d7

Browse files
authored
feat(io_interface): Port Reader and Writer interfaces from CLP with minimal compilation fixes. (#48)
1 parent 3f5186c commit 2bfe6d7

File tree

9 files changed

+442
-0
lines changed

9 files changed

+442
-0
lines changed

src/ystdlib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
add_subdirectory(containers)
22
add_subdirectory(error_handling)
3+
add_subdirectory(io_interface)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
cpp_library(
2+
NAME io_interface
3+
NAMESPACE ystdlib
4+
PUBLIC_HEADERS
5+
ErrorCode.hpp
6+
ReaderInterface.hpp
7+
WriterInterface.hpp
8+
PRIVATE_SOURCES
9+
ReaderInterface.cpp
10+
WriterInterface.cpp
11+
TESTS_SOURCES
12+
test/test_ReaderInterface.cpp
13+
test/test_WriterInterface.cpp
14+
)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef YSTDLIB_IO_INTERFACE_ERRORCODE_HPP
2+
#define YSTDLIB_IO_INTERFACE_ERRORCODE_HPP
3+
4+
// NOLINTBEGIN
5+
6+
namespace ystdlib::io_interface {
7+
typedef enum {
8+
ErrorCode_Success = 0,
9+
ErrorCode_BadParam,
10+
ErrorCode_BadParam_DB_URI,
11+
ErrorCode_Corrupt,
12+
ErrorCode_errno,
13+
ErrorCode_EndOfFile,
14+
ErrorCode_FileExists,
15+
ErrorCode_FileNotFound,
16+
ErrorCode_NoMem,
17+
ErrorCode_NotInit,
18+
ErrorCode_NotReady,
19+
ErrorCode_OutOfBounds,
20+
ErrorCode_TooLong,
21+
ErrorCode_Truncated,
22+
ErrorCode_Unsupported,
23+
ErrorCode_NoAccess,
24+
ErrorCode_Failure,
25+
ErrorCode_Failure_Metadata_Corrupted,
26+
ErrorCode_MetadataCorrupted,
27+
ErrorCode_Failure_DB_Bulk_Write,
28+
ErrorCode_Failure_Network,
29+
} ErrorCode;
30+
} // namespace ystdlib::io_interface
31+
32+
// NOLINTEND
33+
#endif // YSTDLIB_IO_INTERFACE_ERRORCODE_HPP
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// NOLINTBEGIN
2+
#include "ReaderInterface.hpp"
3+
4+
using std::string;
5+
6+
namespace ystdlib::io_interface {
7+
ErrorCode ReaderInterface::try_read_to_delimiter(
8+
char delim,
9+
bool keep_delimiter,
10+
bool append,
11+
std::string& str
12+
) {
13+
if (false == append) {
14+
str.clear();
15+
}
16+
17+
size_t original_str_length = str.length();
18+
19+
// Read character by character into str, until we find a delimiter
20+
char c;
21+
size_t num_bytes_read;
22+
while (true) {
23+
auto error_code = try_read(&c, 1, num_bytes_read);
24+
if (ErrorCode_Success != error_code) {
25+
if (ErrorCode_EndOfFile == error_code && str.length() > original_str_length) {
26+
return ErrorCode_Success;
27+
}
28+
return error_code;
29+
}
30+
31+
if (delim == c) {
32+
break;
33+
}
34+
35+
str += c;
36+
}
37+
38+
// Add delimiter if necessary
39+
if (keep_delimiter) {
40+
str += delim;
41+
}
42+
43+
return ErrorCode_Success;
44+
}
45+
46+
bool ReaderInterface::read(char* buf, size_t num_bytes_to_read, size_t& num_bytes_read) {
47+
ErrorCode error_code = try_read(buf, num_bytes_to_read, num_bytes_read);
48+
if (ErrorCode_EndOfFile == error_code) {
49+
return false;
50+
}
51+
if (ErrorCode_Success != error_code) {
52+
throw OperationFailed(error_code);
53+
}
54+
return true;
55+
}
56+
57+
bool ReaderInterface::read_to_delimiter(char delim, bool keep_delimiter, bool append, string& str) {
58+
ErrorCode error_code = try_read_to_delimiter(delim, keep_delimiter, append, str);
59+
if (ErrorCode_EndOfFile == error_code) {
60+
return false;
61+
}
62+
if (ErrorCode_Success != error_code) {
63+
throw OperationFailed(error_code);
64+
}
65+
66+
return true;
67+
}
68+
69+
ErrorCode ReaderInterface::try_read_exact_length(char* buf, size_t num_bytes) {
70+
size_t num_bytes_read;
71+
auto error_code = try_read(buf, num_bytes, num_bytes_read);
72+
if (ErrorCode_Success != error_code) {
73+
return error_code;
74+
}
75+
if (num_bytes_read < num_bytes) {
76+
return ErrorCode_Truncated;
77+
}
78+
79+
return ErrorCode_Success;
80+
}
81+
82+
bool ReaderInterface::read_exact_length(char* buf, size_t num_bytes, bool eof_possible) {
83+
ErrorCode error_code = try_read_exact_length(buf, num_bytes);
84+
if (eof_possible && ErrorCode_EndOfFile == error_code) {
85+
return false;
86+
}
87+
if (ErrorCode_Success != error_code) {
88+
throw OperationFailed(error_code);
89+
}
90+
return true;
91+
}
92+
93+
ErrorCode ReaderInterface::try_read_string(size_t const str_length, string& str) {
94+
// Resize string to fit str_length
95+
str.resize(str_length);
96+
97+
return try_read_exact_length(&str[0], str_length);
98+
}
99+
100+
bool ReaderInterface::read_string(size_t const str_length, string& str, bool eof_possible) {
101+
ErrorCode error_code = try_read_string(str_length, str);
102+
if (eof_possible && ErrorCode_EndOfFile == error_code) {
103+
return false;
104+
}
105+
if (ErrorCode_Success != error_code) {
106+
throw OperationFailed(error_code);
107+
}
108+
return true;
109+
}
110+
111+
void ReaderInterface::seek_from_begin(size_t pos) {
112+
ErrorCode error_code = try_seek_from_begin(pos);
113+
if (ErrorCode_Success != error_code) {
114+
throw OperationFailed(error_code);
115+
}
116+
}
117+
118+
size_t ReaderInterface::get_pos() {
119+
size_t pos;
120+
ErrorCode error_code = try_get_pos(pos);
121+
if (ErrorCode_Success != error_code) {
122+
throw OperationFailed(error_code);
123+
}
124+
125+
return pos;
126+
}
127+
} // namespace ystdlib::io_interface
128+
129+
// NOLINTEND
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#ifndef YSTDLIB_IO_INTERFACE_READERINTERFACE_HPP
2+
#define YSTDLIB_IO_INTERFACE_READERINTERFACE_HPP
3+
// NOLINTBEGIN
4+
5+
#include <cstddef>
6+
#include <string>
7+
8+
#include "ErrorCode.hpp"
9+
10+
namespace ystdlib::io_interface {
11+
class ReaderInterface {
12+
public:
13+
// Types
14+
class OperationFailed : public std::exception {
15+
public:
16+
OperationFailed(ErrorCode error_code) {}
17+
};
18+
19+
// Destructor
20+
virtual ~ReaderInterface() = default;
21+
22+
// Methods
23+
virtual ErrorCode try_read(char* buf, size_t num_bytes_to_read, size_t& num_bytes_read) = 0;
24+
virtual ErrorCode try_seek_from_begin(size_t pos) = 0;
25+
virtual ErrorCode try_get_pos(size_t& pos) = 0;
26+
27+
/**
28+
* Tries to read up to the next delimiter and stores it in the given string.
29+
* NOTE: Implementations should override this if they can achieve better performance.
30+
* @param delim The delimiter to stop at
31+
* @param keep_delimiter Whether to include the delimiter in the output string or not
32+
* @param append Whether to append to the given string or replace its contents
33+
* @param str The string read
34+
* @return ErrorCode_Success on success
35+
* @return Same as ReaderInterface::try_read otherwise
36+
*/
37+
virtual ErrorCode
38+
try_read_to_delimiter(char delim, bool keep_delimiter, bool append, std::string& str);
39+
40+
/**
41+
* Reads up to a given number of bytes
42+
* @param buf
43+
* @param num_bytes_to_read The number of bytes to try and read
44+
* @param num_bytes_read The actual number of bytes read
45+
* @return false on EOF
46+
* @return true otherwise
47+
*/
48+
bool read(char* buf, size_t num_bytes_to_read, size_t& num_bytes_read);
49+
50+
/**
51+
* Reads up to the next delimiter and stores it in the given string
52+
* @param delim The delimiter to stop at
53+
* @param keep_delimiter Whether to include the delimiter in the output string or not
54+
* @param append Whether to append to the given string or replace its contents
55+
* @param str The string read
56+
* @return false on EOF
57+
* @return true on success
58+
*/
59+
bool read_to_delimiter(char delim, bool keep_delimiter, bool append, std::string& str);
60+
61+
/**
62+
* Tries to read a number of bytes
63+
* @param buf
64+
* @param num_bytes Number of bytes to read
65+
* @return Same as the underlying medium's try_read method
66+
* @return ErrorCode_Truncated if 0 < # bytes read < num_bytes
67+
*/
68+
ErrorCode try_read_exact_length(char* buf, size_t num_bytes);
69+
/**
70+
* Reads a number of bytes
71+
* @param buf
72+
* @param num_bytes Number of bytes to read
73+
* @param eof_possible If EOF should be possible (without reading any bytes)
74+
* @return false if EOF is possible and EOF was hit
75+
* @return true on success
76+
*/
77+
bool read_exact_length(char* buf, size_t num_bytes, bool eof_possible);
78+
79+
/**
80+
* Tries to read a numeric value from a file
81+
* @param value The read value
82+
* @return Same as FileReader::try_read_exact_length's return values
83+
*/
84+
template <typename ValueType>
85+
ErrorCode try_read_numeric_value(ValueType& value);
86+
/**
87+
* Reads a numeric value
88+
* @param value The read value
89+
* @param eof_possible If EOF should be possible (without reading any bytes)
90+
* @return false if EOF is possible and EOF was hit
91+
* @return true on success
92+
*/
93+
template <typename ValueType>
94+
bool read_numeric_value(ValueType& value, bool eof_possible);
95+
96+
/**
97+
* Tries to read a string
98+
* @param str_length
99+
* @param str The string read
100+
* @return Same as ReaderInterface::try_read_exact_length
101+
*/
102+
ErrorCode try_read_string(size_t str_length, std::string& str);
103+
/**
104+
* Reads a string
105+
* @param str_length
106+
* @param str The string read
107+
* @param eof_possible If EOF should be possible (without reading any bytes)
108+
* @return false if EOF is possible and EOF was hit
109+
* @return true on success
110+
*/
111+
bool read_string(size_t str_length, std::string& str, bool eof_possible);
112+
113+
/**
114+
* Seeks from the beginning to the given position
115+
* @param pos
116+
*/
117+
void seek_from_begin(size_t pos);
118+
119+
/**
120+
* Gets the current position of the read head
121+
* @return Position of the read head
122+
*/
123+
size_t get_pos();
124+
};
125+
126+
template <typename ValueType>
127+
ErrorCode ReaderInterface::try_read_numeric_value(ValueType& value) {
128+
ErrorCode error_code = try_read_exact_length(reinterpret_cast<char*>(&value), sizeof(value));
129+
if (ErrorCode_Success != error_code) {
130+
return error_code;
131+
}
132+
return ErrorCode_Success;
133+
}
134+
135+
template <typename ValueType>
136+
bool ReaderInterface::read_numeric_value(ValueType& value, bool eof_possible) {
137+
ErrorCode error_code = try_read_numeric_value(value);
138+
if (ErrorCode_EndOfFile == error_code && eof_possible) {
139+
return false;
140+
}
141+
if (ErrorCode_Success != error_code) {
142+
throw OperationFailed(error_code);
143+
}
144+
return true;
145+
}
146+
} // namespace ystdlib::io_interface
147+
148+
// NOLINTEND
149+
#endif // YSTDLIB_IO_INTERFACE_READERINTERFACE_HPP
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// NOLINTBEGIN
2+
#include "WriterInterface.hpp"
3+
4+
namespace ystdlib::io_interface {
5+
void WriterInterface::write_char(char c) {
6+
write(&c, 1);
7+
}
8+
9+
void WriterInterface::write_string(std::string const& str) {
10+
write(str.c_str(), str.length());
11+
}
12+
13+
void WriterInterface::seek_from_begin(size_t pos) {
14+
auto error_code = try_seek_from_begin(pos);
15+
if (ErrorCode_Success != error_code) {
16+
throw OperationFailed(error_code);
17+
}
18+
}
19+
20+
void WriterInterface::seek_from_current(off_t offset) {
21+
auto error_code = try_seek_from_current(offset);
22+
if (ErrorCode_Success != error_code) {
23+
throw OperationFailed(error_code);
24+
}
25+
}
26+
27+
size_t WriterInterface::get_pos() const {
28+
size_t pos;
29+
ErrorCode error_code = try_get_pos(pos);
30+
if (ErrorCode_Success != error_code) {
31+
throw OperationFailed(error_code);
32+
}
33+
34+
return pos;
35+
}
36+
} // namespace ystdlib::io_interface
37+
38+
// NOLINTEND

0 commit comments

Comments
 (0)