xref: /freebsd/lib/libutil++/libutil++.hh (revision 937e92b5f7cc9495368e64f2d5b45312f6595ed2)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2025 Chelsio Communications, Inc.
5  * Written by: John Baldwin <jhb@FreeBSD.org>
6  */
7 
8 #ifndef __LIBUTILPP_HH__
9 #define	__LIBUTILPP_HH__
10 
11 #include <netdb.h>
12 #include <unistd.h>
13 
14 #include <cstdarg>
15 #include <cstdio>
16 #include <cstdlib>
17 #include <memory>
18 
19 namespace freebsd {
20 	/*
21 	 * FILE_up is a std::unique_ptr<> for FILE objects which uses
22 	 * fclose() to destroy the wrapped pointer.
23 	 */
24 	struct fclose_deleter {
25 		void operator() (std::FILE *fp) const
26 		{
27 			std::fclose(fp);
28 		}
29 	};
30 
31 	using FILE_up = std::unique_ptr<std::FILE, fclose_deleter>;
32 
33 	/*
34 	 * addrinfo_up is a std::unique_ptr<> which uses
35 	 * freeaddrinfo() to destroy the wrapped pointer.  It is
36 	 * intended to wrap arrays allocated by getaddrinfo().
37 	 */
38 	struct freeaddrinfo_deleter {
39 		void operator() (struct addrinfo *ai) const
40 		{
41 			freeaddrinfo(ai);
42 		}
43 	};
44 
45 	using addrinfo_up = std::unique_ptr<addrinfo, freeaddrinfo_deleter>;
46 
47 	/*
48 	 * This class is intended to function similar to unique_ptr<>,
49 	 * but it contains a file descriptor rather than a pointer to
50 	 * an object.  On destruction the descriptor is closed via
51 	 * close(2).
52 	 *
53 	 * Similar to unique_ptr<>, release() returns ownership of the
54 	 * file descriptor to the caller.  reset() closes the current
55 	 * file descriptor and takes ownership of a new one.  A move
56 	 * constructor permits ownership to be transferred via
57 	 * std::move().  An integer file descriptor can be assigned
58 	 * directly which is equivalent to calling reset().
59 	 *
60 	 * An explicit bool conversion operator permits testing this
61 	 * class in logical expressions.  It returns true if it
62 	 * contains a valid descriptor.
63 	 *
64 	 * An implicit int conversion operator returns the underlying
65 	 * file descriptor allowing objects of this type to be passed
66 	 * directly to APIs such as connect(), listen(), etc.
67 	 */
68 	class fd_up {
69 	public:
70 		fd_up() : fd(-1) {}
71 		fd_up(int fd) : fd(fd) {}
72 		fd_up(fd_up &&other) : fd(other.release()) {}
73 		fd_up(fd_up const &) = delete;
74 
75 		~fd_up() { reset(); }
76 
77 		int get() const { return (fd); }
78 
79 		int release()
80 		{
81 			int oldfd = fd;
82 
83 			fd = -1;
84 			return (oldfd);
85 		}
86 
87 		void reset(int newfd = -1)
88 		{
89 			if (fd >= 0)
90 				close(fd);
91 			fd = newfd;
92 		}
93 
94 		fd_up &operator=(fd_up &&other) noexcept
95 		{
96 			if (this == &other)
97 				return *this;
98 
99 			reset(other.release());
100 			return *this;
101 		}
102 
103 		fd_up &operator=(fd_up const &) = delete;
104 
105 		fd_up &operator=(int newfd)
106 		{
107 			reset(newfd);
108 			return *this;
109 		}
110 
111 		explicit operator bool() const { return fd >= 0; }
112 		operator int() const { return fd; }
113 	private:
114 		int	fd;
115 	};
116 
117 	/*
118 	 * malloc_up<T> is a std::unique_ptr<> which uses free() to
119 	 * destroy the wrapped pointer.  This can be used to wrap
120 	 * pointers allocated implicitly by malloc() such as those
121 	 * returned by strdup().
122 	 */
123 	template <class T>
124 	struct free_deleter {
125 		void operator() (T *p) const
126 		{
127 			std::free(p);
128 		}
129 	};
130 
131 	template <class T>
132 	using malloc_up = std::unique_ptr<T, free_deleter<T>>;
133 
134 	/*
135 	 * Returns a std::string containing the same output as
136 	 * sprintf().  Throws std::bad_alloc if an error occurs.
137 	 */
138 	std::string stringf(const char *fmt, ...) __printflike(1, 2);
139 	std::string stringf(const char *fmt, std::va_list ap);
140 }
141 
142 #endif /* !__LIBUTILPP_HH__ */
143