Browse Source

add streams

Kolja Strohm 3 months ago
parent
commit
2a35079df7

+ 14 - 1
Array.h

@@ -5,8 +5,9 @@
 #include <stdexcept>
 
 #include "Errors.h"
-#include "Iterator.h"
 #include "ReferenceCounter.h"
+#include "Stream.h"
+#include "Supplier.h"
 #include "Text.h"
 
 namespace Framework
@@ -509,6 +510,12 @@ namespace Framework
                 add(arr.get(i));
             return *this;
         }
+
+        Stream<TYP> stream()
+        {
+            return Stream<TYP>(new IteratorSupplier<TYP>(
+                new ArrayIterator<TYP>(entries, onRemove)));
+        }
     };
 
     template<class TYP>
@@ -827,6 +834,12 @@ namespace Framework
                 add(arr.get(i));
             return *this;
         }
+
+        Stream<TYP*> stream()
+        {
+            return Stream<TYP*>(new IteratorSupplier<TYP*>(
+                new ArrayIterator<TYP*>(entries, onRemove)));
+        }
     };
 } // namespace Framework
 

+ 1 - 0
Framework Tests/Framework Tests.vcxproj

@@ -176,6 +176,7 @@
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
     </ClCompile>
     <ClCompile Include="Regex.cpp" />
+    <ClCompile Include="Stream.cpp" />
     <ClCompile Include="Text.cpp" />
     <ClCompile Include="Trie.cpp" />
     <ClCompile Include="XML.cpp" />

+ 3 - 0
Framework Tests/Framework Tests.vcxproj.filters

@@ -42,6 +42,9 @@
     <ClCompile Include="Regex.cpp">
       <Filter>Quelldateien</Filter>
     </ClCompile>
+    <ClCompile Include="Stream.cpp">
+      <Filter>Quelldateien</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="pch.h">

+ 92 - 0
Framework Tests/Stream.cpp

@@ -0,0 +1,92 @@
+#include "pch.h"
+
+#include <Cache.h>
+
+#include "CppUnitTest.h"
+
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+namespace FrameworkTests
+{
+    TEST_CLASS (StreamTests)
+    {
+    public:
+        TEST_METHOD (EmtptyTest)
+        {
+            Framework::Array<int> array;
+            array.stream().forEach([](int i) { Assert::Fail(); });
+        }
+
+        TEST_METHOD (FilterTest)
+        {
+            Framework::Array<int> array;
+            array.add(1);
+            array.add(2);
+            array.add(4);
+            array.add(5);
+            array.add(7);
+            int count = 0;
+            array.stream()
+                .filter([](int i) { return i % 2 == 0; })
+                .forEach([&count](int i) { count++; });
+            Assert::AreEqual(2, count);
+        }
+
+        TEST_METHOD (MapTest)
+        {
+            Framework::Array<int> array;
+            array.add(1);
+            array.add(2);
+            array.add(4);
+            array.add(5);
+            array.add(7);
+            Framework::Array<int>* result
+                = array.stream()
+                      .map<int>([](int i) { return i * 2; })
+                      .collect<Framework::Array<int>*>(
+                          [](Framework::Array<int>* curr, int i) {
+                              curr->add(i);
+                              return curr;
+                          },
+                          new Framework::Array<int>());
+            Assert::AreEqual(5, result->getEintragAnzahl());
+            Assert::AreEqual(2, result->get(0));
+            Assert::AreEqual(4, result->get(1));
+            Assert::AreEqual(8, result->get(2));
+            Assert::AreEqual(10, result->get(3));
+            Assert::AreEqual(14, result->get(4));
+            result->release();
+        }
+
+        TEST_METHOD (FlatMapTest)
+        {
+            Framework::RCArray<Framework::Array<int>> array;
+            array.add(new Framework::Array<int>());
+            array.add(new Framework::Array<int>());
+            array.add(new Framework::Array<int>());
+            array.z(1)->add(1);
+            array.z(1)->add(2);
+            array.z(1)->add(4);
+            array.z(2)->add(5);
+            array.z(2)->add(7);
+            Framework::Array<int>* result
+                = array.stream()
+                      .flatMap<int>([](Framework::Array<int>* val) {
+                          return val->stream();
+                      })
+                      .collect<Framework::Array<int>*>(
+                          [](Framework::Array<int>* curr, int i) {
+                              curr->add(i);
+                              return curr;
+                          },
+                          new Framework::Array<int>());
+            Assert::AreEqual(5, result->getEintragAnzahl());
+            Assert::AreEqual(1, result->get(0));
+            Assert::AreEqual(2, result->get(1));
+            Assert::AreEqual(4, result->get(2));
+            Assert::AreEqual(5, result->get(3));
+            Assert::AreEqual(7, result->get(4));
+            result->release();
+        }
+    };
+} // namespace FrameworkTests

