<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchange_StructuredStreamEvents_ObjectReaderRegistry_h_
#define _Stroika_Foundation_DataExchange_StructuredStreamEvents_ObjectReaderRegistry_h_    1

#include    "../../StroikaPreComp.h"

#include    <type_traits>
#include    <typeindex>

#include    "../../Characters/String.h"
#include    "../../Characters/StringBuilder.h"
#include    "../../Configuration/Enumeration.h"
#include    "../../Containers/Bijection.h"
#include    "../../Containers/Collection.h"
#include    "../../Containers/Mapping.h"
#include    "../../Containers/Sequence.h"
#include    "../../Containers/Set.h"
#include    "../../Containers/SortedCollection.h"
#include    "../../Containers/SortedMapping.h"
#include    "../../Containers/SortedSet.h"
#include    "../../Execution/Synchronized.h"
#include    "../../Memory/Common.h"
#include    "../../Memory/Optional.h"
#include    "../../Streams/InputStream.h"
#include    "../../Time/DateTime.h"
#include    "../../Traversal/Range.h"

#include    "../StructFieldMetaInfo.h"

#include    "IConsumer.h"
#include    "Name.h"



/**
 *
 *
 *  \version    <a href="code_status.html#Alpha">Alpha</a>
 *
 *  TODO:
 *
 *
 *      @todo   Make AddCommonType() - when passed in an optional<T> - REquire that
 *              the type T is already in the registry (like with AddClass). To debug!
 *
 *      @todo   https://stroika.atlassian.net/browse/STK-408 - cleanup template specializations
 *
 *      @todo   Review names: I dont think we use the term reader and readerfactory totally uniformly, and
 *              we also need to clearly document why/when we use one versus the other (type system stores factories
 *              because you encounter them in parsing, and need instances to pop on stack to read a particular element).
 *
 *      @todo   Need much improved ObjectReaderRegistry docs
 *
 *      @todo   make more nested READER classes PRIVATE, and improve public ADDCOMMON<T> methods to registry - like we do
 *              For ObjectVariantMapper.
 *
 *      @todo   ConvertReaderToFactory() should do varargs perfect forwarding of extra params!
 *
 *      @todo   Get rid of or do diffenrtly the Run() methods - so can turn on/off Contextg debugging easier.
 *
 *      @todo   USE UnknownSubElementDisposition more throughly...
 *
 */



namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchange {
            namespace   StructuredStreamEvents {


                using   Characters::String;
                using   Containers::Mapping;
                using   Containers::Sequence;
                using   Containers::Set;
                using   Memory::Byte;


                /**
                  */
#ifndef qStroika_Foundation_DataExchange_StructuredStreamEvents_SupportTracing
#define qStroika_Foundation_DataExchange_StructuredStreamEvents_SupportTracing  qDebug
#endif


                /**
                 */
                enum    class  UnknownSubElementDisposition {
                    eIgnore,
                    eEndObject
                };


                /**
                 *      The basic idea of the ObjectReaderRegistry is to make it easier to write C++ code
                 *  to deserialize an XML source (via SAX), into a C++ data structure. This tends to be
                 *  MUCH MUCH harder than doing something similar by loading an XML DOM, and then traversing
                 *  the DOM with XPath. So why would you do it? This way is dramatically more efficient.
                 *  For one thing - there is no need to have the entire source in memory at a time, and there
                 *  is no need to ever construct intermediary DOM nodes.
                 *
                 *      We need good docs - on how to use this - but for the time being, just look at the
                 *  example usage in the regression test.
                 *
                 *    Look back to DataExchange::ObjectVariantmapper, but for now - KISS
                 *
                 *  \par Example Usage
                 *      \code
                 *      struct  Person_ {
                 *          String      firstName;
                 *          String      lastName;
                 *      };
                 *      ObjectReaderRegistry mapper;
                 *      mapper.AddCommonType<String> ();
                 *      mapper.AddClass<Person_> (initializer_list<pair<Name, StructFieldMetaInfo>> {
                 *          { Name { L"FirstName" }, Stroika_Foundation_DataExchange_StructFieldMetaInfo (Person_, firstName) },
                 *          { Name { L"LastName" }, Stroika_Foundation_DataExchange_StructFieldMetaInfo (Person_, lastName) },
                 *      });
                 *      Person_ p;
                 *      ObjectReaderRegistry::IConsumerDelegateToContext tmpCtx1 (mapper, mapper.mkReadDownToReader (mapper.MakeContextReader (&p)));
                 *      XML::SAXParse (mkdata_ (), tmpCtx1);
                 *      \endcode
                 *
                 *  \par Example Usage2
                 *      @see T3_SAXObjectReader_ReadDown2Sample_ in RegressionTest 'Foundation::DataExchangeFormat::XML::SaxParser'
                 *
                 *      \code
                 *      .. start with the types and mapper from Example 1, and add
                 *      Sequence<Person_> people;
                 *      mapper.AddCommonType<Sequence<Person_>> (Name (L"WithWhom"));
                 *      ObjectReaderRegistry::IConsumerDelegateToContext tmpCtx2 { mapper, mapper.mkReadDownToReader (newRegistry.MakeContextReader (&people)) };
                 *      XML::SAXParse (mkdata_ (), tmp);
                 *      \endcode
                 */
                class   ObjectReaderRegistry {
                public:
                    ObjectReaderRegistry () = default;
                    ObjectReaderRegistry (const ObjectReaderRegistry&) = default;

                public:
                    ObjectReaderRegistry& operator= (const ObjectReaderRegistry&) = default;

                public:
                    class   Context;
                    class   IElementConsumer;
                    class   IConsumerDelegateToContext;
                    class   IgnoreNodeReader;
                    template    <typename   T>
                    class   ClassReader;
                    template    <typename   T>
                    class   ListOfObjectReader;
                    template    <typename   T>
                    class   RepeatedElementReader;

                public:
                    /**
                     */
                    template    <typename T>
                    using   ReaderFromTStarFactory = function<shared_ptr<IElementConsumer> (T* destinationObject)>;

                public:
                    /**
                     *  We store in our database factories that read into a 'void*' that must be of the right type,
                     *  but we use (at the last minute) the appropriate type. This is typesafe iff the readers do casts
                     *  safely (and all the readers we provide do).
                     */
                    using   ReaderFromVoidStarFactory = ReaderFromTStarFactory<void>;

                public:
                    /**
                     */
                    nonvirtual  void    Add (type_index forType, const ReaderFromVoidStarFactory& readerFactory);
                    template    <typename T>
                    nonvirtual  void    Add (const ReaderFromTStarFactory<T>& readerFactory);

                public:
                    /**
                     *  Shortcut for Add (MakeCommonReader<T> ());
                     *
                     *  So - this is supported for any type for which (@see MakeCommonReader) is supported.
                     *
                     *  Note this this is not needed (because it's done by default), but is supported,
                     *  for the builtin types.
                     */
                    template    <typename T, typename... ARGS>
                    nonvirtual  void    AddCommonType (ARGS&& ... args);

                public:
                    /**
                     */
                    class   ReadDownToReader;

                public:
                    /**
                     */
                    static  shared_ptr<ReadDownToReader>    mkReadDownToReader (const shared_ptr<IElementConsumer>& theUseReader);
                    static  shared_ptr<ReadDownToReader>    mkReadDownToReader (const shared_ptr<IElementConsumer>& theUseReader, const Name& tagToHandOff);

                public:
                    /**

                    &todo
                    &&&& FROM ObjectVaarianeMapper... .nDOPCS NOT RIGHT BUT A START
                    ....
                     *  This creates serializers for many common types.
                     *      o   Mapping<Key,Value>
                     *      o   Optional<T>
                     *      o   Range<T,TRAITS>
                     *      o   Sequence<T>
                     *      o   Set<T>
                     *  ###NYI    o   T[N]      -- so far cannot get to work
                     *      o   enum types (with eSTART/eEND @see Stroika_Define_Enum_Bounds for bounds checking)
                     *
                     *  This assumes the template parameters for the above objects are also already defined (mostly 'T' above).
                     *
                     *  This function also works (but is generally unneeded for) any of the types defined in
                     *  @see ResetToDefaultTypeRegistry () (int, short, String, etc).
                     *
                     *  Note - all these de-serializers will throw BadDataFormat exceptions if the data somehow doesnt
                     *  fit what the deserailizer expects.
                     */
                    template    <typename T, typename... ARGS>
                    static  ReaderFromVoidStarFactory  MakeCommonReader (ARGS&& ... args);

                public:
                    /**
                     *  \req    AddClass<> requires that each field data type already be pre-loaded into the
                     *          ObjectReaderRegistry. To avoid this requirement, you an use MakeClassReader
                     *          directly, but if this type is absent when you call AddClass<> - its most likely
                     *          a bug.
                     */
                    template    <typename CLASS>
                    nonvirtual  void    AddClass (const Mapping<Name, StructFieldMetaInfo>& fieldInfo);

                public:
                    /**
                     */
                    template    <typename CLASS>
                    nonvirtual  ReaderFromVoidStarFactory    MakeClassReader (const Mapping<Name, StructFieldMetaInfo>& fieldInfo);

                public:
                    /**
                     *  It's pretty easy to code up a 'reader' class - just a simple subclass of IElementConsumer.
                     *  There are lots of examples in this module.
                     *
                     *  But the APIs in the ObjectReaderRegistry require factories, and this utility function constructs
                     *  a factory from the given READER class template parameter.
                     */
                    template    <typename T, typename READER, typename... ARGS>
                    static  auto    ConvertReaderToFactory (ARGS&& ... args) -> ObjectReaderRegistry::ReaderFromVoidStarFactory;

                public:
                    /**
                     *  This is generally just called inside of another composite reader to read sub-objects.
                     */
                    shared_ptr<IElementConsumer>    MakeContextReader (type_index ti, void* destinationObject) const;
                    template    <typename T>
                    shared_ptr<IElementConsumer>    MakeContextReader (T* destinationObject) const;

                private:
                    template    <typename   T>
                    class   SimpleReader_;
                    template    <typename   T>
                    class   OptionalTypesReader_;

                private:
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   cvtFactory_ (const ReaderFromTStarFactory<T>& tf );
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_SimpleReader_ ();
                private:
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const String*);
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const Time::DateTime*);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const T*, typename std::enable_if<std::is_pod<T>::value >::type* = 0);
                    template    <typename T, typename TRAITS>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const Memory::Optional<T, TRAITS>*);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const vector<T>*);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const vector<T>*, const Name& name);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const Sequence<T>*);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const Sequence<T>*, const Name& name);

                private:
                    Mapping<type_index, ReaderFromVoidStarFactory> fFactories_;
                };


                /**
                 *  Subclasses of this abstract class are responsible for consuming data at a given level of the SAX 'tree', and transform
                 *  it into a related object.
                 */
                class   ObjectReaderRegistry::IElementConsumer : public enable_shared_from_this<IElementConsumer> {
                protected:
                    /**
                     */
                    IElementConsumer () = default;

                public:
                    /**
                     */
                    virtual ~IElementConsumer () = default;

                public:
                    /**
                     *  pushed onto context stack
                     */
                    virtual void    Activated (Context& r);

                public:
                    /**
                     */
                    virtual shared_ptr<IElementConsumer>    HandleChildStart (const Name& name);

                public:
                    /**
                     */
                    virtual void    HandleTextInside (const String& text);

                public:
                    /**
                     * About to pop from ontext stack
                     */
                    virtual void    Deactivating ();
                };


                /**
                 *  This concrete class is used to capture the state of an ongoing StructuredStreamParse/transformation. Logically, it
                 *  mainstains the 'stack' you would have in constructing a recursive decent object mapping.
                 *
                 *  \note   Important Design Principle for Reader
                 *
                 *          We only recognize a new 'type' by its 'Start' element. So its at that (or sometimes the start/end of a child) that
                 *          we can PUSH a new reader in place.
                 *
                 *          The current tags and text get delivered to the top of the stack.
                 *
                 *          When we encounter a close tag, we end that reading, and so pop.
                 *
                 *          This means that the start and end tags for a given pair, go to differnt 'IElementConsumer'
                 *          subclasses. The START goes to the parent (so it can create the right type), and the EndTag
                 *          goes to the created/pushed type, so it can close itself and pop back to the parent context.
                 */
                class   ObjectReaderRegistry::Context {
                public:
#if     qStroika_Foundation_DataExchange_StructuredStreamEvents_SupportTracing
                public:
                    bool    fTraceThisReader { false };       // very noisy - off by default even for tracemode
                    nonvirtual  String TraceLeader_ () const;
#endif

                public:
                    Context (const ObjectReaderRegistry& objectReaderRegistry);
                    Context (const ObjectReaderRegistry& objectReaderRegistry, const shared_ptr<IElementConsumer>& initialTop);
                    Context (const Context&) = delete;
                    Context (Context&& from);
                    Context& operator= (const Context&) = delete;
<commit_msg>doc comments<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchange_StructuredStreamEvents_ObjectReaderRegistry_h_
#define _Stroika_Foundation_DataExchange_StructuredStreamEvents_ObjectReaderRegistry_h_    1

#include    "../../StroikaPreComp.h"

#include    <type_traits>
#include    <typeindex>

#include    "../../Characters/String.h"
#include    "../../Characters/StringBuilder.h"
#include    "../../Configuration/Enumeration.h"
#include    "../../Containers/Bijection.h"
#include    "../../Containers/Collection.h"
#include    "../../Containers/Mapping.h"
#include    "../../Containers/Sequence.h"
#include    "../../Containers/Set.h"
#include    "../../Containers/SortedCollection.h"
#include    "../../Containers/SortedMapping.h"
#include    "../../Containers/SortedSet.h"
#include    "../../Execution/Synchronized.h"
#include    "../../Memory/Common.h"
#include    "../../Memory/Optional.h"
#include    "../../Streams/InputStream.h"
#include    "../../Time/DateTime.h"
#include    "../../Traversal/Range.h"

#include    "../StructFieldMetaInfo.h"

#include    "IConsumer.h"
#include    "Name.h"



/**
 *
 *
 *  \version    <a href="code_status.html#Alpha">Alpha</a>
 *
 *  TODO:
 *
 *
 *      @todo   Make AddCommonType() - when passed in an optional<T> - REquire that
 *              the type T is already in the registry (like with AddClass). To debug!
 *
 *      @todo   https://stroika.atlassian.net/browse/STK-408 - cleanup template specializations
 *
 *      @todo   Review names: I dont think we use the term reader and readerfactory totally uniformly, and
 *              we also need to clearly document why/when we use one versus the other (type system stores factories
 *              because you encounter them in parsing, and need instances to pop on stack to read a particular element).
 *
 *      @todo   Need much improved ObjectReaderRegistry docs
 *
 *      @todo   make more nested READER classes PRIVATE, and improve public ADDCOMMON<T> methods to registry - like we do
 *              For ObjectVariantMapper.
 *
 *      @todo   ConvertReaderToFactory() should do varargs perfect forwarding of extra params!
 *
 *      @todo   Get rid of or do diffenrtly the Run() methods - so can turn on/off Contextg debugging easier.
 *
 *      @todo   USE UnknownSubElementDisposition more throughly...
 *
 */



namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchange {
            namespace   StructuredStreamEvents {


                using   Characters::String;
                using   Containers::Mapping;
                using   Containers::Sequence;
                using   Containers::Set;
                using   Memory::Byte;


                /**
                  */
#ifndef qStroika_Foundation_DataExchange_StructuredStreamEvents_SupportTracing
#define qStroika_Foundation_DataExchange_StructuredStreamEvents_SupportTracing  qDebug
#endif


                /**
                 */
                enum    class  UnknownSubElementDisposition {
                    eIgnore,
                    eEndObject
                };


                /**
                 *      The basic idea of the ObjectReaderRegistry is to make it easier to write C++ code
                 *  to deserialize an XML source (via SAX), into a C++ data structure. This tends to be
                 *  MUCH MUCH harder than doing something similar by loading an XML DOM, and then traversing
                 *  the DOM with XPath. So why would you do it? This way is dramatically more efficient.
                 *  For one thing - there is no need to have the entire source in memory at a time, and there
                 *  is no need to ever construct intermediary DOM nodes.
                 *
                 *      We need good docs - on how to use this - but for the time being, just look at the
                 *  example usage in the regression test.
                 *
                 *    Look back to DataExchange::ObjectVariantmapper, but for now - KISS
                 *
                 *  \par Example Usage
                 *      \code
                 *      struct  Person_ {
                 *          String      firstName;
                 *          String      lastName;
                 *      };
                 *      ObjectReaderRegistry mapper;
                 *      mapper.AddCommonType<String> ();
                 *      mapper.AddClass<Person_> (initializer_list<pair<Name, StructFieldMetaInfo>> {
                 *          { Name { L"FirstName" }, Stroika_Foundation_DataExchange_StructFieldMetaInfo (Person_, firstName) },
                 *          { Name { L"LastName" }, Stroika_Foundation_DataExchange_StructFieldMetaInfo (Person_, lastName) },
                 *      });
                 *      Person_ p;
                 *      ObjectReaderRegistry::IConsumerDelegateToContext tmpCtx1 (mapper, mapper.mkReadDownToReader (mapper.MakeContextReader (&p)));
                 *      XML::SAXParse (mkdata_ (), tmpCtx1);
                 *      \endcode
                 *
                 *  \par Example Usage2
                 *      @see T3_SAXObjectReader_ReadDown2Sample_ in RegressionTest 'Foundation::DataExchangeFormat::XML::SaxParser'
                 *
                 *      \code
                 *      .. start with the types and mapper from Example 1, and add
                 *      Sequence<Person_> people;
                 *      mapper.AddCommonType<Sequence<Person_>> (Name (L"WithWhom"));
                 *      ObjectReaderRegistry::IConsumerDelegateToContext tmpCtx2 { mapper, mapper.mkReadDownToReader (newRegistry.MakeContextReader (&people)) };
                 *      XML::SAXParse (mkdata_ (), tmp);
                 *      \endcode
                 */
                class   ObjectReaderRegistry {
                public:
                    ObjectReaderRegistry () = default;
                    ObjectReaderRegistry (const ObjectReaderRegistry&) = default;

                public:
                    ObjectReaderRegistry& operator= (const ObjectReaderRegistry&) = default;

                public:
                    class   Context;
                    class   IElementConsumer;
                    class   IConsumerDelegateToContext;
                    class   IgnoreNodeReader;
                    template    <typename   T>
                    class   ClassReader;
                    template    <typename   T>
                    class   ListOfObjectReader;
                    template    <typename   T>
                    class   RepeatedElementReader;

                public:
                    /**
                     */
                    template    <typename T>
                    using   ReaderFromTStarFactory = function<shared_ptr<IElementConsumer> (T* destinationObject)>;

                public:
                    /**
                     *  We store in our database factories that read into a 'void*' that must be of the right type,
                     *  but we use (at the last minute) the appropriate type. This is typesafe iff the readers do casts
                     *  safely (and all the readers we provide do).
                     */
                    using   ReaderFromVoidStarFactory = ReaderFromTStarFactory<void>;

                public:
                    /**
                     */
                    nonvirtual  void    Add (type_index forType, const ReaderFromVoidStarFactory& readerFactory);
                    template    <typename T>
                    nonvirtual  void    Add (const ReaderFromTStarFactory<T>& readerFactory);

                public:
                    /**
                     *  Shortcut for Add (MakeCommonReader<T> ());
                     *
                     *  So - this is supported for any type for which (@see MakeCommonReader) is supported.
                     *
                     *  Note this this is not needed (because it's done by default), but is supported,
                     *  for the builtin types.
                     */
                    template    <typename T, typename... ARGS>
                    nonvirtual  void    AddCommonType (ARGS&& ... args);

                public:
                    /**
                     */
                    class   ReadDownToReader;

                public:
                    /**
                     */
                    static  shared_ptr<ReadDownToReader>    mkReadDownToReader (const shared_ptr<IElementConsumer>& theUseReader);
                    static  shared_ptr<ReadDownToReader>    mkReadDownToReader (const shared_ptr<IElementConsumer>& theUseReader, const Name& tagToHandOff);

                public:
                    /**

                    &todo
                    &&&& FROM ObjectVaarianeMapper... .nDOPCS NOT RIGHT BUT A START
                    ....
                     *  This creates serializers for many common types.
                     *      o   Mapping<Key,Value>
                     *      o   Optional<T>
                     *      o   Range<T,TRAITS>
                     *      o   Sequence<T>
                     *      o   Set<T>
                     *  ###NYI    o   T[N]      -- so far cannot get to work
                     *      o   enum types (with eSTART/eEND @see Stroika_Define_Enum_Bounds for bounds checking)
                     *
                     *  This assumes the template parameters for the above objects are also already defined (mostly 'T' above).
                     *
                     *  This function also works (but is generally unneeded for) any of the types defined in
                     *  @see ResetToDefaultTypeRegistry () (int, short, String, etc).
                     *
                     *  Note - all these de-serializers will throw BadDataFormat exceptions if the data somehow doesnt
                     *  fit what the deserailizer expects.
                     */
                    template    <typename T, typename... ARGS>
                    static  ReaderFromVoidStarFactory  MakeCommonReader (ARGS&& ... args);

                public:
                    /**
                     *  \req    AddClass<> requires that each field data type already be pre-loaded into the
                     *          ObjectReaderRegistry. To avoid this requirement, you an use MakeClassReader
                     *          directly, but if this type is absent when you call AddClass<> - its most likely
                     *          a bug.
                     */
                    template    <typename CLASS>
                    nonvirtual  void    AddClass (const Mapping<Name, StructFieldMetaInfo>& fieldInfo);

                public:
                    /**
                     */
                    template    <typename CLASS>
                    nonvirtual  ReaderFromVoidStarFactory    MakeClassReader (const Mapping<Name, StructFieldMetaInfo>& fieldInfo);

                public:
                    /**
                     *  It's pretty easy to code up a 'reader' class - just a simple subclass of IElementConsumer.
                     *  There are lots of examples in this module.
                     *
                     *  But the APIs in the ObjectReaderRegistry require factories, and this utility function constructs
                     *  a factory from the given READER class template parameter.
                     */
                    template    <typename T, typename READER, typename... ARGS>
                    static  auto    ConvertReaderToFactory (ARGS&& ... args) -> ObjectReaderRegistry::ReaderFromVoidStarFactory;

                public:
                    /**
                     *  This is generally just called inside of another composite reader to read sub-objects.
                     */
                    shared_ptr<IElementConsumer>    MakeContextReader (type_index ti, void* destinationObject) const;
                    template    <typename T>
                    shared_ptr<IElementConsumer>    MakeContextReader (T* destinationObject) const;

                private:
                    template    <typename   T>
                    class   SimpleReader_;
                    template    <typename   T>
                    class   OptionalTypesReader_;

                private:
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   cvtFactory_ (const ReaderFromTStarFactory<T>& tf );
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_SimpleReader_ ();
                private:
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const String*);
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const Time::DateTime*);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const T*, typename std::enable_if<std::is_pod<T>::value >::type* = 0);
                    template    <typename T, typename TRAITS>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const Memory::Optional<T, TRAITS>*);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const vector<T>*);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const vector<T>*, const Name& name);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const Sequence<T>*);
                    template    <typename T>
                    static  ReaderFromVoidStarFactory   MakeCommonReader_ (const Sequence<T>*, const Name& name);

                private:
                    Mapping<type_index, ReaderFromVoidStarFactory> fFactories_;
                };


                /**
                 *  Subclasses of this abstract class are responsible for consuming data at a given level of the SAX 'tree', and transform
                 *  it into a related object.
                 */
                class   ObjectReaderRegistry::IElementConsumer : public enable_shared_from_this<IElementConsumer> {
                protected:
                    /**
                     */
                    IElementConsumer () = default;

                public:
                    /**
                     */
                    virtual ~IElementConsumer () = default;

                public:
                    /**
                     *  pushed onto context stack
                     */
                    virtual void    Activated (Context& r);

                public:
                    /**
                     */
                    virtual shared_ptr<IElementConsumer>    HandleChildStart (const Name& name);

                public:
                    /**
                     */
                    virtual void    HandleTextInside (const String& text);

                public:
                    /**
                     * About to pop from ontext stack
                     */
                    virtual void    Deactivating ();
                };


                /**
                 *  This concrete class is used to capture the state of an ongoing StructuredStreamParse/transformation. Logically, it
                 *  mainstains the 'stack' you would have in constructing a recursive decent object mapping.
                 *
                 *  \note   Important Design Principle for Reader
                 *
                 *          We only recognize a new 'type' by its 'Start' element. So its at that (or sometimes the start/end of a child) that
                 *          we can PUSH a new reader in place.
                 *
                 *          The current tags and text get delivered to the top of the stack.
                 *
                 *          When we encounter a close tag, we end that reading, and so pop.
                 *
                 *          This means that the start and end tags for a given pair, go to differnt 'IElementConsumer'
                 *          subclasses. The START goes to the parent (so it can create the right type), and the EndTag
                 *          goes to the created/pushed type, so it can close itself and pop back to the parent context.
                 *
                 *  \note   Debugging Note
                 *          It's often helpful to turn on fTraceThisReader while debugging SAX parsing, to see why something
                 *          isn't being read.
                 */
                class   ObjectReaderRegistry::Context {
                public:
#if     qStroika_Foundation_DataExchange_StructuredStreamEvents_SupportTracing
                public:
                    bool    fTraceThisReader { false };       // very noisy - off by default even for tracemode
                    nonvirtual  String TraceLeader_ () const;
#endif

                public:
                    Context (const ObjectReaderRegistry& objectReaderRegistry);
                    Context (const ObjectReaderRegistry& objectReaderRegistry, const shared_ptr<IElementConsumer>& initialTop);
                    Context (const Context&) = delete;
                    Context (Context&& from);
                    Context& operator= (const Context&) = delete;

{'fraction_non_alphanumeric': 0.06979892838624187, 'fraction_numerical': 0.0011522728582128248, 'mean_word_length': 1.3402318996899016, 'pattern_counts': {'":': 0, '<': 135, '<?xml version=': 0, '>': 137, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2148946', 'n_tokens_mistral': 8201, 'n_tokens_neox': 7607, 'n_words': 2466}