diff options
| author | Jörg Frings-Fürst <debian@jff.email> | 2024-03-06 10:24:08 +0100 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff.email> | 2024-03-06 10:24:08 +0100 | 
| commit | aad5ad9bf0c02aa4e79bc6b7d6c934612fff4026 (patch) | |
| tree | 9cc224b059f248a6229ab0dcdc64eb4a73fa9800 /xsd/processing/cardinality | |
| parent | c1034fc5e99197f507caf450aa15bc178698b26e (diff) | |
New upstream version 4.2.0upstream/4.2.0upstream
Diffstat (limited to 'xsd/processing/cardinality')
| -rw-r--r-- | xsd/processing/cardinality/processor.cxx | 407 | ||||
| -rw-r--r-- | xsd/processing/cardinality/processor.hxx | 28 | 
2 files changed, 435 insertions, 0 deletions
| diff --git a/xsd/processing/cardinality/processor.cxx b/xsd/processing/cardinality/processor.cxx new file mode 100644 index 0000000..c8c5dc5 --- /dev/null +++ b/xsd/processing/cardinality/processor.cxx @@ -0,0 +1,407 @@ +// file      : xsd/processing/cardinality/processor.cxx +// license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <map> + +#include <libxsd-frontend/semantic-graph.hxx> +#include <libxsd-frontend/traversal.hxx> + +#include <xsd/elements.hxx> + +#include <xsd/processing/cardinality/processor.hxx> + +using namespace std; + +namespace Processing +{ +  namespace SemanticGraph = XSDFrontend::SemanticGraph; +  namespace Traversal = XSDFrontend::Traversal; + +  namespace Cardinality +  { +    namespace +    { +      // +      // +      struct ElementInfo +      { +        ElementInfo () +            : min (0), max (0), e_ (0) +        { +        } + +        ElementInfo (SemanticGraph::Element& e) +            : min (1), max (1), e_ (&e) +        { +        } + +        ElementInfo (SemanticGraph::Element& e, size_t min_, size_t max_) +            : min (min_), max (max_), e_ (&e) +        { +        } + +        SemanticGraph::Element& +        element () +        { +          assert (e_ != 0); +          return *e_; +        } + +      public: +        size_t min, max; + +      private: +        SemanticGraph::Element* e_; +      }; + +      typedef map<String, ElementInfo> ElementInfoMap; + +      // +      // +      struct AnyInfo +      { +        AnyInfo () +            : min (0), max (0), a_ (0) +        { +        } + +        AnyInfo (SemanticGraph::Any& a) +            : min (1), max (1), a_ (&a) +        { +        } + +        AnyInfo (SemanticGraph::Any& a, size_t min_, size_t max_) +            : min (min_), max (max_), a_ (&a) +        { +        } + +        SemanticGraph::Any& +        any () +        { +          assert (a_ != 0); +          return *a_; +        } + +      public: +        size_t min, max; + +      private: +        SemanticGraph::Any* a_; +      }; + +      typedef map<String, AnyInfo> AnyInfoMap; + +      // +      // +      struct Particle: Traversal::All, +                       Traversal::Choice, +                       Traversal::Sequence, +                       Traversal::Element, +                       Traversal::Any +      { +        virtual void +        traverse (SemanticGraph::All& a) +        { +          traverse_sequence (a); +        } + +        virtual void +        traverse (SemanticGraph::Choice& c) +        { +          using SemanticGraph::Compositor; + +          // Go over all particles we contain and add them to the map. +          // +          for (Compositor::ContainsIterator ci (c.contains_begin ()); +               ci != c.contains_end (); ++ci) +          { +            Particle t; +            t.dispatch (ci->particle ()); + +            // Handle elements. +            // +            if (ci == c.contains_begin ()) +              el_map = t.el_map; // First arm. +            else +            { +              // For elements that are in the map but not in this +              // arm of choice, we need to set min to 0 while for +              // those that are we need to choose minimum between +              // the two for min and maximum for max. +              // +              for (ElementInfoMap::iterator i (el_map.begin ()); +                   i != el_map.end (); ++i) +              { +                String const& name (i->first); +                ElementInfo& ei (i->second); + +                ElementInfoMap::iterator j (t.el_map.find (name)); + +                if (j == t.el_map.end ()) +                  ei.min = 0; +                else +                { +                  ei.min = j->second.min < ei.min ? j->second.min : ei.min; + +                  // Unbounded is encoded as 0. +                  // +                  if (j->second.max == 0 || ei.max == 0) +                    ei.max = 0; +                  else +                    ei.max = j->second.max > ei.max ? j->second.max : ei.max; +                } +              } + +              // Now elements that are in this arm of choice but are +              // not in the map, we need to add to the map and set their +              // min to 0. +              // +              for (ElementInfoMap::iterator i (t.el_map.begin ()); +                   i != t.el_map.end (); ++i) +              { +                String const& name (i->first); +                ElementInfo& ei (i->second); + +                ElementInfoMap::iterator j (el_map.find (name)); + +                if (j == el_map.end ()) +                  el_map[name] = ElementInfo (ei.element (), 0, ei.max); +              } +            } + +            // Handle wildcards. Since each wildcard is treated as unique, +            // we need to copy them from each arm of choice and set min to +            // 0. +            // +            for (AnyInfoMap::iterator i (t.any_map.begin ()); +                 i != t.any_map.end (); ++i) +            { +              String const& name (i->first); +              AnyInfo& ai (i->second); + +              assert (any_map.find (name) == any_map.end ()); + +              any_map[name] = AnyInfo (ai.any (), 0, ai.max); +            } +          } + +          // Choice's min and max. +          // +          size_t cmin (c.min ()), cmax (c.max ()); + +          // Iterate over elements and wildcards in the maps and multiply +          // their cardinality by cmin and cmax. +          // +          for (ElementInfoMap::iterator i (el_map.begin ()); +               i != el_map.end (); ++i) +          { +            i->second.min *= cmin; +            i->second.max *= cmax; +          } + +          for (AnyInfoMap::iterator i (any_map.begin ()); +               i != any_map.end (); ++i) +          { +            i->second.min *= cmin; // Not really necessary since min == 0. +            i->second.max *= cmax; +          } +        } + +        virtual void +        traverse (SemanticGraph::Sequence& s) +        { +          traverse_sequence (s); +        } + +        void +        traverse_sequence (SemanticGraph::Compositor& c) +        { +          using SemanticGraph::Compositor; + +          // Sequence's min and max. +          // +          size_t smin (c.min ()), smax (c.max ()); + +          // Go over all particles we contain and add them to the map. +          // +          for (Compositor::ContainsIterator ci (c.contains_begin ()); +               ci != c.contains_end (); ++ci) +          { +            Particle t; +            t.dispatch (ci->particle ()); + +            // Handle elements. +            // +            for (ElementInfoMap::iterator i (t.el_map.begin ()); +                 i != t.el_map.end (); ++i) +            { +              String const& name (i->first); +              ElementInfo& ei (i->second); +              size_t min (ei.min * smin); +              size_t max (ei.max * smax); +              ElementInfoMap::iterator j (el_map.find (name)); + +              if (j != el_map.end ()) +              { +                // Add i's cardinality to j +                // +                j->second.min += min; +                j->second.max = (j->second.max == 0 || max == 0) ? +                  0 : (j->second.max + max); +              } +              else +                el_map[name] = ElementInfo (ei.element (), min, max); +            } + +            // Handle wildcards. +            // +            for (AnyInfoMap::iterator i (t.any_map.begin ()); +                 i != t.any_map.end (); ++i) +            { +              String const& name (i->first); +              AnyInfo& ai (i->second); +              size_t min (ai.min * smin); +              size_t max (ai.max * smax); + +              assert (any_map.find (name) == any_map.end ()); + +              any_map[name] = AnyInfo (ai.any (), min, max); +            } +          } +        } + +        virtual void +        traverse (SemanticGraph::Element& e) +        { +          SemanticGraph::ContainsParticle& cp (e.contained_particle ()); + +          String name (e.qualified_p () +                       ? e.namespace_ ().name () + L" " + e.name () +                       : e.name ()); + +          el_map[name] = ElementInfo (e, cp.min (), cp.max ()); +        } + +        virtual void +        traverse (SemanticGraph::Any& a) +        { +          SemanticGraph::ContainsParticle& cp (a.contained_particle ()); + +          any_map[a.name ()] = AnyInfo (a, cp.min (), cp.max ()); +        } + +      public: +        AnyInfoMap any_map; +        ElementInfoMap el_map; +      }; + + +      // +      // +      struct Complex: Traversal::Complex +      { +        virtual void +        traverse (Type& c) +        { +          if (c.contains_compositor_p ()) +          { +            Particle t; +            t.dispatch (c.contains_compositor ().compositor ()); + +            for (ElementInfoMap::iterator i (t.el_map.begin ()); +                 i != t.el_map.end (); ++i) +            { +              ElementInfo& ei (i->second); +              SemanticGraph::Context& ctx (ei.element ().context ()); + +              ctx.set ("min", ei.min); +              ctx.set ("max", ei.max); +            } + +            for (AnyInfoMap::iterator i (t.any_map.begin ()); +                 i != t.any_map.end (); ++i) +            { +              AnyInfo& ai (i->second); +              SemanticGraph::Context& ctx (ai.any ().context ()); + +              ctx.set ("min", ai.min); +              ctx.set ("max", ai.max); +            } +          } + +          // Traverse attributes and anonymous types (via elements). +          // +          Complex::names (c); +        } +      }; + + +      // +      // +      struct Attribute: Traversal::Attribute +      { +        virtual void +        traverse (Type& a) +        { +          SemanticGraph::Context& ctx (a.context ()); + +          ctx.set ("min", size_t (a.optional_p () ? 0 : 1)); +          ctx.set ("max", size_t (1)); +        } +      }; + +      // Go into implied/included/imported schemas while making sure +      // we don't process the same stuff more than once. +      // +      struct Uses: Traversal::Uses +      { +        virtual void +        traverse (Type& u) +        { +          SemanticGraph::Schema& s (u.schema ()); + +          if (!s.context ().count ("processing-cardinality-seen")) +          { +            s.context ().set ("processing-cardinality-seen", true); +            Traversal::Uses::traverse (u); +          } +        } +      }; +    } + +    void Processor:: +    process (SemanticGraph::Schema& tu, SemanticGraph::Path const&) +    { +      Traversal::Schema schema; +      Uses uses; + +      schema >> uses >> schema; + +      Traversal::Names schema_names; +      Traversal::Namespace ns; +      Traversal::Names ns_names; + +      schema >> schema_names >> ns >> ns_names; + +      Complex complex_type; +      AnonymousBase anonymous (complex_type); + +      ns_names >> complex_type; +      ns_names >> anonymous; + +      Attribute attribute; +      Traversal::Names names; + +      complex_type >> names; + +      names >> attribute; +      names >> anonymous; + +      // Some twisted schemas do recusive inclusions. +      // +      tu.context ().set ("processing-cardinality-seen", true); + +      schema.dispatch (tu); +    } +  } +} diff --git a/xsd/processing/cardinality/processor.hxx b/xsd/processing/cardinality/processor.hxx new file mode 100644 index 0000000..93a85fb --- /dev/null +++ b/xsd/processing/cardinality/processor.hxx @@ -0,0 +1,28 @@ +// file      : xsd/processing/cardinality/processor.hxx +// license   : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#ifndef XSD_PROCESSING_CARDINALITY_PROCESSOR_HXX +#define XSD_PROCESSING_CARDINALITY_PROCESSOR_HXX + +#include <libxsd-frontend/semantic-graph/elements.hxx> // Path +#include <libxsd-frontend/semantic-graph/schema.hxx> + +#include <xsd/types.hxx> + +namespace Processing +{ +  namespace Cardinality +  { +    class Processor +    { +    public: +      struct Failed {}; + +      void +      process (XSDFrontend::SemanticGraph::Schema&, +               XSDFrontend::SemanticGraph::Path const& file); +    }; +  } +} + +#endif // XSD_PROCESSING_CARDINALITY_PROCESSOR_HXX | 
