Compare commits
6 Commits
e3c4ab65f1
...
811176ad53
Author | SHA1 | Date |
---|---|---|
kayomn | 811176ad53 | |
kayomn | 22a8b63d0f | |
kayomn | 51b73aa823 | |
kayomn | a58b0d7bdb | |
kayomn | 44ee0591a2 | |
kayomn | 340120d920 |
|
@ -458,15 +458,18 @@ export namespace core {
|
|||
// Input/output operations.
|
||||
export namespace core {
|
||||
/**
|
||||
* Tests the equality of `a` against `b`, returning `true` if they contain identical bytes,
|
||||
* otherwise `false`.
|
||||
* Compares `a` and `b`, returning the difference between them or `0` if they are identical.
|
||||
*/
|
||||
bool equals(slice<u8 const> const & a, slice<u8 const> const & b) {
|
||||
if (a.length != b.length) return false;
|
||||
constexpr size compare(slice<u8 const> const & a, slice<u8 const> const & b) {
|
||||
usize const range = min(a.length, b.length);
|
||||
|
||||
for (size_t i = 0; i < a.length; i += 1) if (a[i] != b[i]) return false;
|
||||
for (usize index = 0; index < range; index += 1) {
|
||||
size const difference = static_cast<size>(a[index]) - static_cast<size>(b[index]);
|
||||
|
||||
return true;
|
||||
if (difference != 0) return difference;
|
||||
}
|
||||
|
||||
return static_cast<size>(a.length) - static_cast<size>(b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -477,7 +480,39 @@ export namespace core {
|
|||
void copy(slice<u8> const & target, slice<u8 const> const & origin) {
|
||||
if (target.length < origin.length) core::unreachable();
|
||||
|
||||
for (usize i = 0; i < origin.length; i += 1) target[i] = origin[i];
|
||||
for (usize i = 0; i < target.length; i += 1) target[i] = origin[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeroes the contents of `target`.
|
||||
*/
|
||||
void zero(slice<u8> const & target) {
|
||||
for (usize i = 0; i < target.length; i += 1) target[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the equality of `a` against `b`, returning `true` if they contain identical bytes,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
constexpr bool equals(slice<u8 const> const & a, slice<u8 const> const & b) {
|
||||
if (a.length != b.length) return false;
|
||||
|
||||
for (size_t i = 0; i < a.length; i += 1) if (a[i] != b[i]) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code generated from the values in `bytes`.
|
||||
*
|
||||
* *Note:* the returned hash code is not guaranteed to be unique.
|
||||
*/
|
||||
constexpr usize hash(slice<u8 const> const & bytes) {
|
||||
usize hash_code = 5381;
|
||||
|
||||
for (u8 const byte : bytes) hash_code = ((hash_code << 5) + hash_code) + byte;
|
||||
|
||||
return hash_code;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
export module core.files;
|
||||
|
||||
import core;
|
||||
|
||||
export namespace core {
|
||||
/**
|
||||
* Platform-generalized identifier for a resource in a [file_store].
|
||||
*/
|
||||
struct path {
|
||||
/**
|
||||
* Maximum path length.
|
||||
*/
|
||||
static usize const max = u8_max;
|
||||
|
||||
/**
|
||||
* Common path component separator.
|
||||
*/
|
||||
static char const seperator = '/';
|
||||
|
||||
constexpr path() : buffer{0} {
|
||||
this->buffer[max] = max;
|
||||
}
|
||||
|
||||
template<usize text_size> constexpr path(char const(&text)[text_size]) {
|
||||
static_assert(text_size <= max, "path cannot be longer than maximum length");
|
||||
copy(this->buffer, text.as_bytes());
|
||||
zero(slice{this->buffer}.sliced(text_size, max - text_size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base pointer of the path name.
|
||||
*/
|
||||
char const * begin() const {
|
||||
return reinterpret_cast<char const *>(this->buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes composing the path.
|
||||
*/
|
||||
constexpr usize byte_size() const {
|
||||
return max - this->buffer[max];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the path to `that`, returning the difference between the two paths or `0` if
|
||||
* they are identical.
|
||||
*/
|
||||
constexpr size compare(path const & that) const {
|
||||
return core::compare(slice{this->begin(), this->end()}.as_bytes(),
|
||||
slice{that.begin(), that.end()}.as_bytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tail pointer of the path name.
|
||||
*/
|
||||
char const * end() const {
|
||||
return reinterpret_cast<char const *>(this->buffer) + this->byte_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the path against `that` for equality, returning `true` if they are identical,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
constexpr bool equals(path const & that) const {
|
||||
return core::equals(slice{this->begin(), this->end()}.as_bytes(),
|
||||
slice{that.begin(), that.end()}.as_bytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path hash code.
|
||||
*
|
||||
* *Note:* the returned hash code is not guaranteed to be unique.
|
||||
*/
|
||||
constexpr u64 hash() const {
|
||||
return core::hash(slice{this->begin(), this->end()}.as_bytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new [path] composed of the current path joined with `text`.
|
||||
*
|
||||
* *Note:* should the new path exceed [max] bytes in size, an empty [path] is returned instead.
|
||||
*/
|
||||
constexpr path joined(slice<char const> const & text) const {
|
||||
if (text.length > this->buffer[max]) return path{};
|
||||
|
||||
path joined_path = *this;
|
||||
|
||||
for (char const c : text) {
|
||||
joined_path.buffer[joined_path.byte_size()] = c;
|
||||
joined_path.buffer[max] -= 1;
|
||||
}
|
||||
|
||||
return joined_path;
|
||||
}
|
||||
|
||||
private:
|
||||
u8 buffer[max + 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Platform-generalized file system interface.
|
||||
*/
|
||||
struct fs {
|
||||
/**
|
||||
* The result from a file access operation.
|
||||
*
|
||||
* [file_result::ok] indicates a successful file access operation.
|
||||
*
|
||||
* [file_result::not_found] signals that the file was not found.
|
||||
*
|
||||
* [file_result::access_denied] warns that the file was found but cannot be opened through
|
||||
* the file system interface. The most common scenario for this error is a lack of required
|
||||
* file permissions.
|
||||
*/
|
||||
enum class [[nodiscard]] access_result {
|
||||
ok,
|
||||
not_found,
|
||||
access_denied,
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempts to read the file in the file system located at `file_path` relative, calling
|
||||
* `then` if it was successfully opened for reading.
|
||||
*
|
||||
* The returned [access_result] indicates whether the operation was successful or not.
|
||||
*
|
||||
* Once `then` returns, access to the file is closed automatically.
|
||||
*/
|
||||
virtual access_result read_file(path const & file_path,
|
||||
callable<void(readable const &)> const & then) = 0;
|
||||
|
||||
/**
|
||||
* Attempts to write the file in the file system located at `file_path` relative, calling
|
||||
* `then` if it was successfully opened for writing.
|
||||
*
|
||||
* The returned [access_result] indicates whether the operation was successful or not.
|
||||
*
|
||||
* Once `then` returns, access to the file is closed automatically.
|
||||
*/
|
||||
virtual access_result write_file(path const & file_path,
|
||||
callable<void(writable const &)> const & then) = 0;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue