+#include "simgrid/s4u/storage.hpp"
+
+std::unordered_map<std::string, simgrid::s4u::Host*> host_list; // FIXME: move it to Engine
+
+int MSG_HOST_LEVEL = -1;
+int USER_HOST_LEVEL = -1;
+
+namespace simgrid {
+
+namespace xbt {
+template class Extendable<simgrid::s4u::Host>;
+}
+
+namespace s4u {
+
+simgrid::xbt::signal<void(Host&)> Host::onCreation;
+simgrid::xbt::signal<void(Host&)> Host::onDestruction;
+simgrid::xbt::signal<void(Host&)> Host::onStateChange;
+
+Host::Host(const char* name)
+ : name_(name)
+{
+ xbt_assert(sg_host_by_name(name) == nullptr, "Refusing to create a second host named '%s'.", name);
+ host_list[name_] = this;
+}
+
+Host::~Host()
+{
+ xbt_assert(currentlyDestroying_, "Please call h->destroy() instead of manually deleting it.");
+
+ delete pimpl_;
+ delete pimpl_cpu;
+ delete pimpl_netcard;
+ delete mounts;
+}
+
+/** @brief Fire the required callbacks and destroy the object
+ *
+ * Don't delete directly an Host, call h->destroy() instead.
+ *
+ * This is cumbersome but this is the simplest solution to ensure that the
+ * onDestruction() callback receives a valid object (because of the destructor
+ * order in a class hierarchy).
+ */
+void Host::destroy()
+{
+ if (!currentlyDestroying_) {
+ currentlyDestroying_ = true;
+ onDestruction(*this);
+ host_list.erase(name_);
+ delete this;
+ }
+}
+
+Host* Host::by_name(std::string name)
+{
+ return host_list.at(name); // Will raise a std::out_of_range if the host does not exist
+}
+Host* Host::by_name_or_null(const char* name)
+{
+ if (host_list.find(name) == host_list.end())
+ return nullptr;
+ return host_list.at(name);
+}
+
+Host *Host::current(){
+ smx_actor_t smx_proc = SIMIX_process_self();
+ if (smx_proc == nullptr)
+ xbt_die("Cannot call Host::current() from the maestro context");
+ return smx_proc->host;
+}
+
+void Host::turnOn() {
+ if (isOff()) {
+ simgrid::simix::kernelImmediate([&]{
+ this->extension<simgrid::simix::Host>()->turnOn();
+ this->pimpl_cpu->turnOn();
+ });
+ }
+}