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