iostream support for unsigned ints,float,double,bool

In <limits> added support for unsigned long and unsigned long long.
diff --git a/include/limits b/include/limits
index 6f6d9f3..5213a65 100644
--- a/include/limits
+++ b/include/limits
@@ -182,6 +182,22 @@
     static const int digits10 = digits10<int, digits, is_signed>::value;
 };
 
+// numeric_limits<unsigned long>
+template<>
+struct numeric_limits<unsigned long>
+{
+    static const bool is_specialized = true;
+
+    static unsigned long min() { return 0; }
+    static unsigned long max() { return ULONG_MAX; }
+
+    static const bool is_signed = true;
+    static const bool is_integer = true;
+
+    static const int digits = LONG_BIT;
+    static const int digits10 = digits10<int, digits, is_signed>::value;
+};
+
 // numeric_limits<long long>
 template<>
 struct numeric_limits<long long>
@@ -198,6 +214,22 @@
     static const int digits10 = digits10<int, digits, is_signed>::value;
 };
 
+// numeric_limits<unsigned long long>
+template<>
+struct numeric_limits<unsigned long long>
+{
+    static const bool is_specialized = true;
+
+    static unsigned long long min() { return 0; }
+    static unsigned long long max() { return ULLONG_MAX; }
+
+    static const bool is_signed = true;
+    static const bool is_integer = true;
+
+    static const int digits = static_cast<int>(sizeof(unsigned long long) * CHAR_BIT);
+    static const int digits10 = digits10<int, digits, is_signed>::value;
+};
+
 }  // namespace std
 
 
diff --git a/include/ostream b/include/ostream
index f7f2734..dc0b8e0 100644
--- a/include/ostream
+++ b/include/ostream
@@ -73,9 +73,21 @@
         return *this;
     }
 
-    ostream& operator<<(const char_type *str);
-    ostream& operator<<(int val);
+    ostream& operator<<(unsigned long int val);
+    ostream& operator<<(long int val);
     ostream& operator<<(unsigned int val);
+    ostream& operator<<(int val);
+    ostream& operator<<(unsigned long long int val);
+    ostream& operator<<(long long int val);
+
+    ostream& operator<<(double val);
+    ostream& operator<<(float val);
+
+    ostream& operator<<(char_type c);
+    ostream& operator<<(const char_type *str);
+    ostream& operator<<(bool val);
+
+    // '(nil)' if p == 0
     ostream& operator<<(const void *p);
 
     // This is non standard, used by string.
diff --git a/src/ostream.cpp b/src/ostream.cpp
index 50d71d4..e4e902f 100644
--- a/src/ostream.cpp
+++ b/src/ostream.cpp
@@ -29,6 +29,7 @@
 #include <ostream>
 #include <streambuf>
 #include <cstring>
+#include <limits>
 
 namespace std {
 // Defined in bionic/libstdc++/src/one_time_construction.cpp
@@ -44,6 +45,16 @@
     return *this;
 }
 
+ostream& ostream::operator<<(char_type c) {
+    // TODO: Should format according to flags.
+    return put(c);
+}
+
+ostream& ostream::operator<<(bool val) {
+    // TODO: Should format according to flags (e.g write "true" or "false").
+    return put(val?'1':'0');
+}
+
 // 64 bits int in octal is 22 digits. There is one for the sign and 2
 // for the format specifier + 1 for the terminating \0. A total of 26
 // chars should be enough to hold any integer representation.
@@ -62,6 +73,49 @@
     return write(buf, size);
 }
 
+ostream& ostream::operator<<(long int val) {
+    const char *fmt = "%ld";
+    char buf[kNumSize];
+    int size = snprintf(buf, kNumSize, fmt, val);
+    return write(buf, size);
+}
+
+ostream& ostream::operator<<(unsigned long int val) {
+    const char *fmt = "%lu";
+    char buf[kNumSize];
+    int size = snprintf(buf, kNumSize, fmt, val);
+    return write(buf, size);
+}
+
+ostream& ostream::operator<<(long long int val) {
+    const char *fmt = "%lld";
+    char buf[kNumSize];
+    int size = snprintf(buf, kNumSize, fmt, val);
+    return write(buf, size);
+}
+
+ostream& ostream::operator<<(unsigned long long int val) {
+    const char *fmt = "%llu";
+    char buf[kNumSize];
+    int size = snprintf(buf, kNumSize, fmt, val);
+    return write(buf, size);
+}
+
+// Double max 1.7976931348623157E+308 = 23 < kNumSize so we reuse it.
+ostream& ostream::operator<<(double val) {
+    const char *fmt = "%.*e";
+    char buf[kNumSize];
+    int size = snprintf(buf, kNumSize, fmt, precision(), val);
+    return write(buf, size);
+}
+
+ostream& ostream::operator<<(float val) {
+    const char *fmt = "%.*e";
+    char buf[kNumSize];
+    int size = snprintf(buf, kNumSize, fmt, precision(), val);
+    return write(buf, size);
+}
+
 ostream& ostream::operator<<(const void *p) {
     const char *fmt = "%p";
     char buf[kNumSize];
diff --git a/tests/test_iostream.cpp b/tests/test_iostream.cpp
index 53fbb60..7836c40 100644
--- a/tests/test_iostream.cpp
+++ b/tests/test_iostream.cpp
@@ -32,6 +32,7 @@
 #error "Wrong header included!!"
 #endif
 #include "common.h"
+#include <limits>
 #include <string>
 
 namespace android {
@@ -81,10 +82,27 @@
 bool testOutputFormat() {
     using std::endl;
     using std::cout;
-    cout << endl << "Int: " << 10 << endl;
-    cout << "Negative int: " << -10 << endl;
-    cout << "Unsigned int: " << 0xffffffff << endl;
+    using std::numeric_limits;
+    cout << endl << "Int: " << numeric_limits<int>::max() << endl;
+    cout << "Negative int: " << numeric_limits<int>::min() << endl;
+    cout << "Unsigned int: " << numeric_limits<unsigned int>::max() << endl;
+    cout << "Long: " << numeric_limits<long>::max() << endl;
+    cout << "Negative long: " << numeric_limits<long>::min() << endl;
+    cout << "Unsigned long int: " << numeric_limits<unsigned long>::max() << endl;
+    cout << "Long long: " << numeric_limits<long long>::max() << endl;
+    cout << "Negative long long: " << numeric_limits<long long>::min() << endl;
+    cout << "Unsigned long long: " << numeric_limits<unsigned long long>::max() << endl;
+
+    cout.precision(std::numeric_limits<double>::digits10);
+    cout << "Double: " << numeric_limits<double>::max() << endl;
+    cout << "Negative double: " << numeric_limits<double>::min() << endl;
+    cout << "Float: " << numeric_limits<float>::max() << endl;
+    cout << "Negative float: " << numeric_limits<float>::min() << endl;
+
     cout << "Void *: " << static_cast<void*>(&std::cout) << endl;
+    cout << "NULL *: " << static_cast<void*>(0) << endl;
+    cout << "bool: " << true << " " << false << endl;
+    cout << "char: " << 'A' << endl;
     cout << "string: " << std::string("hello world") << endl;
     return true;
 }