{"id":36813,"date":"2005-01-04T07:00:00","date_gmt":"2005-01-04T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/01\/04\/using-fibers-to-simplify-enumerators-part-5-composition\/"},"modified":"2005-01-04T07:00:00","modified_gmt":"2005-01-04T07:00:00","slug":"using-fibers-to-simplify-enumerators-part-5-composition","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050104-00\/?p=36813","title":{"rendered":"Using fibers to simplify enumerators, part 5: Composition"},"content":{"rendered":"<p>\nAnother type of higher-order enumeration is composition,\nwhere one enumerator actually combines the results of\nmultiple enumerators.\n(Everybody knows about derivation, but\ncomposition is another powerful concept in\nobject-oriented programming.\n<a HREF=\"\/oldnewthing\/archive\/2004\/10\/07\/239197.aspx\">\nWe&#8217;ve seen it before when building context menus<\/a>.)\n<\/p>\n<p>\nIn a producer-driven enumerator, you would implement composition\nby calling the two enumeration functions one after the other.\nIn a consumer-driven enumerator, you would implement composition\nby wrapping the two enumerators inside a large enumerator\nwhich then chooses between the two based on which enumerator\nwas currently active.\n<\/p>\n<p>\nA fiber-based enumerator behaves more like a consumer-driven\nenumerator, again, with easier state management.\n<\/p>\n<p>\nLet&#8217;s write a composite enumerator that enumerates everything\nin the root of your C: drive (no subdirectories),\nplus everything in the current directory (including subdirectories).\n<\/p>\n<pre>\nclass CompositeEnumerator : public FiberEnumerator {\npublic:\n CompositeEnumerator()\n   : m_eFiltered(TEXT(\"C:\\\\\"))\n   , m_eCd(TEXT(\".\")) { }\n LPCTSTR GetCurDir()\n    { return m_peCur-&gt;GetCurDir(); }\n LPCTSTR GetCurPath()\n    { return m_peCur-&gt;GetCurPath(); }\n const WIN32_FIND_DATA* GetCurFindData()\n    { return m_peCur-&gt;GetCurFindData(); }\nprivate:\n void FiberProc();\nprivate:\n FiberEnumerator* m_peCur;\n FilteredEnumerator m_eFiltered;\n DirectoryTreeEnumerator m_eCd;\n};\nvoid CompositeEnumerator::FiberProc()\n{\n FEFOUND fef;\n m_peCur = &amp;m_eFiltered;\n while ((fef = m_peCur-&gt;Next()) != FEF_DONE &amp;&amp;\n        fef != FEF_LEAVEDIR) {\n  m_peCur-&gt;SetResult(Produce(fef));\n }\n m_peCur = &amp;m_eCd;\n while ((fef = m_peCur-&gt;Next()) != FEF_DONE) {\n  m_peCur-&gt;SetResult(Produce(fef));\n }\n}\n<\/pre>\n<p>\n<strong>Sidebar<\/strong>:\nOur composite enumeration is complicated by the\nfact that our <code>FilteredEnumerator<\/code>\nspits out a <code>FEF_LEAVEDIR<\/code> at the\nend, but which we want to suppress, so we have to\ncheck for it and eat it.\n<\/p>\n<p>\nIn the more common case where the enumerator is generating\na flat list, it would be a simple matter of just forwarding\nthe two enumerators one after the other.\nSomething like this:\n<\/p>\n<pre>\nvoid CompositeEnumerator2::FiberProc()\n{\n Enum(&amp;m_eFiltered);\n Enum(&amp;m_eCd);\n}\nvoid CompositeEnumerator2::Enum(FiberEnumerator *pe)\n{\n m_peCur = pe;\n FEFOUND fef;\n while ((fef = m_peCur-&gt;Next()) != FEF_DONE) {\n  m_peCur-&gt;SetResult(Produce(fef));\n }\n}\n<\/pre>\n<p>\n<strong>End sidebar<\/strong>.\n<\/p>\n<p>\nYou can try out this <code>CompositeEnumerator<\/code>\nwith the program you&#8217;ve been playing with for the past\nfew days.  Just change the line in <code>main<\/code>\nthat creates the enumerator to the following:\n<\/p>\n<pre>\n CompositeEnumerator e;\n<\/pre>\n<p>\n<strong>Exercise<\/strong>: Gosh, why is the total so unusually large?\n<\/p>\n<p>\n<strong>Exercise<\/strong>: How many fibers are there in the program?\n<\/p>\n<p>\n<strong>Exercise<\/strong>: Draw a diagram showing how control flows\namong the various fibers in this program.\n<\/p>\n<p>\nBefore you get all excited about fibers, consider the following:\n<\/p>\n<ul>\n<li>Converting a thread to a fiber needs to be coordinated among\n    all the components in the process so that it is converted only\n    once and stays converted until everybody is finished.\n    This means that if you are writing a plug-in that will go into\n    some other process, you probably should avoid fibers,\n    since you don&#8217;t know what the other components in the process\n    are going to do with fibers.<\/p>\n<li>Fibers do not completely solve the one-thread-per-connection problem.\n    They do reduce the context switching, but the memory footprint\n    will still limit you to 2000 fibers per process (assuming a\n    2GB user-mode address space) since each fiber has a stack,\n    which defaults to 1MB.\n<\/ul>\n<p>\nI think that&#8217;s enough about fibers for now.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Another type of higher-order enumeration is composition, where one enumerator actually combines the results of multiple enumerators. (Everybody knows about derivation, but composition is another powerful concept in object-oriented programming. We&#8217;ve seen it before when building context menus.) In a producer-driven enumerator, you would implement composition by calling the two enumeration functions one after the [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-36813","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Another type of higher-order enumeration is composition, where one enumerator actually combines the results of multiple enumerators. (Everybody knows about derivation, but composition is another powerful concept in object-oriented programming. We&#8217;ve seen it before when building context menus.) In a producer-driven enumerator, you would implement composition by calling the two enumeration functions one after the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36813","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=36813"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36813\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=36813"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=36813"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=36813"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}