+ 2 - 0
Framework.vcxproj

@@ -254,6 +254,7 @@ copy "x64\Release\Framework.dll" "..\..\Spiele Platform\SMP\Fertig\x64\framework
     <ClInclude Include="RCPointer.h" />
     <ClInclude Include="ReferenceCounter.h" />
     <ClInclude Include="Slider.h" />
+    <ClInclude Include="Stream.h" />
     <ClInclude Include="UIDialog.h" />
     <ClInclude Include="Model2D.h" />
     <ClInclude Include="M2DVorschau.h" />
@@ -353,6 +354,7 @@ copy "x64\Release\Framework.dll" "..\..\Spiele Platform\SMP\Fertig\x64\framework
     <ClCompile Include="ReferenceCounter.cpp" />
     <ClCompile Include="Shader.cpp" />
     <ClCompile Include="Slider.cpp" />
+    <ClCompile Include="Supplier.h" />
     <ClCompile Include="Textur.cpp" />
     <ClCompile Include="Textur2D.cpp" />
     <ClCompile Include="TexturList.cpp" />

+ 6 - 0
Framework.vcxproj.filters

@@ -352,6 +352,9 @@
     <ClInclude Include="Iterator.h">
       <Filter>Framework\Data</Filter>
     </ClInclude>
+    <ClInclude Include="Stream.h">
+      <Filter>Framework\Data</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Model3DCollection.h">
@@ -597,6 +600,9 @@
     <ClCompile Include="Regex.cpp">
       <Filter>Framework\Regex</Filter>
     </ClCompile>
+    <ClCompile Include="Supplier.h">
+      <Filter>Framework\Data</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <FxCompile Include="DX12VertexShader.hlsl">

+ 9 - 8
HashMap.h

@@ -37,7 +37,7 @@ namespace Framework
     {
     private:
         int bucketIndex;
-        Iterator<MapEntry<K, V>> iterator;
+        ArrayIterator<MapEntry<K, V>> iterator;
         Array<MapEntry<K, V>>** buckets;
         int bucketCount;
 
@@ -45,7 +45,7 @@ namespace Framework
         MapIterator(Array<MapEntry<K, V>>** buckets,
             int bucketCount,
             int bucketIndex,
-            Iterator<MapEntry<K, V>> iterator)
+            ArrayIterator<MapEntry<K, V>> iterator)
             : iterator(iterator)
         {
             while (bucketIndex < bucketCount
@@ -53,7 +53,7 @@ namespace Framework
                        || buckets[bucketIndex]->getEintragAnzahl() == 0))
             {
                 bucketIndex++;
-                iterator = Iterator<MapEntry<K, V>>(0, 0);
+                iterator = ArrayIterator<MapEntry<K, V>>(0, 0);
             }
             if (bucketIndex < bucketCount)
             {
@@ -61,7 +61,7 @@ namespace Framework
             }
             else
             {
-                this->iterator = Iterator<MapEntry<K, V>>(0, 0);
+                this->iterator = ArrayIterator<MapEntry<K, V>>(0, 0);
                 this->bucketIndex = 0;
                 this->buckets = 0;
                 this->bucketCount = 0;
@@ -116,7 +116,7 @@ namespace Framework
                 return MapIterator(buckets,
                     bucketCount,
                     bucketIndex + 1,
-                    Iterator<MapEntry<K, V>>(0, 0));
+                    ArrayIterator<MapEntry<K, V>>(0, 0));
         }
 
         operator bool()
@@ -151,7 +151,7 @@ namespace Framework
                     this->iterator = buckets[bucketIndex]->begin();
                 else
                 {
-                    this->iterator = Iterator<MapEntry<K, V>>(0, 0);
+                    this->iterator = ArrayIterator<MapEntry<K, V>>(0, 0);
                     this->bucketIndex = 0;
                     this->buckets = 0;
                     this->bucketCount = 0;
@@ -324,12 +324,13 @@ namespace Framework
         MapIterator<K, V> begin()
         {
             return MapIterator<K, V>(
-                buckets, bucketCount, 0, Iterator<MapEntry<K, V>>(0, 0));
+                buckets, bucketCount, 0, ArrayIterator<MapEntry<K, V>>(0, 0));
         }
 
         MapIterator<K, V> end()
         {
-            return MapIterator<K, V>(0, 0, 0, Iterator<MapEntry<K, V>>(0, 0));
+            return MapIterator<K, V>(
+                0, 0, 0, ArrayIterator<MapEntry<K, V>>(0, 0));
         }
     };
 } // namespace Framework

