diff --git a/src/madness/tensor/srconf.h b/src/madness/tensor/srconf.h index 9ecb4858b48..6e5797c60d8 100644 --- a/src/madness/tensor/srconf.h +++ b/src/madness/tensor/srconf.h @@ -663,7 +663,7 @@ namespace madness { public: /// return the number of physical dimensions int dim_per_vector(int idim) const { - MADNESS_ASSERT(vector_.size()>idim); + MADNESS_ASSERT(vector_.size()>size_t(idim)); return vector_[idim].ndim()-1; // remove dimension for the rank } diff --git a/src/madness/world/parallel_archive.h b/src/madness/world/parallel_archive.h index bcfedf9e2af..45cb9c8a61c 100644 --- a/src/madness/world/parallel_archive.h +++ b/src/madness/world/parallel_archive.h @@ -104,7 +104,7 @@ namespace madness { /// \return The process doing I/O for this node. ProcessID my_io_node() const { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); return io_node(world->rank()); } @@ -112,7 +112,7 @@ namespace madness { /// \return The number of I/O clients for this node, including self (zero if not an I/O node). int num_io_clients() const { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); return nclient; } @@ -120,7 +120,7 @@ namespace madness { /// \return True if this node is doing physical I/O. bool is_io_node() const { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); return world->rank() == my_io_node(); } @@ -128,7 +128,7 @@ namespace madness { /// \return A pointer to the world. World* get_world() const { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); return world; } @@ -166,12 +166,12 @@ namespace madness { if (nio > maxio) nio = maxio; // Sanity? if (nio > world.size()) nio = world.size(); - MADNESS_ASSERT(filename); - MADNESS_ASSERT(strlen(filename)-1::value || std::is_same::value, bool> exists(World& world, const char* filename) { - constexpr std::size_t bufsize=256; + constexpr std::size_t bufsize=512; char buf[bufsize]; - MADNESS_ASSERT(strlen(filename)+7 <= sizeof(buf)); + MADNESS_CHECK(strlen(filename)+7 <= sizeof(buf)); snprintf(buf,bufsize, "%s.%5.5d", filename, world.rank()); bool status; if (world.rank() == 0) @@ -237,7 +237,7 @@ namespace madness { /// Closes the parallel archive. void close() { - MADNESS_ASSERT(world); + MADNESS_CHECK(world); if (is_io_node()) ar.close(); } @@ -246,8 +246,8 @@ namespace madness { /// \throw MadnessException If not an I/O node. /// \return A reference to the local archive. Archive& local_archive() const { - MADNESS_ASSERT(world); - MADNESS_ASSERT(is_io_node()); + MADNESS_CHECK(world); + MADNESS_CHECK(is_io_node()); return ar; } @@ -273,9 +273,9 @@ namespace madness { void> remove(World& world, const char* filename) { if (world.rank() == 0) { - constexpr std::size_t bufsize=268; + constexpr std::size_t bufsize=512; char buf[bufsize]; - MADNESS_ASSERT(strlen(filename)+7 <= sizeof(buf)); + MADNESS_CHECK(strlen(filename)+7 <= sizeof(buf)); for (ProcessID p=0; p + struct ArchivePrePostImpl { + /// Store the preamble. + + /// \param[in] ar The archive. + static void preamble_store(const ContainerRecordOutputArchive& ar) {}; + + /// Store the postamble. + + /// \param[in] ar The archive. + static inline void postamble_store(const ContainerRecordOutputArchive& ar) {}; + }; + + /// Implementation of functions for loading the pre/postamble in ContainerRecord archives. + + /// \attention No type checking over ContainerRecord buffers, for efficiency. + /// \tparam T The data type. + template + struct ArchivePrePostImpl { + /// Load the preamble. + + /// \param[in] ar The archive. + static inline void preamble_load(const ContainerRecordInputArchive& ar) {}; + + /// Load the postamble. + + /// \param[in] ar The archive. + static inline void postamble_load(const ContainerRecordInputArchive& ar) {}; + }; + + // Forward storing to VectorOutputArchive template struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { - ParallelOutputArchive par(*(ar.get_world()), ar.local_archive().get_archive()); + std::vector v; + VectorOutputArchive dummyar(v,0); + const int me = ar.get_world()->rank(); + + // Need to pass local archive by reference + ParallelOutputArchive par(*(ar.get_world()), (me==0) ? ar.local_archive().get_archive() : dummyar); par & t; } }; + + } diff --git a/src/madness/world/test_dc.cc b/src/madness/world/test_dc.cc index bf03c72ee6f..f908df1dc64 100644 --- a/src/madness/world/test_dc.cc +++ b/src/madness/world/test_dc.cc @@ -270,7 +270,16 @@ void test_local(World& world) { void test_florian(World& world) { WorldContainer c(world); - long nlarge=200000; + + long nlarge=20000; + // get nlarge variable from the environment and convert it into long + char* nlarge_env = getenv("NLARGE"); + if (nlarge_env) { + nlarge = atol(nlarge_env); + } + if (world.rank()==0) print("size of the container",nlarge); + + if (world.rank() == 0) { for (int i=0; i v; { archive::VectorOutputArchive var(v); @@ -287,7 +296,7 @@ void test_florian(World& world) { ar & c; } double wall1=wall_time(); - printf("ending at time %8.4f after %8.4fs\n",wall1,wall1-wall0); + if (world.rank() == 0) printf("ending at time %8.4f after %8.4fs\n",wall1,wall1-wall0); WorldContainer c2(world); { @@ -303,7 +312,7 @@ void test_florian(World& world) { } world.gop.fence(); - print("test_florian passed"); + if (world.rank() == 0) print("test_florian passed"); } int main(int argc, char** argv) { diff --git a/src/madness/world/vector_archive.h b/src/madness/world/vector_archive.h index 129c35e44e9..3530a5a258d 100644 --- a/src/madness/world/vector_archive.h +++ b/src/madness/world/vector_archive.h @@ -144,6 +144,40 @@ namespace madness { void close() {} }; + /// Implementation of functions for storing the pre/postamble in Vector archives. + + /// \attention No type checking over Vector buffers, for efficiency. + /// \tparam T The data type. + template + struct ArchivePrePostImpl { + /// Store the preamble. + + /// \param[in] ar The archive. + static void preamble_store(const VectorOutputArchive& ar) {}; + + /// Store the postamble. + + /// \param[in] ar The archive. + static inline void postamble_store(const VectorOutputArchive& ar) {}; + }; + + /// Implementation of functions for loading the pre/postamble in Vector archives. + + /// \attention No type checking over Vector buffers, for efficiency. + /// \tparam T The data type. + template + struct ArchivePrePostImpl { + /// Load the preamble. + + /// \param[in] ar The archive. + static inline void preamble_load(const VectorInputArchive& ar) {}; + + /// Load the postamble. + + /// \param[in] ar The archive. + static inline void postamble_load(const VectorInputArchive& ar) {}; + }; + /// @} } } diff --git a/src/madness/world/worlddc.h b/src/madness/world/worlddc.h index c6ead97b07e..88a61dc3f43 100644 --- a/src/madness/world/worlddc.h +++ b/src/madness/world/worlddc.h @@ -48,7 +48,8 @@ #include #include -namespace madness { +namespace madness +{ template class WorldContainer; @@ -57,37 +58,40 @@ namespace madness { class WorldContainerImpl; template - void swap(WorldContainer&, WorldContainer&); + void swap(WorldContainer &, WorldContainer &); template class WorldDCPmapInterface; template - class WorldDCRedistributeInterface { + class WorldDCRedistributeInterface + { public: virtual std::size_t size() const = 0; - virtual void redistribute_phase1(const std::shared_ptr< WorldDCPmapInterface >& newmap) = 0; + virtual void redistribute_phase1(const std::shared_ptr> &newmap) = 0; virtual void redistribute_phase2() = 0; virtual void redistribute_phase3() = 0; - virtual ~WorldDCRedistributeInterface() {}; + virtual ~WorldDCRedistributeInterface() {}; }; - /// Interface to be provided by any process map /// \ingroup worlddc template - class WorldDCPmapInterface { + class WorldDCPmapInterface + { public: - typedef WorldDCRedistributeInterface* ptrT; + typedef WorldDCRedistributeInterface *ptrT; + private: std::set ptrs; + public: /// Maps key to processor /// @param[in] key Key for container /// @return Processor that logically owns the key - virtual ProcessID owner(const keyT& key) const = 0; + virtual ProcessID owner(const keyT &key) const = 0; virtual ~WorldDCPmapInterface() {} @@ -96,14 +100,16 @@ namespace madness { /// Registers object for receipt of redistribute callbacks /// @param[in] ptr Pointer to class derived from WorldDCRedistributedInterface - void register_callback(ptrT ptr) { + void register_callback(ptrT ptr) + { ptrs.insert(ptr); } /// Deregisters object for receipt of redistribute callbacks /// @param[in] ptr Pointer to class derived from WorldDCRedistributedInterface - void deregister_callback(ptrT ptr) { + void deregister_callback(ptrT ptr) + { ptrs.erase(ptr); } @@ -113,26 +119,30 @@ namespace madness { /// new map and no objects will be registered in the current map. /// @param[in] world The associated world /// @param[in] newpmap The new process map - void redistribute(World& world, const std::shared_ptr< WorldDCPmapInterface >& newpmap) { + void redistribute(World &world, const std::shared_ptr> &newpmap) + { print_data_sizes(world, "before redistributing"); world.gop.fence(); for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); - ++iter) { + ++iter) + { (*iter)->redistribute_phase1(newpmap); } world.gop.fence(); for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); - ++iter) { + ++iter) + { (*iter)->redistribute_phase2(); newpmap->register_callback(*iter); } world.gop.fence(); for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); - ++iter) { - (*iter)->redistribute_phase3(); + ++iter) + { + (*iter)->redistribute_phase3(); } world.gop.fence(); ptrs.clear(); @@ -142,7 +152,8 @@ namespace madness { /// Counts global number of entries in all containers associated with this process map /// Collective operation with global fence - std::size_t global_size(World& world) const { + std::size_t global_size(World &world) const + { world.gop.fence(); std::size_t sum = local_size(); world.gop.sum(sum); @@ -151,9 +162,11 @@ namespace madness { } /// Counts local number of entries in all containers associated with this process map - std::size_t local_size() const { + std::size_t local_size() const + { std::size_t sum = 0; - for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); ++iter) { + for (typename std::set::iterator iter = ptrs.begin(); iter != ptrs.end(); ++iter) + { sum += (*iter)->size(); } return sum; @@ -162,17 +175,20 @@ namespace madness { /// Prints size info to std::cout /// Collective operation with global fence - void print_data_sizes(World& world, const std::string msg="") const { + void print_data_sizes(World &world, const std::string msg = "") const + { world.gop.fence(); std::size_t total = global_size(world); std::vector sizes(world.size()); sizes[world.rank()] = local_size(); - world.gop.sum(&sizes[0],world.size()); - if (world.rank() == 0) { + world.gop.sum(&sizes[0], world.size()); + if (world.rank() == 0) + { madness::print("data distribution info", msg); madness::print(" total: ", total); std::cout << " procs: "; - for (int i=0; i > - class WorldDCDefaultPmap : public WorldDCPmapInterface { + template > + class WorldDCDefaultPmap : public WorldDCPmapInterface + { private: const int nproc; hashfunT hashfun; + public: - WorldDCDefaultPmap(World& world, const hashfunT& hf = hashfunT()) : - nproc(world.mpi.nproc()), - hashfun(hf) - { } + WorldDCDefaultPmap(World &world, const hashfunT &hf = hashfunT()) : nproc(world.mpi.nproc()), + hashfun(hf) + { + } - ProcessID owner(const keyT& key) const { - if (nproc == 1) return 0; - return hashfun(key)%nproc; + ProcessID owner(const keyT &key) const + { + if (nproc == 1) + return 0; + return hashfun(key) % nproc; } }; /// Local process map will always return the current process as owner /// \ingroup worlddc - template > - class WorldDCLocalPmap : public WorldDCPmapInterface { + template > + class WorldDCLocalPmap : public WorldDCPmapInterface + { private: - ProcessID me; + ProcessID me; + public: - WorldDCLocalPmap(World& world) : me(world.rank()) { } - ProcessID owner(const keyT& key) const { - return me; - } + WorldDCLocalPmap(World &world) : me(world.rank()) {} + ProcessID owner(const keyT &key) const + { + return me; + } }; /// Iterator for distributed container wraps the local iterator /// \ingroup worlddc template - class WorldContainerIterator { + class WorldContainerIterator + { public: - typedef typename std::iterator_traits::iterator_category iterator_category; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::pointer pointer; - typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::iterator_category iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::pointer pointer; + typedef typename std::iterator_traits::reference reference; private: - internal_iteratorT it; ///< Iterator from local container + internal_iteratorT it; ///< Iterator from local container // TODO: Convert this to a scoped pointer. - mutable value_type* value; ///< holds the remote values + mutable value_type *value; ///< holds the remote values public: /// Default constructor makes a local uninitialized value explicit WorldContainerIterator() - : it(), value(nullptr) {} + : it(), value(nullptr) {} /// Initializes from a local iterator - explicit WorldContainerIterator(const internal_iteratorT& it) - : it(it), value(nullptr) {} + explicit WorldContainerIterator(const internal_iteratorT &it) + : it(it), value(nullptr) {} /// Initializes to cache a remote value - explicit WorldContainerIterator(const value_type& v) - : it(), value(nullptr) + explicit WorldContainerIterator(const value_type &v) + : it(), value(nullptr) { value = new value_type(v); } - WorldContainerIterator(const WorldContainerIterator& other) - : it(), value(nullptr) + WorldContainerIterator(const WorldContainerIterator &other) + : it(), value(nullptr) { copy(other); } template - WorldContainerIterator(const WorldContainerIterator& other) - : it(), value(nullptr) + WorldContainerIterator(const WorldContainerIterator &other) + : it(), value(nullptr) { copy(other); } - ~WorldContainerIterator() { + ~WorldContainerIterator() + { delete value; } /// Assignment - WorldContainerIterator& operator=(const WorldContainerIterator& other) { + WorldContainerIterator &operator=(const WorldContainerIterator &other) + { copy(other); return *this; } /// Determines if two iterators are identical - bool operator==(const WorldContainerIterator& other) const { + bool operator==(const WorldContainerIterator &other) const + { return (((!is_cached()) && (!other.is_cached())) && it == other.it) || - ((is_cached() && other.is_cached()) && value->first == other.value->first); + ((is_cached() && other.is_cached()) && value->first == other.value->first); } - /// Determines if two iterators are different - bool operator!=(const WorldContainerIterator& other) const { + bool operator!=(const WorldContainerIterator &other) const + { return !(*this == other); } - /// Pre-increment of an iterator (i.e., ++it) --- \em local iterators only /// Trying to increment a remote iterator will throw - WorldContainerIterator& operator++() { - MADNESS_ASSERT( !is_cached() ); + WorldContainerIterator &operator++() + { + MADNESS_ASSERT(!is_cached()); ++it; return *this; } - WorldContainerIterator operator++(int) { - MADNESS_ASSERT( !is_cached() ); + WorldContainerIterator operator++(int) + { + MADNESS_ASSERT(!is_cached()); WorldContainerIterator result(*this); ++it; return result; } /// Iterators dereference to std::pair - pointer operator->() const { - return (is_cached() ? value : it.operator->() ); + pointer operator->() const + { + return (is_cached() ? value : it.operator->()); } /// Iterators dereference to std::pair - reference operator*() const { - return (is_cached() ? *value : *it ); + reference operator*() const + { + return (is_cached() ? *value : *it); } /// Private: (or should be) Returns iterator of internal container - const internal_iteratorT& get_internal_iterator() const { + const internal_iteratorT &get_internal_iterator() const + { return it; } /// Returns true if this is non-local or cached value - bool is_cached() const { + bool is_cached() const + { return value != nullptr; } template - void serialize(const Archive&) { + void serialize(const Archive &) + { MADNESS_EXCEPTION("Serializing DC iterator ... why?", false); } @@ -328,13 +361,18 @@ namespace madness { friend class WorldContainerIterator; template - void copy(const WorldContainerIterator& other) { - if (static_cast(this) != static_cast(&other)) { + void copy(const WorldContainerIterator &other) + { + if (static_cast(this) != static_cast(&other)) + { delete value; - if(other.is_cached()) { - value = new value_type(* other.value); + if (other.is_cached()) + { + value = new value_type(*other.value); it = internal_iteratorT(); - } else { + } + else + { it = other.it; value = nullptr; } @@ -345,22 +383,23 @@ namespace madness { /// Internal implementation of distributed container to facilitate shallow copy /// \ingroup worlddc - template + template class WorldContainerImpl - : public WorldObject< WorldContainerImpl > - , public WorldDCRedistributeInterface + : public WorldObject>, + public WorldDCRedistributeInterface #ifndef MADNESS_DISABLE_SHARED_FROM_THIS - , public std::enable_shared_from_this > + , + public std::enable_shared_from_this> #endif // MADNESS_DISABLE_SHARED_FROM_THIS { public: - typedef typename std::pair pairT; + typedef typename std::pair pairT; typedef const pairT const_pairT; - typedef WorldContainerImpl implT; + typedef WorldContainerImpl implT; - typedef ConcurrentHashMap< keyT,valueT,hashfunT > internal_containerT; + typedef ConcurrentHashMap internal_containerT; - //typedef WorldObject< WorldContainerImpl > worldobjT; + // typedef WorldObject< WorldContainerImpl > worldobjT; typedef typename internal_containerT::iterator internal_iteratorT; typedef typename internal_containerT::const_iterator internal_const_iteratorT; @@ -371,82 +410,87 @@ namespace madness { typedef WorldContainerIterator const_iteratorT; typedef WorldContainerIterator const_iterator; - friend class WorldContainer; + friend class WorldContainer; -// template -// inline -// static -// typename containerT::iterator replace(containerT& c, const datumT& d) { -// std::pair p = c.insert(d); -// if (!p.second) p.first->second = d.second; // Who's on first? -// return p.first; -// } + // template + // inline + // static + // typename containerT::iterator replace(containerT& c, const datumT& d) { + // std::pair p = c.insert(d); + // if (!p.second) p.first->second = d.second; // Who's on first? + // return p.first; + // } private: + WorldContainerImpl(); // Inhibit default constructor - WorldContainerImpl(); // Inhibit default constructor - - std::shared_ptr< WorldDCPmapInterface > pmap;///< Function/class to map from keys to owning process - const ProcessID me; ///< My MPI rank - internal_containerT local; ///< Locally owned data - std::vector* move_list; ///< Tempoary used to record data that needs redistributing + std::shared_ptr> pmap; ///< Function/class to map from keys to owning process + const ProcessID me; ///< My MPI rank + internal_containerT local; ///< Locally owned data + std::vector *move_list; ///< Tempoary used to record data that needs redistributing /// Handles find request - void find_handler(ProcessID requestor, const keyT& key, const RemoteReference< FutureImpl >& ref) { + void find_handler(ProcessID requestor, const keyT &key, const RemoteReference> &ref) + { internal_iteratorT r = local.find(key); - if (r == local.end()) { - //print("find_handler: failure:", key); + if (r == local.end()) + { + // print("find_handler: failure:", key); this->send(requestor, &implT::find_failure_handler, ref); } - else { - //print("find_handler: success:", key, r->first, r->second); + else + { + // print("find_handler: success:", key, r->first, r->second); this->send(requestor, &implT::find_success_handler, ref, *r); } } /// Handles successful find response - void find_success_handler(const RemoteReference< FutureImpl >& ref, const pairT& datum) { - FutureImpl* f = ref.get(); + void find_success_handler(const RemoteReference> &ref, const pairT &datum) + { + FutureImpl *f = ref.get(); f->set(iterator(datum)); - //print("find_success_handler: success:", datum.first, datum.second, f->get()->first, f->get()->second); - // Todo: Look at this again. -// ref.reset(); // Matching inc() in find() where ref was made + // print("find_success_handler: success:", datum.first, datum.second, f->get()->first, f->get()->second); + // Todo: Look at this again. + // ref.reset(); // Matching inc() in find() where ref was made } /// Handles unsuccessful find response - void find_failure_handler(const RemoteReference< FutureImpl >& ref) { - FutureImpl* f = ref.get(); + void find_failure_handler(const RemoteReference> &ref) + { + FutureImpl *f = ref.get(); f->set(end()); - //print("find_failure_handler"); - // Todo: Look at this again. -// ref.reset(); // Matching inc() in find() where ref was made + // print("find_failure_handler"); + // Todo: Look at this again. + // ref.reset(); // Matching inc() in find() where ref was made } public: - - WorldContainerImpl(World& world, - const std::shared_ptr< WorldDCPmapInterface >& pm, - const hashfunT& hf) - : WorldObject< WorldContainerImpl >(world) - , pmap(pm) - , me(world.mpi.rank()) - , local(5011, hf) { + WorldContainerImpl(World &world, + const std::shared_ptr> &pm, + const hashfunT &hf) + : WorldObject>(world), pmap(pm), me(world.mpi.rank()), local(5011, hf) + { pmap->register_callback(this); } - virtual ~WorldContainerImpl() { + virtual ~WorldContainerImpl() + { pmap->deregister_callback(this); } - const std::shared_ptr< WorldDCPmapInterface >& get_pmap() const { + const std::shared_ptr> &get_pmap() const + { return pmap; } - std::shared_ptr< WorldDCPmapInterface >& get_pmap() { + std::shared_ptr> &get_pmap() + { return pmap; } - void reset_pmap_to_local() { + void reset_pmap_to_local() + { pmap->deregister_callback(this); pmap.reset(new WorldDCLocalPmap(this->get_world())); pmap->register_callback(this); @@ -454,51 +498,61 @@ namespace madness { /// replicates this WorldContainer on all ProcessIDs and generates a /// ProcessMap where all nodes are local - void replicate(bool fence) { - - World& world=this->get_world(); - pmap->deregister_callback(this); - pmap.reset(new WorldDCLocalPmap(world)); - pmap->register_callback(this); - - for (ProcessID rank=0; rankfirst; - valueT value = it->second; - world.gop.broadcast_serializable(key, rank); - world.gop.broadcast_serializable(value, rank); - } - } - else { - size_t sz; - world.gop.broadcast_serializable(sz, rank); - for (size_t i=0; iget_world(); + pmap->deregister_callback(this); + pmap.reset(new WorldDCLocalPmap(world)); + pmap->register_callback(this); + + for (ProcessID rank = 0; rank < world.size(); rank++) + { + if (rank == world.rank()) + { + std::size_t sz = size(); + world.gop.broadcast_serializable(sz, rank); + + for (auto it = begin(); it != end(); ++it) + { + keyT key = it->first; + valueT value = it->second; + world.gop.broadcast_serializable(key, rank); + world.gop.broadcast_serializable(value, rank); + } + } + else + { + size_t sz; + world.gop.broadcast_serializable(sz, rank); + for (size_t i = 0; i < sz; i++) + { + keyT key; + valueT value; + world.gop.broadcast_serializable(key, rank); + world.gop.broadcast_serializable(value, rank); + insert(pairT(key, value)); + } + } + } + if (fence) + world.gop.fence(); + } + + hashfunT &get_hash() const { return local.get_hash(); } + + bool is_local(const keyT &key) const + { return owner(key) == me; } - ProcessID owner(const keyT& key) const { + ProcessID owner(const keyT &key) const + { return pmap->owner(key); } - bool probe(const keyT& key) const { + bool probe(const keyT &key) const + { ProcessID dest = owner(key); if (dest == me) return local.find(key) != local.end(); @@ -506,123 +560,146 @@ namespace madness { return false; } - std::size_t size() const { + std::size_t size() const + { return local.size(); } - void insert(const pairT& datum) { + void insert(const pairT &datum) + { ProcessID dest = owner(datum.first); - if (dest == me) { + if (dest == me) + { // Was using iterator ... try accessor ????? accessor acc; // N.B. key might already exist if want to simply replace - [[maybe_unused]] auto inserted = local.insert(acc,datum.first); + [[maybe_unused]] auto inserted = local.insert(acc, datum.first); acc->second = datum.second; } - else { - // Must be send (not task) for sequential consistency (and relies on single-threaded remote server) + else + { + // Must be send (not task) for sequential consistency (and relies on single-threaded remote server) this->send(dest, &implT::insert, datum); } } - bool insert_acc(accessor& acc, const keyT& key) { + bool insert_acc(accessor &acc, const keyT &key) + { MADNESS_ASSERT(owner(key) == me); - return local.insert(acc,key); + return local.insert(acc, key); } - bool insert_const_acc(const_accessor& acc, const keyT& key) { + bool insert_const_acc(const_accessor &acc, const keyT &key) + { MADNESS_ASSERT(owner(key) == me); - return local.insert(acc,key); + return local.insert(acc, key); } - void clear() { + void clear() + { local.clear(); } - - void erase(const keyT& key) { + void erase(const keyT &key) + { ProcessID dest = owner(key); - if (dest == me) { + if (dest == me) + { [[maybe_unused]] auto erased = local.try_erase(key); MADNESS_ASSERT(erased); } - else { - void(implT::*eraser)(const keyT&) = &implT::erase; + else + { + void (implT::*eraser)(const keyT &) = &implT::erase; this->send(dest, eraser, key); } } template - void erase(InIter it) { + void erase(InIter it) + { MADNESS_ASSERT(!it.is_cached()); MADNESS_ASSERT(it != end()); erase(it->first); } template - void erase(InIter first, InIter last) { + void erase(InIter first, InIter last) + { InIter it = first; - do { + do + { first++; erase(it->first); it = first; - } while(first != last); + } while (first != last); } - iterator begin() { + iterator begin() + { return iterator(local.begin()); } - const_iterator begin() const { + const_iterator begin() const + { return const_iterator(local.begin()); } - iterator end() { + iterator end() + { return iterator(local.end()); } - const_iterator end() const { + const_iterator end() const + { return const_iterator(local.end()); } - Future find(const keyT& key) const { + Future find(const keyT &key) const + { // Ugliness here to avoid replicating find() and // associated handlers for const. Assumption is that // const and non-const iterators are identical except for // const attribute ... at some point probably need to do // the right thing. - Future r = const_cast(this)->find(key); - return *(Future*)(&r); + Future r = const_cast(this)->find(key); + return *(Future *)(&r); } - - Future find(const keyT& key) { + Future find(const keyT &key) + { ProcessID dest = owner(key); - if (dest == me) { + if (dest == me) + { return Future(iterator(local.find(key))); - } else { + } + else + { Future result; this->send(dest, &implT::find_handler, me, key, result.remote_ref(this->get_world())); return result; } } - bool find(accessor& acc, const keyT& key) { - if (owner(key) != me) return false; - return local.find(acc,key); + bool find(accessor &acc, const keyT &key) + { + if (owner(key) != me) + return false; + return local.find(acc, key); } - - bool find(const_accessor& acc, const keyT& key) const { - if (owner(key) != me) return false; - return local.find(acc,key); + bool find(const_accessor &acc, const keyT &key) const + { + if (owner(key) != me) + return false; + return local.find(acc, key); } - // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun) { + itemfun(const keyT &key, memfunT memfun) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); @@ -632,7 +709,8 @@ namespace madness { // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); @@ -642,110 +720,122 @@ namespace madness { // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2); + return (acc->second.*memfun)(arg1, arg2); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3); + return (acc->second.*memfun)(arg1, arg2, arg3); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3,arg4); + return (acc->second.*memfun)(arg1, arg2, arg3, arg4); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3,arg4,arg5); + return (acc->second.*memfun)(arg1, arg2, arg3, arg4, arg5); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3,arg4,arg5,arg6); + return (acc->second.*memfun)(arg1, arg2, arg3, arg4, arg5, arg6); } // Used to forward call to item member function template MEMFUN_RETURNT(memfunT) - itemfun(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, - const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const arg7T& arg7) { + itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, + const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7) + { accessor acc; // N.B. key may already exist, this is just to ensure lock is held by acc [[maybe_unused]] auto inserted = local.insert(acc, key); - return (acc->second.*memfun)(arg1,arg2,arg3,arg4,arg5,arg6,arg7); + return (acc->second.*memfun)(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } // First phase of redistributions changes pmap and makes list of stuff to move - void redistribute_phase1(const std::shared_ptr< WorldDCPmapInterface >& newpmap) { + void redistribute_phase1(const std::shared_ptr> &newpmap) + { pmap = newpmap; move_list = new std::vector(); - for (typename internal_containerT::iterator iter=local.begin(); iter!=local.end(); ++iter) { - if (owner(iter->first) != me) move_list->push_back(iter->first); + for (typename internal_containerT::iterator iter = local.begin(); iter != local.end(); ++iter) + { + if (owner(iter->first) != me) + move_list->push_back(iter->first); } } - struct P2Op { - implT * impl; - typedef Range::const_iterator> rangeT; - P2Op(implT* impl) : impl(impl) {} - P2Op(const P2Op& p) : impl(p.impl) {} - bool operator()(typename rangeT::iterator& iterator) const { - typename internal_containerT::iterator iter = impl->local.find(*iterator); - MADNESS_ASSERT(iter != impl->local.end()); - - //impl->insert(*iter); - impl->task(impl->owner(*iterator), &implT::insert, *iter); - - impl->local.erase(iter); // delete local copy of the data - return true; - } - }; + struct P2Op + { + implT *impl; + typedef Range::const_iterator> rangeT; + P2Op(implT *impl) : impl(impl) {} + P2Op(const P2Op &p) : impl(p.impl) {} + bool operator()(typename rangeT::iterator &iterator) const + { + typename internal_containerT::iterator iter = impl->local.find(*iterator); + MADNESS_ASSERT(iter != impl->local.end()); + + // impl->insert(*iter); + impl->task(impl->owner(*iterator), &implT::insert, *iter); + + impl->local.erase(iter); // delete local copy of the data + return true; + } + }; // Second phase moves data - void redistribute_phase2() { - this->get_world().taskq.for_each(typename P2Op::rangeT(move_list->begin(), move_list->end()), P2Op(this)); - //std::vector& mvlist = *move_list; - //for (unsigned int i=0; isize(); ++i) { - // typename internal_containerT::iterator iter = local.find(mvlist[i]); - // MADNESS_ASSERT(iter != local.end()); - // insert(*iter); - // local.erase(iter); - //} - //delete move_list; + void redistribute_phase2() + { + this->get_world().taskq.for_each(typename P2Op::rangeT(move_list->begin(), move_list->end()), P2Op(this)); + // std::vector& mvlist = *move_list; + // for (unsigned int i=0; isize(); ++i) { + // typename internal_containerT::iterator iter = local.find(mvlist[i]); + // MADNESS_ASSERT(iter != local.end()); + // insert(*iter); + // local.erase(iter); + // } + // delete move_list; } // Third phase cleans up - void redistribute_phase3() { - delete move_list; + void redistribute_phase3() + { + delete move_list; } }; - /// Makes a distributed container with specified attributes /// \ingroup worlddc @@ -771,11 +861,12 @@ namespace madness { /// All operations, including constructors and destructors, are /// non-blocking and return immediately. If communication occurs /// it is asynchronous, otherwise operations are local. - template > - class WorldContainer : public archive::ParallelSerializableObject { + template > + class WorldContainer : public archive::ParallelSerializableObject + { public: - typedef WorldContainer containerT; - typedef WorldContainerImpl implT; + typedef WorldContainer containerT; + typedef WorldContainerImpl implT; typedef typename implT::pairT pairT; typedef typename implT::iterator iterator; typedef typename implT::const_iterator const_iterator; @@ -787,20 +878,21 @@ namespace madness { private: std::shared_ptr p; - inline void check_initialized() const { + inline void check_initialized() const + { MADNESS_ASSERT(p); } - public: + public: /// Makes an uninitialized container (no communication) /// The container is useless until assigned to from a fully /// constructed container. There is no need to worry about /// default constructors being executed in order. WorldContainer() - : p() - {} - + : p() + { + } /// Makes an initialized, empty container with default data distribution (no communication) @@ -809,12 +901,12 @@ namespace madness { /// making a container, we have to assume that all processes /// execute this constructor in the same order (does not apply /// to the non-initializing, default constructor). - WorldContainer(World& world, bool do_pending=true, const hashfunT& hf = hashfunT()) + WorldContainer(World &world, bool do_pending = true, const hashfunT &hf = hashfunT()) : p(new implT(world, - std::shared_ptr< WorldDCPmapInterface >(new WorldDCDefaultPmap(world, hf)), + std::shared_ptr>(new WorldDCDefaultPmap(world, hf)), hf)) { - if(do_pending) + if (do_pending) p->process_pending(); } @@ -825,22 +917,21 @@ namespace madness { /// making a container, we have to assume that all processes /// execute this constructor in the same order (does not apply /// to the non-initializing, default constructor). - WorldContainer(World& world, - const std::shared_ptr< WorldDCPmapInterface >& pmap, - bool do_pending=true, - const hashfunT& hf = hashfunT()) + WorldContainer(World &world, + const std::shared_ptr> &pmap, + bool do_pending = true, + const hashfunT &hf = hashfunT()) : p(new implT(world, pmap, hf)) { - if(do_pending) + if (do_pending) p->process_pending(); } - /// Copy constructor is shallow (no communication) /// The copy refers to exactly the same container as other /// which must be initialized. - WorldContainer(const WorldContainer& other) + WorldContainer(const WorldContainer &other) : p(other.p) { check_initialized(); @@ -850,8 +941,10 @@ namespace madness { /// The copy refers to exactly the same container as other /// which must be initialized. - containerT& operator=(const containerT& other) { - if (this != &other) { + containerT &operator=(const containerT &other) + { + if (this != &other) + { other.check_initialized(); p = other.p; } @@ -859,140 +952,146 @@ namespace madness { } /// Returns the world associated with this container - World& get_world() const { + World &get_world() const + { check_initialized(); return p->get_world(); } - std::shared_ptr< WorldDCPmapInterface >& get_impl() { + std::shared_ptr> &get_impl() + { check_initialized(); return p; } /// replicates this WorldContainer on all ProcessIDs - void replicate(bool fence=true) { - p->replicate(fence); + void replicate(bool fence = true) + { + p->replicate(fence); } /// Inserts/replaces key+value pair (non-blocking communication if key not local) - void replace(const pairT& datum) { + void replace(const pairT &datum) + { check_initialized(); p->insert(datum); } - /// Inserts/replaces key+value pair (non-blocking communication if key not local) - void replace(const keyT& key, const valueT& value) { - replace(pairT(key,value)); + void replace(const keyT &key, const valueT &value) + { + replace(pairT(key, value)); } - /// Write access to LOCAL value by key. Returns true if found, false otherwise (always false for remote). - bool find(accessor& acc, const keyT& key) { + bool find(accessor &acc, const keyT &key) + { check_initialized(); - return p->find(acc,key); + return p->find(acc, key); } - /// Read access to LOCAL value by key. Returns true if found, false otherwise (always false for remote). - bool find(const_accessor& acc, const keyT& key) const { + bool find(const_accessor &acc, const keyT &key) const + { check_initialized(); - return p->find(acc,key); + return p->find(acc, key); } - /// Write access to LOCAL value by key. Returns true if inserted, false if already exists (throws if remote) - bool insert(accessor& acc, const keyT& key) { + bool insert(accessor &acc, const keyT &key) + { check_initialized(); - return p->insert_acc(acc,key); + return p->insert_acc(acc, key); } - /// Read access to LOCAL value by key. Returns true if inserted, false if already exists (throws if remote) - bool insert(const_accessor& acc, const keyT& key) { + bool insert(const_accessor &acc, const keyT &key) + { check_initialized(); - return p->insert_acc(acc,key); + return p->insert_acc(acc, key); } - /// Inserts pairs (non-blocking communication if key(s) not local) template - void replace(input_iterator& start, input_iterator& end) { + void replace(input_iterator &start, input_iterator &end) + { check_initialized(); using std::placeholders::_1; - std::for_each(start,end,std::bind(this,std::mem_fn(&containerT::insert),_1)); + std::for_each(start, end, std::bind(this, std::mem_fn(&containerT::insert), _1)); } - /// Returns true if local data is immediately available (no communication) - bool probe(const keyT& key) const { + bool probe(const keyT &key) const + { check_initialized(); return p->probe(key); } - /// Returns processor that logically owns key (no communication) /// Local remapping may have changed its physical location, but all /// operations should forward correctly. - inline ProcessID owner(const keyT& key) const { + inline ProcessID owner(const keyT &key) const + { check_initialized(); return p->owner(key); } - /// Returns true if the key maps to the local processor (no communication) - bool is_local(const keyT& key) const { + bool is_local(const keyT &key) const + { check_initialized(); return p->is_local(key); } - /// Returns a future iterator (non-blocking communication if key not local) /// Like an std::map an iterator "points" to an std::pair. /// /// Refer to Future for info on how to avoid blocking. - Future find(const keyT& key) { // + Future find(const keyT &key) + { // check_initialized(); return p->find(key); } - /// Returns a future iterator (non-blocking communication if key not local) /// Like an std::map an iterator "points" to an std::pair. /// /// Refer to Future for info on how to avoid blocking. - Future find(const keyT& key) const { + Future find(const keyT &key) const + { check_initialized(); - return const_cast(p.get())->find(key); + return const_cast(p.get())->find(key); } - /// Returns an iterator to the beginning of the \em local data (no communication) - iterator begin() { + iterator begin() + { check_initialized(); return p->begin(); } - /// Returns an iterator to the beginning of the \em local data (no communication) - const_iterator begin() const { + const_iterator begin() const + { check_initialized(); - return const_cast(p.get())->begin(); + return const_cast(p.get())->begin(); } /// Returns an iterator past the end of the \em local data (no communication) - iterator end() { + iterator end() + { check_initialized(); return p->end(); } /// Returns an iterator past the end of the \em local data (no communication) - const_iterator end() const { + const_iterator end() const + { check_initialized(); - return const_cast(p.get())->end(); + return const_cast(p.get())->end(); } /// Erases entry from container (non-blocking comm if remote) @@ -1003,51 +1102,58 @@ namespace madness { /// remote end. This is just the same as what happens when /// using STL iterators on an STL container in a sequential /// algorithm. - void erase(const keyT& key) { + void erase(const keyT &key) + { check_initialized(); p->erase(key); } /// Erases entry corresponding to \em local iterator (no communication) - void erase(const iterator& it) { + void erase(const iterator &it) + { check_initialized(); p->erase(it); } /// Erases range defined by \em local iterators (no communication) - void erase(const iterator& start, const iterator& finish) { + void erase(const iterator &start, const iterator &finish) + { check_initialized(); - p->erase(start,finish); + p->erase(start, finish); } - /// Clears all \em local data (no communication) /// Invalidates all iterators - void clear() { + void clear() + { check_initialized(); p->clear(); } /// Returns the number of \em local entries (no communication) - std::size_t size() const { + std::size_t size() const + { check_initialized(); return p->size(); } /// Returns shared pointer to the process mapping - inline const std::shared_ptr< WorldDCPmapInterface >& get_pmap() const { + inline const std::shared_ptr> &get_pmap() const + { check_initialized(); return p->get_pmap(); } /// Returns shared pointer to the process mapping - inline void reset_pmap_to_local() { + inline void reset_pmap_to_local() + { p->reset_pmap_to_local(); } /// Returns a reference to the hashing functor - hashfunT& get_hash() const { + hashfunT &get_hash() const + { check_initialized(); return p->get_hash(); } @@ -1057,7 +1163,8 @@ namespace madness { /// If the constructor was given \c do_pending=false then you /// \em must invoke this routine in order to process both /// prior and future messages. - inline void process_pending() { + inline void process_pending() + { check_initialized(); p->process_pending(); } @@ -1072,14 +1179,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< MEMFUN_RETURNT(memfunT) > - send(const keyT& key, memfunT memfun) { + Future + send(const keyT &key, memfunT memfun) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun); } - /// Sends message "resultT memfun(arg1T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1090,18 +1198,19 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, const memfunT& memfun, const arg1T& arg1) { + Future + send(const keyT &key, const memfunT &memfun, const arg1T &arg1) + { check_initialized(); // To work around bug in g++ 4.3.* use static cast as alternative mechanism to force type deduction - MEMFUN_RETURNT(memfunT) (implT::*itemfun)(const keyT&, memfunT, const arg1T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1); /*return p->send(owner(key), static_cast(&implT:: template itemfun), key, memfun, arg1);*/ } - /// Sends message "resultT memfun(arg1T,arg2T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1112,17 +1221,18 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2) + { check_initialized(); // To work around bug in g++ 4.3.* use static cast as alternative mechanism to force type deduction - MEMFUN_RETURNT(memfunT) (implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2); /*return p->send(owner(key), static_cast(&implT:: template itemfun), key, memfun, arg1, arg2);*/ } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1133,14 +1243,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1151,14 +1262,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&, const arg4T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1169,14 +1281,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&, const arg4T&, const arg5T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &, const arg5T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1187,14 +1300,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&, const arg4T&, const arg5T&, const arg6T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &, const arg5T &, const arg6T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T)" to item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1205,91 +1319,98 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, - const arg5T& arg5, const arg6T& arg6, const arg7T& arg7) { + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, + const arg5T &arg5, const arg6T &arg6, const arg7T &arg7) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const arg1T&, const arg2T&, const arg3T&, const arg4T&, const arg5T&, const arg6T&, const arg7T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &, const arg5T &, const arg6T &, const arg7T &) = &implT::template itemfun; return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - /// Sends message "resultT memfun() const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun) const { - return const_cast(this)->send(key,memfun); + Future + send(const keyT &key, memfunT memfun) const + { + return const_cast(this)->send(key, memfun); } /// Sends message "resultT memfun(arg1T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1) const { - return const_cast(this)->send(key,memfun,arg1); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1) const + { + return const_cast(this)->send(key, memfun, arg1); } /// Sends message "resultT memfun(arg1T,arg2T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2) const { - return const_cast(this)->send(key,memfun,arg1,arg2); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2) const + { + return const_cast(this)->send(key, memfun, arg1, arg2); } - /// Sends message "resultT memfun(arg1T,arg2T,arg3T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3); } /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3,arg4); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3, arg4); } /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3,arg4,arg5); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3, arg4, arg5); } /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, - const arg4T& arg4, const arg5T& arg5, const arg6T& arg6) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3,arg4,arg5,arg6); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, + const arg4T &arg4, const arg5T &arg5, const arg6T &arg6) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6); } /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T) const" to item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - send(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, - const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const arg7T& arg7) const { - return const_cast(this)->send(key,memfun,arg1,arg2,arg3,arg4,arg5,arg6,arg7); + Future + send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, + const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7) const + { + return const_cast(this)->send(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - /// Adds task "resultT memfun()" in process owning item (non-blocking comm if remote) /// If item does not exist it is made with the default constructor. @@ -1301,10 +1422,12 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, attr); } @@ -1319,11 +1442,13 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, attr); } @@ -1338,12 +1463,14 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, attr); } @@ -1358,13 +1485,15 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; typedef REMFUTURE(arg3T) a3T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, attr); } @@ -1379,14 +1508,16 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; typedef REMFUTURE(arg3T) a3T; typedef REMFUTURE(arg4T) a4T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&, const a4T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, attr); } @@ -1401,15 +1532,17 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; typedef REMFUTURE(arg3T) a3T; typedef REMFUTURE(arg4T) a4T; typedef REMFUTURE(arg5T) a5T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&, const a4T&, const a5T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &, const a5T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, attr); } @@ -1424,8 +1557,9 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; @@ -1433,7 +1567,8 @@ namespace madness { typedef REMFUTURE(arg4T) a4T; typedef REMFUTURE(arg5T) a5T; typedef REMFUTURE(arg6T) a6T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&, const a4T&, const a5T&, const a6T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &, const a5T &, const a6T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, attr); } @@ -1448,8 +1583,9 @@ namespace madness { /// /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const arg7T& arg7, const TaskAttributes& attr = TaskAttributes()) { + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7, const TaskAttributes &attr = TaskAttributes()) + { check_initialized(); typedef REMFUTURE(arg1T) a1T; typedef REMFUTURE(arg2T) a2T; @@ -1458,7 +1594,8 @@ namespace madness { typedef REMFUTURE(arg5T) a5T; typedef REMFUTURE(arg6T) a6T; typedef REMFUTURE(arg7T) a7T; - MEMFUN_RETURNT(memfunT)(implT::*itemfun)(const keyT&, memfunT, const a1T&, const a2T&, const a3T&, const a4T&, const a5T&, const a6T&, const a7T&) = &implT:: template itemfun; + MEMFUN_RETURNT(memfunT) + (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &, const a5T &, const a6T &, const a7T &) = &implT::template itemfun; return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7, attr); } @@ -1466,80 +1603,88 @@ namespace madness { /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,attr); + Future + task(const keyT &key, memfunT memfun, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, attr); } /// Adds task "resultT memfun(arg1T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, attr); } /// Adds task "resultT memfun(arg1T,arg2T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T, arg4T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,arg4,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, arg4, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,arg4,arg5,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, arg4, arg5, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,arg4,arg5,arg6,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, attr); } /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T) const" in process owning item (non-blocking comm if remote) /// The method executes with a write lock on the item. template - Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > - task(const keyT& key, memfunT memfun, const arg1T& arg1, const arg2T& arg2, const arg3T& arg3, const arg4T& arg4, const arg5T& arg5, const arg6T& arg6, const arg7T& arg7, const TaskAttributes& attr = TaskAttributes()) const { - return const_cast(this)->task(key,memfun,arg1,arg2,arg3,arg4,arg5,arg6,arg7,attr); + Future + task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7, const TaskAttributes &attr = TaskAttributes()) const + { + return const_cast(this)->task(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7, attr); } - /// (de)Serialize --- *Local* data only to/from anything *except* Buffer*Archive and Parallel*Archive /// Advisable for *you* to fence before and after this to ensure consistency template - void serialize(const Archive& ar) { + void serialize(const Archive &ar) + { // // !! If you change the format of this stream make sure that // !! the parallel in/out archive below is compatible @@ -1548,18 +1693,23 @@ namespace madness { unsigned long count = 0; check_initialized(); - if (Archive::is_output_archive) { + if (Archive::is_output_archive) + { ar & magic; - for (iterator it=begin(); it!=end(); ++it) count++; + for (iterator it = begin(); it != end(); ++it) + count++; ar & count; - for (iterator it=begin(); it!=end(); ++it) ar & *it; + for (iterator it = begin(); it != end(); ++it) + ar &*it; } - else { + else + { long cookie = 0l; ar & cookie; MADNESS_ASSERT(cookie == magic); ar & count; - while (count--) { + while (count--) + { pairT datum; ar & datum; replace(datum); @@ -1570,49 +1720,55 @@ namespace madness { /// (de)Serialize --- !! ONLY for purpose of interprocess communication /// This just writes/reads the unique id to/from the Buffer*Archive. - void serialize(const archive::BufferOutputArchive& ar) { + void serialize(const archive::BufferOutputArchive &ar) + { check_initialized(); - ar & static_cast*>(p.get()); + ar &static_cast *>(p.get()); } /// (de)Serialize --- !! ONLY for purpose of interprocess communication /// This just writes/reads the unique id to/from the Buffer*Archive. - void serialize(const archive::BufferInputArchive& ar) { - WorldObject* ptr = nullptr; + void serialize(const archive::BufferInputArchive &ar) + { + WorldObject *ptr = nullptr; ar & ptr; MADNESS_ASSERT(ptr); #ifdef MADNESS_DISABLE_SHARED_FROM_THIS - p.reset(static_cast(ptr), [] (implT *p_) -> void {}); + p.reset(static_cast(ptr), [](implT *p_) -> void{}); #else - p = static_cast(ptr)->shared_from_this(); + p = static_cast(ptr)->shared_from_this(); #endif // MADNESS_DISABLE_SHARED_FROM_THIS } /// Returns the associated unique id ... must be initialized - const uniqueidT& id() const { + const uniqueidT &id() const + { check_initialized(); return p->id(); } /// Destructor passes ownership of implementation to world for deferred cleanup - virtual ~WorldContainer() { + virtual ~WorldContainer() + { detail::deferred_cleanup(p->get_world(), p); } - friend void swap<>(WorldContainer&, WorldContainer&); + friend void swap<>(WorldContainer &, WorldContainer &); }; /// Swaps the content of two WorldContainer objects. It should be called on all nodes. /// \ingroup worlddc template - void swap(WorldContainer& dc0, WorldContainer& dc1) { - std::swap(dc0.p, dc1.p); + void swap(WorldContainer &dc0, WorldContainer &dc1) + { + std::swap(dc0.p, dc1.p); } - namespace archive { + namespace archive + { /// Write container to parallel archive @@ -1620,119 +1776,189 @@ namespace madness { /// all threads on each process serialize some values into a buffer, which gets concatenated /// and finally serialized to localarchive (aka VectorOutputArchive). template - struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { - static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { + struct ArchiveStoreImpl, WorldContainer> + { + static void store(const ParallelOutputArchive &ar, const WorldContainer &t) + { using localarchiveT = VectorOutputArchive; const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) - typedef WorldContainer dcT; + typedef WorldContainer dcT; using const_iterator = typename dcT::const_iterator; + int count = t.size(); // Must be INT for MPI and NOT const since we'll do a global sum eventually - // const size_t default_size = 100*1024*1024; - // const size_t default_size = 8ul<<30; + // Strategy: + // 1. Serialize local data to a buffer in parallel over threads + // a) Compute the size of the buffer needed by each task + // b) Sum sizes and allocate the buffer of exact sizes needed for all threads + // c) Serialize the data into the buffer in parallel over threads + // 2. Gather all buffers to process 0 - World* world = ar.get_world(); - world->gop.fence(); + World *world = ar.get_world(); + world->gop.fence(); // Global fence here - class op_serialize : public TaskInterface { - const size_t ntasks; - const size_t taskid; - const dcT& t; - std::vector& v; + class op_inspector : public TaskInterface + { + const_iterator start, end; + size_t &size; public: - op_serialize(size_t ntasks, size_t taskid, const dcT& t, std::vector& v) - : ntasks(ntasks), taskid(taskid), t(t), v(v) {} - void run(World& world) { - std::size_t hint_size=(1ul<<30)/ntasks; - VectorOutputArchive var(v,hint_size); - const_iterator it=t.begin(); - size_t n = 0; - /// threads serialize round-robin over the container - while (it!=t.end()) { - if ((n%ntasks) == taskid) { - var & *it; - } - ++it; - n++; - } + op_inspector(const_iterator start, const_iterator end, size_t &size) + : start(start), end(end), size(size) {} + void run(World &world) + { + BufferOutputArchive bo; + for (const_iterator it = start; it != end; ++it) + bo &*it; + size = bo.size(); } }; - class op_concat : public TaskInterface { - unsigned char* all_data; - const std::vector& v; + class op_executor : public TaskInterface + { + const_iterator start, end; + unsigned char *buf; + const size_t size; + public: - op_concat(unsigned char* all_data, const std::vector& v) - : all_data(all_data), v(v) {} - void run(World& world) { - memcpy(all_data, v.data(), v.size()); + op_executor(const_iterator start, const_iterator end, unsigned char *buf, size_t size) + : start(start), end(end), buf(buf), size(size) {} + void run(World &world) + { + BufferOutputArchive bo(buf, size); + for (const_iterator it = start; it != end; ++it) + { + bo &*it; + } + MADNESS_CHECK(size == bo.size()); } }; - world->gop.fence(); - double wall0=wall_time(); - Mutex mutex; - size_t ntasks = std::max(size_t(1), ThreadPool::size()); + // No need for LOCAL fence here since only master thread is busy + double wall0 = wall_time(); + const size_t ntasks = std::min(size_t(count), std::max(size_t(1), ThreadPool::size())); + size_t local_size = 0; + double wall1 = wall0; + unsigned char* buf = 0; + if (ntasks > 0) + { + const size_t max_items_per_task = (std::max(1, count) - 1) / ntasks + 1; + // Compute the size of the buffer needed by each task + const_iterator starts[ntasks], ends[ntasks]; + size_t local_sizes[ntasks]; + const_iterator start = t.begin(); + size_t nleft = count; + for (size_t taskid = 0; taskid < ntasks; taskid++) + { + const_iterator end = start; + if (taskid == (ntasks - 1)) + { + end = t.end(); + } + else + { + size_t nitems = std::min(max_items_per_task, nleft); + std::advance(end, max_items_per_task); + nleft -= nitems; + } + starts[taskid] = start; + ends[taskid] = end; + world->taskq.add(new op_inspector(start, end, local_sizes[taskid])); // Be sure to pass iterators by value!! + start = end; + } + world->taskq.fence(); // just need LOCAL fence + wall1 = wall_time(); + if (world->rank() == 0) + printf("time in op_inspector: %8.4fs\n", wall1 - wall0); + wall0 = wall1; + + // total size over all threads + for (size_t taskid = 0; taskid < ntasks; taskid++) + { + local_size += local_sizes[taskid]; + // print("taskid",taskid,"size",local_sizes[taskid]); + } - std::vector> v(ntasks); - for (size_t taskid=0; taskidtaskq.add(new op_serialize(ntasks, taskid, t, v[taskid])); - world->gop.fence(); - // total size of all vectors - size_t total_size = 0; - for (size_t taskid=0; taskid vtotal(total_size); - - size_t offset = 0; - for (size_t taskid=0; taskidtaskq.add(new op_concat(&vtotal[offset], v[taskid])); - offset += v[taskid].size(); + // Allocate the buffer for all threads + buf = new unsigned char[local_size]; + + // Now execute the serialization + size_t offset = 0; + for (size_t taskid = 0; taskid < ntasks; taskid++) + { + world->taskq.add(new op_executor(starts[taskid], ends[taskid], buf + offset, local_sizes[taskid])); + offset += local_sizes[taskid]; + } + world->taskq.fence(); // just need LOCAL fence + + wall1 = wall_time(); + if (world->rank() == 0) + printf("time in op_executor: %8.4fs\n", wall1 - wall0); + wall0 = wall1; } - v.clear(); + // VERify that the serialization worked!! + // { + // BufferInputArchive bi(buf, local_size); + // for (int item=0; item datum; + // bi & datum; + // print("deserializing",datum.first); + // } + // } - double wall1=wall_time(); - if (world->rank()==0) printf("time in the taskq: %8.4fs\n",wall1-wall0); // Gather all buffers to process 0 // first gather all of the sizes and counts to a vector in process 0 - int size = vtotal.size(); - int count = t.size(); + const int size = local_size; std::vector sizes(world->size()); MPI_Gather(&size, 1, MPI_INT, sizes.data(), 1, MPI_INT, 0, world->mpi.comm().Get_mpi_comm()); world->gop.sum(count); // just need total number of elements - print("time 3",wall_time()); - // build the cumulative sum of sizes + // print("time 3",wall_time()); + // build the cumulative sum of sizes std::vector offsets(world->size()); offsets[0] = 0; - for (int i=1; isize(); ++i) offsets[i] = offsets[i-1] + sizes[i-1]; - MADNESS_CHECK(offsets.back() + sizes.back() == total_size); + for (int i = 1; i < world->size(); ++i) + offsets[i] = offsets[i - 1] + sizes[i - 1]; + size_t total_size = offsets.back() + sizes.back(); + if (world->rank() == 0) + print("total_size", total_size); - print("time 4",wall_time()); + // print("time 4",wall_time()); // gather the vector of data v from each process to process 0 - unsigned char* all_data=0; - if (world->rank() == 0) { + unsigned char *all_data = 0; + if (world->rank() == 0) + { all_data = new unsigned char[total_size]; } - MPI_Gatherv(vtotal.data(), vtotal.size(), MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); + MPI_Gatherv(buf, local_size, MPI_BYTE, all_data, sizes.data(), offsets.data(), MPI_BYTE, 0, world->mpi.comm().Get_mpi_comm()); + + wall1 = wall_time(); + if (world->rank() == 0) + printf("time in gather+gatherv: %8.4fs\n", wall1 - wall0); + wall0 = wall1; + + delete[] buf; - print("time 5",wall_time()); - if (world->rank() == 0) { - auto& localar = ar.local_archive(); + // print("time 5",wall_time()); + if (world->rank() == 0) + { + auto &localar = ar.local_archive(); localar & magic & 1; // 1 client // localar & t; - ArchivePrePostImpl::preamble_store(localar); - localar & -magic & count; + ArchivePrePostImpl::preamble_store(localar); + localar & -magic &(unsigned long)(count); localar.store(all_data, total_size); - ArchivePrePostImpl::postamble_store(localar); + ArchivePrePostImpl::postamble_store(localar); + wall1 = wall_time(); + if (world->rank() == 0) + printf("time in final copy on node 0: %8.4fs\n", wall1 - wall0); delete[] all_data; } world->gop.fence(); - print("time 6",wall_time()); + // print("time 6",wall_time()); } }; - /// Write container to parallel archive with optional fence /// \ingroup worlddc @@ -1751,57 +1977,68 @@ namespace madness { /// subsequent modifications. Also, there is always at least /// some synchronization between a client and its IO server. template - struct ArchiveStoreImpl< ParallelOutputArchive, WorldContainer > { - static void store(const ParallelOutputArchive& ar, const WorldContainer& t) { + struct ArchiveStoreImpl, WorldContainer> + { + static void store(const ParallelOutputArchive &ar, const WorldContainer &t) + { const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) - typedef WorldContainer dcT; + typedef WorldContainer dcT; // typedef typename dcT::const_iterator iterator; // unused? typedef typename dcT::pairT pairT; - World* world = ar.get_world(); + World *world = ar.get_world(); Tag tag = world->mpi.unique_tag(); ProcessID me = world->rank(); - if (ar.dofence()) world->gop.fence(); - if (ar.is_io_node()) { - auto& localar = ar.local_archive(); + if (ar.dofence()) + world->gop.fence(); + if (ar.is_io_node()) + { + auto &localar = ar.local_archive(); localar & magic & ar.num_io_clients(); - for (ProcessID p=0; psize(); ++p) { - if (p == me) { + for (ProcessID p = 0; p < world->size(); ++p) + { + if (p == me) + { localar & t; } - else if (ar.io_node(p) == me) { - world->mpi.Send(int(1),p,tag); // Tell client to start sending + else if (ar.io_node(p) == me) + { + world->mpi.Send(int(1), p, tag); // Tell client to start sending archive::MPIInputArchive source(*world, p); long cookie = 0l; unsigned long count = 0ul; - ArchivePrePostImpl::preamble_store(localar); + ArchivePrePostImpl::preamble_store(localar); source & cookie & count; localar & cookie & count; - while (count--) { + while (count--) + { pairT datum; source & datum; localar & datum; } - ArchivePrePostImpl::postamble_store(localar); + ArchivePrePostImpl::postamble_store(localar); } } } - else { + else + { ProcessID p = ar.my_io_node(); int flag; - world->mpi.Recv(flag,p,tag); + world->mpi.Recv(flag, p, tag); MPIOutputArchive dest(*world, p); dest & t; dest.flush(); } - if (ar.dofence()) world->gop.fence(); + if (ar.dofence()) + world->gop.fence(); } }; template - struct ArchiveLoadImpl< ParallelInputArchive, WorldContainer > { + struct ArchiveLoadImpl, WorldContainer> + { /// Read container from parallel archive /// \ingroup worlddc @@ -1811,24 +2048,29 @@ namespace madness { /// can always run a separate job to copy to a different number. /// /// The IO node simply reads all data and inserts entries. - static void load(const ParallelInputArchive& ar, WorldContainer& t) { + static void load(const ParallelInputArchive &ar, WorldContainer &t) + { const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!) // typedef WorldContainer dcT; // unused // typedef typename dcT::iterator iterator; // unused // typedef typename dcT::pairT pairT; // unused - World* world = ar.get_world(); - if (ar.dofence()) world->gop.fence(); - if (ar.is_io_node()) { + World *world = ar.get_world(); + if (ar.dofence()) + world->gop.fence(); + if (ar.is_io_node()) + { long cookie = 0l; int nclient = 0; - auto& localar = ar.local_archive(); + auto &localar = ar.local_archive(); localar & cookie & nclient; MADNESS_CHECK(cookie == magic); - while (nclient--) { + while (nclient--) + { localar & t; } } - if (ar.dofence()) world->gop.fence(); + if (ar.dofence()) + world->gop.fence(); } }; }