lib: add for_abuse.nit
authorJean Privat <jean@pryen.org>
Tue, 11 Jun 2013 02:36:17 +0000 (04:36 +0200)
committerJean Privat <jean@pryen.org>
Tue, 11 Jun 2013 02:36:17 +0000 (04:36 +0200)
Signed-off-by: Jean Privat <jean@pryen.org>

lib/for_abuse.nit [new file with mode: 0644]
tests/sav/for_abuse.res [new file with mode: 0644]
tests/sav/test_for_abuse.res [new file with mode: 0644]
tests/test_for_abuse.nit [new file with mode: 0644]

diff --git a/lib/for_abuse.nit b/lib/for_abuse.nit
new file mode 100644 (file)
index 0000000..1e06ec3
--- /dev/null
@@ -0,0 +1,163 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT.  This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A 
+# PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You  are  allowed  to  redistribute it and sell it, alone or is a part of
+# another product.
+
+# Service management trough the `for` control structure.
+#
+# The module is a proof-of-concept to investigate the abuse of
+# the `for` structure to implement various services.
+#
+# The idea is that, with a `for`, the service-provider can:
+# * control the end of the service (thus can finalize things
+#   like releasing ressources)
+# * communicate data with the user on each iteration; the used can
+#   also communicate results to the provider.
+module for_abuse
+
+# Encapsulation of service in a `for`-compatible interface.
+#
+# The service is not effectively started until the iterate method
+# is called. Then, each step of the iteration is a step in the service.
+#
+# While, for a typing point of view, abusers are just collections,
+# the point of this class is to tag services that return a ForAbuser
+# object.
+# Note that using abuser as genuine collection should work but is not
+# recommended since it may cause mental health issues.
+interface ForAbuser[E]
+       super Collection[E]
+end
+
+# Abuser to read a file, see `file_open`
+private class ReadFileForAbuser
+       super ForAbuser[IFStream]
+       var path: String
+       redef fun iterator do return new ReadFileForAbuserIterator(path)
+end
+
+# Abuser iterator to read a file, see `file_open`
+private class ReadFileForAbuserIterator
+       super Iterator[IFStream]
+       redef var item: IFStream
+       redef var is_ok = true
+       init(path: String)
+       do
+               # start of service is to open the file, and return in
+               item = new IFStream.open(path)
+       end
+       redef fun next
+       do
+               # end of service is to close the file
+               # there is only one iteration
+               is_ok = false
+               item.close
+       end
+end
+
+####
+
+# A comparison query.
+# The user is asked to compare `a` with `b` then set `res` accordingly.
+#
+# * if `a < b` then the user sets `res` to -1
+# * if `a > b` then the user sets `res` to 1
+# * if `a == b` then the user sets `res` to 0
+#
+# It is the responsibility of the user to implement a total order.
+# ie. the implemented comparison must be asymmetric, transitive and total.
+class CompareQuery[E]
+       # The first element to compare
+       var a: E
+       # The second element to compare
+       var b: E
+       # The result of the comparison (according to the user)
+       var res writable = 0
+end
+
+# Abuser for sorting array, see `sort_fa`
+private class SortAbuser[E]
+       super ForAbuser[CompareQuery[E]]
+       var array: Array[E]
+       redef fun iterator do return new SortAbuserIterator[E](array)
+end
+
+# Abuser iterator for sorting array, see `sort_fa`
+# Implements a sort by permutation
+private class SortAbuserIterator[E]
+       super Iterator[CompareQuery[E]]
+       # The index of the big loop
+       var i: Int
+       # The index of the small loop
+       var j: Int
+       # The array to sort
+       var array: Array[E]
+       # The query used to communicate with the user.
+       # For ecological concerns, a unique CompareQuery is instatiated.
+       var query: nullable CompareQuery[E]
+       redef fun item do return query.as(not null)
+       init(array: Array[E])
+       do
+               self.array = array
+               # Initialize the algorithm, see `next` for the rest
+               i = 0
+               j = 0
+               if not is_ok then return
+               query = new CompareQuery[E](array[i], array[j])
+       end
+       redef fun is_ok do return i < array.length - 1
+       redef fun next
+       do
+               # Process the last query
+               if item.res > 0 then
+                       var tmp = array[i]
+                       array[i] = array[j]
+                       array[j] = tmp
+               end
+               # Get the next iteration
+               j += 1
+               if j >= array.length then
+                       # End of small loop
+                       i += 1
+                       j = i + 1
+               end
+               if not is_ok then return
+               # Prepare the next query
+               item.a = array[i]
+               item.b = array[j]
+               item.res = 0
+       end
+end
+
+redef class Array[E]
+       # Sort an array trough a `for` abuse.
+       # The user uses the provided query (item) to implements its own comparison
+       #
+       #     var a = [1, 3, 2]
+       #     for q in a do q.res = q.a <=> q.b
+       #     print a # => 123
+       #
+       # Implements a sort by permutation.
+       fun sort_fa: ForAbuser[CompareQuery[E]]
+       do
+               return new SortAbuser[E](self)
+       end
+end
+
+####
+
+# Open and read a file trough a `for` abuse.
+# The abuse just ensures that the file is closed after the reading.
+#
+#     for f in file_open(path) do
+#       print path.read_line
+#     end # f is automatically closed here
+fun file_open(path: String): ForAbuser[IFStream]
+do
+       return new ReadFileForAbuser(path)
+end
diff --git a/tests/sav/for_abuse.res b/tests/sav/for_abuse.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/sav/test_for_abuse.res b/tests/sav/test_for_abuse.res
new file mode 100644 (file)
index 0000000..51ef296
--- /dev/null
@@ -0,0 +1 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
diff --git a/tests/test_for_abuse.nit b/tests/test_for_abuse.nit
new file mode 100644 (file)
index 0000000..545440b
--- /dev/null
@@ -0,0 +1,25 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import for_abuse
+
+for f in file_open("test_for_abuse.nit") do
+       print f.read_line
+end
+
+var array = ["*", "****", "**", "*******"]
+for q in array.sort_fa do
+       q.res = q.b.length <=> q.b.length
+end
+