• R/O
  • SSH

posixpp: Commit

The main posixpp library and associated tests.


Commit MetaInfo

Revision845b89885277181b72a9841b917c8bb7a4789200 (tree)
Time2021-05-03 15:30:36
AuthorEric Hopper <hopper@omni...>
CommiterEric Hopper

Log Message

Make read, write, and open be 'free' functions. Justification...

These are not intrinsic to every kind of file descriptor. If open is a
member, so should epoll_create, socket, and signalfd (among others). But
that would require dragging in a whole bunch of constants and types
associated solely with each of these calls. That doesn't seem right, the
fd type should be thin.

So, the fd type will now contain only a very few functions that are relevant
for just about any kind of file descriptor.

Of course, the magic of argument dependent lookup enables some of these now
'free' functions (like read and write) to be called without referencing the
namespace they're in because C++ rightly considers them part of the
interface for the fd type they take.

Change Summary

Incremental Difference

diff -r 21ff2fa93f67 -r 845b89885277 CMakeLists.txt
--- a/CMakeLists.txt Sun May 02 10:03:13 2021 -0700
+++ b/CMakeLists.txt Sun May 02 23:30:36 2021 -0700
@@ -10,7 +10,7 @@
1010
1111 find_package(fmt REQUIRED)
1212
13-add_library(posixpp SHARED empty.cpp)
13+add_library(posixpp SHARED empty.cpp pubincludes/posixpp/simpleio.h)
1414 set_property(TARGET posixpp PROPERTY CXX_EXTENSIONS OFF)
1515 target_compile_features(posixpp PUBLIC cxx_std_20)
1616 target_include_directories(posixpp PUBLIC
@@ -18,7 +18,7 @@
1818 $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
1919 )
2020
21-add_library(posixpp_static STATIC empty.cpp)
21+add_library(posixpp_static STATIC empty.cpp pubincludes/posixpp/simpleio.h)
2222 set_property(TARGET posixpp_static PROPERTY CXX_EXTENSIONS OFF)
2323 target_compile_features(posixpp_static PUBLIC cxx_std_20)
2424 target_include_directories(posixpp_static PUBLIC
@@ -32,7 +32,7 @@
3232 pubincludes/pppbase/flagset.h tests/flagset.cpp
3333 pubincludes/syscalls/linux/x86_64/fdflags.h tests/fdflags.cpp
3434 pubincludes/syscalls/linux/x86_64/modeflags.h
35- pubincludes/posixpp/modeflags.h pubincludes/syscalls/linux/basic.h pubincludes/posixpp/basic.h)
35+ pubincludes/posixpp/modeflags.h pubincludes/syscalls/linux/basic.h pubincludes/posixpp/basic.h pubincludes/posixpp/simpleio.h)
3636 set_property(TARGET all_tests PROPERTY CXX_EXTENSIONS OFF)
3737 target_compile_features(all_tests PUBLIC cxx_std_20)
3838 target_link_libraries(all_tests Catch2::Catch2 fmt::fmt posixpp)
diff -r 21ff2fa93f67 -r 845b89885277 examples/helloworld.cpp
--- a/examples/helloworld.cpp Sun May 02 10:03:13 2021 -0700
+++ b/examples/helloworld.cpp Sun May 02 23:30:36 2021 -0700
@@ -1,12 +1,12 @@
11 #include <posixpp/fd.h>
2-#include <posixpp/expected.h>
32 #include <posixpp/basic.h>
3+#include <posixpp/simpleio.h>
44
55 int main(int argc, char const * const *argv)
66 {
77 const ::posixpp::fd fdout{1};
88 static constexpr char msg[] = "Hello World!\n";
99 // sizeof(msg) - 1 to skip trailing '\0'
10- auto result = fdout.write(msg, sizeof(msg) - 1);
10+ auto result = write(fdout, msg, sizeof(msg) - 1);
1111 ::posixpp::exit(result.has_error());
1212 }
diff -r 21ff2fa93f67 -r 845b89885277 pubincludes/posixpp/fd.h
--- a/pubincludes/posixpp/fd.h Sun May 02 10:03:13 2021 -0700
+++ b/pubincludes/posixpp/fd.h Sun May 02 23:30:36 2021 -0700
@@ -78,20 +78,6 @@
7878 }
7979 }
8080
81- expected<::std::size_t>
82- write(char const *buf, ::std::size_t size) const noexcept {
83- using posixpp::error_cascade;
84- return error_cascade(::syscalls::linux::write(fd_, buf, size),
85- [](auto r) { return static_cast<::std::size_t>(r);});
86- }
87-
88- expected<::std::size_t>
89- read(char *buf, ::std::size_t size) const noexcept {
90- using posixpp::error_cascade;
91- return error_cascade(::syscalls::linux::read(fd_, buf, size),
92- [](auto r) { return static_cast<::std::size_t>(r);});
93- }
94-
9581 //! \brief Sets fd to invalid value and also calls close regardless of
9682 //! whether fd is currently an invalid value.
9783 [[nodiscard]] expected<void> close() noexcept {
@@ -101,64 +87,6 @@
10187 return close(tmpfd);
10288 }
10389
104-
105- ///@{
106- [[nodiscard]] static expected<fd>
107- open(char const *pathname, openflags flags) noexcept {
108- // Hard coded the value for AT_FDCWD
109- return openat(fd(-100), pathname, flags, modeflags{});
110- }
111- [[nodiscard]] static expected<fd>
112- open(char const *pathname, fdflags flags) noexcept {
113- return open(pathname, openflags{flags});
114- }
115-
116- [[nodiscard]] static expected<fd>
117- open(char const *pathname, openflags flags, modeflags mode) noexcept
118- {
119- return openat(fd(-100), pathname, flags, mode);
120- }
121- [[nodiscard]] static expected<fd>
122- open(char const *pathname, fdflags flags, modeflags mode) noexcept
123- {
124- return open(pathname, openflags{flags}, mode);
125- }
126-
127- [[nodiscard]] static expected<fd>
128- openat(fd const &dirfd, char const *pathname, openflags flags) noexcept
129- {
130- using ::syscalls::linux::openat;
131- using posixpp::error_cascade;
132- auto const dfd = dirfd.as_fd();
133- return error_cascade(openat(dfd, pathname, flags.getbits(), 0),
134- int_to_fd);
135- }
136- [[nodiscard]] static expected<fd>
137- openat(fd const &dirfd, char const *pathname, fdflags flags) noexcept
138- {
139- return openat(dirfd, pathname, openflags{flags});
140- }
141-
142- [[nodiscard]] static expected<fd>
143- openat(fd const &dirfd, char const *pathname,
144- openflags flags, modeflags mode) noexcept
145- {
146- using ::syscalls::linux::openat;
147- using posixpp::error_cascade;
148- return error_cascade(openat(dirfd.as_fd(),
149- pathname,
150- flags.getbits(),
151- mode.getbits()),
152- int_to_fd);
153- }
154- [[nodiscard]] static expected<fd>
155- openat(fd const &dirfd, char const *pathname,
156- fdflags flags, modeflags mode) noexcept
157- {
158- return openat(dirfd, pathname, openflags{flags}, mode);
159- }
160- ///@}
161-
16290 protected:
16391 static fd int_to_fd(int fdes) noexcept {
16492 return fd{fdes};
diff -r 21ff2fa93f67 -r 845b89885277 pubincludes/posixpp/simpleio.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pubincludes/posixpp/simpleio.h Sun May 02 23:30:36 2021 -0700
@@ -0,0 +1,87 @@
1+// Copyright 2021 Eric Hopper
2+// Distributed under the terms of the LGPLv3.
3+
4+#pragma once
5+
6+#include <posixpp/fd.h>
7+#include <syscalls/linux/simple_io.h>
8+
9+namespace posixpp {
10+
11+//! See write(2)
12+expected<::std::size_t>
13+inline write(fd const &file, char const *buf, ::std::size_t size) noexcept {
14+ using posixpp::error_cascade;
15+ return error_cascade(::syscalls::linux::write(file.as_fd(), buf, size),
16+ [](auto r) { return static_cast<::std::size_t>(r);});
17+}
18+
19+//! See read(2)
20+expected<::std::size_t>
21+inline read(fd const &file, char *buf, ::std::size_t size) noexcept {
22+ using posixpp::error_cascade;
23+ return error_cascade(::syscalls::linux::read(file.as_fd(), buf, size),
24+ [](auto r) { return static_cast<::std::size_t>(r);});
25+}
26+
27+///@{
28+[[nodiscard]] expected<fd>
29+inline openat(fd const &dirfd, char const *pathname,
30+ openflags flags, modeflags mode) noexcept
31+{
32+ // What all the other versions turn into, so it has to be first.
33+ using ::syscalls::linux::openat;
34+ using posixpp::error_cascade;
35+ return error_cascade(openat(dirfd.as_fd(),
36+ pathname,
37+ flags.getbits(),
38+ mode.getbits()),
39+ [](int fdint){return fd{fdint};});
40+}
41+
42+[[nodiscard]] expected<fd>
43+inline open(char const *pathname, openflags flags) noexcept {
44+ // Hard coded the value for AT_FDCWD
45+ return openat(fd(-100), pathname, flags, modeflags{});
46+}
47+[[nodiscard]] expected<fd>
48+inline open(char const *pathname, fdflags flags) noexcept {
49+ return open(pathname, openflags{flags});
50+}
51+
52+[[nodiscard]] expected<fd>
53+inline open(char const *pathname, openflags flags, modeflags mode) noexcept
54+{
55+ return openat(fd(-100), pathname, flags, mode);
56+}
57+[[nodiscard]] expected<fd>
58+inline open(char const *pathname, fdflags flags, modeflags mode) noexcept
59+{
60+ return open(pathname, openflags{flags}, mode);
61+}
62+
63+[[nodiscard]] expected<fd>
64+inline openat(fd const &dirfd, char const *pathname, openflags flags) noexcept
65+{
66+ using ::syscalls::linux::openat;
67+ using posixpp::error_cascade;
68+ auto const dfd = dirfd.as_fd();
69+ return error_cascade(openat(dfd, pathname, flags.getbits(), 0),
70+ [](int fdint){return fd{fdint};});
71+}
72+
73+[[nodiscard]] expected<fd>
74+inline openat(fd const &dirfd, char const *pathname, fdflags flags) noexcept
75+{
76+ return openat(dirfd, pathname, openflags{flags});
77+}
78+
79+[[nodiscard]] expected<fd>
80+inline openat(fd const &dirfd, char const *pathname,
81+ fdflags flags, modeflags mode) noexcept
82+{
83+ return openat(dirfd, pathname, openflags{flags}, mode);
84+}
85+///@}
86+
87+}
diff -r 21ff2fa93f67 -r 845b89885277 tests/simplefd.cpp
--- a/tests/simplefd.cpp Sun May 02 10:03:13 2021 -0700
+++ b/tests/simplefd.cpp Sun May 02 23:30:36 2021 -0700
@@ -1,6 +1,7 @@
11 #include <algorithm>
22 #include <posixpp/fd.h>
33 #include <posixpp/expected.h>
4+#include <posixpp/simpleio.h>
45 #include <fcntl.h>
56 #include <unistd.h>
67 #include "tempdir.h"
@@ -19,8 +20,9 @@
1920 using of = ::posixpp::openflags;
2021 using fdf = ::posixpp::fdflags;
2122 using ::posixpp::modeflags;
23+ using ::posixpp::open;
2224 auto foo{
23- fd::open(
25+ open(
2426 fooname.native().c_str(),
2527 of::creat | fdf::wronly,
2628 modeflags::irwall
@@ -49,18 +51,18 @@
4951 "the same as the data read, and no more data can be read"
5052 ) {
5153 // sizeof(msg) - 1 to skip the trailing '\8'
52- auto const write_result = foo.write(msg, sizeof(msg) - 1);
54+ auto const write_result = write(foo, msg, sizeof(msg) - 1);
5355 REQUIRE(write_result.result() == sizeof(msg) - 1);
5456 auto const close_result = foo.close();
5557 REQUIRE_FALSE(close_result.has_error());
5658 REQUIRE_FALSE(foo.is_valid());
5759
58- foo = fd::open(fooname.native().c_str(), fdf::rdonly).result();
60+ foo = open(fooname.native().c_str(), fdf::rdonly).result();
5961 REQUIRE(foo.is_valid());
6062
6163 // Try to read more than was written to make sure we can't read
6264 // extra (as per the description in the WHEN clause above).
63- auto read_result = foo.read(readmsg, sizeof(readmsg));
65+ auto read_result = read(foo, readmsg, sizeof(readmsg));
6466 REQUIRE(read_result.result() == sizeof(readmsg) - 1);
6567 REQUIRE(::std::equal(msg, msg + (sizeof(msg) - 1), readmsg));
6668 }
@@ -82,17 +84,18 @@
8284 using of = ::posixpp::openflags;
8385 using fdf = ::posixpp::fdflags;
8486 using ::posixpp::modeflags;
87+ using ::posixpp::open;
8588 auto foo{
86- fd::open(
89+ open(
8790 fooname.native().c_str(),
8891 of::creat | fdf::wronly,
8992 modeflags::irwall
9093 ).result()
9194 };
9295 // Don't write out the trailing '\0';
93- REQUIRE(foo.write(known_text, sizeof(known_text) - 1).result() == sizeof(known_text) - 1);
96+ REQUIRE(write(foo, known_text, sizeof(known_text) - 1).result() == sizeof(known_text) - 1);
9497 foo.close().throw_if_error();
95- foo = fd::open(fooname.native().c_str(), fdf::rdonly).result();
98+ foo = open(fooname.native().c_str(), fdf::rdonly).result();
9699 WHEN("The foo.dup() is called.") {
97100 fd bar{ foo.dup().result() };
98101
@@ -102,13 +105,13 @@
102105 }
103106 AND_WHEN("You read one character from it.") {
104107 char buf[1];
105- REQUIRE(bar.read(buf, 1).result() == 1);
108+ REQUIRE(read(bar, buf, 1).result() == 1);
106109 THEN("you read the first character of the known text.") {
107110 REQUIRE(buf[0] == known_text[0]);
108111 }
109112 AND_WHEN("you then read one character from the original fd.") {
110113 char buf2[1];
111- REQUIRE(foo.read(buf2, 1).result() == 1);
114+ REQUIRE(read(foo, buf2, 1).result() == 1);
112115 THEN("that character is the second character of the known text.") {
113116 REQUIRE(buf2[0] == known_text[1]);
114117 }
@@ -122,12 +125,12 @@
122125 }
123126 THEN( "a byte read from foo is the first byte of known_text") {
124127 char buf_foo[1];
125- REQUIRE(foo.read(buf_foo, 1).result() == 1);
128+ REQUIRE(read(foo, buf_foo, 1).result() == 1);
126129 REQUIRE(buf_foo[0] == known_text[0]);
127130 }
128131 }
129132 AND_GIVEN("Another file descriptor opened on the same file.") {
130- auto foo2{fd::open(fooname.native().c_str(), fdf::rdonly).result()};
133+ auto foo2{open(fooname.native().c_str(), fdf::rdonly).result()};
131134 THEN("It is valid.") {
132135 REQUIRE(foo2.is_valid());
133136 }
@@ -137,8 +140,8 @@
137140 // Initialize to 0 to make sure they change when read into.
138141 char buf_foo[1] = {};
139142 char buf_foo2[1] = {};
140- REQUIRE(foo.read(buf_foo, 1).result() == 1);
141- REQUIRE(foo2.read(buf_foo2, 1).result() == 1);
143+ REQUIRE(read(foo, buf_foo, 1).result() == 1);
144+ REQUIRE(read(foo2, buf_foo2, 1).result() == 1);
142145 THEN(
143146 "it's the same byte, and the first byte of the known "
144147 "text, demonstrating that they each refer to a different "
@@ -154,8 +157,8 @@
154157 } AND_WHEN ("we then read read a byte from each file.") {
155158 char buff2_foo[1];
156159 char buf2_foo2[1];
157- REQUIRE(foo.read(buff2_foo, 1).result() == 1);
158- REQUIRE(foo2.read(buf2_foo2, 1).result() == 1);
160+ REQUIRE(read(foo, buff2_foo, 1).result() == 1);
161+ REQUIRE(read(foo2, buf2_foo2, 1).result() == 1);
159162 THEN(
160163 "then we get the 2nd and 3rd bytes of known "
161164 "text, demonstrating they now refer to the same "
Show on old repository browser