Anonymous avatar Anonymous committed 7bee57e

reading unsigned ints with tests

Comments (0)

Files changed (4)

 reinstall :
 	-$(MAKE) uninstall
 	$(MAKE) install
+
+test_it :
+	ocamlbuild test_it.byte
+	./test_it.byte
 <**/*> : warn_A
 <**/*.ml> | <**/*.mli> : camlp4r
+<test_it.*> : pkg_iteratees

dumbstreaming_it.ml

+(*
+value dbg fmt = Printf.eprintf fmt
+;
+*)
+value dbg fmt = Printf.ifprintf stdout fmt
+;
+
 module type IT_TYPE
  =
   sig
     ;
 
     value bindI :
-      iteratee 'el 'a -> ('a -> iteratee 'el 'b) -> iteratee 'el 'b
+      ('a -> iteratee 'el 'b) -> iteratee 'el 'a -> iteratee 'el 'b
+    ;
+
+    value joinI :
+      iteratee 'el (iteratee 'el 'a) -> iteratee 'el 'a
+    ;
+
+    value drop : int -> iteratee 'el unit
     ;
 
     value drop_while : ('el -> bool) -> iteratee 'el unit
               -> I.iteratee 'i 'a
               -> I.iteratee char (option 'a)
     ;
+
+
+    (* for tests: *)
+    value read_uint : I.iteratee char int;
+
+    (* for tests: *)
+    value read_uint_nz : I.iteratee char int;
+
   end
  =
   struct
 
+    (* todo: move to ocaml-iteratees: *)
     module It_add
      :
       sig
         ;
 
         (* leading zeroes accepted *)
-        value read_uint30 : I.iteratee char int
+        value read_uint : I.iteratee char int
         ;
 
         (* leading zeroes = error *)
-        value read_uint30nz : I.iteratee char int
+        value read_uint_nz : I.iteratee char int
         ;
 
       end
         value ( >>% ) = IO.bind_rev;
 
         open I;
-        value ( >>= ) = bindI;
+        value ( >>= ) m f = bindI f m;
  
         value itlist_step_firstresult_lasterror
           (lst : list (iteratee 'el 'a))
             type t;
             value max_int : t;
             (* min_int = -max_int - 1 *)
+
+            (* must work for small ints and small numbers:t : *)
             value of_int : int -> t;
             value to_int : t -> int;
 
           sig
             (* value digits : S.t -> int; *)
 
-            value read_unsigned_noleadingzeroes : iteratee char S.t;
+            value read_unsigned_gen : ~allow0:bool -> iteratee char S.t;
           end
          =
           struct
                 then string_reverse_inplace (Buffer.contents buf)
                 else loop n'
               in
-                loop n_
+                loop n
             ;
 
             value to_dec = to_base ten
             value max_int_dec = to_dec max_int;
 
             value from_base_neg b maxstr str =
+              let len = String.length str in
               let rec loop acc i =
-                if i < 0
+                if i = len
                 then acc
                 else
                   let digit ch =
                   in
                   let ch = str.[i] in
                   let acc' = acc * b - digit ch in
-                  loop acc' (P.( - ) i 1)
+                  loop acc' (P.( + ) i 1)
               in
-                let len = String.length str in
                 if len = 0
                 then `Empty
                 else
                 let maxlen = String.length maxstr in
                 if len > maxlen
-                then `Overflow
+                then
+                  let () = dbg "(from_base: len>maxlen) %!" in
+                  `Overflow
                 else if len = maxlen && str > maxstr
-                then `Overflow
+                then
+                  let () = dbg "(from_base: str>maxstr) %!" in
+                  `Overflow
                 else
                   try
-                    `Ok (loop zero (P.( - ) len 1))
+                    `Ok (loop zero 0)
                   with
                   [ SInt_not_a_number _ -> `Not_a_number ]
             ;
             value from_dec_neg = from_base_neg ten max_int_dec
             ;
 
-            value read_unsigned_noleadingzeroes
+            value is_digit c = (c <= '9' && c >= '0')
+            ;
+
+            value is_not_digit c = not (is_digit c)
+            ;
+
+            (* to iteratees: *)
+            value junk = drop 1
+            ;
+
+            value inan msg = I.throw_err (SInt_not_a_number msg)
+            ;
+
+            value peek_digit =
+              peek >>= fun optc ->
+              I.return (
+                match optc with
+                [ Some c when is_digit c -> optc
+                | None | Some _ -> None
+                ]
+              )
+            ;
+
+            value read_unsigned_gen
+              ~allow0
              :
               iteratee char S.t
              =
-              let is_digit c = (c <= '9' && c >= '0') in
-              (I.limit max_int_digits & I.break_chars is_digit) >>= fun
-              [ I.IE_done str ->
-                  let () = assert (String.length str <= max_int_digits) in
-                  peek >>= fun optch ->
-                  let next_is_digit = match optch with
-                    [ None -> False | Some ch -> is_digit ch ] in
-                  if next_is_digit
-                  then I.throw_err SInt_overflow
-                  else
-                    match from_dec_neg str with
-                    [ `Empty | `Not_a_number -> I.throw_err (SInt_not_a_number
-                        "read_unsigned_noleadingzeroes")
-                    | `Ok r -> I.return (-r)
-                    | `Overflow -> I.throw_err SInt_overflow
+              let rec read_beginning ~read0 =
+                peek_digit >>= fun optd ->
+                match optd with
+                [ None ->
+                    if read0
+                    then I.return (Some zero)
+                    else inan "begins with not a digit"
+                | Some d ->
+                    match (d, read0, allow0) with
+                    [ ('0', _, True)
+                    | ('0', False, False) ->
+                      junk >>= fun () ->
+                      read_beginning ~read0:True
+                    | (_, True, False) -> inan "leading zeroes"
+                    | (_, False, _) -> I.return None
+                    | (_, True, True) -> I.return None
                     ]
-              | I.IE_cont (Some e) _ -> I.throw_err e
-              | I.IE_cont None _ -> I.throw_err SInt_overflow
+                ]
+              in
+              read_beginning ~read0:False >>= fun
+              [ Some r -> I.return r
+              | None ->
+                   (I.limit max_int_digits &
+                    I.break_chars is_not_digit
+                   ) >>= fun it ->
+                   I.joinI (I.return it) >>= fun res ->
+                   peek_digit >>= fun optd ->
+                   match (it, res, optd) with
+                   [ (I.IE_done _, _, Some _) ->
+                       assert False
+                       (* так как limit должен был выдать IE_cont *)
+                   | (I.IE_cont (Some _) _, _, _) ->
+                       assert False
+                       (* так как joinI кинет эту ошибку сам *)
+                   | (I.IE_done str, _, None)
+                   | (I.IE_cont None _, str, None) ->
+                       let () = assert
+                         (String.length str <= max_int_digits) in
+                       match from_dec_neg str with
+                       [ `Not_a_number -> assert False
+                       | `Empty -> assert False
+                       | `Ok r -> I.return (-r)
+                       | `Overflow -> I.throw_err SInt_overflow
+                       ]
+
+                   | (IE_cont _ _, _, Some _) ->
+                       let () = dbg "(read_gen: cont/digit) %!" in
+                       I.throw_err SInt_overflow
+                   ]
               ]
             ;
 
         module SInt = SInt_F(SInt_T)
         ;
 
-
         (* leading zeroes = error *)
-        value read_uint30nz
+        value read_uint_nz
          : I.iteratee char int
          =
-          SInt.read_unsigned_noleadingzeroes
+          SInt.read_unsigned_gen ~allow0:False
         ;
 
-        value drop_zeroes = I.drop_while ( ( = ) '0' )
-        ;
-
-        value read_uint30 =
-          drop_zeroes >>= fun () ->
-          read_uint30nz
+        value read_uint =
+          SInt.read_unsigned_gen ~allow0:True
         ;
 
       end
     open It_add
     ;
 
+    value read_uint = read_uint;
+    value read_uint_nz = read_uint_nz;
+
 
     value itpair_anyresult_lasterror it1 it2 =
       itlist_anyresult_lasterror [it1; it2]
+module I = Iteratees.Make(It_Lwt_IO.It_Lwt_IO);
+
+module D = Dumbstreaming_it.Make(I);
+
+value ( >>% ) = I.It_IO.bind_rev;
+value ( % ) f g = fun x -> f (g x);
+module IO = I.It_IO;
+
+value enum1 s i =
+  match i with
+  [ I.IE_cont None k -> k s >>% IO.return % fst
+  | I.IE_cont (Some _) _ | I.IE_done _ -> IO.return i
+  ]
+;
+
+value rec printexc e =
+  match e with
+  [ I.Iteratees_err_msg e -> printexc e
+  | e -> Printexc.to_string e
+  ]
+;
+
+value test_uint reader string =
+  let stream = I.Chunk (I.Subarray.of_string string) in
+  let () = Printf.printf "%S -> %!" string in
+  match IO.runIO ((enum1 stream reader) >>% I.run) with
+  [ `Ok r -> Printf.printf "ok %i\n%!" r
+  | `Error e -> Printf.printf "error \"%s\"\n%!"
+      (printexc e)
+  ]
+;
+
+
+open Printf
+;
+
+value () =
+  let maxint = Int64.of_int max_int in
+  let pr = Printf.sprintf "%Li" in
+  let samples =
+    [ "0"
+    ; "00"
+    ; "123"
+    ; "0123"
+    ; "-123"
+    ; pr maxint
+    ; "000000" ^ pr maxint
+    ; pr (Int64.add 1L maxint)
+    ; "19223372036854775806"
+    ]
+  in
+    ( printf "reading unsigned ints with leading zeroes allowed:\n"
+    ; List.iter (test_uint D.read_uint) samples
+    ; print_newline ()
+    ; printf "reading unsigned ints with leading zeroes forbidden:\n"
+    ; List.iter (test_uint D.read_uint_nz) samples
+    ; print_newline ()
+    )
+;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.