+ 59 - 43
Iterator.h

@@ -1,59 +1,75 @@
 #pragma once
 
-/**
- * Iterator interface
- * \tparam T type of the value that is iterated
- * \tparam I type of the iterator subclass
- */
-template<typename T, typename I> class Iterator
+namespace Framework
 {
-public:
-    virtual ~Iterator()
+    template<typename T> class BasicIterator
     {
-        static_assert(std::is_base_of<Iterator, I>::value,
-            "Type Argument I must be an implementation of Iterator");
-    }
+    public:
+        virtual ~BasicIterator() {}
 
-    virtual bool hasNext()
-    {
-        return (bool)next();
-    }
+        virtual operator bool() = 0;
 
-    virtual I next() = 0;
+        virtual T val() = 0;
 
-    virtual operator bool() = 0;
+        virtual void plusPlus() = 0;
+    };
 
-    virtual I& operator++() //! prefix
+    /**
+     * Iterator interface
+     * \tparam T type of the value that is iterated
+     * \tparam I type of the iterator subclass
+     */
+    template<typename T, typename I> class Iterator : public BasicIterator<T>
     {
-        *(I*)this = next();
-        return *(I*)this;
-    }
+    public:
+        virtual ~Iterator()
+        {
+            static_assert(std::is_base_of<Iterator, I>::value,
+                "Type Argument I must be an implementation of Iterator");
+        }
 
-    virtual I operator++(int) //! postfix
-    {
-        I tmp(*(I*)this);
-        operator++();
-        return tmp;
-    }
+        virtual bool hasNext()
+        {
+            return (bool)next();
+        }
 
-    virtual T val() = 0;
+        virtual I next() = 0;
 
-    virtual void set(T val) = 0;
+        virtual void plusPlus() override
+        {
+            *(I*)this = next();
+        }
 
-    virtual void remove() = 0;
+        virtual I& operator++() //! prefix
+        {
+            *(I*)this = next();
+            return *(I*)this;
+        }
 
-    operator T()
-    {
-        return val();
-    }
+        virtual I operator++(int) //! postfix
+        {
+            I tmp(*(I*)this);
+            operator++();
+            return tmp;
+        }
 
-    virtual T operator->()
-    {
-        return val();
-    }
+        virtual void set(T val) = 0;
 
-    virtual T operator*()
-    {
-        return val();
-    }
-};
+        virtual void remove() = 0;
+
+        operator T()
+        {
+            return val();
+        }
+
+        virtual T operator->()
+        {
+            return val();
+        }
+
+        virtual T operator*()
+        {
+            return val();
+        }
+    };
+} // namespace Framework

+ 80 - 0
Stream.h

@@ -0,0 +1,80 @@
+#pragma once
+
+#include <functional>
+
+#include "Supplier.h"
+
+namespace Framework
+{
+    template<typename T> class Stream
+    {
+    private:
+        Supplier<T>* supplier;
+
+    public:
+        Stream(Supplier<T>* supplier)
+            : supplier(supplier)
+        {}
+
+        ~Stream()
+        {
+            supplier->release();
+        }
+
+        Stream<T> filter(std::function<bool(T)> f)
+        {
+            return Stream<T>(new FilteredSupplier<T>(
+                dynamic_cast<Supplier<T>*>(supplier->getThis()), f));
+        }
+
+        template<typename R> Stream<R> map(std::function<R(T)> f)
+        {
+            return Stream<R>(new MappedSupplier<T, R>(
+                dynamic_cast<Supplier<T>*>(supplier->getThis()), f));
+        }
+
+        template<typename R> Stream<R> flatMap(std::function<Stream<R>(T)> f)
+        {
+            return Stream<R>(new FlatMappedSupplier<T, R>(
+                dynamic_cast<Supplier<T>*>(supplier->getThis()),
+                [this, f](T arg) {
+                    return dynamic_cast<Supplier<R>*>(
+                        f(arg).zSupplier()->getThis());
+                }));
+        }
+
+        void forEach(std::function<void(T)> action)
+        {
+            while (true)
+            {
+                try
+                {
+                    action(supplier->next());
+                } catch (Exceptions::EndOfSupplier)
+                {
+                    return;
+                }
+            }
+        }
+
+        template<typename R>
+        R collect(std::function<R(R, T)> combinator, R initialValue)
+        {
+            while (true)
+            {
+                try
+                {
+                    initialValue = combinator(initialValue, supplier->next());
+                } catch (Exceptions::EndOfSupplier)
+                {
+                    return initialValue;
+                }
+            }
+        }
+
+        Supplier<T>* zSupplier()
+        {
+            return supplier;
+        }
+    };
+} // namespace Framework

