1 #pragma once
2 
3 
4 #include <type_traits>
5 #include <algorithm>
6 #include <stdexcept>
7 #include <cstddef>
8 #include <utility>
9 #include <string>
10 #include <vector>
11 #include <memory>
12 #include <array>
13 #include <uv.h>
14 
15 
16 #ifdef _WIN32
17 // MSVC doesn't have C++14 relaxed constexpr support yet. Hence the jugglery.
18 #define CONSTEXPR_SPECIFIER
19 #else
20 #define CONSTEXPR_SPECIFIER constexpr
21 #endif
22 
23 
24 namespace uvw {
25 
26 
27 namespace details {
28 
29 
30 enum class UVHandleType: std::underlying_type_t<uv_handle_type> {
31     UNKNOWN = UV_UNKNOWN_HANDLE,
32     ASYNC = UV_ASYNC,
33     CHECK = UV_CHECK,
34     FS_EVENT = UV_FS_EVENT,
35     FS_POLL = UV_FS_POLL,
36     HANDLE = UV_HANDLE,
37     IDLE = UV_IDLE,
38     PIPE = UV_NAMED_PIPE,
39     POLL = UV_POLL,
40     PREPARE = UV_PREPARE,
41     PROCESS = UV_PROCESS,
42     STREAM = UV_STREAM,
43     TCP = UV_TCP,
44     TIMER = UV_TIMER,
45     TTY = UV_TTY,
46     UDP = UV_UDP,
47     SIGNAL = UV_SIGNAL,
48     FILE = UV_FILE
49 };
50 
51 
52 template<typename T>
53 struct UVTypeWrapper {
54     using Type = T;
55 
UVTypeWrapperuvw::details::UVTypeWrapper56     constexpr UVTypeWrapper(): value{} {}
UVTypeWrapperuvw::details::UVTypeWrapper57     constexpr UVTypeWrapper(Type val): value{val} {}
58 
operator Typeuvw::details::UVTypeWrapper59     constexpr operator Type() const noexcept { return value; }
60 
operator ==uvw::details::UVTypeWrapper61     bool operator==(UVTypeWrapper other) const noexcept {
62         return value == other.value;
63     }
64 
65 private:
66     const Type value;
67 };
68 
69 
70 template<typename T>
operator ==(UVTypeWrapper<T> lhs,UVTypeWrapper<T> rhs)71 bool operator==(UVTypeWrapper<T> lhs, UVTypeWrapper<T> rhs) {
72     return !(lhs == rhs);
73 }
74 
75 
76 }
77 
78 
79 /**
80  * @brief Utility class to handle flags.
81  *
82  * This class can be used to handle flags of a same enumeration type.<br/>
83  * It is meant to be used as an argument for functions and member methods and
84  * as part of events.<br/>
85  * `Flags<E>` objects can be easily _or-ed_ and _and-ed_ with other instances of
86  * the same type or with instances of the type `E` (that is, the actual flag
87  * type), thus converted to the underlying type when needed.
88  */
89 template<typename E>
90 class Flags final {
91     using InnerType = std::underlying_type_t<E>;
92 
toInnerType(E flag) const93     constexpr InnerType toInnerType(E flag) const noexcept { return static_cast<InnerType>(flag); }
94 
95 public:
96     using Type = InnerType;
97 
98     /**
99      * @brief Utility factory method to pack a set of values all at once.
100      * @return A valid instance of Flags instantiated from values `V`.
101      */
102     template<E... V>
from()103     static CONSTEXPR_SPECIFIER Flags<E> from() {
104         auto flags = Flags<E>{};
105         int _[] = { 0, (flags = flags | V, 0)... };
106         return void(_), flags;
107     }
108 
109     /**
110      * @brief Constructs a Flags object from a value of the enum `E`.
111      * @param flag A value of the enum `E`.
112      */
Flags(E flag)113     constexpr Flags(E flag) noexcept: flags{toInnerType(flag)} {}
114 
115     /**
116      * @brief Constructs a Flags object from an instance of the underlying type
117      * of the enum `E`.
118      * @param f An instance of the underlying type of the enum `E`.
119      */
Flags(Type f)120     constexpr Flags(Type f): flags{f} {}
121 
122     /**
123      * @brief Constructs an uninitialized Flags object.
124      */
Flags()125     constexpr Flags(): flags{} {}
126 
Flags(const Flags & f)127     constexpr Flags(const Flags &f) noexcept: flags{f.flags} {  }
Flags(Flags && f)128     constexpr Flags(Flags &&f) noexcept: flags{std::move(f.flags)} {  }
129 
~Flags()130     ~Flags() noexcept { static_assert(std::is_enum<E>::value, "!"); }
131 
operator =(const Flags & f)132     CONSTEXPR_SPECIFIER Flags & operator=(const Flags &f) noexcept {
133         flags = f.flags;
134         return *this;
135     }
136 
operator =(Flags && f)137     CONSTEXPR_SPECIFIER Flags & operator=(Flags &&f) noexcept {
138         flags = std::move(f.flags);
139         return *this;
140     }
141 
142     /**
143      * @brief Or operator.
144      * @param f A valid instance of Flags.
145      * @return This instance _or-ed_ with `f`.
146      */
operator |(const Flags & f) const147     constexpr Flags operator|(const Flags &f) const noexcept { return Flags{flags | f.flags}; }
148 
149     /**
150      * @brief Or operator.
151      * @param flag A value of the enum `E`.
152      * @return This instance _or-ed_ with `flag`.
153      */
operator |(E flag) const154     constexpr Flags operator|(E flag) const noexcept { return Flags{flags | toInnerType(flag)}; }
155 
156     /**
157      * @brief And operator.
158      * @param f A valid instance of Flags.
159      * @return This instance _and-ed_ with `f`.
160      */
operator &(const Flags & f) const161     constexpr Flags operator&(const Flags &f) const noexcept { return Flags{flags & f.flags}; }
162 
163     /**
164      * @brief And operator.
165      * @param flag A value of the enum `E`.
166      * @return This instance _and-ed_ with `flag`.
167      */
operator &(E flag) const168     constexpr Flags operator&(E flag) const noexcept { return Flags{flags & toInnerType(flag)}; }
169 
170     /**
171      * @brief Checks if this instance is initialized.
172      * @return False if it's uninitialized, true otherwise.
173      */
operator bool() const174     explicit constexpr operator bool() const noexcept { return !(flags == InnerType{}); }
175 
176     /**
177      * @brief Casts the instance to the underlying type of `E`.
178      * @return An integral representation of the contained flags.
179      */
operator Type() const180     constexpr operator Type() const noexcept { return flags; }
181 
182 private:
183     InnerType flags;
184 };
185 
186 
187 /**
188  * @brief Windows size representation.
189  */
190 struct WinSize {
191     int width; /*!< The _width_ of the given window. */
192     int height; /*!< The _height_ of the given window. */
193 };
194 
195 
196 using HandleType = details::UVHandleType; /*!< The type of a handle. */
197 
198 using HandleCategory = details::UVTypeWrapper<uv_handle_type>; /*!< Utility class that wraps an internal handle type. */
199 using FileHandle = details::UVTypeWrapper<uv_file>; /*!< Utility class that wraps an internal file handle. */
200 using OSSocketHandle = details::UVTypeWrapper<uv_os_sock_t>; /*!< Utility class that wraps an os socket handle. */
201 using OSFileDescriptor = details::UVTypeWrapper<uv_os_fd_t>; /*!< Utility class that wraps an os file descriptor. */
202 using PidType = details::UVTypeWrapper<uv_pid_t>; /*!< Utility class that wraps a cross platform representation of a pid. */
203 
204 constexpr FileHandle StdIN{0}; /*!< Placeholder for stdin descriptor. */
205 constexpr FileHandle StdOUT{1}; /*!< Placeholder for stdout descriptor. */
206 constexpr FileHandle StdERR{2}; /*!< Placeholder for stderr descriptor. */
207 
208 using TimeSpec = uv_timespec_t; /*!< Library equivalent for uv_timespec_t. */
209 using Stat = uv_stat_t; /*!< Library equivalent for uv_stat_t. */
210 using Uid = uv_uid_t; /*!< Library equivalent for uv_uid_t. */
211 using Gid = uv_gid_t; /*!< Library equivalent for uv_gid_t. */
212 
213 using TimeVal = uv_timeval_t; /*!< Library equivalent for uv_timeval_t. */
214 using RUsage = uv_rusage_t; /*!< Library equivalent for uv_rusage_t. */
215 
216 
217 /**
218  * @brief Utility class.
219  *
220  * This class can be used to query the subset of the password file entry for the
221  * current effective uid (not the real uid).
222  *
223  * \sa Utilities::passwd
224  */
225 struct Passwd {
Passwduvw::Passwd226     Passwd(std::shared_ptr<uv_passwd_t> pwd): passwd{pwd} {}
227 
228     /**
229      * @brief Gets the username.
230      * @return The username of the current effective uid (not the real uid).
231      */
usernameuvw::Passwd232     std::string username() const noexcept {
233         return ((passwd && passwd->username) ? passwd->username : "");
234     }
235 
236     /**
237      * @brief Gets the uid.
238      * @return The current effective uid (not the real uid).
239      */
uiduvw::Passwd240     auto uid() const noexcept {
241         return (passwd ? passwd->uid : decltype(uv_passwd_t::uid){});
242     }
243 
244     /**
245      * @brief Gets the gid.
246      * @return The gid of the current effective uid (not the real uid).
247      */
giduvw::Passwd248     auto gid() const noexcept {
249         return (passwd ?  passwd->gid : decltype(uv_passwd_t::gid){});
250     }
251 
252     /**
253      * @brief Gets the shell.
254      * @return The shell of the current effective uid (not the real uid).
255      */
shelluvw::Passwd256     std::string shell() const noexcept {
257         return ((passwd && passwd->shell) ? passwd->shell : "");
258     }
259 
260     /**
261      * @brief Gets the homedir.
262      * @return The homedir of the current effective uid (not the real uid).
263      */
homediruvw::Passwd264     std::string homedir() const noexcept {
265         return ((passwd && passwd->homedir) ? passwd->homedir: "");
266     }
267 
268     /**
269      * @brief Checks if the instance contains valid data.
270      * @return True if data are all valid, false otherwise.
271      */
operator booluvw::Passwd272     operator bool() const noexcept {
273         return static_cast<bool>(passwd);
274     }
275 
276 private:
277     std::shared_ptr<uv_passwd_t> passwd;
278 };
279 
280 
281 /**
282  * @brief The IPv4 tag.
283  *
284  * To be used as template parameter to switch between IPv4 and IPv6.
285  */
286 struct IPv4 {};
287 
288 
289 /**
290  * @brief The IPv6 tag.
291  *
292  * To be used as template parameter to switch between IPv4 and IPv6.
293  */
294 struct IPv6 {};
295 
296 
297 /**
298  * @brief Address representation.
299  */
300 struct Addr {
301     std::string ip; /*!< Either an IPv4 or an IPv6. */
302     unsigned int port; /*!< A valid service identifier. */
303 };
304 
305 
306 /**
307  * \brief CPU information.
308  */
309 struct CPUInfo {
310     using CPUTime = decltype(uv_cpu_info_t::cpu_times);
311 
312     std::string model; /*!< The model of the CPU. */
313     int speed; /*!< The frequency of the CPU. */
314 
315     /**
316      * @brief CPU times.
317      *
318      * It is built up of the following data members: `user`, `nice`, `sys`,
319      * `idle`, `irq`, all of them having type `uint64_t`.
320      */
321     CPUTime times;
322 };
323 
324 
325 /**
326  * \brief Interface address.
327  */
328 struct InterfaceAddress {
329     std::string name; /*!< The name of the interface (as an example _eth0_). */
330     char physical[6]; /*!< The physical address. */
331     bool internal; /*!< True if it is an internal interface (as an example _loopback_), false otherwise. */
332     Addr address; /*!< The address of the given interface. */
333     Addr netmask; /*!< The netmask of the given interface. */
334 };
335 
336 
337 namespace details {
338 
339 
340 static constexpr std::size_t DEFAULT_SIZE = 128;
341 
342 
343 template<typename>
344 struct IpTraits;
345 
346 
347 template<>
348 struct IpTraits<IPv4> {
349     using Type = sockaddr_in;
350     using AddrFuncType = int(*)(const char *, int, Type *);
351     using NameFuncType = int(*)(const Type *, char *, std::size_t);
352     static constexpr AddrFuncType addrFunc = &uv_ip4_addr;
353     static constexpr NameFuncType nameFunc = &uv_ip4_name;
sinPortuvw::details::IpTraits354     static constexpr auto sinPort(const Type *addr) { return addr->sin_port; }
355 };
356 
357 
358 template<>
359 struct IpTraits<IPv6> {
360     using Type = sockaddr_in6;
361     using AddrFuncType = int(*)(const char *, int, Type *);
362     using NameFuncType = int(*)(const Type *, char *, std::size_t);
363     static constexpr AddrFuncType addrFunc = &uv_ip6_addr;
364     static constexpr NameFuncType nameFunc = &uv_ip6_name;
sinPortuvw::details::IpTraits365     static constexpr auto sinPort(const Type *addr) { return addr->sin6_port; }
366 };
367 
368 
369 template<typename I>
address(const typename details::IpTraits<I>::Type * aptr)370 Addr address(const typename details::IpTraits<I>::Type *aptr) noexcept {
371     Addr addr;
372     char name[DEFAULT_SIZE];
373 
374     int err = details::IpTraits<I>::nameFunc(aptr, name, DEFAULT_SIZE);
375 
376     if(0 == err) {
377         addr.port = ntohs(details::IpTraits<I>::sinPort(aptr));
378         addr.ip = std::string{name};
379     }
380 
381     return addr;
382 }
383 
384 
385 template<typename I, typename F, typename H>
address(F && f,const H * handle)386 Addr address(F &&f, const H *handle) noexcept {
387     sockaddr_storage ssto;
388     int len = sizeof(ssto);
389     Addr addr{};
390 
391     int err = std::forward<F>(f)(handle, reinterpret_cast<sockaddr *>(&ssto), &len);
392 
393     if(0 == err) {
394         typename IpTraits<I>::Type *aptr = reinterpret_cast<typename IpTraits<I>::Type *>(&ssto);
395         addr = address<I>(aptr);
396     }
397 
398     return addr;
399 }
400 
401 
402 template<typename F, typename... Args>
tryRead(F && f,Args &&...args)403 std::string tryRead(F &&f, Args&&... args) noexcept {
404     std::size_t size = DEFAULT_SIZE;
405     char buf[DEFAULT_SIZE];
406     std::string str{};
407     auto err = std::forward<F>(f)(args..., buf, &size);
408 
409     if(UV_ENOBUFS == err) {
410         std::unique_ptr<char[]> data{new char[size]};
411         err = std::forward<F>(f)(args..., data.get(), &size);
412 
413         if(0 == err) {
414             str = data.get();
415         }
416     } else if(0 == err) {
417         str.assign(buf, size);
418     }
419 
420     return str;
421 }
422 
423 
424 }
425 
426 
427 /**
428  * @brief Miscellaneous utilities.
429  *
430  * Miscellaneous functions that don’t really belong to any other class.
431  */
432 struct Utilities {
433     using MallocFuncType = void*(*)(size_t);
434     using ReallocFuncType = void*(*)(void*, size_t);
435     using CallocFuncType = void*(*)(size_t, size_t);
436     using FreeFuncType = void(*)(void*);
437 
438     /**
439      * @brief OS dedicated utilities.
440      */
441     struct OS {
442         /**
443          * @brief Returns the current process id.
444          *
445          * See the official
446          * [documentation](http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_getpid)
447          * for further details.
448          *
449          * @return The current process id.
450          */
piduvw::Utilities::OS451         static PidType pid() noexcept {
452             return uv_os_getpid();
453         }
454 
455         /**
456          * @brief Returns the parent process id.
457          *
458          * See the official
459          * [documentation](http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_getppid)
460          * for further details.
461          *
462          * @return The parent process id.
463          */
parentuvw::Utilities::OS464         static PidType parent() noexcept {
465             return uv_os_getppid();
466         }
467 
468         /**
469          * @brief Gets the current user's home directory.
470          *
471          * See the official
472          * [documentation](http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_homedir)
473          * for further details.
474          *
475          * @return The current user's home directory, an empty string in case of
476          * errors.
477          */
homediruvw::Utilities::OS478         static std::string homedir() noexcept {
479             return details::tryRead(&uv_os_homedir);
480         }
481 
482         /**
483          * @brief Gets the temp directory.
484          *
485          * See the official
486          * [documentation](http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_tmpdir)
487          * for further details.
488          *
489          * @return The temp directory, an empty string in case of errors.
490          */
tmpdiruvw::Utilities::OS491         static std::string tmpdir() noexcept {
492             return details::tryRead(&uv_os_tmpdir);
493         }
494 
495         /**
496          * @brief Retrieves an environment variable.
497          * @param name The name of the variable to be retrieved.
498          * @return The value of the environment variable, an empty string in
499          * case of errors.
500          */
envuvw::Utilities::OS501         static std::string env(const std::string &name) noexcept {
502             return details::tryRead(&uv_os_getenv, name.c_str());
503         }
504 
505         /**
506          * @brief Creates, updates or deletes an environment variable.
507          * @param name The name of the variable to be updated.
508          * @param value The value to be used for the variable (an empty string
509          * to unset it).
510          * @return True in case of success, false otherwise.
511          */
envuvw::Utilities::OS512         static bool env(const std::string &name, const std::string &value) noexcept {
513             return (0 == (value.empty() ? uv_os_unsetenv(name.c_str()) : uv_os_setenv(name.c_str(), value.c_str())));
514         }
515 
516         /**
517          * @brief Returns the hostname.
518          * @return The hostname, an empty string in case of errors.
519          */
hostnameuvw::Utilities::OS520         static std::string hostname() noexcept {
521             return details::tryRead(&uv_os_gethostname);
522         }
523 
524         /**
525          * @brief Gets a subset of the password file entry.
526          *
527          * This function can be used to get the subset of the password file
528          * entry for the current effective uid (not the real uid).
529          *
530          * See the official
531          * [documentation](http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_get_passwd)
532          * for further details.
533          *
534          * @return The accessible subset of the password file entry.
535          */
passwduvw::Utilities::OS536         static Passwd passwd() noexcept {
537             auto deleter = [](uv_passwd_t *passwd){
538                 uv_os_free_passwd(passwd);
539                 delete passwd;
540             };
541 
542             std::shared_ptr<uv_passwd_t> ptr{new uv_passwd_t, std::move(deleter)};
543             uv_os_get_passwd(ptr.get());
544             return ptr;
545         }
546     };
547 
548     /**
549      * @brief Retrieves the scheduling priority of a process.
550      *
551      * The returned value is between -20 (high priority) and 19 (low priority).
552      * A value that is out of range is returned in case of errors.
553      *
554      * @note
555      * On Windows, the result won't equal necessarily the exact value of the
556      * priority because of a mapping to a Windows priority class.
557      *
558      * @param pid A valid process id.
559      * @return The scheduling priority of the process.
560      */
osPriorityuvw::Utilities561     static int osPriority(PidType pid) {
562         int prio = 0;
563 
564         if(uv_os_getpriority(pid, &prio)) {
565             prio = UV_PRIORITY_LOW + 1;
566         }
567 
568         return prio;
569     }
570 
571     /**
572      * @brief Sets the scheduling priority of a process.
573      *
574      * The returned value range is between -20 (high priority) and 19 (low
575      * priority).
576      *
577      * @note
578      * On Windows, the priority is mapped to a Windows priority class. When
579      * retrieving the process priority, the result won't equal necessarily the
580      * exact value of the priority.
581      *
582      * @param pid A valid process id.
583      * @param prio The scheduling priority to set to the process.
584      * @return True in case of success, false otherwise.
585      */
osPriorityuvw::Utilities586     static bool osPriority(PidType pid, int prio) {
587         return 0 == uv_os_setpriority(pid, prio);
588     }
589 
590     /**
591      * @brief Gets the type of the handle given a category.
592      * @param category A properly initialized handle category.
593      * @return The actual type of the handle as defined by HandleType
594      */
guessHandleuvw::Utilities595     static HandleType guessHandle(HandleCategory category) noexcept {
596         switch(category) {
597         case UV_ASYNC:
598             return HandleType::ASYNC;
599         case UV_CHECK:
600             return HandleType::CHECK;
601         case UV_FS_EVENT:
602             return HandleType::FS_EVENT;
603         case UV_FS_POLL:
604             return HandleType::FS_POLL;
605         case UV_HANDLE:
606             return HandleType::HANDLE;
607         case UV_IDLE:
608             return HandleType::IDLE;
609         case UV_NAMED_PIPE:
610             return HandleType::PIPE;
611         case UV_POLL:
612             return HandleType::POLL;
613         case UV_PREPARE:
614             return HandleType::PREPARE;
615         case UV_PROCESS:
616             return HandleType::PROCESS;
617         case UV_STREAM:
618             return HandleType::STREAM;
619         case UV_TCP:
620             return HandleType::TCP;
621         case UV_TIMER:
622             return HandleType::TIMER;
623         case UV_TTY:
624             return HandleType::TTY;
625         case UV_UDP:
626             return HandleType::UDP;
627         case UV_SIGNAL:
628             return HandleType::SIGNAL;
629         case UV_FILE:
630             return HandleType::FILE;
631         default:
632             return HandleType::UNKNOWN;
633         }
634     }
635 
636     /**
637      * @brief Gets the type of the stream to be used with the given descriptor.
638      *
639      * Returns the type of stream that should be used with a given file
640      * descriptor.<br/>
641      * Usually this will be used during initialization to guess the type of the
642      * stdio streams.
643      *
644      * @param file A valid descriptor.
645      * @return One of the following types:
646      *
647      * * `HandleType::UNKNOWN`
648      * * `HandleType::PIPE`
649      * * `HandleType::TCP`
650      * * `HandleType::TTY`
651      * * `HandleType::UDP`
652      * * `HandleType::FILE`
653      */
guessHandleuvw::Utilities654     static HandleType guessHandle(FileHandle file) noexcept {
655         HandleCategory category = uv_guess_handle(file);
656         return guessHandle(category);
657     }
658 
659 
660     /** @brief Gets information about the CPUs on the system.
661      *
662      * This function can be used to query the underlying system and get a set of
663      * descriptors of all the available CPUs.
664      *
665      * @return A set of descriptors of all the available CPUs.
666      */
cpuInfouvw::Utilities667     static std::vector<CPUInfo> cpuInfo() noexcept {
668         std::vector<CPUInfo> cpuinfos;
669 
670         uv_cpu_info_t *infos;
671         int count;
672 
673         if(0 == uv_cpu_info(&infos, &count)) {
674             std::for_each(infos, infos+count, [&cpuinfos](const auto &info) {
675                 cpuinfos.push_back({ info.model, info.speed, info.cpu_times });
676             });
677 
678             uv_free_cpu_info(infos, count);
679         }
680 
681         return cpuinfos;
682     }
683 
684     /**
685      * @brief Gets a set of descriptors of all the available interfaces.
686      *
687      * This function can be used to query the underlying system and get a set of
688      * descriptors of all the available interfaces, either internal or not.
689      *
690      * @return A set of descriptors of all the available interfaces.
691      */
interfaceAddressesuvw::Utilities692     static std::vector<InterfaceAddress> interfaceAddresses() noexcept {
693         std::vector<InterfaceAddress> interfaces;
694 
695         uv_interface_address_t *ifaces{nullptr};
696         int count{0};
697 
698         if(0 == uv_interface_addresses(&ifaces, &count)) {
699             std::for_each(ifaces, ifaces+count, [&interfaces](const auto &iface) {
700                 InterfaceAddress interfaceAddress;
701 
702                 interfaceAddress.name = iface.name;
703                 std::copy(iface.phys_addr, (iface.phys_addr+6), interfaceAddress.physical);
704                 interfaceAddress.internal = iface.is_internal == 0 ? false : true;
705 
706                 if(iface.address.address4.sin_family == AF_INET) {
707                     interfaceAddress.address = details::address<IPv4>(&iface.address.address4);
708                     interfaceAddress.netmask = details::address<IPv4>(&iface.netmask.netmask4);
709                 } else if(iface.address.address4.sin_family == AF_INET6) {
710                     interfaceAddress.address = details::address<IPv6>(&iface.address.address6);
711                     interfaceAddress.netmask = details::address<IPv6>(&iface.netmask.netmask6);
712                 }
713 
714                 interfaces.push_back(std::move(interfaceAddress));
715             });
716 
717             uv_free_interface_addresses(ifaces, count);
718         }
719 
720         return interfaces;
721     }
722 
723     /**
724      * @brief IPv6-capable implementation of
725      * [if_indextoname](https://linux.die.net/man/3/if_indextoname).
726      *
727      * Mapping between network interface names and indexes.
728      *
729      * See the official
730      * [documentation](http://docs.libuv.org/en/v1.x/misc.html#c.uv_if_indextoname)
731      * for further details.
732      *
733      * @param index Network interface index.
734      * @return Network interface name.
735      */
indexToNameuvw::Utilities736     static std::string indexToName(unsigned int index) noexcept {
737         return details::tryRead(&uv_if_indextoname, index);
738     }
739 
740     /**
741      * @brief Retrieves a network interface identifier.
742      *
743      * See the official
744      * [documentation](http://docs.libuv.org/en/v1.x/misc.html#c.uv_if_indextoiid)
745      * for further details.
746      *
747      * @param index Network interface index.
748      * @return Network interface identifier.
749      */
indexToIiduvw::Utilities750     static std::string indexToIid(unsigned int index) noexcept {
751         return details::tryRead(&uv_if_indextoiid, index);
752     }
753 
754     /**
755      * @brief Override the use of some standard library’s functions.
756      *
757      * Override the use of the standard library’s memory allocation
758      * functions.<br/>
759      * This method must be invoked before any other `uvw` function is called or
760      * after all resources have been freed and thus the underlying library
761      * doesn’t reference any allocated memory chunk.
762      *
763      * If any of the function pointers is _null_, the invokation will fail.
764      *
765      * @note
766      * There is no protection against changing the allocator multiple times. If
767      * the user changes it they are responsible for making sure the allocator is
768      * changed while no memory was allocated with the previous allocator, or
769      * that they are compatible.
770      *
771      * @param mallocFunc Replacement function for _malloc_.
772      * @param reallocFunc Replacement function for _realloc_.
773      * @param callocFunc Replacement function for _calloc_.
774      * @param freeFunc Replacement function for _free_.
775      * @return True in case of success, false otherwise.
776      */
replaceAllocatoruvw::Utilities777     static bool replaceAllocator(MallocFuncType mallocFunc, ReallocFuncType reallocFunc, CallocFuncType callocFunc, FreeFuncType freeFunc) noexcept {
778         return (0 == uv_replace_allocator(mallocFunc, reallocFunc, callocFunc, freeFunc));
779     }
780 
781     /**
782      * @brief Gets the load average.
783      * @return `[0,0,0]` on Windows (not available), the load average otherwise.
784      */
loadAverageuvw::Utilities785     static std::array<double, 3> loadAverage() noexcept {
786         std::array<double, 3> avg;
787         uv_loadavg(avg.data());
788         return avg;
789     }
790 
791     /**
792      * @brief Store the program arguments.
793      *
794      * Required for getting / setting the process title.
795      *
796      * @return Arguments that haven't been consumed internally.
797      */
setupArgsuvw::Utilities798     static char ** setupArgs(int argc, char** argv) {
799         return uv_setup_args(argc, argv);
800     }
801 
802     /**
803      * @brief Gets the title of the current process.
804      * @return The process title.
805      */
processTitleuvw::Utilities806     static std::string processTitle() {
807         std::size_t size = details::DEFAULT_SIZE;
808         char buf[details::DEFAULT_SIZE];
809         std::string str{};
810 
811         if(0 == uv_get_process_title(buf, size)) {
812             str.assign(buf, size);
813         }
814 
815         return str;
816     }
817 
818     /**
819      * @brief Sets the current process title.
820      * @param title The process title to be set.
821      * @return True in case of success, false otherwise.
822      */
processTitleuvw::Utilities823     static bool processTitle(std::string title) {
824         return (0 == uv_set_process_title(title.c_str()));
825     }
826 
827     /**
828      * @brief Gets memory information (in bytes).
829      * @return Memory information.
830      */
totalMemoryuvw::Utilities831     static uint64_t totalMemory() noexcept {
832         return uv_get_total_memory();
833     }
834 
835     /**
836      * @brief Gets the current system uptime.
837      * @return The current system uptime or 0 in case of errors.
838      */
uptimeuvw::Utilities839     static double uptime() noexcept {
840         double ret;
841 
842         if(0 != uv_uptime(&ret)) {
843             ret = 0;
844         }
845 
846         return ret;
847     }
848 
849     /**
850      * @brief Gets the resource usage measures for the current process.
851      * @return Resource usage measures, zeroes-filled object in case of errors.
852      */
rusageuvw::Utilities853     static RUsage rusage() noexcept {
854         RUsage ru;
855         auto err = uv_getrusage(&ru);
856         return err ? RUsage{} : ru;
857     }
858 
859     /**
860      * @brief Gets the current high-resolution real time.
861      *
862      * The time is expressed in nanoseconds. It is relative to an arbitrary time
863      * in the past. It is not related to the time of the day and therefore not
864      * subject to clock drift. The primary use is for measuring performance
865      * between interval.
866      *
867      * @return The current high-resolution real time.
868      */
hrtimeuvw::Utilities869     static uint64_t hrtime() noexcept {
870         return uv_hrtime();
871     }
872 
873     /**
874      * @brief Gets the executable path.
875      * @return The executable path, an empty string in case of errors.
876      */
pathuvw::Utilities877     static std::string path() noexcept {
878         return details::tryRead(&uv_exepath);
879     }
880 
881     /**
882      * @brief Gets the current working directory.
883      * @return The current working directory, an empty string in case of errors.
884      */
cwduvw::Utilities885     static std::string cwd() noexcept {
886         return details::tryRead(&uv_cwd);
887     }
888 
889     /**
890      * @brief Changes the current working directory.
891      * @param dir The working directory to be set.
892      * @return True in case of success, false otherwise.
893      */
chdiruvw::Utilities894     static bool chdir(const std::string &dir) noexcept {
895         return (0 == uv_chdir(dir.data()));
896     }
897 };
898 
899 
900 }
901