stasher::current<classptr>, stasher::currentptr<classptr>: a basic stasher::currentBaseObj subclass
    The following example is based on
    showinventory2.C.
    This example uses
    stasher::current; this is an
    x::ref to a
    stasher::currentObj
    subclass that implements its update() and
    connection_update() methods
    (there's also a
    stasher::currentptr that defines an
    x::ptr):
  
#include <stasher/client.H> #include <stasher/manager.H> #include <stasher/current.H> #include <x/strtok.H> #include <sstream> #include <vector> #include "inventory.H" void show_inventory(const inventoryptr &, bool initial); void status(stasher::req_stat_t status); bool has_inventory(const inventoryptr &ptr, const std::string &what, int howmuch); void showinventory(int argc, char **argv) { if (argc < 2) return; auto client=stasher::client::base::connect(); auto manager=stasher::manager::create(); typedef stasher::current<inventoryptr> warehouse_t; warehouse_t warehouse=warehouse_t::create(); x::ref<x::obj> mcguffin=warehouse->manage(manager, client, argv[1]); std::cout << "Enter for the current inventory, \"what\" \"howmuch\" to wait until we have it," << std::endl << "EOF to quit" << std::endl; std::string dummy; while (!std::getline(std::cin, dummy).eof()) { std::vector<std::string> words; x::strtok_str(dummy, " \t\r\n", words); warehouse_t::base::current_value_t::lock lock(warehouse->current_value); if (words.size() == 2) { int i=-1; std::istringstream(words[1]) >> i; if (i < 0) { std::cerr << "Eh?" << std::endl; continue; } std::cout << "Waiting for " << i << " " << words[0] << std::endl; lock.wait([&lock, &words, i] { return has_inventory(lock->value, words[0], i); }); } show_inventory(lock->value, lock->isinitial); status(lock->connection_status); } } bool has_inventory(const inventoryptr &ptr, const std::string &what, int howmuch) { if (ptr.null()) { std::cout << "No inventory yet..." << std::endl; return false; } auto iter=ptr->stock.find(what); int wehave=iter == ptr->stock.end() ? 0:iter->second; std::cout << "We have " << wehave << " of them, now." << std::endl; return wehave >= howmuch; } void show_inventory(const inventoryptr &ptr, bool initial) { std::cout << (initial ? "Current inventory:":"Updated inventory:") << std::endl; if (ptr.null()) { std::cout << " (none)" << std::endl; } else { std::cout << " " << std::setw(30) << std::left << "Item" << " " << std::setw(8) << std::right << "Count" << std::setw(0) << std::endl; std::cout << " " << std::setfill('-') << std::setw(30) << "" << " " << std::setw(8) << "" << std::setw(0) << std::setfill(' ') << std::endl; for (auto &item:ptr->stock) { std::cout << " " << std::setw(30) << std::left << item.first << " " << std::setw(8) << std::right << item.second << std::setw(0) << std::endl; } std::cout << std::setw(75) << std::setfill('=') << "" << std::setw(0) << std::setfill(' ') << std::endl; } } void status(stasher::req_stat_t status) { std::cout << "Connection status: " << x::tostring(status) << std::endl; } int main(int argc, char **argv) { try { showinventory(argc, argv); } catch (const x::exception &e) { std::cerr << e << std::endl; return 1; } return 0; }
    showinventory3.C waits for Enter
    before showing the current inventory. Entering “grapes 3”
    before Enter waits until there are 3 grapes in the
    inventory, then the current inventory gets shown:
  
       ./showinventory3 instock
Enter for the current inventory, "what" "howmuch" to wait until we have it,
EOF to quit
<Enter>
Current inventory:
    Item                                Count
    ------------------------------   --------
    apples                                  2
===========================================================================
Connection status: Transaction/request processed
grapes 3<Enter>
Waiting for 3 grapes
We have 0 of them, now.
We have 1 of them, now.
We have 3 of them, now.
Updated inventory:
    Item                                Count
    ------------------------------   --------
    apples                                  2
    grapes                                  3
===========================================================================
Connection status: Transaction/request processed
    In this example, there were two updates to the inventory in the interim. First, “grapes” was 1, then the second update set it to 3.
    stasher::current<
    (and
    classptr>stasher::currentptr<)
    refers to a
    classptr>stasher::currentObj<,
    a subclass of
    classptr>stasher::currentBaseObj<.
    classptr>stasher::currentObj contains a member called
    current_value, of type
    stasher::current<.
  classptr>::base::current_value_t
    This is an x::mpcobj,
    a mutex-protected object with
    value,
    a  to the
    current value of the object in the repository (a classptrnullptr
    if there isn't one), a bool
    isinitial flag, indicating whether
    value is the initial object value retrieved from the
    object repository, or an updated one, and a
    stasher::req_stat_t
    connection_status, the latest connection status with
    the stasher repository server, reported by the manager.
  
    stasher::currentObj<,
    implements
    classptr>stasher::currentBaseObj<'s
    classptr>update() and
    connection_update() by locking the
    current_value, updating its contents, and then
    notifying the lock's condition variable, before releasing the lock.
    showinventory3.C waits for Enter,
    locks the current_value, and displays its contents.
    Until the next Enter,
    current_value gets automatically updated, by the
    stasher::currentObj, when the object in the repository
    changes.
  
To summarize:
	Create a stasher::current<, where
	classptr> is
	an classptrx::ref to a class
	that meets the requirements described
	in the section called “Requirements”, and manage it.
      
	To check the current contents of the object in the repository,
	acquire a lock on the mutex-protected
	current_value.
      
      The lock on the current_value should be short and
      brief. If the object gets updated in the repository, a new object gets
      constructed, and
      stasher::currentObj's callback gets invoked.
      This all happens in the client connection thread. The client connection thread waits to acquire a lock on the
      current_value, and won't do anything else until it
      does, and finishes updating the object.
    
      The same thing happens if the connection to the server gets dropped, or
      it gets reconnected. This results in the
      connection_update update getting invoked, which
      also needs to acquire a lock on the
      current_value, so that the
      status can get updated.
    
      An application that needs to take special action for an
      isinitial object value must explicitly subclass
      the stasher::currentObj, and override the
      connection_update method. This is because the
      initial value of the object may or may not be installed before
      manage() returns, since the
      connection_update gets called from a different
      thread. Since an object in a stasher object repository can get updated at
      any time, this means that it can also get updated before
      manage() returns as well, before the application
      has a chance to lock the
      current_value.
    
      The contract for the
      created managed object's
      connection_update() methods guarantees that
      it gets called with a value that's marked as an initial value, but not
      when.