+ 164 - 0
Supplier.h

@@ -0,0 +1,164 @@
+#pragma once
+
+#include <functional>
+
+#include "Iterator.h"
+#include "ReferenceCounter.h"
+
+namespace Framework
+{
+    namespace Exceptions
+    {
+        class EndOfSupplier
+        {
+            const char* msg;
+
+        public:
+            EndOfSupplier()
+                : msg("End of Supplier")
+            {}
+        };
+    } // namespace Exceptions
+
+    template<typename T> class Supplier : public ReferenceCounter
+    {
+    public:
+        Supplier()
+            : ReferenceCounter()
+        {}
+
+        virtual ~Supplier() {}
+
+        virtual T next() noexcept(false) = 0;
+    };
+
+    template<typename T> class IteratorSupplier : public Supplier<T>
+    {
+    private:
+        BasicIterator<T>* iterator;
+
+    public:
+        IteratorSupplier(BasicIterator<T>* iterator)
+            : Supplier<T>(),
+              iterator(iterator)
+        {}
+
+        ~IteratorSupplier()
+        {
+            delete iterator;
+        }
+
+        T next() noexcept(false) override
+        {
+            if (!*iterator)
+            {
+                throw Exceptions::EndOfSupplier();
+            }
+            T val = iterator->val();
+            iterator->plusPlus();
+            return val;
+        }
+    };
+
+    template<typename T> class FilteredSupplier : public Supplier<T>
+
+    {
+    private:
+        Supplier<T>* supplier;
+        std::function<bool(T)> filter;
+
+    public:
+        FilteredSupplier(Supplier<T>* supplier, std::function<bool(T)> filter)
+            : Supplier<T>(),
+              supplier(supplier),
+              filter(filter)
+        {}
+
+        ~FilteredSupplier()
+        {
+            supplier->release();
+        }
+
+        T next() noexcept(false) override
+        {
+            T val = supplier->next();
+            while (!filter(val))
+            {
+                val = supplier->next();
+            }
+            return val;
+        }
+    };
+
+    template<typename T, typename R> class MappedSupplier : public Supplier<R>
+    {
+    private:
+        Supplier<T>* supplier;
+        std::function<R(T)> mapper;
+
+    public:
+        MappedSupplier(Supplier<T>* supplier, std::function<R(T)> mapper)
+            : Supplier(),
+              supplier(supplier),
+              mapper(mapper)
+        {}
+
+        ~MappedSupplier()
+        {
+            supplier->release();
+        }
+
+        R next() noexcept(false) override
+        {
+            return mapper(supplier->next());
+        }
+    };
+
+    template<typename T> class Stream;
+
+    template<typename T, typename R> class FlatMappedSupplier
+        : public Supplier<R>
+    {
+    private:
+        Supplier<T>* supplier;
+        std::function<Supplier<R>*(T)> mapper;
+        Supplier<R>* currentSupplier;
+
+    public:
+        FlatMappedSupplier(
+            Supplier<T>* supplier, std::function<Supplier<R>*(T)> mapper)
+            : Supplier<R>(),
+              supplier(supplier),
+              mapper(mapper),
+              currentSupplier(nullptr)
+        {}
+
+        ~FlatMappedSupplier()
+        {
+            if (currentSupplier != nullptr)
+            {
+                currentSupplier->release();
+            }
+            supplier->release();
+        }
+
+        R next() noexcept(false) override
+        {
+            while (true)
+            {
+                if (currentSupplier == nullptr)
+                {
+                    currentSupplier = mapper(supplier->next());
+                }
+                try
+                {
+                    return currentSupplier->next();
+                } catch (Exceptions::EndOfSupplier)
+                {
+                    currentSupplier->release();
+                    currentSupplier = nullptr;
+                }
+            }
+        }
+    };
+} // namespace Framework