Created
February 24, 2025 01:54
-
-
Save DrkWithT/111ef99ab8c9464126e50089a9b08ab1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <utility> | |
#include <concepts> | |
#include <algorithm> | |
#include <array> | |
#include <string> | |
template <template <typename> typename Buffer, typename ItemT> | |
concept BufferKind = requires(Buffer<ItemT>&& arg, std::size_t count) { | |
{arg.getPtr()} -> std::same_as<ItemT*>; | |
{arg.getSize()} -> std::same_as<std::size_t>; | |
{arg.getLength()} -> std::same_as<std::size_t>; | |
{arg.markLength(count)}; | |
}; | |
template <typename T, template <typename> typename B, typename ItemT> | |
concept IOProviderKind = requires(T&& arg, B<ItemT>&& buffer, int Fd, std::size_t N) { | |
{arg.readOne(Fd)} -> std::same_as<char>; | |
{arg.readBlob(Fd, N, buffer)} -> std::same_as<bool>; | |
{arg.writeBlob(Fd, buffer)} -> std::same_as<bool>; | |
} and BufferKind<B, ItemT>; | |
template <typename ItemT> | |
class FixedBuffer { | |
private: | |
static constexpr auto limit = 1024UL; | |
std::array<ItemT, limit> m_data; | |
std::size_t m_length; | |
public: | |
FixedBuffer() noexcept | |
: m_data {}, m_length {0UL} { | |
std::fill(m_data.begin(), m_data.end(), ItemT {}); | |
} | |
[[nodiscard]] ItemT* getPtr() noexcept { | |
return m_data.data(); | |
} | |
[[nodiscard]] std::size_t getSize() const noexcept { | |
return limit; | |
} | |
[[nodiscard]] std::size_t getLength() const noexcept { | |
return m_length; | |
} | |
void markLength(std::size_t count) noexcept { | |
m_length = count; | |
} | |
}; | |
/// @note Decouple I/O logic from the socket for easier mocking of the socket interface's functionality. | |
class MockIO { | |
private: | |
std::string m_input; | |
int m_pos; | |
[[nodiscard]] bool isEmpty() const noexcept { | |
return m_pos >= m_input.size(); | |
} | |
public: | |
MockIO(std::string temp) noexcept | |
: m_input {std::move(temp)}, m_pos {0} {} | |
char readOne(int fd) noexcept { | |
if (isEmpty()) { | |
return '\0'; | |
} | |
return m_input[m_pos++]; | |
} | |
template <template <typename> typename Buffer, typename ItemT> requires (BufferKind<Buffer, ItemT>) | |
[[nodiscard]] bool readBlob(int fd, std::size_t count, Buffer<ItemT>& target) noexcept { | |
return true; // dud behavior: pretend this read works... | |
} | |
template <template <typename> typename Buffer, typename ItemT> requires (BufferKind<Buffer, ItemT>) | |
[[nodiscard]] bool writeBlob(int fd, const Buffer<ItemT>& source) noexcept { | |
return true; // dud behavior: pretend writing works... | |
} | |
}; | |
enum class SocketPolicy { | |
mock, | |
real | |
}; | |
template <SocketPolicy P> | |
class Socket {}; | |
template <> | |
class Socket <SocketPolicy::mock> { | |
private: | |
int m_fd {42}; | |
bool m_closed {false}; | |
public: | |
template <typename Provider, template <typename> typename Buffer, typename ItemT> requires (IOProviderKind<Provider, Buffer, ItemT>) | |
[[nodiscard]] bool readLine(Provider& service, Buffer<ItemT>& target, ItemT delim) noexcept { | |
auto space_n = target.getSize(); | |
auto done_n = 0UL; | |
bool found_delim = false; | |
while (not m_closed and space_n > 0) { | |
auto temp = service.readOne(m_fd); | |
if (temp == ItemT {}) { | |
m_closed = true; | |
continue; | |
} | |
if (temp == delim) { | |
found_delim = true; | |
break; | |
} | |
target.getPtr()[done_n] = temp; | |
done_n++; | |
space_n--; | |
} | |
return not m_closed and found_delim; | |
} | |
}; | |
template <> | |
class Socket <SocketPolicy::real> { | |
// pretend this uses open, close, recv, send functions from a real socket API... | |
}; | |
int main() { | |
FixedBuffer<char> buffer {}; | |
MockIO io {"hello world\n"}; | |
Socket<SocketPolicy::mock> socket {}; | |
if (not socket.readLine(io, buffer, '\n')) { | |
return 1; | |
} | |
std::string expected_line {"hello world"}; | |
if (expected_line != buffer.getPtr()) { | |
return 1; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment