1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/**
17 * @file unique_fd.h
18 *
19 * @brief Provides APIs to manage file descriptors (FDs) implemented in c_utils.
20 *
21 * The manager class `UniqueFdAddDeletor`,
22 * the default deleter class `DefaultDeleter`,
23 * and related global overloaded operator functions are provided.
24 */
25#ifndef UNIQUE_FD_H
26#define UNIQUE_FD_H
27
28#include <unistd.h>
29
30namespace OHOS {
31
32/**
33 * @brief Provides the default implementation for a deleter,
34 * including a static function to close FDs.
35 *
36 * The deleter is used for closing FDs. You can implement a deleter to
37 * deal with a different scenario. When `Deleter::Close()` is called to enable
38 * a `UniqueFdAddDeletor` object to release the management of an FD,
39 * the FD can no longer be taken over by other `UniqueFdAddDeletor` objects.
40 */
41class DefaultDeleter {
42public:
43    /**
44     * @brief Default function to close an FD.
45     *
46     * Call `close()` if the input FD is valid (greater than or equal to 0).
47     *
48     * @param fd Indicates an FD.
49     */
50    static void Close(int fd)
51    {
52        if (fd >= 0) {
53            close(fd);
54        }
55    }
56};
57
58template <typename Deleter>
59class UniqueFdAddDeletor;
60template <typename Deleter>
61bool operator==(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
62template <typename Deleter>
63bool operator!=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
64template <typename Deleter>
65bool operator>=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
66template <typename Deleter>
67bool operator>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
68template <typename Deleter>
69bool operator<=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
70template <typename Deleter>
71bool operator<(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
72
73/**
74 * @brief Defines an FD manager.
75 *
76 * To ensure unique management on an FD, avoid the double-close issue,
77 * which may cause a file to be incorrectly closed./n
78 * The management of an FD can be delivered between `UniqueFdAddDeletor`
79 * objects. An FD will be closed if no `UniqueFdAddDeletor` object is available
80 * to take over its management.
81 *
82 * @tparam Deleter Indicates a deleter.
83 * @see DefaultDeleter
84 */
85template <typename Deleter = DefaultDeleter>
86class UniqueFdAddDeletor final {
87    friend bool operator==<Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
88
89    friend bool operator!=<Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
90
91    friend bool operator>=<Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
92
93    friend bool operator><Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
94
95    friend bool operator<=<Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
96
97    friend bool operator< <Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
98
99public:
100    /**
101     * @brief Creates a `UniqueFdAddDeletor` object to manage an FD.
102     *
103     * @param value Indicates the FD to be managed.
104     */
105    explicit UniqueFdAddDeletor(const int& value)
106        : fd_(value)
107    {
108    }
109
110    /**
111     * @brief Constructor used to create a `UniqueFdAddDeletor` object
112     * with the FD set to `-1`.
113     */
114    UniqueFdAddDeletor()
115        : fd_(-1)
116    {
117    }
118
119    /**
120     * @brief Destructor used to destroy this `UniqueFdAddDeletor` object.
121     *
122     * This function is used to close the FD and set the FD to `-1`.
123     */
124    ~UniqueFdAddDeletor() { Reset(-1); }
125
126    /**
127     * @brief Releases the management on the current FD and sets it to `-1`.
128     *
129     * @return Returns the original FD before release.
130     * @note The released FD needs to be taken over by another
131     * `UniqueFdAddDeletor` object; otherwise, it must be closed manually.
132     */
133    int Release()
134    {
135        int tmp = fd_;
136        fd_ = -1;
137        return tmp;
138    }
139
140    // this is dangerous, when you use it , you should know it,
141    // do not operator on the ret
142    /**
143     * @brief An overloaded cast operator function.
144     *
145     * This function will be called when passing a `UniqueFdAddDeletor` object
146     * to a function that requires a parameter of `int`.
147     *
148     * @return Returns the current FD under management.
149     */
150    operator int() const { return Get(); } // NOLINT
151
152    // this is dangerous, when you use it , you should know it, do not operator
153    // on the ret
154    /**
155     * @brief Obtains the current FD under management, without releasing it.
156     *
157     * @return Returns the current FD.
158     */
159    int Get() const
160    {
161        return fd_;
162    }
163
164    // we need move fd from one to another
165    /**
166     * @brief Move constructor used to deliver the management of an FD from a
167     * `UniqueFdAddDeletor` object to this object.
168     *
169     * @param rhs Indicates the source `UniqueFdAddDeletor` object.
170     */
171    UniqueFdAddDeletor(UniqueFdAddDeletor&& rhs)
172    {
173        int rhsfd = rhs.Release();
174        fd_ = rhsfd;
175    }
176
177    /**
178     * @brief Overloaded move assignment operator function used to deliver the
179     * management of an FD from a `UniqueFdAddDeletor` object to this object.
180     *
181     * @param rhs Indicates the source `UniqueFdAddDeletor` object.
182     * @return Returns this `UniqueFdAddDeletor` object.
183     * @note The current FD manged by this `UniqueFdAddDeletor` object will be
184     * closed, and this object will take over
185     * the FD originally managed by `rhs`.
186     */
187    UniqueFdAddDeletor& operator=(UniqueFdAddDeletor&& rhs)
188    {
189        int rhsfd = rhs.Release();
190        Reset(rhsfd);
191        return *this;
192    }
193
194    /**
195     * @brief Checks whether the FD managed by this object and that managed by
196     * the source object are equal.
197     *
198     * @param rhs Indicates the source `UniqueFdAddDeletor` object.
199     *
200     * @return Returns `true` if the two FDs are equal; returns `false`
201     * otherwise.
202     */
203    bool operator==(const int& rhs) const
204    {
205        return fd_ == rhs;
206    }
207
208    /**
209     * @brief Checks whether the FD managed by this object and that managed by
210     * the source object are not equal.
211     *
212     * @param rhs Indicates the source `UniqueFdAddDeletor` object.
213     *
214     * @return Returns `true` if the two FDs are not equal; returns `false`
215     * otherwise.
216     */
217    bool operator!=(const int& rhs) const
218    {
219        return !(fd_ == rhs);
220    }
221
222    /**
223     * @brief Checks whether the FD managed by this object is greater than or
224     * equal to that managed by the source object.
225     *
226     * @param rhs Indicates the source `UniqueFdAddDeletor` object.
227     *
228     * @return Returns `true` if FD managed by this object is greater than or
229     * equal to that managed by the source object; returns `false` otherwise.
230     */
231    bool operator>=(const int& rhs) const
232    {
233        return fd_ >= rhs;
234    }
235
236    /**
237     * @brief Checks whether the FD managed by this object is greater than that
238     * managed by the source object.
239     *
240     * @param rhs Indicates the source `UniqueFdAddDeletor` object.
241     *
242     * @return Returns `true` if FD managed by this object is greater than that
243     * managed by the source object; returns `false` otherwise.
244     */
245    bool operator>(const int& rhs) const
246    {
247        return fd_ > rhs;
248    }
249
250    /**
251     * @brief Checks whether the FD managed by this object is less than or equal
252     * to that managed by the source object.
253     *
254     * @param rhs Indicates the source `UniqueFdAddDeletor` object.
255     *
256     * @return Returns `true` if FD managed by this object is less than or equal
257     * to that managed by the source object; returns `false` otherwise.
258     */
259    bool operator<=(const int& rhs) const
260    {
261        return fd_ <= rhs;
262    }
263
264    /**
265     * @brief Checks whether the FD managed by this object is less than that
266     * managed by the source object.
267     *
268     * @param rhs Indicates the source `UniqueFdAddDeletor` object.
269     *
270     * @return Returns `true` if FD managed by this object is less than that
271     * managed by the source object; returns `false` otherwise.
272     */
273    bool operator<(const int& rhs) const
274    {
275        return fd_ < rhs;
276    }
277
278private:
279    int fd_ = -1;
280
281    void Reset(int newValue)
282    {
283        if (fd_ >= 0) {
284            Deleter::Close(fd_);
285        }
286        fd_ = newValue;
287    }
288
289    // disallow copy ctor and copy assign
290    UniqueFdAddDeletor(const UniqueFdAddDeletor& rhs) = delete;
291    UniqueFdAddDeletor& operator=(const UniqueFdAddDeletor& rhs) = delete;
292};
293
294/**
295* @brief Checks whether the FD managed by two objects (specified by `lhs` and
296* `rhs` respectively) are equal.
297*
298 * @tparam Deleter Indicates a deleter.
299 * @param lhs Indicates the first `UniqueFdAddDeletor` object.
300 * @param rhs Indicates the second `UniqueFdAddDeletor` object.
301 *
302 * @return Returns `true` if the two FDs are equal; returns `false` otherwise.
303 * @see DefaultDeleter
304 */
305template <typename Deleter = DefaultDeleter>
306bool operator==(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
307{
308    return lhs == rhs.fd_;
309}
310
311/**
312* @brief Checks whether the FD managed by two objects (specified by `lhs` and
313* `rhs` respectively) are not equal.
314*
315 * @tparam Deleter Indicates a deleter.
316 * @param lhs Indicates the first `UniqueFdAddDeletor` object.
317 * @param rhs Indicates the second `UniqueFdAddDeletor` object.
318 *
319 * @return Returns `true` if the two FDs are not equal; returns `false`
320 * otherwise.
321 * @see DefaultDeleter
322 */
323template <typename Deleter = DefaultDeleter>
324bool operator!=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
325{
326    return !(lhs == rhs.fd_);
327}
328
329/**
330 * @brief Checks whether the FD managed by `lhs` is greater than or equal to
331 * that managed by `rhs`.
332 *
333 * @tparam Deleter Indicates a deleter.
334 * @param lhs Indicates the first `UniqueFdAddDeletor` object.
335 * @param rhs Indicates the second `UniqueFdAddDeletor` object.
336 *
337 * @return Returns `true` if the FD managed by `lhs` is greater than or equal to
338 * that managed by `rhs`; returns `false` otherwise.
339 * @see DefaultDeleter
340 */
341template <typename Deleter = DefaultDeleter>
342bool operator>=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
343{
344    return lhs >= rhs.fd_;
345}
346
347/**
348 * @brief Checks whether the FD managed by `lhs` is greater than that
349 * managed by `rhs`.
350 *
351 * @tparam Deleter Indicates a deleter.
352 * @param lhs Indicates the first `UniqueFdAddDeletor` object.
353 * @param rhs Indicates the second `UniqueFdAddDeletor` object.
354 *
355 * @return Returns `true` if the FD managed by `lhs` is greater than that
356 * managed by `rhs`; returns `false` otherwise.
357 * @see DefaultDeleter
358 */
359template <typename Deleter = DefaultDeleter>
360bool operator>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
361{
362    return lhs > rhs.fd_;
363}
364
365/**
366 * @brief Checks whether the FD managed by `lhs` is less than or equal to that
367 * managed by `rhs`.
368 *
369 * @tparam Deleter Indicates a deleter.
370 * @param lhs Indicates the first `UniqueFdAddDeletor` object.
371 * @param rhs Indicates the second `UniqueFdAddDeletor` object.
372 *
373 * @return Returns `true` if the FD managed by `lhs` is less than or equal to
374 * that managed by `rhs`; returns `false` otherwise.
375 * @see DefaultDeleter
376 */
377template <typename Deleter = DefaultDeleter>
378bool operator<=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
379{
380    return lhs <= rhs.fd_;
381}
382
383/**
384 * @brief Checks whether the FD managed by `lhs` is less than that
385 * managed by `rhs`.
386 *
387 * @tparam Deleter Indicates a deleter.
388 * @param lhs Indicates the first `UniqueFdAddDeletor` object.
389 * @param rhs Indicates the second `UniqueFdAddDeletor` object.
390 *
391 * @return Returns `true` if the FD managed by `lhs` is less than that
392 * managed by `rhs`; returns `false` otherwise.
393 * @see DefaultDeleter
394 */
395template <typename Deleter = DefaultDeleter>
396bool operator<(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
397{
398    return lhs < rhs.fd_;
399}
400
401using UniqueFd = UniqueFdAddDeletor<DefaultDeleter>;
402} // namespace OHOS
403#endif
404