All arguments use their declared C++ parameter types. Strings are case-sensitive. Ingredients and steps are lists of strings; empty lists, empty items, and duplicates are allowed and preserve order. Every returned value record/list is a detached snapshot, including nested lists. Instances must have independent state. No persistence or deletion is required.

Prototype: implement RecipeDraft(name, ingredients, steps) and snapshot(). The snapshot is the fields declared in the value record below. Copy the input lists. The draft does not validate the name or manage permissions.

Final: implement RecipeManager() with these methods:

  • add_user(): permissions is a list containing only "read" and/or "write"; duplicates are harmless. Empty permissions are allowed. Empty user IDs or unknown permissions raise std::invalid_argument, even for an existing ID. Return false for an existing valid ID, preserving its original permissions; otherwise register a copied permission set and return true.
  • add(): requires write. Empty name raises std::invalid_argument before permission checks. Return nullopt for no permission or a currently used name. Success returns "recipe1", "recipe2", ... and creates v1. Rejected requests consume no identifier.
  • update(): the same name validation and write check apply. Missing recipe or name owned by another recipe returns nullopt. Success appends a revision, even for identical content, and returns its number. Renaming frees the old current name.
  • get(): requires read. nullopt selects latest; an integer version selects that positive revision. Return nullopt for no permission, missing recipe, or nonexistent version. A snapshot has exactly id, version, name, ingredients, and steps.
  • history(): requires read. Return snapshots in increasing version order, or [] for no permission/missing recipe.
  • rollback(): requires write; invalid target, missing recipe, or conflicting historical name returns nullopt. Append the selected content as a new latest revision and return its number. Preserve all existing versions and the same recipe ID.
  • by_ingredient(): requires read; otherwise []. Match exact ingredient membership in current content. Sort by ingredient count ascending, current name ascending, then ID ascending. A recipe appears once despite duplicate ingredients.

Invalid or rejected calls leave all state 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.

cpp
struct DraftSnapshot {std::string name;Strings ingredients,steps;bool operator==(const DraftSnapshot&)const=default;};
struct Recipe {std::string id;Int version;std::string name;Strings ingredients,steps;bool operator==(const Recipe&)const=default;};
class RecipeDraft { public:
 RecipeDraft(std::string name,Strings ingredients,Strings steps);
 DraftSnapshot snapshot() const;
};
class RecipeManager { public:
 RecipeManager();
 bool add_user(const std::string& id,const Strings& permissions);
 Opt<std::string> add(const std::string& user,const std::string& name,const Strings& ingredients,const Strings& steps);
 Opt<Int> update(const std::string& user,const std::string& id,const std::string& name,const Strings& ingredients,const Strings& steps);
 Opt<Recipe> get(const std::string& user,const std::string& id,Opt<Int> version=std::nullopt) const;
 Vec<Recipe> history(const std::string& user,const std::string& id) const;
 Opt<Int> rollback(const std::string& user,const std::string& id,Int version);
 Strings by_ingredient(const std::string& user,const std::string& ingredient) const;
};

Compile and run from this directory:

Shell
c++ -std=c++20 -O2 -Wall -Wextra -pedantic -pthread main.cpp -o practice
./practice --stage prototype
./practice --stage final

Edit 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.

Drag or use the arrow keys to resize. Home collapses the question; End collapses the editor. Enter or double-click resets the split.
Loading editor…
No results yet.

Complete the starter code, then run the checks.
Results and errors will appear here.

C++ runtime powered by Wasmer.