xref: /freebsd/lib/libutil++/libutil++.hh (revision 63ffcf6971a36e00efc138c3261b499aa48e102f)
1b3127a2dSJohn Baldwin /*-
2b3127a2dSJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause
3b3127a2dSJohn Baldwin  *
4b3127a2dSJohn Baldwin  * Copyright (c) 2025 Chelsio Communications, Inc.
5b3127a2dSJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
6b3127a2dSJohn Baldwin  */
7b3127a2dSJohn Baldwin 
8b3127a2dSJohn Baldwin #ifndef __LIBUTILPP_HH__
9b3127a2dSJohn Baldwin #define	__LIBUTILPP_HH__
10b3127a2dSJohn Baldwin 
11*63ffcf69SJohn Baldwin #include <sys/nv.h>
1222ce7be7SJohn Baldwin #include <netdb.h>
13937e92b5SJohn Baldwin #include <unistd.h>
1422ce7be7SJohn Baldwin 
15b3127a2dSJohn Baldwin #include <cstdarg>
16b3127a2dSJohn Baldwin #include <cstdio>
17b3127a2dSJohn Baldwin #include <cstdlib>
18b3127a2dSJohn Baldwin #include <memory>
19b3127a2dSJohn Baldwin 
20b3127a2dSJohn Baldwin namespace freebsd {
21b3127a2dSJohn Baldwin 	/*
22b3127a2dSJohn Baldwin 	 * FILE_up is a std::unique_ptr<> for FILE objects which uses
23b3127a2dSJohn Baldwin 	 * fclose() to destroy the wrapped pointer.
24b3127a2dSJohn Baldwin 	 */
25b3127a2dSJohn Baldwin 	struct fclose_deleter {
26b3127a2dSJohn Baldwin 		void operator() (std::FILE *fp) const
27b3127a2dSJohn Baldwin 		{
28b3127a2dSJohn Baldwin 			std::fclose(fp);
29b3127a2dSJohn Baldwin 		}
30b3127a2dSJohn Baldwin 	};
31b3127a2dSJohn Baldwin 
32b3127a2dSJohn Baldwin 	using FILE_up = std::unique_ptr<std::FILE, fclose_deleter>;
33b3127a2dSJohn Baldwin 
34b3127a2dSJohn Baldwin 	/*
3522ce7be7SJohn Baldwin 	 * addrinfo_up is a std::unique_ptr<> which uses
3622ce7be7SJohn Baldwin 	 * freeaddrinfo() to destroy the wrapped pointer.  It is
3722ce7be7SJohn Baldwin 	 * intended to wrap arrays allocated by getaddrinfo().
3822ce7be7SJohn Baldwin 	 */
3922ce7be7SJohn Baldwin 	struct freeaddrinfo_deleter {
4022ce7be7SJohn Baldwin 		void operator() (struct addrinfo *ai) const
4122ce7be7SJohn Baldwin 		{
4222ce7be7SJohn Baldwin 			freeaddrinfo(ai);
4322ce7be7SJohn Baldwin 		}
4422ce7be7SJohn Baldwin 	};
4522ce7be7SJohn Baldwin 
4622ce7be7SJohn Baldwin 	using addrinfo_up = std::unique_ptr<addrinfo, freeaddrinfo_deleter>;
4722ce7be7SJohn Baldwin 
4822ce7be7SJohn Baldwin 	/*
49937e92b5SJohn Baldwin 	 * This class is intended to function similar to unique_ptr<>,
50937e92b5SJohn Baldwin 	 * but it contains a file descriptor rather than a pointer to
51937e92b5SJohn Baldwin 	 * an object.  On destruction the descriptor is closed via
52937e92b5SJohn Baldwin 	 * close(2).
53937e92b5SJohn Baldwin 	 *
54937e92b5SJohn Baldwin 	 * Similar to unique_ptr<>, release() returns ownership of the
55937e92b5SJohn Baldwin 	 * file descriptor to the caller.  reset() closes the current
56937e92b5SJohn Baldwin 	 * file descriptor and takes ownership of a new one.  A move
57937e92b5SJohn Baldwin 	 * constructor permits ownership to be transferred via
58937e92b5SJohn Baldwin 	 * std::move().  An integer file descriptor can be assigned
59937e92b5SJohn Baldwin 	 * directly which is equivalent to calling reset().
60937e92b5SJohn Baldwin 	 *
61937e92b5SJohn Baldwin 	 * An explicit bool conversion operator permits testing this
62937e92b5SJohn Baldwin 	 * class in logical expressions.  It returns true if it
63937e92b5SJohn Baldwin 	 * contains a valid descriptor.
64937e92b5SJohn Baldwin 	 *
65937e92b5SJohn Baldwin 	 * An implicit int conversion operator returns the underlying
66937e92b5SJohn Baldwin 	 * file descriptor allowing objects of this type to be passed
67937e92b5SJohn Baldwin 	 * directly to APIs such as connect(), listen(), etc.
68937e92b5SJohn Baldwin 	 */
69937e92b5SJohn Baldwin 	class fd_up {
70937e92b5SJohn Baldwin 	public:
71937e92b5SJohn Baldwin 		fd_up() : fd(-1) {}
72937e92b5SJohn Baldwin 		fd_up(int fd) : fd(fd) {}
73937e92b5SJohn Baldwin 		fd_up(fd_up &&other) : fd(other.release()) {}
74937e92b5SJohn Baldwin 		fd_up(fd_up const &) = delete;
75937e92b5SJohn Baldwin 
76937e92b5SJohn Baldwin 		~fd_up() { reset(); }
77937e92b5SJohn Baldwin 
78937e92b5SJohn Baldwin 		int get() const { return (fd); }
79937e92b5SJohn Baldwin 
80937e92b5SJohn Baldwin 		int release()
81937e92b5SJohn Baldwin 		{
82937e92b5SJohn Baldwin 			int oldfd = fd;
83937e92b5SJohn Baldwin 
84937e92b5SJohn Baldwin 			fd = -1;
85937e92b5SJohn Baldwin 			return (oldfd);
86937e92b5SJohn Baldwin 		}
87937e92b5SJohn Baldwin 
88937e92b5SJohn Baldwin 		void reset(int newfd = -1)
89937e92b5SJohn Baldwin 		{
90937e92b5SJohn Baldwin 			if (fd >= 0)
91937e92b5SJohn Baldwin 				close(fd);
92937e92b5SJohn Baldwin 			fd = newfd;
93937e92b5SJohn Baldwin 		}
94937e92b5SJohn Baldwin 
95937e92b5SJohn Baldwin 		fd_up &operator=(fd_up &&other) noexcept
96937e92b5SJohn Baldwin 		{
97937e92b5SJohn Baldwin 			if (this == &other)
98937e92b5SJohn Baldwin 				return *this;
99937e92b5SJohn Baldwin 
100937e92b5SJohn Baldwin 			reset(other.release());
101937e92b5SJohn Baldwin 			return *this;
102937e92b5SJohn Baldwin 		}
103937e92b5SJohn Baldwin 
104937e92b5SJohn Baldwin 		fd_up &operator=(fd_up const &) = delete;
105937e92b5SJohn Baldwin 
106937e92b5SJohn Baldwin 		fd_up &operator=(int newfd)
107937e92b5SJohn Baldwin 		{
108937e92b5SJohn Baldwin 			reset(newfd);
109937e92b5SJohn Baldwin 			return *this;
110937e92b5SJohn Baldwin 		}
111937e92b5SJohn Baldwin 
112937e92b5SJohn Baldwin 		explicit operator bool() const { return fd >= 0; }
113937e92b5SJohn Baldwin 		operator int() const { return fd; }
114937e92b5SJohn Baldwin 	private:
115937e92b5SJohn Baldwin 		int	fd;
116937e92b5SJohn Baldwin 	};
117937e92b5SJohn Baldwin 
118937e92b5SJohn Baldwin 	/*
119b3127a2dSJohn Baldwin 	 * malloc_up<T> is a std::unique_ptr<> which uses free() to
120b3127a2dSJohn Baldwin 	 * destroy the wrapped pointer.  This can be used to wrap
121b3127a2dSJohn Baldwin 	 * pointers allocated implicitly by malloc() such as those
122b3127a2dSJohn Baldwin 	 * returned by strdup().
123b3127a2dSJohn Baldwin 	 */
124b3127a2dSJohn Baldwin 	template <class T>
125b3127a2dSJohn Baldwin 	struct free_deleter {
126b3127a2dSJohn Baldwin 		void operator() (T *p) const
127b3127a2dSJohn Baldwin 		{
128b3127a2dSJohn Baldwin 			std::free(p);
129b3127a2dSJohn Baldwin 		}
130b3127a2dSJohn Baldwin 	};
131b3127a2dSJohn Baldwin 
132b3127a2dSJohn Baldwin 	template <class T>
133b3127a2dSJohn Baldwin 	using malloc_up = std::unique_ptr<T, free_deleter<T>>;
134b3127a2dSJohn Baldwin 
135b3127a2dSJohn Baldwin 	/*
136*63ffcf69SJohn Baldwin 	 * nvlist_up is a std::unique_ptr<> for nvlist_t objects which
137*63ffcf69SJohn Baldwin 	 * uses nvlist_destroy() to destroy the wrapped pointer.
138*63ffcf69SJohn Baldwin 	 */
139*63ffcf69SJohn Baldwin 	struct nvlist_deleter {
140*63ffcf69SJohn Baldwin 		void operator() (nvlist_t *nvl) const
141*63ffcf69SJohn Baldwin 		{
142*63ffcf69SJohn Baldwin 			nvlist_destroy(nvl);
143*63ffcf69SJohn Baldwin 		}
144*63ffcf69SJohn Baldwin 	};
145*63ffcf69SJohn Baldwin 
146*63ffcf69SJohn Baldwin 	using nvlist_up = std::unique_ptr<nvlist_t, nvlist_deleter>;
147*63ffcf69SJohn Baldwin 
148*63ffcf69SJohn Baldwin 	/*
149b3127a2dSJohn Baldwin 	 * Returns a std::string containing the same output as
150b3127a2dSJohn Baldwin 	 * sprintf().  Throws std::bad_alloc if an error occurs.
151b3127a2dSJohn Baldwin 	 */
152b3127a2dSJohn Baldwin 	std::string stringf(const char *fmt, ...) __printflike(1, 2);
153b3127a2dSJohn Baldwin 	std::string stringf(const char *fmt, std::va_list ap);
154b3127a2dSJohn Baldwin }
155b3127a2dSJohn Baldwin 
156b3127a2dSJohn Baldwin #endif /* !__LIBUTILPP_HH__ */
157