{"id":4160,"date":"2019-03-02T18:25:10","date_gmt":"2019-03-02T17:25:10","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=4160"},"modified":"2019-03-03T09:03:41","modified_gmt":"2019-03-03T08:03:41","slug":"c-guns-a-sorted-data-type","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=4160","title":{"rendered":"C++ Guns: A Sorted Data Type"},"content":{"rendered":"<p>Mit dem C++ Typsystem ist es m\u00f6glich Informationen und Algorithmen in das Programm zu codieren, die schon vor der Compilezeit fest stehen. <\/p>\n<p>Wie w\u00fcrdet ihr folgendes Problem l\u00f6sen:<br \/>\nEin Algorithmus, zum Beispiel die bin\u00e4re Suche, ben\u00f6tigt einen bereits sortieren Datensatz. Den Datensatz zu sortieren und danach die Suche anzuwenden ist trivial. Aber in einem anderen Teil des Programms muss danach noch einmal die bin\u00e4re Suche angewendet werden. Nur kann dieser andere Programm Teil nicht annehmen, dass der \u00fcbergebene Datensatz sortiert ist. Noch einmal die Sortierung angewandt kostet viel Laufzeit. Zu testen ob die Daten bereit sortiert sind, ist immer noch ein linearer Algorithmus.<br \/>\nDer Programmierer k\u00f6nnte auch eine bool Variable mit geben, die aussagt ob die Daten bereits sortiert sind. Das ist immerhin nur ein konstanter Mehraufwand. Der Datensatz muss stark mit dieser Statusvariable gekoppelt sein, damit keine Inkonsistenz entsteht. Also kommen beide zusammen in einem neuen Datentyp. Wenn man den sortierten Datensatz noch read-only macht, muss man kein Aufwand treiben festzustellen, ob der Datensatz durch ein Schreibzugriff nun nicht mehr sortiert ist. Damit ist auch die Statusvariable konstant. <\/p>\n<p>Jetzt passiert etwas besonderes. Die Statusvariable wird von einer Funktion erzeugt und hat immer den selben Wert. N\u00e4mlich <em>true<\/em>, f\u00fcr \"sortiert\". Damit ist es m\u00f6glich, diese Idee auch zur Compilezeit auszuf\u00fchren und einen neuen Datentype <em>Sorted<\/em> einzuf\u00fchren, der nur von einer <em>sort()<\/em> Funktion erzeugt werden kann und IMMER sortierte Daten enth\u00e4lt. Die bool Variable f\u00e4llt komplett weg. Ihre Semantik ist im neuen Datentyp kodiert. <\/p>\n<p>Wie sieht diese Idee in der Praxis aus? Es braucht eine <em>sorted()<\/em> Funktion welche die Daten sortiert und einen <em>Sorted<\/em> Typ zur\u00fcck gibt. Damit, bei Bedarf, keine unn\u00f6tigen Kopien erstellt werden, ist es auch m\u00f6glich mit <a href=\"http:\/\/roboblog.fatal-fury.de\/?p=4141\"><em>moveOwnership()<\/em><\/a> die Daten in den Sorted Typ zu verschieben.<\/p>\n<p>Jeder Algorithmus welcher sortiere Daten ben\u00f6tigt, soll nur Datens\u00e4tze von Typ <em>Sorted<\/em> akzeptieren. Damit ist zur Compilezeit sichergestellt, dass nie aus Versehen unsortierte Daten \u00fcbergeben werden und es wird nur einmal der Datensatz sortiert. Und alles kommt dank statischer Typisierung mit zero-overhead.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nstd::vector&lt;int&gt; vec {3,2,1};\r\n\/\/ sort and move ownership to Sorted\r\nSorted sortedVec = sorted(acpl::moveOwnership(vec));\r\n\r\n\/\/ can be used with the strong typed binary_search function\r\nbinary_search(sortedVec, valueToSearch);\r\n<\/pre>\n<p>Der Type <em>Sorted<\/em> implementiert nur ein read-only Interface und ist ein Wrapper um einen beliebigen Container. Der Konstruktor ist privat, damit nur die spezielle <em>sorted<\/em> Funktion diesen Typen erstellen kann.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nauto nope = Sorted&lt;std::vector&lt;int&gt;&gt;{vec}; \/\/ error: \u2018Sorted&lt;Container&gt;::Sorted(Container&amp;&amp;) is private within this context\r\n<\/pre>\n<p>F\u00fcr bestehende Algorithmen k\u00f6nnen leicht Wrapper geschrieben werden. Wie beispielsweise f\u00fcr die bin\u00e4re Suche:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\ntemplate&lt;typename Container, typename T&gt;\r\nbool binary_search(const Sorted&lt;Container&gt;&amp; data, const T&amp; value) {\r\n    return std::binary_search(data.begin(), data.end(), value);\r\n}\r\n<\/pre>\n<p>Die Implementierung der <em>sorted()<\/em> Funktion ist relativ einfach, wenn die Sache mit <a href=\"http:\/\/roboblog.fatal-fury.de\/?p=4138\">Universal Referenz<\/a> gekl\u00e4rt ist<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\ntemplate&lt;typename Container&gt;\r\nSorted&lt;std::remove_reference_t&lt;Container&gt;&gt; sorted(Container&amp;&amp; data) {\r\n    \/\/ variable data is a univeral reference. pattern: &quot;deducted type&amp;&amp;&quot; so we use forward\r\n    std::remove_reference_t&lt;Container&gt; sorted(std::forward&lt;Container&gt;(data));\r\n    std::sort(sorted.begin(), sorted.end());\r\n    \/\/ variable sorted is not a universal reference so we use move\r\n    return {std::move(sorted)};\r\n}\r\n<\/pre>\n<p>Nat\u00fcrlich gibt es auch einen overload f\u00fcr die Funktion <em>isSorted()<\/em> diese gibt trivialierweise immer <em>true<\/em> zur\u00fcck.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\ntemplate&lt;typename Container&gt;\r\nbool isSorted(const Sorted&lt;Container&gt;&amp;) {\r\n    return true;\r\n}\r\n<\/pre>\n<p>Und die Implementierung des Typ <em>Sorted<\/em> selbst<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\ntemplate&lt;typename Container&gt;\r\n\/\/ requires Sequence container\r\nclass Sorted {\r\n\r\n\r\n    Sorted(Container&amp;&amp; data)\r\n        : c(std::forward&lt;Container&gt;(data))\r\n    {  }\r\n\r\npublic:\r\n    using value_type = typename Container::value_type;\r\n    using const_iterator = typename Container::const_iterator;\r\n    using const_reference = typename Container::const_reference;\r\n\r\n    auto size() const {\r\n        return std::size(c);\r\n    }\r\n\r\n    const_iterator begin() const {\r\n        return c.begin();\r\n    }\r\n\r\n    const_iterator end() const {\r\n        return c.end();\r\n    }\r\n\r\n    const_reference at(const auto&amp; i) const {\r\n        return c.at(i);\r\n    }\r\n\r\n    const_reference operator&#x5B;](const auto&amp; i) const {\r\n        return c&#x5B;i];\r\n    }\r\n\r\n    const_reference front() const {\r\n        return c.front();\r\n    }\r\n\r\n    template&lt;typename C&gt;\r\n    friend Sorted&lt;std::remove_reference_t&lt;C&gt;&gt; sorted(C&amp;&amp; data);\r\n\r\n    const Container c;\r\n};\r\n\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Mit dem C++ Typsystem ist es m\u00f6glich Informationen und Algorithmen in das Programm zu codieren, die schon vor der Compilezeit fest stehen. Wie w\u00fcrdet ihr folgendes Problem l\u00f6sen: Ein Algorithmus, zum Beispiel die bin\u00e4re Suche, ben\u00f6tigt einen bereits sortieren Datensatz. Den Datensatz zu sortieren und danach die Suche anzuwenden ist trivial. Aber in einem anderen [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[17],"class_list":["post-4160","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4160","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4160"}],"version-history":[{"count":11,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4160\/revisions"}],"predecessor-version":[{"id":4171,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4160\/revisions\/4171"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4160"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4160"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4160"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}