Inputs have the documented types: names/prefixes are strings; sizes, quota, timestamps, limits, and supplied TTLs are integers. Sizes are bytes; no unit parsing is required. Instances are independent. Every returned value record and list must be fresh. There is no overwrite, filesystem access, or historical rollback.
Prototype: implement FileCatalog() with upload() and get(). An empty upload name or negative size raises std::invalid_argument. Duplicate names return false and retain their size. Otherwise upload returns true. Zero-byte files are valid. Missing get returns nullopt. The prototype has no quota or expiration.
Final: implement FileStorage(quota):
- Negative quota raises
std::invalid_argument; zero is valid. Start at logical time 0 with usage 0. advance_to(): require timestamp >= current time (and thus nonnegative), otherwise raisestd::invalid_argumentwithout changing state or time. Equal timestamps are allowed. Set time and remove every entry withexpires_at <= timestamp, releasing its size exactly once. No other method advances time.upload(): empty name, negative size, or a supplied TTL below 1 raisesstd::invalid_argumentbefore other checks. Omitted TTL means no expiration. Returnfalsefor an existing name or insufficient quota, unchanged. On success store expirycurrent_time + ttlornullopt, charge size, and returntrue.get(): return exactly the fields declared in the value record below for an existing entry, otherwisenullopt.copy(): empty destination raisesstd::invalid_argumentbefore other checks. Missing source, existing destination (including source == destination), or insufficient quota returnsfalseunchanged. Success creates distinct metadata with the same size and absolute expiry as the source, charges the full size again, and returnstrue.erase(): returntrueand release the size if present; returnfalseif absent. Repeated deletion must not release space twice.usage(): return the total sizes of all current entries.search(): match case-sensitivename.starts_with(prefix). Empty prefix matches all. Sort by size descending then name ascending, return at mostlimitsnapshots. Negative limit raisesstd::invalid_argumentwithout mutation; zero returns[].
Rejected calls leave all entries and quota accounting unchanged.
The public C++ API below is authoritative for field types and return values. erase is used where another language might use a method named delete, because delete is a C++ keyword. Returned records are value snapshots with the documented named fields; mutating a record or its nested vectors cannot affect the service.
struct File {std::string name;Int size;Opt<Int> expires_at;bool operator==(const File&)const=default;};
class FileCatalog { public:
FileCatalog();
bool upload(const std::string& name,Int size);
Opt<Int> get(const std::string& name) const;
};
class FileStorage { public:
explicit FileStorage(Int quota);
void advance_to(Int ts);
bool upload(const std::string& name,Int size,Opt<Int> ttl=std::nullopt);
Opt<File> get(const std::string& name) const;
bool copy(const std::string& source,const std::string& destination);
bool erase(const std::string& name);
Int usage() const;
Vec<File> search(const std::string& prefix,Int limit=10) const;
};Compile and run from this directory:
c++ -std=c++20 -O2 -Wall -Wextra -pedantic -pthread main.cpp -o practice
./practice --stage prototype
./practice --stage finalEdit exercise.hpp. Both stages start unfinished and must report failures until implemented. Keep main.cpp as the executable contract. The runner returns nonzero for a failed check, an unexpected exception, an invalid stage, or an empty suite. C++20 and only the standard library are required.
Complete the starter code, then run the checks.
Results and errors will appear here.
C++ runtime powered by Wasmer.