MarlinMT  0.1.0
BookStore.h
Go to the documentation of this file.
1 #pragma once
2 
3 // -- std includes
4 #include <atomic>
5 #include <filesystem>
6 #include <memory>
7 #include <mutex>
8 #include <shared_mutex>
9 #include <stdexcept>
10 #include <string>
11 #include <string_view>
12 #include <thread>
13 #include <typeindex>
14 #include <typeinfo>
15 #include <unordered_map>
16 
17 // -- Marlin includes
18 // #include "marlinmt/Exceptions.h"
19 
20 // -- MarlinBook includes
22 #include "marlinmt/book/Entry.h"
24 #include "marlinmt/book/Flags.h"
27 #include "marlinmt/book/Types.h"
28 
29 namespace marlinmt {
31  namespace book {
32 
33  // -- MarlinBook forward declaration
34  class StoreWriter;
35 
36  template < typename T >
37  class Entry {} ;
38 
39  template < typename T >
40  class Handle< Entry< T > > {
41  friend BookStore ;
42  friend WeakEntry ;
43 
44  using ThreadId_t = std::thread::id;
45  using IdMap_t = std::unordered_map< ThreadId_t, std::size_t > ;
46 
48  explicit Handle( std::shared_ptr< const details::Entry > entry )
49  : _entry{std::move( entry )},
50  _mapping( std::make_unique< IdMap_t >() ) {}
51 
53  std::size_t unmap( const ThreadId_t& id ) ;
54 
55  public:
56  Handle() = default ;
58  Handle( const Handle & ) = delete ;
60  Handle &operator=( const Handle & ) = delete ;
61 
62  ~Handle() = default ;
63 
65  Handle( Handle &&hnd ) noexcept ;
66 
68  Handle &operator=( Handle &&hnd ) noexcept ;
69 
74  Handle< T > handle() ;
75 
76  const T& merged() const ;
77 
78  [[nodiscard]] const EntryKey& key() const {
79  return _entry->key();
80  }
81 
82  private:
84  std::shared_ptr< const details::Entry > _entry{nullptr} ;
86  std::unique_ptr< IdMap_t > _mapping{} ;
88  std::atomic< std::size_t > _count{0} ;
90  std::shared_mutex _mappingAccess{};
91  } ;
92 
96  class BookStore {
97  template < typename, unsigned long long >
98  friend class EntryData ;
99 
103  class Identifier {
104  public:
106  struct Hash {
107  std::size_t operator()( const Identifier &id ) const ;
108  } ;
109 
110  explicit Identifier( std::filesystem::path path)
111  : _path{std::move(path)} {}
112 
113  bool operator==( const Identifier &id ) const {
114  return _path == id._path ;
115  }
116 
117  private:
118  std::filesystem::path _path;
119  } ;
120 
126  std::shared_ptr< details::Entry >
127  addEntry( const std::shared_ptr< EntryBase > &entry, EntryKey key ) ;
128 
135  const std::shared_ptr<details::Entry>
136  &getPtr( const EntryKey &key ) const {
137  try {
138  return _entries[key.idx] ;
139  } catch ( const std::out_of_range& ) {
140  MARLIN_BOOK_THROW( "Invalid key." ) ;
141  }
142  }
143 
152  template < class T, typename... Args_t >
153  std::shared_ptr< details::Entry > bookSingle(
154  std::filesystem::path path,
155  Args_t... ctor_p ) ;
156 
165  template < class T,
166  void ( *MERGE )( const std::shared_ptr< T > &,
167  const std::shared_ptr< T > & ),
168  typename... Args_t >
169  std::shared_ptr< details::Entry > bookMultiCopy(
170  std::size_t n,
171  std::filesystem::path path,
172  Args_t... ctor_p ) ;
173 
174 
180  template < class T, typename... Args_t >
181  std::shared_ptr<details::Entry> bookMultiShared(
182  std::size_t n,
183  std::filesystem::path path,
184  Args_t... ctor_p) ;
185 
191  static std::filesystem::path normalizeDirPath(const std::filesystem::path& path);
192 
197  const details::Entry &get( std::size_t const idx ) const {
198  try {
199  return *_entries[idx] ;
200  } catch ( const std::out_of_range & ) {
201  MARLIN_BOOK_THROW( "Invalid key." ) ;
202  }
203  }
204 
209  const details::Entry &get( const EntryKey &key ) const { return get( key.idx ); }
210 
215  details::Entry &get( std::size_t const idx ) {
216  try {
217  return *_entries[idx] ;
218  } catch ( const std::out_of_range & ) {
219  MARLIN_BOOK_THROW( "Invalid key." ) ;
220  }
221  }
222 
227  details::Entry &get( const EntryKey &key ) { return get( key.idx ); }
228 
229 
230  public:
231 
232  explicit BookStore( bool allowMoving = false )
233  : _constructThread( std::this_thread::get_id() ),
234  _allowMoving{allowMoving} { }
235 
246  template < class T >
248  book( const std::filesystem::path& path,
249  const std::string_view& name,
250  const T &data ) ;
251 
252 
256  template<typename T>
257  Handle<Entry<T>> entry(const EntryKey &key ) const ;
258 
263  Selection find( const Condition &cond ) const ;
264 
269  WeakEntry findFirst(const Condition &cond ) const ;
270 
276  void remove( const EntryKey &key ) ;
277 
283  void remove( const Selection &selection ) ;
284 
290  void clear() ;
291 
298  void store( StoreWriter& writer ) const ;
299 
307  template<typename Itr>
308  void storeList( StoreWriter& writer, Itr begin, Itr end) const ;
309 
315  void storeSelection( StoreWriter& writer, const Selection& selection ) const ;
316 
317  private:
319  std::vector< std::shared_ptr< details::Entry > > _entries{} ;
321  std::unordered_map< Identifier, std::size_t, Identifier::Hash >
322  _idToEntry{} ;
323  std::thread::id _constructThread ;
325  const bool _allowMoving{false} ;
326  } ;
327 
328  //--------------------------------------------------------------------------
329 
330  template < class T, typename... Args_t >
331  std::shared_ptr< details::Entry >
332  BookStore::bookSingle( std::filesystem::path path,
333  Args_t... ctor_p ) {
334  EntryKey key{std::type_index( typeid( T ) )} ;
335  key.path = std::move( path ) ;
336  key.mInstances = 1 ;
337  key.flags = Flags::Book::Single ;
338 
339  auto entry = std::make_shared< EntrySingle< T > >( Context(
340  std::make_shared< SingleMemLayout< T, Args_t... > >( ctor_p... ), 1) ) ;
341 
342  return addEntry( entry, key ) ;
343  }
344 
345  //--------------------------------------------------------------------------
346 
347  template < class T,
348  void ( *MERGE )( const std::shared_ptr< T > &,
349  const std::shared_ptr< T > & ),
350  typename... Args_t >
351  std::shared_ptr< details::Entry >
352  BookStore::bookMultiCopy( std::size_t n,
353  std::filesystem::path path,
354  Args_t... ctor_p ) {
355  EntryKey key{std::type_index( typeid( T ) )} ;
356  key.path = std::move( path ) ;
357  key.mInstances = n ;
358  key.flags = Flags::Book::MultiCopy ;
359 
360  auto entry = std::make_shared< EntryMultiCopy< T > >(
361  Context( std::make_shared< SharedMemLayout< T, MERGE, Args_t... > >(
362  n, ctor_p... ) , n) ) ;
363 
364  return addEntry( entry, key ) ;
365  }
366 
367  //--------------------------------------------------------------------------
368  template < class T, typename... Args_t >
369  std::shared_ptr< details::Entry >
371  std::size_t n,
372  std::filesystem::path path,
373  Args_t... ctor_p ) {
374  EntryKey key{std::type_index( typeid( T ) )} ;
375  key.path = std::move(path) ;
376  key.mInstances = std::max<std::size_t>(1, n) ;
377  key.flags = Flags::Book::MultiShared ;
378 
379  auto entry = std::make_shared< EntryMultiShared< T > >( Context(
380  std::make_shared< SingleMemLayout< T, Args_t... > >( ctor_p... ) , n ) ) ;
381 
382  return addEntry( entry, key ) ;
383  }
384 
385  //--------------------------------------------------------------------------
386 
387  template < class T >
389  BookStore::book( const std::filesystem::path &path,
390  const std::string_view &name,
391  const T &data ) {
392  std::filesystem::path nPath = normalizeDirPath(path);
393  nPath /= name;
394  if ( !_allowMoving && std::this_thread::get_id() != _constructThread ) {
395  MARLIN_BOOK_THROW( "Booking is only allowed "
396  "from the construction Thread" ) ;
397  }
398 
399  auto entry = _idToEntry.find( Identifier(nPath)) ;
400  if ( entry == _idToEntry.end() ) {
402  data.template book< std::filesystem::path >(
403  *this, nPath ) ) ;
404  }
405 
406  MARLIN_BOOK_THROW(std::string( "Entry path:'" )
407  + static_cast< std::string >( nPath ) + "' name:'"
408  + static_cast< std::string >( name )
409  + "' is already booked!" ) ;
410  }
411 
412  //--------------------------------------------------------------------------
413 
414  template < typename T >
415  std::size_t Handle< Entry< T > >::unmap(
416  const Handle<Entry<T>>::ThreadId_t& id ) {
417  {
418  std::shared_lock lock(_mappingAccess);
419  auto itr = _mapping->find( id ) ;
420  if ( itr != _mapping->end() ) {
421  return itr->second;
422  }
423  }
424 
425  std::unique_lock lock(_mappingAccess);
426  return _mapping->insert(std::make_pair( id, _count++ ) ).first->second;
427  }
428 
429  //--------------------------------------------------------------------------
430 
431  template< typename T >
432  const T& Handle< Entry< T > >::merged() const {
433  return _entry->handle<T>(0).merged();
434  }
435 
436  //--------------------------------------------------------------------------
437 
438  template < typename T >
439  Handle< Entry< T > >::Handle( Handle &&hnd ) noexcept
440  : _entry( nullptr ), _mapping( nullptr ), _count( hnd._count.load() ) {
441  _entry = hnd._entry ;
442  _mapping = std::move( hnd._mapping ) ;
443 
444  hnd._entry.reset() ;
445  }
446 
447  //--------------------------------------------------------------------------
448 
449  template < typename T >
451  operator=( Handle<Entry<T>> &&hnd ) noexcept {
452  _entry = hnd._entry ;
453  _mapping = std::move( hnd._mapping ) ;
454  _count = hnd._count.load() ;
455 
456  hnd._entry.reset() ;
457  return *this ;
458  }
459 
460  //--------------------------------------------------------------------------
461 
462  template < typename T >
464  std::size_t id = unmap( std::this_thread::get_id() ) ;
465  return _entry->handle< T >( id < _entry->key().mInstances ? id : -1) ;
466  }
467 
468  //--------------------------------------------------------------------------
469 
470  template < typename Itr >
471  void BookStore::storeList( StoreWriter& writer, Itr begin, Itr end) const {
472  static_assert(std::is_same_v<
473  EntryKey,
474  std::remove_cv_t<std::remove_reference_t<decltype(*begin)>>>);
475  decltype(_entries) storeList{};
476  for( Itr itr = begin; itr != end; ++itr) {
477  storeList.push_back(getPtr(*itr));
478  }
479  storeSelection(
480  writer,
482  storeList.begin(),
483  storeList.end(),
485  );
486  }
487 
488  //--------------------------------------------------------------------------
489 
490  template<typename T>
492  return Handle<Entry<T>>(getPtr(key)) ;
493  }
494 
495  } // end namespace book
496 
497 } // end namespace marlinmt
std::unordered_map< ThreadId_t, std::size_t > IdMap_t
Definition: BookStore.h:45
Data selection to identify and manage an Entry.
Definition: EntryData.h:21
MemLayout for mutable object instances.
Definition: MemLayout.h:70
Managed Access and creation of Objects.
Definition: BookStore.h:96
Container for data to construct and setup booked object.
Definition: EntryData.h:66
bool operator==(const Identifier &id) const
Definition: BookStore.h:113
Definition: EntryData.h:93
#define MARLIN_BOOK_THROW(message)
Definition: Types.h:10
std::filesystem::path path
virtual Entry path
Definition: EntryData.h:30
std::shared_ptr< details::Entry > bookMultiShared(std::size_t n, std::filesystem::path path, Args_t... ctor_p)
creates an Entry for parallel access.
Definition: BookStore.h:370
BookStore(bool allowMoving=false)
Definition: BookStore.h:232
const EntryKey & key() const
Definition: BookStore.h:78
std::shared_ptr< details::Entry > bookSingle(std::filesystem::path path, Args_t... ctor_p)
creates an Entry for a default Object.
Definition: BookStore.h:332
Functor for hashing Identifier.
Definition: BookStore.h:106
Handle< Entry< T > > entry(const EntryKey &key) const
get access to entry from key.
Definition: BookStore.h:491
static Selection find(T begin, T end, const Condition &cond)
Construct Selection from range of Entries.
Definition: Selection.h:191
constexpr Flag_t MultiShared(1U<< 1U)
create one instance witch concurrent access.
Wrapper for weak pointer to Entry.
Definition: Selection.h:29
const std::shared_ptr< details::Entry > & getPtr(const EntryKey &key) const
Definition: BookStore.h:136
Handle< Entry< typename T::Object_t > > book(const std::filesystem::path &path, const std::string_view &name, const T &data)
book new object.
Definition: BookStore.h:389
Identifier(std::filesystem::path path)
Definition: BookStore.h:110
std::thread::id _constructThread
Definition: BookStore.h:323
Handle(std::shared_ptr< const details::Entry > entry)
constructor
Definition: BookStore.h:48
void storeList(StoreWriter &writer, Itr begin, Itr end) const
stores only Objects which key is listed.
Definition: BookStore.h:471
helper to create a Condition.
Definition: Condition.h:92
constexpr Flag_t MultiCopy(1U<< 2U)
create multiple instances of booked object (if possible) to avoid sync points
Contains references to entries.
Definition: Selection.h:75
holds references for identify an entry.
Definition: BookStore.h:103
vanilla Handle.
Definition: Handle.h:54
std::shared_ptr< details::Entry > bookMultiCopy(std::size_t n, std::filesystem::path path, Args_t... ctor_p)
creates an Entry for parallel access.
Definition: BookStore.h:352
std::size_t idx
unique number for Entry
Definition: EntryData.h:38
MemLayout for Single object instance.
Definition: MemLayout.h:125
Data selection for the Entry to work properly.
Definition: EntryData.h:71
class to store and manage objects in BookStore.
Definition: Entry.h:124
constexpr Flag_t Single(1U<< 0U)
vanilla object.
wrapper class for an Entry filter function.
Definition: Condition.h:21