summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2019-10-28 14:21:27 -0400
committerNat Goodspeed <nat@lindenlab.com>2020-03-25 19:05:17 -0400
commit9f446be76ee804bcd2f6ff8546612c9fcaf2a73e (patch)
treed0f3ab27ac198681c69ee37783ddd54358dda1ca
parentcc6f1d6195c457dc744ff23ac06ccd3a2d948aca (diff)
DRTVWR-476: Add LLUniqueFile, adding RAII semantics to LLFILE*.
LLUniqueFile wraps an LLFILE* in a move-only class that closes the wrapped LLFILE* on destruction. It provides conversion operators to permit idiomatic usage as an LLFILE* value.
-rw-r--r--indra/llcommon/llfile.h63
1 files changed, 63 insertions, 0 deletions
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 398938b729..9de095b45d 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -86,6 +86,69 @@ public:
static const char * tmpdir();
};
+/// RAII class
+class LLUniqueFile
+{
+public:
+ // empty
+ LLUniqueFile(): mFileHandle(nullptr) {}
+ // wrap (e.g.) result of LLFile::fopen()
+ LLUniqueFile(LLFILE* f): mFileHandle(f) {}
+ // no copy
+ LLUniqueFile(const LLUniqueFile&) = delete;
+ // move construction
+ LLUniqueFile(LLUniqueFile&& other)
+ {
+ mFileHandle = other.mFileHandle;
+ other.mFileHandle = nullptr;
+ }
+ // The point of LLUniqueFile is to close on destruction.
+ ~LLUniqueFile()
+ {
+ close();
+ }
+
+ // simple assignment
+ LLUniqueFile& operator=(LLFILE* f)
+ {
+ close();
+ mFileHandle = f;
+ return *this;
+ }
+ // copy assignment deleted
+ LLUniqueFile& operator=(const LLUniqueFile&) = delete;
+ // move assignment
+ LLUniqueFile& operator=(LLUniqueFile&& other)
+ {
+ close();
+ std::swap(mFileHandle, other.mFileHandle);
+ return *this;
+ }
+
+ // explicit close operation
+ void close()
+ {
+ if (mFileHandle)
+ {
+ // in case close() throws, set mFileHandle null FIRST
+ LLFILE* h{nullptr};
+ std::swap(h, mFileHandle);
+ LLFile::close(h);
+ }
+ }
+
+ // detect whether the wrapped LLFILE is open or not
+ explicit operator bool() const { return bool(mFileHandle); }
+ bool operator!() { return ! mFileHandle; }
+
+ // LLUniqueFile should be usable for any operation that accepts LLFILE*
+ // (or FILE* for that matter)
+ operator LLFILE*() const { return mFileHandle; }
+
+private:
+ LLFILE* mFileHandle;
+};
+
#if LL_WINDOWS
/**
* @brief Controlling input for files.