[libc-commits] [libc] feat(filemode): implement class and helper functions to handle file modes for an opened file (PR #220906)
David Dada via libc-commits
libc-commits at lists.llvm.org
Wed Sep 9 08:54:09 PDT 2026
https://github.com/obadafidii updated https://github.com/llvm/llvm-project/pull/220906
>From e3dc3a646ef6c422e75810881826e211aebb7a3b Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Thu, 3 Sep 2026 13:21:11 +0100
Subject: [PATCH 1/7] feat(filemode): implement class and helper functions to
handle file modes for an opened file
Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
libc/src/__support/File/file_mode.h | 125 ++++++++++++++++++++++++++++
1 file changed, 125 insertions(+)
create mode 100644 libc/src/__support/File/file_mode.h
diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
new file mode 100644
index 0000000000000..6b837ea46f652
--- /dev/null
+++ b/libc/src/__support/File/file_mode.h
@@ -0,0 +1,125 @@
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
+#define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
+#include <cstdint>
+
+namespace LIBC_NAMESPACE_DECL {
+
+// FileMode class handles everything regarding the mode of the file, be it's opening mode or content type.
+class FileMode {
+public:
+ // FileMode constructor accepts the mode string as an argument.
+ // It performs validation against several rules and records the `file_mode` property to
+ // the specific mode.
+ explicit FileMode(const char *mode) : file_mode_(0) {
+ // First character in |mode| should be 'a', 'r' or 'w'.
+ if (*mode != 'a' && *mode != 'r' && *mode != 'w')
+ return;
+
+ // There should be exactly one main mode ('a', 'r' or 'w') character.
+ // If there are more than one main mode characters listed, then
+ // we will consider |mode| as incorrect and return 0;
+ int main_mode_count = 0;
+
+ for (; *mode != '\0'; ++mode) {
+ switch (*mode) {
+ case 'r':
+ file_mode_ |= static_cast<Mode>(OpenMode::READ);
+ ++main_mode_count;
+ break;
+ case 'w':
+ file_mode_ |= static_cast<Mode>(OpenMode::WRITE);
+ ++main_mode_count;
+ break;
+ case '+':
+ file_mode_ |= static_cast<Mode>(OpenMode::PLUS);
+ break;
+ case 'b':
+ file_mode_ |= static_cast<Mode>(ContentType::BINARY);
+ break;
+ case 'a':
+ file_mode_ |= static_cast<Mode>(OpenMode::APPEND);
+ ++main_mode_count;
+ break;
+ case 'x':
+ file_mode_ |= static_cast<Mode>(CreateType::EXCLUSIVE);
+ break;
+ default:
+ file_mode_ = 0;
+ }
+ }
+
+ if (main_mode_count != 1)
+ file_mode_ = 0;
+ }
+
+ // helper function to show if file allows writing
+ bool write_allowed() const {
+ return (file_mode_ & static_cast<Mode>(OpenMode::WRITE)) != 0;
+ }
+
+ // helper function to show if file allows reading
+ bool read_allowed() const {
+ return (file_mode_ & static_cast<Mode>(OpenMode::READ)) != 0;
+ }
+
+ // helper function to show if file allows appending
+ bool append_allowed() const {
+ return (file_mode_ & static_cast<Mode>(OpenMode::APPEND)) != 0;
+ }
+
+ // helper function to denote if the file is in binary format.
+ bool is_binary_format() const {
+ return (file_mode_ & static_cast<Mode>(ContentType::BINARY)) != 0;
+ }
+
+ // '+' means update is allowed
+ // TODO: ask michael if I need to give it a better name like "update_allowed" or just continue with the
+ // old convention.
+ bool is_plus() const {
+ return (file_mode_ & static_cast<Mode>(OpenMode::PLUS)) != 0;
+ }
+
+ // checks if a file was created for writing
+ bool is_exclusive_create() const {
+ return (file_mode_ & static_cast<Mode>(CreateType::EXCLUSIVE)) != 0;
+ }
+
+private:
+ // Mode is a generic or abstract mode bit for all kinds of modes
+ // (open-mode, 'content-mode', 'create-modes')
+ using Mode = uint32_t;
+
+ // Denotes the mode of the file.
+ //
+ // The three different types of flags below are to be used with '|' operator.
+ // Their values correspond to mutually exclusive bits in a 32-bit unsigned
+ // integer value. A flag set can include both READ and WRITE if the file
+ // is opened in update mode (ie. if the file was opened with a '+' the mode
+ // string.)
+ enum class OpenMode: Mode {
+ READ = 0x1,
+ WRITE = 0x2,
+ APPEND = 0x4,
+ PLUS = 0x8,
+ };
+
+ // Denotes a file opened in binary mode (which is specified by including
+ // the 'b' character in teh mode string.)
+ enum class ContentType: Mode {
+ BINARY = 0x10,
+ };
+
+ // Denotes a file to be created for writing.
+ enum class CreateType: Mode {
+ EXCLUSIVE = 0x100,
+ };
+
+ // This property tracks the mode for the particular file instance (i.e currently opened file)
+ int file_mode_;
+};
+
+
+}
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
>From b0470fe313766fcb4fac92b63d41d39314a90f75 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Thu, 3 Sep 2026 14:08:49 +0100
Subject: [PATCH 2/7] feat(lint): lint file mode class to conform to standards
Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
libc/src/__support/File/file_mode.h | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
index 6b837ea46f652..707a448c5955d 100644
--- a/libc/src/__support/File/file_mode.h
+++ b/libc/src/__support/File/file_mode.h
@@ -5,12 +5,13 @@
namespace LIBC_NAMESPACE_DECL {
-// FileMode class handles everything regarding the mode of the file, be it's opening mode or content type.
+// FileMode class handles everything regarding the mode of the file, be it's
+// opening mode or content type.
class FileMode {
public:
// FileMode constructor accepts the mode string as an argument.
- // It performs validation against several rules and records the `file_mode` property to
- // the specific mode.
+ // It performs validation against several rules and records the `file_mode`
+ // property to the specific mode.
explicit FileMode(const char *mode) : file_mode_(0) {
// First character in |mode| should be 'a', 'r' or 'w'.
if (*mode != 'a' && *mode != 'r' && *mode != 'w')
@@ -74,8 +75,8 @@ class FileMode {
}
// '+' means update is allowed
- // TODO: ask michael if I need to give it a better name like "update_allowed" or just continue with the
- // old convention.
+ // TODO: ask michael if I need to give it a better name like "update_allowed"
+ // or just continue with the old convention.
bool is_plus() const {
return (file_mode_ & static_cast<Mode>(OpenMode::PLUS)) != 0;
}
@@ -97,7 +98,7 @@ class FileMode {
// integer value. A flag set can include both READ and WRITE if the file
// is opened in update mode (ie. if the file was opened with a '+' the mode
// string.)
- enum class OpenMode: Mode {
+ enum class OpenMode : Mode {
READ = 0x1,
WRITE = 0x2,
APPEND = 0x4,
@@ -106,20 +107,20 @@ class FileMode {
// Denotes a file opened in binary mode (which is specified by including
// the 'b' character in teh mode string.)
- enum class ContentType: Mode {
+ enum class ContentType : Mode {
BINARY = 0x10,
};
// Denotes a file to be created for writing.
- enum class CreateType: Mode {
+ enum class CreateType : Mode {
EXCLUSIVE = 0x100,
};
- // This property tracks the mode for the particular file instance (i.e currently opened file)
+ // This property tracks the mode for the particular file instance (i.e
+ // currently opened file)
int file_mode_;
};
-
-}
+} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
>From d208bddb974f3c55dcbcc35a17523eaccff20c79 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 14:31:48 +0100
Subject: [PATCH 3/7] feat(file_mode): update write_allowed and read_allowed
method to use new api
Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
libc/src/__support/File/file.h | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h
index 67879e6c9933e..08f8b93b8f215 100644
--- a/libc/src/__support/File/file.h
+++ b/libc/src/__support/File/file.h
@@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_FILE_FILE_H
#define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_H
+#include "file_mode.h"
#include "hdr/stdint_proxy.h"
#include "hdr/stdio_macros.h"
#include "hdr/types/off_t.h"
@@ -122,8 +123,12 @@ class File {
bool own_buf;
// The mode in which the file was opened.
+ //TODO: old way of doing things
+ // clean up when totally done with pr
ModeFlags mode;
+ FileMode file_mode;
+
// Current read or write pointer.
size_t pos;
@@ -155,14 +160,13 @@ class File {
protected:
constexpr bool write_allowed() const {
- return mode & (static_cast<ModeFlags>(OpenMode::WRITE) |
- static_cast<ModeFlags>(OpenMode::APPEND) |
- static_cast<ModeFlags>(OpenMode::PLUS));
+ return file_mode.write_allowed() ||
+ file_mode.append_allowed() ||
+ file_mode.is_plus(); //TODO: if micheal agrees for me to convert it change it here
}
constexpr bool read_allowed() const {
- return mode & (static_cast<ModeFlags>(OpenMode::READ) |
- static_cast<ModeFlags>(OpenMode::PLUS));
+ return file_mode.read_allowed() || file_mode.is_plus();
}
void reset_stream_state_unlocked(ModeFlags new_mode) {
>From 91f4a23232fb9d2992a69286e74241002513c86e Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 16:47:57 +0100
Subject: [PATCH 4/7] feat: add method to check validity of a file mode
Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
libc/src/__support/File/file_mode.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
index 707a448c5955d..92647decd2e76 100644
--- a/libc/src/__support/File/file_mode.h
+++ b/libc/src/__support/File/file_mode.h
@@ -1,7 +1,8 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
#define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
-#include <cstdint>
+
+#include "hdr/stdint_proxy.h"
namespace LIBC_NAMESPACE_DECL {
@@ -54,6 +55,8 @@ class FileMode {
file_mode_ = 0;
}
+ bool is_valid() const { return file_mode_ != 0; }
+
// helper function to show if file allows writing
bool write_allowed() const {
return (file_mode_ & static_cast<Mode>(OpenMode::WRITE)) != 0;
>From 86ef8ab5c1b9efc429df6ce9e9dfedb2bfa822e9 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 16:49:02 +0100
Subject: [PATCH 5/7] add config header for namespace resolution
Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
libc/src/__support/File/file_mode.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
index 92647decd2e76..e7f46d6172833 100644
--- a/libc/src/__support/File/file_mode.h
+++ b/libc/src/__support/File/file_mode.h
@@ -3,6 +3,7 @@
#define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
#include "hdr/stdint_proxy.h"
+#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
>From e97d27a9e2d28d37a0e75790be6b4820e5f0d27e Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 16:50:49 +0100
Subject: [PATCH 6/7] feat: make FileMode constructor a constexpr
Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
libc/src/__support/File/file_mode.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
index e7f46d6172833..88ca0f5a2aa21 100644
--- a/libc/src/__support/File/file_mode.h
+++ b/libc/src/__support/File/file_mode.h
@@ -14,7 +14,7 @@ class FileMode {
// FileMode constructor accepts the mode string as an argument.
// It performs validation against several rules and records the `file_mode`
// property to the specific mode.
- explicit FileMode(const char *mode) : file_mode_(0) {
+ constexpr FileMode(const char *mode) : file_mode_(0) {
// First character in |mode| should be 'a', 'r' or 'w'.
if (*mode != 'a' && *mode != 'r' && *mode != 'w')
return;
>From 85003b267932ad24be42eff1f569321c7854944d Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 16:53:22 +0100
Subject: [PATCH 7/7] feat(file.h): refactor File class to use FileMode to
handle mode related operations
Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
libc/src/__support/File/file.h | 50 ++++++----------------------------
1 file changed, 8 insertions(+), 42 deletions(-)
diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h
index 6e06e0d6d28bd..a0ea9b7e9d156 100644
--- a/libc/src/__support/File/file.h
+++ b/libc/src/__support/File/file.h
@@ -68,31 +68,6 @@ class File {
using SeekFunc = ErrorOr<off_t>(File *, off_t, int);
using CloseFunc = int(File *);
- using ModeFlags = uint32_t;
-
- // The three different types of flags below are to be used with '|' operator.
- // Their values correspond to mutually exclusive bits in a 32-bit unsigned
- // integer value. A flag set can include both READ and WRITE if the file
- // is opened in update mode (ie. if the file was opened with a '+' the mode
- // string.)
- enum class OpenMode : ModeFlags {
- READ = 0x1,
- WRITE = 0x2,
- APPEND = 0x4,
- PLUS = 0x8,
- };
-
- // Denotes a file opened in binary mode (which is specified by including
- // the 'b' character in teh mode string.)
- enum class ContentType : ModeFlags {
- BINARY = 0x10,
- };
-
- // Denotes a file to be created for writing.
- enum class CreateType : ModeFlags {
- EXCLUSIVE = 0x100,
- };
-
// This is a convenience RAII class to lock and unlock file objects.
class FileLock {
File *file;
@@ -135,12 +110,7 @@ class File {
// free-ed when close method is called on the stream.
bool own_buf;
- // The mode in which the file was opened.
- //TODO: old way of doing things
- // clean up when totally done with pr
- ModeFlags mode;
-
- FileMode file_mode;
+ FileMode mode;
// Current read or write pointer.
size_t pos;
@@ -160,16 +130,16 @@ class File {
protected:
constexpr bool write_allowed() const {
- return file_mode.write_allowed() ||
- file_mode.append_allowed() ||
- file_mode.is_plus(); //TODO: if micheal agrees for me to convert it change it here
+ return mode.write_allowed() || mode.append_allowed() ||
+ mode.is_plus(); // TODO: if micheal agrees for me to convert it
+ // change it here
}
constexpr bool read_allowed() const {
- return file_mode.read_allowed() || file_mode.is_plus();
+ return mode.read_allowed() || mode.is_plus();
}
- void reset_stream_state_unlocked(ModeFlags new_mode) {
+ void reset_stream_state_unlocked(FileMode new_mode) {
mode = new_mode;
pos = 0;
prev_op = FileOp::NONE;
@@ -191,12 +161,12 @@ class File {
// the set_buffer method and allocate a buffer.
constexpr File(WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, CloseFunc *cf,
uint8_t *buffer, size_t buffer_size, int buffer_mode,
- bool owned, ModeFlags modeflags)
+ bool owned, FileMode mode)
: platform_write(wf), platform_read(rf), platform_seek(sf),
platform_close(cf), mutex(/*timed=*/false, /*recursive=*/false,
/*robust=*/false, /*pshared=*/false),
ungetc_buf{}, buf(buffer), bufsize(buffer_size), bufmode(buffer_mode),
- own_buf(owned), mode(modeflags), pos(0), prev_op(FileOp::NONE),
+ own_buf(owned), mode(mode), pos(0), prev_op(FileOp::NONE),
read_limit(0), eof(false), err(false),
orientation(Orientation::UNORIENTED), mbstate(), prev(nullptr),
next(nullptr) {
@@ -356,10 +326,6 @@ class File {
return try_set_orientation_unlocked(o);
}
- // Returns an bit map of flags corresponding to enumerations of
- // OpenMode, ContentType and CreateType.
- static ModeFlags mode_flags(const char *mode);
-
private:
FileIOResult write_unlocked_impl(const void *data, size_t len);
FileIOResult read_unlocked_impl(void *data, size_t len);
More information about the libc-commits
mailing list