Injector.hpp
Go to the documentation of this file.
1 // @formatter:off
2 //
3 // Balau core C++ library
4 //
5 // Copyright (C) 2008 Bora Software (contact@borasoftware.com)
6 //
7 // Licensed under the Boost Software License - Version 1.0 - August 17th, 2003.
8 // See the LICENSE file for the full license text.
9 //
10 
16 
17 #ifndef COM_BORA_SOFTWARE__BALAU_APPLICATION__INJECTOR
18 #define COM_BORA_SOFTWARE__BALAU_APPLICATION__INJECTOR
19 
22 #include <Balau/Util/Memory.hpp>
23 
24 #pragma clang diagnostic push
25 #pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
26 
27 namespace Balau {
28 
41 class Injector final : public std::enable_shared_from_this<Injector> {
43 
51  public: template <typename ... Conf> static std::shared_ptr<Injector> create(const Conf & ... conf) {
52  return createInjector(std::shared_ptr<Injector>(), conf ...);
53  }
54 
61  public: static std::shared_ptr<Injector> create(const std::vector<std::shared_ptr<InjectorConfiguration>> & conf) {
62  return createInjector(std::shared_ptr<Injector>(), conf);
63  }
64 
76  public: void registerPostConstructionCall(const std::function<void (const Injector &)> & call) const {
77  registerPostConstructionCallImpl(call);
78  }
79 
95  public: void registerPreDestructionCall(const std::function<void ()> & call) const {
96  registerPreDestructionCallImpl(call);
97  }
98 
119  public: template <typename T> void registerStaticSingleton(std::shared_ptr<T> * ptrPtr, std::string_view name = std::string_view()) const {
120  registerPostConstructionCallImpl([ptrPtr, name] (const Injector & injector) { *ptrPtr = injector.getShared<T>(name); });
121  registerPreDestructionCallImpl([ptrPtr] () { ptrPtr->reset(); });
122  }
123 
125 
133  public: template <typename ... Conf> std::shared_ptr<Injector> createChild(const Conf & ... conf) const {
134  return createInjector(shared_from_this(), conf ...);
135  }
136 
143  public: std::shared_ptr<Injector> createChild(const std::vector<std::shared_ptr<InjectorConfiguration>> & conf) const {
144  return createInjector(shared_from_this(), conf);
145  }
146 
164  public: std::shared_ptr<Injector> createChild(const std::shared_ptr<Injector> & prototype) const {
165  return std::shared_ptr<Injector>(new Injector(PrototypeConstruction(), shared_from_this(), prototype));
166  }
167 
169 
179  public: class ValidationParent {
180  private: std::shared_ptr<const Injector> parent;
181 
182  private: explicit ValidationParent(std::shared_ptr<const Injector> parent_)
183  : parent(std::move(parent_)) {}
184 
185  friend class Injector;
186  };
187 
199  public: template <typename ... Conf>
200  static ValidationParent validate(const Conf & ... conf) {
201  return performValidation(std::shared_ptr<Injector>(), conf ...);
202  }
203 
214  public: static ValidationParent validate(const std::vector<std::shared_ptr<InjectorConfiguration>> & conf) {
215  return performValidation(std::shared_ptr<Injector>(), conf);
216  }
217 
230  public: template <typename ... Conf>
231  static ValidationParent validateChild(ValidationParent parent, const Conf & ... conf) {
232  return performValidation(parent.parent, conf ...);
233  }
234 
246  public: static ValidationParent validateChild(const ValidationParent & parent,
247  const std::vector<std::shared_ptr<InjectorConfiguration>> & conf) {
248  return performValidation(parent.parent, conf);
249  }
250 
261  public: template <typename InstT>
262  bool hasBinding(std::string_view name = std::string_view()) const {
263  return GetInstance<InstT>(this).hasBinding(name);
264  }
265 
276  public: template <typename InstT>
277  static Impl::BindingKey createBindingKey(const std::string & name = "") {
278  return GetInstance<InstT>::createBindingKey(name);
279  }
280 
289  public: std::string printBindings(bool printAncestor = false) const {
290  return performPrintBindings(printAncestor);
291  }
292 
304  public: std::string printBindingsDetailed() const {
305  return performPrintBindingsDetailed();
306  }
307 
309 
323  public: template <typename InstT>
324  InstT getInstance(std::string_view name = std::string_view()) const {
325  return GetInstance<InstT>(this).get(name);
326  }
327 
329 
342  public: template <typename ValueT>
343  ValueT getValue(std::string_view name = std::string_view()) const {
344  return GetInstance<ValueT>(this).get(name);
345  }
346 
358  public: template <typename ValueT>
359  ValueT getValue(const ValueT & defaultValue) const {
360  return GetInstance<ValueT>(this).get(std::string_view(), defaultValue);
361  }
362 
375  public: template <typename ValueT>
376  ValueT getValue(std::string_view name, const ValueT & defaultValue) const {
377  return GetInstance<ValueT>(this).get(name, defaultValue);
378  }
379 
391  public: template <typename ValueT>
392  ValueT getValue(const std::function<ValueT ()> & defaultValueSupplier) const {
393  return GetInstance<ValueT>(this).get(std::string_view(), defaultValueSupplier);
394  }
395 
408  public: template <typename ValueT>
409  ValueT getValue(std::string_view name, const std::function<ValueT ()> & defaultValueSupplier) const {
410  return GetInstance<ValueT>(this).get(name, defaultValueSupplier);
411  }
412 
414 
427  public: template <typename BaseT, typename DeleterT = std::default_delete<BaseT>>
428  std::unique_ptr<BaseT, DeleterT> getUnique(std::string_view name = std::string_view()) const {
429  return GetInstance<std::unique_ptr<BaseT, DeleterT>>(this).get(name);
430  }
431 
443  public: template <typename BaseT, typename DeleterT = std::default_delete<BaseT>>
444  std::unique_ptr<BaseT, DeleterT> getUnique(std::unique_ptr<BaseT> && defaultValue) const {
445  return GetInstance<std::unique_ptr<BaseT, DeleterT>>(this).get("", std::move(defaultValue));
446  }
447 
460  public: template <typename BaseT, typename DeleterT = std::default_delete<BaseT>>
461  std::unique_ptr<BaseT, DeleterT> getUnique(std::string_view name, std::unique_ptr<BaseT, DeleterT> && defaultValue) const {
462  return GetInstance<std::unique_ptr<BaseT, DeleterT>>(this).get(name, std::move(defaultValue));
463  }
464 
476  public: template <typename BaseT, typename DeleterT = std::default_delete<BaseT>>
477  std::unique_ptr<BaseT, DeleterT> getUnique(std::function<std::unique_ptr<BaseT, DeleterT> ()> & defaultValueSupplier) const {
478  return GetInstance<std::unique_ptr<BaseT, DeleterT>>(this).get("", defaultValueSupplier);
479  }
480 
493  public: template <typename BaseT, typename DeleterT = std::default_delete<BaseT>>
494  std::unique_ptr<BaseT, DeleterT> getUnique(std::string_view name, std::function<std::unique_ptr<BaseT, DeleterT> ()> & defaultValueSupplier) const {
495  return GetInstance<std::unique_ptr<BaseT, DeleterT>>(this).get(name, defaultValueSupplier);
496  }
497 
509  public: template <typename BaseT, typename DeleterT = std::default_delete<BaseT>>
510  std::unique_ptr<BaseT, DeleterT> getUniqueOrNull(std::string_view name = std::string_view()) const {
511  return GetInstance<std::unique_ptr<BaseT, DeleterT>>(this).get(name, std::unique_ptr<BaseT, DeleterT>());
512  }
513 
515 
526  public: template <typename BaseT> BaseT & getReference(std::string_view name = std::string_view()) const {
527  return GetInstance<BaseT &>(this).get(name);
528  }
529 
539  public: template <typename BaseT> BaseT & getReference(BaseT & defaultValue) const {
540  return GetInstance<BaseT &>(this).get(std::string_view(), defaultValue);
541  }
542 
553  public: template <typename BaseT> BaseT & getReference(std::string_view name, BaseT & defaultValue) const {
554  return GetInstance<BaseT &>(this).get(name, defaultValue);
555  }
556 
558 
571  public: template <typename BaseT> std::shared_ptr<BaseT> getShared(std::string_view name = std::string_view()) const {
572  return GetInstance<std::shared_ptr<BaseT>>(this).get(name);
573  }
574 
586  public: template <typename BaseT>
587  std::shared_ptr<BaseT> getShared(const std::shared_ptr<BaseT> & defaultValue) const {
588  return GetInstance<std::shared_ptr<BaseT>>(this).get(std::string_view(), defaultValue);
589  }
590 
603  public: template <typename BaseT>
604  std::shared_ptr<BaseT> getShared(std::string_view name, const std::shared_ptr<BaseT> & defaultValue) const {
605  return GetInstance<std::shared_ptr<BaseT>>(this).get(name, defaultValue);
606  }
607 
619  public: template <typename BaseT>
620  std::shared_ptr<BaseT> getShared(const std::function<std::shared_ptr<BaseT> ()> & defaultValueSupplier) const {
621  return GetInstance<std::shared_ptr<BaseT>>(this).get(std::string_view(), defaultValueSupplier);
622  }
623 
636  public: template <typename BaseT>
637  std::shared_ptr<BaseT> getShared(std::string_view name, const std::function<std::shared_ptr<BaseT> ()> & defaultValueSupplier) const {
638  return GetInstance<std::shared_ptr<BaseT>>(this).get(name, defaultValueSupplier);
639  }
640 
652  public: template <typename BaseT>
653  std::shared_ptr<BaseT> getSharedOrNull(std::string_view name = std::string_view()) const {
654  return GetInstance<std::shared_ptr<BaseT>>(this).get(name, std::shared_ptr<BaseT>());
655  }
656 
658 
666  public: template <typename BaseT>
667  void iterate(const std::function<void (std::shared_ptr<BaseT>)> & func, bool includeThreadLocal = false) const {
668  iterateOverShared<BaseT>(func, includeThreadLocal);
669  }
670 
678  public: template <typename BaseT>
679  void iterate(const std::function<void (std::shared_ptr<const BaseT>)> & func, bool includeThreadLocal = false) const {
680  iterateOverShared<BaseT>(func, includeThreadLocal);
681  }
682 
684 
685  //
686  // Non-specialised GetInstance template class.
687  // This GetInstance template class deals with the non-const value meta-type.
688  //
689  private: template <typename T> struct GetInstance {
690  T get(std::string_view name) const {
691  return injector->getValueImpl<T>(name);
692  }
693 
694  T get(std::string_view name, const T & defaultValue) const {
695  return injector->getValueImpl<T>(name, defaultValue);
696  }
697 
698  T get(std::string_view name, const std::function<T ()> & defaultValueSupplier) const {
699  return injector->getValueImpl<T>(name, defaultValueSupplier);
700  }
701 
702  bool hasBinding(std::string_view name) const {
703  return injector->hasBinding(createBindingKeyView(name));
704  }
705 
706  static Impl::BindingKey createBindingKey(std::string name) {
707  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Value, T>), std::move(name));
708  }
709 
710  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
711  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Value, T>), name);
712  }
713 
714  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
715  const Injector * injector;
716  };
717 
718  //
719  // GetInstance template class specialised for const T.
720  // This immediately promotes to T.
721  //
722  private: template <typename T> struct GetInstance<const T> {
723  using U = typename std::remove_const<T>::type;
724 
725  U get(std::string_view name) const {
726  return injector->getValueImpl<U>(name);
727  }
728 
729  U get(std::string_view name, const T & defaultValue) const {
730  return injector->getValueImpl<U>(name, defaultValue);
731  }
732 
733  U get(std::string_view name, const std::function<T ()> & defaultValueSupplier) const {
734  return injector->getValueImpl<U>(name, defaultValueSupplier);
735  }
736 
737  bool hasBinding(std::string_view name) const {
738  return injector->hasBinding(createBindingKeyView(name));
739  }
740 
741  static Impl::BindingKey createBindingKey(std::string name) {
742  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Value, T>), std::move(name));
743  }
744 
745  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
746  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Value, T>), name);
747  }
748 
749  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
750  const Injector * injector;
751  };
752 
753  //
754  // GetInstance template class specialised for std::unique_ptr<T>.
755  //
756  private: template <typename BaseT, typename DeleterT> struct GetInstance<std::unique_ptr<BaseT, DeleterT>> {
757  std::unique_ptr<BaseT, DeleterT> get(std::string_view name) const {
758  return injector->getUniqueImpl<BaseT, DeleterT>(name);
759  }
760 
761  std::unique_ptr<BaseT, DeleterT> get(std::string_view name, std::unique_ptr<BaseT, DeleterT> & defaultValue) const {
762  return injector->getUniqueImpl<BaseT, DeleterT>(name, defaultValue);
763  }
764 
765  std::unique_ptr<BaseT, DeleterT> get(std::string_view name, const std::function<std::unique_ptr<BaseT, DeleterT> ()> & defaultValueSupplier) const {
766  return injector->getUniqueImpl<BaseT, DeleterT>(name, defaultValueSupplier);
767  }
768 
769  bool hasBinding(std::string_view name) const {
770  return injector->hasBinding(createBindingKeyView(name));
771  }
772 
773  static Impl::BindingKey createBindingKey(std::string name) {
774  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), std::move(name));
775  }
776 
777  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
778  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), name);
779  }
780 
781  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
782  const Injector * injector;
783  };
784 
785  //
786  // GetInstance template class specialised for const std::unique_ptr<T>.
787  // This immediately promotes to std::unique_ptr<T>.
788  //
789  private: template <typename BaseT, typename DeleterT> struct GetInstance<const std::unique_ptr<BaseT, DeleterT>> {
790  std::unique_ptr<BaseT, DeleterT> get(std::string_view name) const {
791  return injector->getUniqueImpl<BaseT, DeleterT>(name);
792  }
793 
794  std::unique_ptr<BaseT, DeleterT> get(std::string_view name, std::unique_ptr<BaseT, DeleterT> & defaultValue) const {
795  return injector->getUniqueImpl<BaseT, DeleterT>(name, defaultValue);
796  }
797 
798  std::unique_ptr<BaseT, DeleterT> get(std::string_view name, const std::function<std::unique_ptr<BaseT, DeleterT> ()> & defaultValueSupplier) const {
799  return injector->getUniqueImpl<BaseT, DeleterT>(name, defaultValueSupplier);
800  }
801 
802  bool hasBinding(std::string_view name) const {
803  return injector->hasBinding(createBindingKeyView(name));
804  }
805 
806  static Impl::BindingKey createBindingKey(std::string name) {
807  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), std::move(name));
808  }
809 
810  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
811  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), name);
812  }
813 
814  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
815  const Injector * injector;
816  };
817 
818  //
819  // GetInstance template class specialised for std::unique_ptr<const T>.
820  // This immediately promotes to std::unique_ptr<T>.
821  //
822  private: template <typename BaseT, typename DeleterT> struct GetInstance<std::unique_ptr<const BaseT, DeleterT>> {
823  std::unique_ptr<BaseT, DeleterT> get(std::string_view name) const {
824  return injector->getUniqueImpl<BaseT, DeleterT>(name);
825  }
826 
827  std::unique_ptr<BaseT, DeleterT> get(std::string_view name, std::unique_ptr<BaseT, DeleterT> & defaultValue) const {
828  return injector->getUniqueImpl<BaseT, DeleterT>(name, defaultValue);
829  }
830 
831  std::unique_ptr<BaseT, DeleterT> get(std::string_view name, const std::function<std::unique_ptr<BaseT, DeleterT> ()> & defaultValueSupplier) const {
832  return injector->getUniqueImpl<BaseT, DeleterT>(name, defaultValueSupplier);
833  }
834 
835  bool hasBinding(std::string_view name) const {
836  return injector->hasBinding(createBindingKeyView(name));
837  }
838 
839  static Impl::BindingKey createBindingKey(std::string name) {
840  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), std::move(name));
841  }
842 
843  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
844  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), name);
845  }
846 
847  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
848  const Injector * injector;
849  };
850 
851  //
852  // GetInstance template class specialised for const std::unique_ptr<const T>.
853  // This immediately promotes to std::unique_ptr<T>.
854  //
855  private: template <typename BaseT, typename DeleterT> struct GetInstance<const std::unique_ptr<const BaseT, DeleterT>> {
856  std::unique_ptr<BaseT, DeleterT> get(std::string_view name) const {
857  return injector->getUniqueImpl<BaseT, DeleterT>(name);
858  }
859 
860  std::unique_ptr<BaseT, DeleterT> get(std::string_view name, std::unique_ptr<BaseT, DeleterT> & defaultValue) const {
861  return injector->getUniqueImpl<BaseT, DeleterT>(name, defaultValue);
862  }
863 
864  std::unique_ptr<BaseT, DeleterT> get(std::string_view name, const std::function<std::unique_ptr<BaseT, DeleterT> ()> & defaultValueSupplier) const {
865  return injector->getUniqueImpl<BaseT, DeleterT>(name, defaultValueSupplier);
866  }
867 
868  bool hasBinding(std::string_view name) const {
869  return injector->hasBinding(createBindingKeyView(name));
870  }
871 
872  static Impl::BindingKey createBindingKey(std::string name) {
873  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), std::move(name));
874  }
875 
876  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
877  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), name);
878  }
879 
880  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
881  const Injector * injector;
882  };
883 
884  //
885  // GetInstance template class specialised for T &.
886  //
887  private: template <typename T> struct GetInstance<T &> {
888  T & get(std::string_view name) const {
889  return injector->getReferenceImpl<T>(name);
890  }
891 
892  T & get(std::string_view name, T & defaultValue) const {
893  return injector->getReferenceImpl<T>(name, defaultValue);
894  }
895 
896  bool hasBinding(std::string_view name) const {
897  return injector->hasBinding(createBindingKeyView(name));
898  }
899 
900  static Impl::BindingKey createBindingKey(std::string name) {
901  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Reference, T>), std::move(name));
902  }
903 
904  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
905  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Reference, T>), name);
906  }
907 
908  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
909  const Injector * injector;
910  };
911 
912  //
913  // GetInstance template class specialised for const T &.
914  // This will use a suitable non-const T & binding if no const T & binding is not available.
915  //
916  private: template <typename T> struct GetInstance<const T &> {
917  const T & get(std::string_view name) const {
918  return injector->getReferenceImpl<const T>(name);
919  }
920 
921  const T & get(std::string_view name, const T & defaultValue) const {
922  return injector->getReferenceImpl<const T>(name, defaultValue);
923  }
924 
925  bool hasBinding(std::string_view name) const {
926  return injector->hasBinding(createBindingKeyView(name));
927  }
928 
929  static Impl::BindingKey createBindingKey(std::string name) {
930  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Reference, const T>), std::move(name));
931  }
932 
933  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
934  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Reference, const T>), name);
935  }
936 
937  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
938  const Injector * injector;
939  };
940 
941  //
942  // GetInstance template class specialised for std::shared_ptr<BaseT>.
943  //
944  private: template <typename BaseT> struct GetInstance<std::shared_ptr<BaseT>> {
945  std::shared_ptr<BaseT> get(std::string_view name) const {
946  return injector->getSharedImpl<BaseT>(name);
947  }
948 
949  std::shared_ptr<BaseT> get(std::string_view name, const std::shared_ptr<BaseT> & defaultValue) const {
950  return injector->getSharedImpl<BaseT>(name, defaultValue);
951  }
952 
953  std::shared_ptr<BaseT> get(std::string_view name, const std::function<std::shared_ptr<BaseT> ()> & defaultValueSupplier) const {
954  return injector->getSharedImpl<BaseT>(name, defaultValueSupplier);
955  }
956 
957  bool hasBinding(std::string_view name) const {
958  return injector->hasBinding(createBindingKeyView(name));
959  }
960 
961  static Impl::BindingKey createBindingKey(std::string name) {
962  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), std::move(name));
963  }
964 
965  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
966  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), name);
967  }
968 
969  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
970  const Injector * injector;
971  };
972 
973  //
974  // GetInstance template class specialised for const std::shared_ptr<BaseT>.
975  // This immediately promotes to std::shared_ptr<T>.
976  //
977  private: template <typename BaseT> struct GetInstance<const std::shared_ptr<BaseT>> {
978  std::shared_ptr<BaseT> get(std::string_view name) const {
979  return injector->getSharedImpl<BaseT>(name);
980  }
981 
982  std::shared_ptr<BaseT> get(std::string_view name, const std::shared_ptr<BaseT> & defaultValue) const {
983  return injector->getSharedImpl<BaseT>(name, defaultValue);
984  }
985 
986  std::shared_ptr<BaseT> get(std::string_view name, const std::function<std::shared_ptr<BaseT> ()> & defaultValueSupplier) const {
987  return injector->getSharedImpl<BaseT>(name, defaultValueSupplier);
988  }
989 
990  bool hasBinding(std::string_view name) const {
991  return injector->hasBinding(createBindingKeyView(name));
992  }
993 
994  static Impl::BindingKey createBindingKey(std::string name) {
995  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), std::move(name));
996  }
997 
998  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
999  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), name);
1000  }
1001 
1002  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
1003  const Injector * injector;
1004  };
1005 
1006  //
1007  // GetInstance template class specialised for std::shared_ptr<const T>.
1008  // This will use a suitable non-const std::shared_ptr<const T> binding
1009  // if no const std::shared_ptr<const T> binding is available.
1010  //
1011  private: template <typename BaseT> struct GetInstance<std::shared_ptr<const BaseT>> {
1012  std::shared_ptr<const BaseT> get(std::string_view name) const {
1013  return injector->getSharedImpl<const BaseT>(name);
1014  }
1015 
1016  std::shared_ptr<const BaseT> get(std::string_view name, std::shared_ptr<const BaseT> & defaultValue) const {
1017  return injector->getSharedImpl<const BaseT>(name, defaultValue);
1018  }
1019 
1020  std::shared_ptr<const BaseT> get(std::string_view name, const std::function<std::shared_ptr<const BaseT> ()> & defaultValueSupplier) const {
1021  return injector->getSharedImpl<const BaseT>(name, defaultValueSupplier);
1022  }
1023 
1024  bool hasBinding(std::string_view name) const {
1025  return injector->hasBinding(createBindingKeyView(name));
1026  }
1027 
1028  static Impl::BindingKey createBindingKey(std::string name) {
1029  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, const BaseT>), std::move(name));
1030  }
1031 
1032  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
1033  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, const BaseT>), name);
1034  }
1035 
1036  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
1037  const Injector * injector;
1038  };
1039 
1040  //
1041  // GetInstance template class specialised for const std::shared_ptr<const T>.
1042  // This immediately promotes to std::shared_ptr<const T>.
1043  //
1044  private: template <typename BaseT> struct GetInstance<const std::shared_ptr<const BaseT>> {
1045  std::shared_ptr<const BaseT> get(std::string_view name) const {
1046  return injector->getSharedImpl<const BaseT>(name);
1047  }
1048 
1049  std::shared_ptr<const BaseT> get(std::string_view name, std::shared_ptr<const BaseT> & defaultValue) const {
1050  return injector->getSharedImpl<const BaseT>(name, defaultValue);
1051  }
1052 
1053  std::shared_ptr<const BaseT> get(std::string_view name, const std::function<std::shared_ptr<const BaseT> ()> & defaultValueSupplier) const {
1054  return injector->getSharedImpl<const BaseT>(name, defaultValueSupplier);
1055  }
1056 
1057  bool hasBinding(std::string_view name) const {
1058  return injector->hasBinding(createBindingKeyView(name));
1059  }
1060 
1061  static Impl::BindingKey createBindingKey(std::string name) {
1062  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, const BaseT>), std::move(name));
1063  }
1064 
1065  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
1066  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, const BaseT>), name);
1067  }
1068 
1069  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
1070  const Injector * injector;
1071  };
1072 
1073  //
1074  // GetInstance template class specialised for std::weak_ptr<T>.
1075  // This immediately promotes to std::shared_ptr<T>.
1076  //
1077  private: template <typename BaseT> struct GetInstance<std::weak_ptr<BaseT>> {
1078  std::shared_ptr<BaseT> get(std::string_view name) const {
1079  return injector->getSharedImpl<BaseT>(name);
1080  }
1081 
1082  std::shared_ptr<BaseT> get(std::string_view name, std::shared_ptr<BaseT> & defaultValue) const {
1083  return injector->getSharedImpl<BaseT>(name, defaultValue);
1084  }
1085 
1086  std::shared_ptr<BaseT> get(std::string_view name, const std::function<std::shared_ptr<BaseT> ()> & defaultValueSupplier) const {
1087  return injector->getSharedImpl<BaseT>(name, defaultValueSupplier);
1088  }
1089 
1090  bool hasBinding(std::string_view name) const {
1091  return injector->hasBinding(createBindingKeyView(name));
1092  }
1093 
1094  static Impl::BindingKey createBindingKey(std::string name) {
1095  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), std::move(name));
1096  }
1097 
1098  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
1099  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), name);
1100  }
1101 
1102  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
1103  const Injector * injector;
1104  };
1105 
1106  //
1107  // GetInstance template class specialised for const std::weak_ptr<T>.
1108  // This immediately promotes to std::shared_ptr<T>.
1109  //
1110  private: template <typename BaseT> struct GetInstance<const std::weak_ptr<BaseT>> {
1111  std::shared_ptr<BaseT> get(std::string_view name) const {
1112  return injector->getSharedImpl<BaseT>(name);
1113  }
1114 
1115  std::shared_ptr<BaseT> get(std::string_view name, std::shared_ptr<BaseT> & defaultValue) const {
1116  return injector->getSharedImpl<BaseT>(name, defaultValue);
1117  }
1118 
1119  std::shared_ptr<BaseT> get(std::string_view name, const std::function<std::shared_ptr<BaseT> ()> & defaultValueSupplier) const {
1120  return injector->getSharedImpl<BaseT>(name, defaultValueSupplier);
1121  }
1122 
1123  bool hasBinding(std::string_view name) const {
1124  return injector->hasBinding(createBindingKeyView(name));
1125  }
1126 
1127  static Impl::BindingKey createBindingKey(std::string name) {
1128  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), std::move(name));
1129  }
1130 
1131  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
1132  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), name);
1133  }
1134 
1135  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
1136  const Injector * injector;
1137  };
1138 
1139  //
1140  // GetInstance template class specialised for std::weak_ptr<const T>.
1141  // This immediately promotes to std::shared_ptr<const T>.
1142  //
1143  private: template <typename BaseT> struct GetInstance<std::weak_ptr<const BaseT>> {
1144  std::shared_ptr<const BaseT> get(std::string_view name) const {
1145  return injector->getSharedImpl<const BaseT>(name);
1146  }
1147 
1148  std::shared_ptr<const BaseT> get(std::string_view name, std::shared_ptr<const BaseT> & defaultValue) const {
1149  return injector->getSharedImpl<const BaseT>(name, defaultValue);
1150  }
1151 
1152  std::shared_ptr<const BaseT> get(std::string_view name, const std::function<std::shared_ptr<const BaseT> ()> & defaultValueSupplier) const {
1153  return injector->getSharedImpl<const BaseT>(name, defaultValueSupplier);
1154  }
1155 
1156  bool hasBinding(std::string_view name) const {
1157  return injector->hasBinding(createBindingKeyView(name));
1158  }
1159 
1160  static Impl::BindingKey createBindingKey(std::string name) {
1161  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, const BaseT>), std::move(name));
1162  }
1163 
1164  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
1165  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, const BaseT>), name);
1166  }
1167 
1168  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
1169  const Injector * injector;
1170  };
1171 
1172  //
1173  // GetInstance template class specialised for const std::weak_ptr<const T>.
1174  // This immediately promotes to std::shared_ptr<const T>.
1175  //
1176  private: template <typename BaseT> struct GetInstance<const std::weak_ptr<const BaseT>> {
1177  std::shared_ptr<const BaseT> get(std::string_view name) const {
1178  return injector->getSharedImpl<const BaseT>(name);
1179  }
1180 
1181  std::shared_ptr<const BaseT> get(std::string_view name, std::shared_ptr<const BaseT> & defaultValue) const {
1182  return injector->getSharedImpl<const BaseT>(name, defaultValue);
1183  }
1184 
1185  std::shared_ptr<const BaseT> get(std::string_view name, const std::function<std::shared_ptr<const BaseT> ()> & defaultValueSupplier) const {
1186  return injector->getSharedImpl<const BaseT>(name, defaultValueSupplier);
1187  }
1188 
1189  bool hasBinding(std::string_view name) const {
1190  return injector->hasBinding(createBindingKeyView(name));
1191  }
1192 
1193  static Impl::BindingKey createBindingKey(std::string name) {
1194  return Impl::BindingKey(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, const BaseT>), std::move(name));
1195  }
1196 
1197  static Impl::BindingKeyView createBindingKeyView(std::string_view name) {
1198  return Impl::BindingKeyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, const BaseT>), name);
1199  }
1200 
1201  explicit GetInstance(const Injector * injector_) : injector(injector_) {}
1202  const Injector * injector;
1203  };
1204 
1206 
1207  private: template <typename T> T getValueImpl(std::string_view name) const {
1208  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Value, T>), name);
1209 
1210  const auto * binding = bindings->find(keyView);
1211 
1212  if (binding != nullptr) {
1213  return createValueInstance<T>(*binding);
1214  } else if (parent) {
1215  return parent->getValueImpl<T>(name);
1216  } else {
1218  }
1219  }
1220 
1221  private: template <typename T> T getValueImpl(std::string_view name, const T & defaultValue) const {
1222  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Value, T>), name);
1223 
1224  const auto * binding = bindings->find(keyView);
1225 
1226  if (binding != nullptr) {
1227  return createValueInstance<T>(*binding);
1228  } else if (parent) {
1229  return parent->getValueImpl<T>(name, defaultValue);
1230  } else {
1231  return defaultValue;
1232  }
1233  }
1234 
1235  private: template <typename T> T getValueImpl(std::string_view name, const std::function<T ()> & defaultValueSupplier) const {
1236  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Value, T>), name);
1237 
1238  const auto * binding = bindings->find(keyView);
1239 
1240  if (binding != nullptr) {
1241  return createValueInstance<T>(*binding);
1242  } else if (parent) {
1243  return parent->getValueImpl<T>(name, defaultValueSupplier);
1244  } else {
1245  return defaultValueSupplier();
1246  }
1247  }
1248 
1249  private: template <typename T>
1250  T & getReferenceImpl(std::string_view name) const {
1251  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Reference, T>), name);
1252 
1253  const auto * binding = bindings->find(keyView);
1254 
1255  if (binding != nullptr) {
1256  return getReferenceInstance<T>(*binding);
1257  } else if (parent) {
1258  return parent->getReferenceImpl<T>(name);
1259  } else {
1260  // Try a non-const binding?
1261  if (Impl::BindingKeyType<Impl::BindingMetaType::Reference, T>::isConst) {
1262  return getReferenceImpl<typename std::remove_const<T>::type>(name);
1263  } else {
1265  }
1266  }
1267  }
1268 
1269  private: template <typename T>
1270  T & getReferenceImpl(std::string_view name, T & defaultValue) const {
1271  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Reference, T>), name);
1272 
1273  const auto * binding = bindings->find(keyView);
1274 
1275  if (binding != nullptr) {
1276  return getReferenceInstance<T>(*binding);
1277  } else if (parent) {
1278  return parent->getReferenceImpl<T>(name, defaultValue);
1279  } else {
1280  // Try a non-const binding?
1281  if (Impl::BindingKeyType<Impl::BindingMetaType::Reference, T>::isConst) {
1282  return getReferenceImpl<typename std::remove_const<T>::type>(name, defaultValue);
1283  } else {
1284  return defaultValue;
1285  }
1286  }
1287  }
1288 
1289  private: template <typename BaseT, typename DeleterT>
1290  std::unique_ptr<BaseT, DeleterT> getUniqueImpl(std::string_view name) const {
1291  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), name);
1292 
1293  const auto * binding = bindings->find(keyView);
1294 
1295  if (binding != nullptr) {
1296  return createUniqueInstance<BaseT, DeleterT>(*binding);
1297  } else if (parent) {
1298  return parent->getUniqueImpl<BaseT, DeleterT>(name);
1299  } else {
1301  }
1302  }
1303 
1304  private: template <typename BaseT, typename DeleterT>
1305  std::unique_ptr<BaseT, DeleterT> getUniqueImpl(std::string_view name, std::unique_ptr<BaseT> && defaultValue) const {
1306  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), name);
1307 
1308  const auto * binding = bindings->find(keyView);
1309 
1310  if (binding != nullptr) {
1311  return createUniqueInstance<BaseT, DeleterT>(*binding);
1312  } else if (parent) {
1313  return parent->getUniqueImpl<BaseT, DeleterT>(name, std::move(defaultValue));
1314  } else {
1315  return std::move(defaultValue);
1316  }
1317  }
1318 
1319  private: template <typename BaseT, typename DeleterT>
1320  std::unique_ptr<BaseT, DeleterT> getUniqueImpl(std::string_view name, std::function<std::unique_ptr<BaseT> ()> & defaultValueSupplier) const {
1321  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Unique, BaseT, DeleterT>), name);
1322 
1323  const auto * binding = bindings->find(keyView);
1324 
1325  if (binding != nullptr) {
1326  return createUniqueInstance<BaseT, DeleterT>(*binding);
1327  } else if (parent) {
1328  return parent->getUniqueImpl<BaseT, DeleterT>(name, defaultValueSupplier);
1329  } else {
1330  return defaultValueSupplier();
1331  }
1332  }
1333 
1334  private: template <typename BaseT>
1335  std::shared_ptr<BaseT> getSharedImpl(std::string_view name) const {
1336  const auto typeIndex = std::type_index(typeid(BaseT));
1337  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), name);
1338 
1339  const auto * binding = bindings->find(keyView);
1340 
1341  if (binding != nullptr) {
1342  return getSharedInstance<BaseT>(*binding);
1343  } else if (typeIndex == std::type_index(typeid(Injector))) {
1344  // If we are here, then BaseT == Injector and the cast disappears.
1345  auto ptr = std::const_pointer_cast<Injector>(shared_from_this());
1346  return std::reinterpret_pointer_cast<BaseT>(ptr);
1347  } else if (parent) {
1348  return parent->getSharedImpl<BaseT>(name);
1349  } else {
1350  // Try a non-const binding?
1351  if (Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>::isConst) {
1352  return getSharedImpl<typename std::remove_const<BaseT>::type>(name);
1353  } else {
1355  }
1356  }
1357  }
1358 
1359  private: template <typename BaseT>
1360  std::shared_ptr<BaseT> getSharedImpl(std::string_view name, const std::shared_ptr<BaseT> & defaultValue) const {
1361  const auto typeIndex = std::type_index(typeid(BaseT));
1362  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), name);
1363 
1364  const auto * binding = bindings->find(keyView);
1365 
1366  if (binding != nullptr) {
1367  return getSharedInstance<BaseT>(*binding);
1368  } else if (typeIndex == std::type_index(typeid(Injector))) {
1369  // If we are here, then BaseT == Injector and the cast disappears.
1370  auto ptr = std::const_pointer_cast<Injector>(shared_from_this());
1371  return std::reinterpret_pointer_cast<BaseT>(ptr);
1372  } else if (parent) {
1373  return parent->getSharedImpl<BaseT>(name, defaultValue);
1374  } else {
1375  // Try a non-const binding?
1376  if (Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>::isConst) {
1377  return getSharedImpl<typename std::remove_const<BaseT>::type>(name, defaultValue);
1378  } else {
1379  return defaultValue;
1380  }
1381  }
1382  }
1383 
1384  private: template <typename BaseT>
1385  std::shared_ptr<BaseT> getSharedImpl(std::string_view name, const std::function<std::shared_ptr<BaseT> ()> & defaultValueSupplier) const {
1386  const auto typeIndex = std::type_index(typeid(BaseT));
1387  const Impl::BindingKeyView keyView(typeid(Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>), name);
1388 
1389  const auto * binding = bindings->find(keyView);
1390 
1391  if (binding != nullptr) {
1392  return getSharedInstance<BaseT>(*binding);
1393  } else if (typeIndex == std::type_index(typeid(Injector))) {
1394  // If we are here, then BaseT == Injector and the cast disappears.
1395  auto ptr = std::const_pointer_cast<Injector>(shared_from_this());
1396  return std::reinterpret_pointer_cast<BaseT>(ptr);
1397  } else if (parent) {
1398  return parent->getSharedImpl<BaseT>(name, defaultValueSupplier);
1399  } else {
1400  // Try a non-const binding?
1401  if (Impl::BindingKeyType<Impl::BindingMetaType::Shared, BaseT>::isConst) {
1402  return getSharedImpl<typename std::remove_const<BaseT>::type>(name, defaultValueSupplier);
1403  } else {
1404  return defaultValueSupplier();
1405  }
1406  }
1407  }
1408 
1409  private: template <typename BaseT>
1410  void iterateOverShared(const std::function<void (std::shared_ptr<BaseT>)> & func, bool includeThreadLocal = false) {
1411  const auto typeIndex = std::type_index(typeid(BaseT));
1412 
1413  for (const auto & binding : (*bindings)) {
1414  if (binding.key.getType() == typeIndex) {
1415  if (includeThreadLocal || !binding.value->isThreadLocalBinding()) {
1416  func(getSharedInstance<BaseT>(binding.value));
1417  }
1418  }
1419  }
1420  }
1421 
1422  private: template <typename BaseT>
1423  void iterateOverShared(const std::function<void (std::shared_ptr<const BaseT>)> & func, bool includeThreadLocal = false) {
1424  const auto typeIndex = std::type_index(typeid(BaseT));
1425 
1426  for (const auto & binding : (*bindings)) {
1427  if (binding.key.getType() == typeIndex) {
1428  if (includeThreadLocal || !binding.value->isThreadLocalBinding()) {
1429  func(getSharedInstance<BaseT>(binding.value));
1430  }
1431  }
1432  }
1433  }
1434 
1436 
1437  // Create a non-polymorphic value from the supplied value, prototype, or value provider
1438  // binding. The type T has been tunnelled through and matched to the binding.
1439  private: template <typename T>
1440  T createValueInstance(const std::unique_ptr<Impl::AbstractBinding> & binding) const {
1441  return static_cast<const Impl::AbstractValueBinding<T> *>(binding.get())->get(this);
1442  }
1443 
1444  // Get a reference from the supplied reference binding. The type T has been
1445  // tunnelled through and matched to the binding.
1446  private: template <typename T>
1447  T & getReferenceInstance(const std::unique_ptr<Impl::AbstractBinding> & binding) const {
1448  return static_cast<const Impl::AbstractReferenceBinding<T> *>(binding.get())->get(this);
1449  }
1450 
1451  // Create a polymorphic unique ptr from the supplied unique ptr or unique ptr provider
1452  // binding. The type T has been tunnelled through and matched to the binding.
1453  private: template <typename T, typename DeleterT = std::default_delete<T>>
1454  std::unique_ptr<T, DeleterT> createUniqueInstance(const std::unique_ptr<Impl::AbstractBinding> & binding) const {
1455  return static_cast<const Impl::AbstractUniquePtrBinding<T, DeleterT> *>(binding.get())->get(this);
1456  }
1457 
1458  // Get a polymorphic shared ptr from the supplied thread-local singleton or singleton binding.
1459  // The type T has been tunnelled through and matched to the binding.
1460  private: template <typename T>
1461  std::shared_ptr<T> getSharedInstance(const std::unique_ptr<Impl::AbstractBinding> & binding) const {
1462  return static_cast<const Impl::AbstractSharedPtrBinding<T> *>(binding.get())->get(this);
1463  }
1464 
1466 
1467  // Used to determine presence of a binding the injector or its parent.
1468  private: bool hasBinding(const Impl::BindingKeyView & keyView) const {
1469  return bindings->hasBinding(keyView) || (parent && parent->hasBinding(keyView));
1470  }
1471 
1472  public: Injector(const Injector &) = delete;
1473  public: Injector & operator = (const Injector &) = delete;
1474 
1475  //
1476  // Environment property text is owned by the injector.
1477  //
1478  // This allows the const char pointers of the strings to be used in the
1479  // binding keys without dangling pointer issues.
1480  //
1481  using PropertyTextVectorPtr = std::shared_ptr<std::vector<std::string>>;
1482 
1483  private: template <typename ... Conf>
1484  static std::shared_ptr<Injector> createInjector(const std::shared_ptr<const Injector> & parent, const Conf & ... conf) {
1485  auto injector = std::shared_ptr<Injector>(new Injector(parent, conf ...)); // NOLINT
1486  Impl::BindingGraph graph;
1487  injector->performValidation(graph);
1488 
1489  // Instantiate eager singletons in the correct order.
1490  for (auto & key : graph.dependencyOrder()) {
1491  injector->bindings->get(key)->instantiateIfEager(*injector);
1492  }
1493 
1494  if (Impl::InjectorLogger::log().enabled(LoggingLevel::TRACE)) {
1495  Impl::InjectorLogger::log().trace(injector->printBindings(false).c_str());
1496  }
1497 
1498  for (const auto & f : injector->postConstructionCalls) {
1499  f(*injector);
1500  }
1501 
1502  return injector;
1503  }
1504 
1505  private: static std::shared_ptr<Injector> createInjector(const std::shared_ptr<const Injector> & parent,
1506  const std::vector<std::shared_ptr<InjectorConfiguration>> & conf) {
1507  auto injector = std::shared_ptr<Injector>(new Injector(parent, conf)); // NOLINT
1508  Impl::BindingGraph graph;
1509  injector->performValidation(graph);
1510 
1511  // Instantiate eager singletons in the correct order.
1512  for (auto & key : graph.dependencyOrder()) {
1513  injector->bindings->get(key)->instantiateIfEager(*injector);
1514  }
1515 
1516  if (Impl::InjectorLogger::log().enabled(LoggingLevel::TRACE)) {
1517  Impl::InjectorLogger::log().trace(injector->printBindings(false).c_str());
1518  }
1519 
1520  for (const auto & f : injector->postConstructionCalls) {
1521  f(*injector);
1522  }
1523 
1524  return injector;
1525  }
1526 
1527  // Main constructor.
1528  private: template <typename ... Conf>
1529  explicit Injector(std::shared_ptr<const Injector> parent_, const Conf & ... conf)
1530  : parent(std::move(parent_))
1531  , bindings(createBindings(conf ...)) {}
1532 
1533  // Main constructor.
1534  private: Injector(std::shared_ptr<const Injector> parent_, const std::vector<std::shared_ptr<InjectorConfiguration>> & conf)
1535  : parent(std::move(parent_))
1536  , bindings(createBindings(conf)) {}
1537 
1538  private: class PrototypeConstruction {};
1539 
1540  // Prototype constructor.
1541  // Copy the bindings shared ptr instead of moving it.
1542  private: Injector(PrototypeConstruction,
1543  std::shared_ptr<const Injector> parent_,
1544  const std::shared_ptr<const Injector> & prototype)
1545  : parent(std::move(parent_))
1546  , bindings(prototype->bindings) {}
1547 
1548  public: ~Injector() {
1549  for (const auto & f : preDestructionCalls) {
1550  f();
1551  }
1552  }
1553 
1554  private: template <typename ... Conf> std::shared_ptr<Impl::BindingMap> createBindings(const Conf & ... conf) {
1555  std::vector<const InjectorConfiguration *> extraConfiguration;
1556 
1557  auto builders = Util::Memory::makeSharedV<InjectorConfiguration, Impl::BindingBuilderBase>(
1558  [&extraConfiguration, this] (const InjectorConfiguration & conf) {
1559  auto b = conf.execute();
1560  Util::Containers::append(postConstructionCalls, conf.getPostConstructionCalls());
1561  Util::Containers::append(preDestructionCalls, conf.getPreDestructionCalls());
1562 
1563  auto s = conf.getStaticSingletonPostConstructionCalls();
1564 
1565  auto extra = conf.getExtraConfiguration();
1566  extraConfiguration.insert(extraConfiguration.end(), extra.begin(), extra.end());
1567  return b;
1568  }
1569  , conf ...
1570  );
1571 
1572  for (const auto & c : extraConfiguration) {
1573  Util::Containers::append(builders, c->execute());
1574  Util::Containers::append(postConstructionCalls, c->getPostConstructionCalls());
1575  Util::Containers::append(preDestructionCalls, c->getPreDestructionCalls());
1576  }
1577 
1578  auto theBindings = std::make_shared<Impl::BindingMap>();
1579 
1580  for (auto & builder : builders) {
1581  Impl::BindingKey key(builder->key);
1582 
1583  // Check for duplicates.
1584  if (theBindings->hasBinding(key)) {
1586  }
1587 
1588  theBindings->put(key, builder->build());
1589  }
1590 
1591  return theBindings;
1592  }
1593 
1594  private: std::shared_ptr<Impl::BindingMap> createBindings(const std::vector<std::shared_ptr<InjectorConfiguration>> & conf) {
1595  std::vector<std::shared_ptr<Impl::BindingBuilderBase>> builders;
1596 
1597  for (const auto & c : conf) {
1598  Util::Containers::append(builders, c->execute());
1599  Util::Containers::append(postConstructionCalls, c->getPostConstructionCalls());
1600  Util::Containers::append(preDestructionCalls, c->getPreDestructionCalls());
1601  }
1602 
1603  for (const auto & c : conf) {
1604  for (const auto * c2 : c->getExtraConfiguration()) {
1605  Util::Vectors::append(builders, c2->execute());
1606  Util::Containers::append(postConstructionCalls, c2->getPostConstructionCalls());
1607  Util::Containers::append(preDestructionCalls, c2->getPreDestructionCalls());
1608  }
1609  }
1610 
1611  auto theBindings = std::make_shared<Impl::BindingMap>();
1612 
1613  for (auto & builder : builders) {
1614  Impl::BindingKey key(builder->key);
1615 
1616  // Check for duplicates.
1617  if (theBindings->hasBinding(key)) {
1619  }
1620 
1621  theBindings->put(key, builder->build());
1622  }
1623 
1624  return theBindings;
1625  }
1626 
1627  private: void registerPostConstructionCallImpl(const std::function<void (const Injector &)> & call) const {
1628  std::lock_guard<std::recursive_mutex> lock(callSync);
1629  postConstructionCalls.push_back(call);
1630  }
1631 
1632  private: void registerPreDestructionCallImpl(const std::function<void ()> & call) const {
1633  std::lock_guard<std::recursive_mutex> lock(callSync);
1634  preDestructionCalls.push_back(call);
1635  }
1636 
1637  private: template <typename ... Conf>
1638  static ValidationParent performValidation(const std::shared_ptr<const Injector> & parent, const Conf & ... conf) {
1639  auto injector = std::shared_ptr<Injector>(new Injector(parent, conf ...)); // NOLINT
1640  Impl::BindingGraph graph;
1641  injector->performValidation(graph);
1642  return ValidationParent(injector);
1643  }
1644 
1645  private: static ValidationParent performValidation(const std::shared_ptr<const Injector> & parent,
1646  const std::vector<std::shared_ptr<InjectorConfiguration>> & conf) {
1647  auto injector = std::shared_ptr<Injector>(new Injector(std::move(parent), conf)); // NOLINT
1648  Impl::BindingGraph graph;
1649  injector->performValidation(graph);
1650  return ValidationParent(injector);
1651  }
1652 
1653  private: void performValidation(Impl::BindingGraph & graph) const {
1654  // Create the vertices of the dependency graph.
1655  for (const auto & binding : *bindings) {
1656  const auto & key = binding.key;
1657 
1658  // Check for duplicates.
1659  if (graph.lookupDependency(key) != nullptr) {
1661  }
1662 
1663  graph.addDependency(key);
1664  }
1665 
1666  const auto weak = Impl::BindingMetaType::WeakPromotion;
1667  const auto shared = Impl::BindingMetaType::Shared;
1668  const Impl::BindingKey weakKey(typeid(Impl::BindingKeyType<weak, Injector>), "");
1669  const Impl::BindingKey constWeakKey(typeid(Impl::BindingKeyType<weak, const Injector>), "");
1670  const Impl::BindingKey sharedKey(typeid(Impl::BindingKeyType<shared, Injector>), "");
1671  const Impl::BindingKey constSharedKey(typeid(Impl::BindingKeyType<shared, const Injector>), "");
1672 
1673  // Validate and create the edges of the dependency graph.
1674  for (const auto & binding : (*bindings)) {
1675  binding.value->registerDependencies(graph, weakKey, constWeakKey, sharedKey, constSharedKey);
1676  }
1677 
1678  graph.logGraph(LoggingLevel::TRACE, "Injector dependency graph");
1679 
1680  std::vector<std::pair<Impl::BindingKey, Impl::BindingKey>> cycleEdges;
1681 
1682  if (graph.hasCycles(cycleEdges)) {
1683  ThrowBalauException(Exception::CyclicDependencyException, "Cycle edges found:\n" + printCyclicEdges(cycleEdges));
1684  }
1685  }
1686 
1687  private: std::string performPrintBindings(bool printAncestor) const {
1688  std::ostringstream builder;
1689  std::string_view prefix;
1690  performPrintBindings(builder, prefix, printAncestor);
1691  return builder.str();
1692  }
1693 
1694  private: void performPrintBindings(std::ostream & builder, std::string_view & prefix, bool pa) const {
1695  for (const auto & binding : (*bindings)) {
1696  builder << prefix << Impl::toString(binding.key);
1697  prefix = "\n";
1698  }
1699 
1700  if (pa && parent) {
1701  parent->performPrintBindings(builder, prefix, pa);
1702  }
1703  }
1704 
1705  private: std::string performPrintBindingsDetailed() const {
1706  std::ostringstream builder;
1707  std::string_view prefix;
1708  performPrintBindingsDetailed(builder, prefix);
1709  return builder.str();
1710  }
1711 
1712  private: void performPrintBindingsDetailed(std::ostream & builder, std::string_view & prefix) const {
1713  for (const auto & binding : (*bindings)) {
1714  builder << prefix << Impl::toString(binding.key);
1715  prefix = "\n";
1716 
1717  for (const auto & dependency : binding.value->getDependencyKeys()) {
1718  builder << prefix << " " << Impl::toString(dependency);
1719  }
1720  }
1721 
1722  if (parent) {
1723  parent->performPrintBindingsDetailed(builder, prefix);
1724  }
1725  }
1726 
1727  private: static std::string printCyclicEdges(const std::vector<std::pair<Impl::BindingKey, Impl::BindingKey>> & cycleEdges) {
1728  std::ostringstream builder;
1729  std::string_view prefix;
1730 
1731  for (const auto & cycleEdge : cycleEdges) {
1732  builder << prefix << Impl::toString(cycleEdge.first) << " --> " << Impl::toString(cycleEdge.second);
1733  prefix = "\n";
1734  }
1735 
1736  return builder.str();
1737  }
1738 
1739  // Main injector state.
1740  private: const std::shared_ptr<const Injector> parent;
1741  private: const std::shared_ptr<const Impl::BindingMap> bindings;
1742 
1743  // Data structures for callbacks.
1744  private: mutable std::list<std::function<void (const Injector& )>> postConstructionCalls;
1745  private: mutable std::list<std::function<void ()>> preDestructionCalls;
1746  private: mutable std::recursive_mutex callSync;
1747 };
1748 
1749 } // namespace Balau
1750 
1751 #pragma clang diagnostic pop
1752 
1753 #endif // COM_BORA_SOFTWARE__BALAU_APPLICATION__INJECTOR
static void append(DstT< D ... > &dst, const SrcT< S ... > &src, const SrcMT< SM ... > &... srcMore)
Appends the source containers to the destination container.
Definition: Containers.hpp:38
std::unique_ptr< BaseT, DeleterT > getUnique(std::function< std::unique_ptr< BaseT, DeleterT >()> &defaultValueSupplier) const
Get-instance method for unique pointers (polymorphic new instances).
Definition: Injector.hpp:477
std::unique_ptr< BaseT, DeleterT > getUnique(std::string_view name, std::unique_ptr< BaseT, DeleterT > &&defaultValue) const
Get-instance method for unique pointers (polymorphic new instances).
Definition: Injector.hpp:461
ValueT getValue(const ValueT &defaultValue) const
Get-instance method for values (non-polymorphic new instances).
Definition: Injector.hpp:359
std::shared_ptr< Injector > createChild(const std::vector< std::shared_ptr< InjectorConfiguration >> &conf) const
Construct a child injector with one or more injector configurations supplied in a vector...
Definition: Injector.hpp:143
Thrown when the supplied binding configuration has a cyclic dependency.
Definition: InjectorExceptions.hpp:28
Application configurations specify application injector bindings.
static ValidationParent validate(const std::vector< std::shared_ptr< InjectorConfiguration >> &conf)
Validate the runtime specified injector configuration.
Definition: Injector.hpp:214
InstT getInstance(std::string_view name=std::string_view()) const
Get an instance, the meta-type of which is determined by the specified type.
Definition: Injector.hpp:324
Log to the logger&#39;s trace stream if the logger is trace enabled.
#define ThrowBalauException(ExceptionClass,...)
Throw a Balau style exception, with implicit file and line number, and optional stacktrace.
Definition: BalauException.hpp:45
static Impl::BindingKey createBindingKey(const std::string &name="")
Used for binding error reporting.
Definition: Injector.hpp:277
static std::shared_ptr< Injector > create(const std::vector< std::shared_ptr< InjectorConfiguration >> &conf)
Construct an injector with one or more injector configurations supplied in a vector.
Definition: Injector.hpp:61
std::shared_ptr< BaseT > getShared(std::string_view name=std::string_view()) const
Get-instance method for shared pointers (polymorphic thread-local or non-thread-local singletons)...
Definition: Injector.hpp:571
ValueT getValue(std::string_view name, const std::function< ValueT()> &defaultValueSupplier) const
Get-instance method for values (non-polymorphic new instances).
Definition: Injector.hpp:409
Balau::U8String< AllocatorT > toString(const BalauException &e)
Base class toString<AllocatorT> function for Balau exceptions.
Definition: BalauException.hpp:122
void registerPreDestructionCall(const std::function< void()> &call) const
Register with the injector a callback that will be called in the injector&#39;s destructor, before the bindings are deleted.
Definition: Injector.hpp:95
The root Balau namespace.
Definition: ApplicationConfiguration.hpp:23
void iterate(const std::function< void(std::shared_ptr< const BaseT >)> &func, bool includeThreadLocal=false) const
For all singleton bindings of the specified type, call the supplied function with the binding&#39;s singl...
Definition: Injector.hpp:679
std::unique_ptr< BaseT, DeleterT > getUnique(std::string_view name=std::string_view()) const
Get-instance method for unique pointers (polymorphic new instances).
Definition: Injector.hpp:428
static ValidationParent validateChild(const ValidationParent &parent, const std::vector< std::shared_ptr< InjectorConfiguration >> &conf)
Validate the runtime specified child injector configuration.
Definition: Injector.hpp:246
std::unique_ptr< BaseT, DeleterT > getUnique(std::unique_ptr< BaseT > &&defaultValue) const
Get-instance method for unique pointers (polymorphic new instances).
Definition: Injector.hpp:444
ValueT getValue(std::string_view name=std::string_view()) const
Get-instance method for values (non-polymorphic new instances).
Definition: Injector.hpp:343
BaseT & getReference(std::string_view name=std::string_view()) const
Get-instance method for reference providers.
Definition: Injector.hpp:526
void iterate(const std::function< void(std::shared_ptr< BaseT >)> &func, bool includeThreadLocal=false) const
For all singleton bindings of the specified type, call the supplied function with the binding&#39;s singl...
Definition: Injector.hpp:667
std::shared_ptr< BaseT > getShared(const std::shared_ptr< BaseT > &defaultValue) const
Get-instance method for shared pointers (polymorphic thread-local or non-thread-local singletons)...
Definition: Injector.hpp:587
The main dependency injector class.
Definition: Injector.hpp:41
void registerPostConstructionCall(const std::function< void(const Injector &)> &call) const
Register with the injector a callback that will be called by the injector at the end of construction...
Definition: Injector.hpp:76
static std::shared_ptr< Injector > create(const Conf &... conf)
Construct an injector with one or more injector configurations.
Definition: Injector.hpp:51
Environment configurations specify environment injector bindings via properties files.
BaseT & getReference(BaseT &defaultValue) const
Get-instance method for reference providers.
Definition: Injector.hpp:539
static void append(std::vector< T > &dst, const std::vector< T > &src)
Appends the source vector to the destination vector.
Definition: Vectors.hpp:105
Utilities for memory.
std::shared_ptr< BaseT > getShared(const std::function< std::shared_ptr< BaseT >()> &defaultValueSupplier) const
Get-instance method for shared pointers (polymorphic thread-local or non-thread-local singletons)...
Definition: Injector.hpp:620
std::shared_ptr< Injector > createChild(const Conf &... conf) const
Construct a child injector with one or more injector configurations.
Definition: Injector.hpp:133
std::shared_ptr< BaseT > getShared(std::string_view name, const std::function< std::shared_ptr< BaseT >()> &defaultValueSupplier) const
Get-instance method for shared pointers (polymorphic thread-local or non-thread-local singletons)...
Definition: Injector.hpp:637
std::unique_ptr< BaseT, DeleterT > getUniqueOrNull(std::string_view name=std::string_view()) const
Get-instance method for unique pointers (polymorphic new instances).
Definition: Injector.hpp:510
std::shared_ptr< BaseT > getSharedOrNull(std::string_view name=std::string_view()) const
Get-instance method for shared pointers (polymorphic thread-local or non-thread-local singletons)...
Definition: Injector.hpp:653
void registerStaticSingleton(std::shared_ptr< T > *ptrPtr, std::string_view name=std::string_view()) const
Register a static singleton pointer that the injector will set up post-construction and invalidate pr...
Definition: Injector.hpp:119
static ValidationParent validate(const Conf &... conf)
Validate the runtime specified injector configuration.
Definition: Injector.hpp:200
static ValidationParent validateChild(ValidationParent parent, const Conf &... conf)
Validate the runtime specified child injector configuration.
Definition: Injector.hpp:231
std::string printBindingsDetailed() const
Print detailed bindings of this injector and the injector&#39;s ancestors.
Definition: Injector.hpp:304
Injector configurations specify injector bindings.
Definition: InjectorConfiguration.hpp:32
ValueT getValue(std::string_view name, const ValueT &defaultValue) const
Get-instance method for values (non-polymorphic new instances).
Definition: Injector.hpp:376
BaseT & getReference(std::string_view name, BaseT &defaultValue) const
Get-instance method for reference providers.
Definition: Injector.hpp:553
Encapsulates a validated parent injector for subsequent child validation calls.
Definition: Injector.hpp:179
Thrown when an illegal injector binding configuration is attempted.
Definition: InjectorExceptions.hpp:64
std::string printBindings(bool printAncestor=false) const
Print the bindings of this injector and optionally the injector&#39;s ancestors.
Definition: Injector.hpp:289
bool hasBinding(std::string_view name=std::string_view()) const
Returns true if the injector or its parent has a binding matching the specified type and name...
Definition: Injector.hpp:262
std::shared_ptr< BaseT > getShared(std::string_view name, const std::shared_ptr< BaseT > &defaultValue) const
Get-instance method for shared pointers (polymorphic thread-local or non-thread-local singletons)...
Definition: Injector.hpp:604
std::shared_ptr< Injector > createChild(const std::shared_ptr< Injector > &prototype) const
Construct a child injector from the previously constructed prototype.
Definition: Injector.hpp:164
Thrown when no binding is found in the injector.
Definition: InjectorExceptions.hpp:75
ValueT getValue(const std::function< ValueT()> &defaultValueSupplier) const
Get-instance method for values (non-polymorphic new instances).
Definition: Injector.hpp:392
std::unique_ptr< BaseT, DeleterT > getUnique(std::string_view name, std::function< std::unique_ptr< BaseT, DeleterT >()> &defaultValueSupplier) const
Get-instance method for unique pointers (polymorphic new instances).
Definition: Injector.hpp:494