Niklas Frykholm avatar Niklas Frykholm committed 6a82e99

Added string_stream.

Comments (0)

Files changed (5)

 
 * **Hash<T>** Implements a lightweight hash that assumes that *T* is a POD-object. The hash keys are always uint64_t numbers. If you want to use some other type of key, just hash it to a uint64_t first. (The hash function should not have any collisions in your domain.) The hash can be used as a regular hash, or as a multi_hash, through the *multi_hash* interface.
 
+* **string_stream** Functions for using an Array<char> as a stream of characters that you can print formatted messages to.
+
 ### Math
 
 * Basic data definitions for vectors, quaternions and matrices.
 # Use -DPLATFORM_BIG_ENDIAN for big endian platforms
 FLAGS = "-Wall -Wextra -g"
 
-OBJECTS = %w(unit_test.o memory.o murmur_hash.o)
-HEADERS = %w(array.h collection_types.h memory.h memory_types.h types.h temp_allocator.h hash.h)
+OBJECTS = %w(unit_test.o memory.o murmur_hash.o string_stream.o)
+HEADERS = %w(array.h collection_types.h memory.h memory_types.h types.h 
+	temp_allocator.h hash.h string_stream.h)
 
 # tasks
 
 
 file 'unit_test.o' => %w(unit_test.cpp) + HEADERS
 file 'memory.o' => %w(memory.cpp) + %w(types.h memory_types.h memory.h)
-file 'murmur_hash.o' => %w(murmur_hash.cpp) + %w(murmur_hash.h)
+file 'murmur_hash.o' => %w(murmur_hash.cpp) + %w(murmur_hash.h)
+file 'string_stream.o' => %w(string_stream.cpp) + %w(string_stream.h collection_types.h array.h types.h memory_types.h  )

string_stream.cpp

+#include "string_stream.h"
+
+#include <stdarg.h>
+
+namespace foundation 
+{
+	namespace string_stream
+	{
+		Buffer & printf(Buffer &b, const char *format, ...)
+		{
+			va_list args;
+			
+			va_start(args, format);
+			int n = vsnprintf(NULL, 0, format, args);
+			va_end(args);
+
+			uint32_t end = array::size(b);
+			array::resize(b, end + n + 1);
+			
+			va_start(args, format);
+			vsnprintf(array::begin(b) + end, n + 1, format, args);
+			va_end(args);
+			
+			array::resize(b, end + n);
+
+			return b;
+		}
+
+		Buffer & tab(Buffer &b, uint32_t column)
+		{
+			uint32_t current_column = 0;
+			uint32_t i = array::size(b) - 1;
+			while (i != 0xffffffffu && b[i] != '\n' && b[i] != '\r') {
+				++current_column;
+				--i;
+			}
+			if (current_column < column)
+				repeat(b, column - current_column, ' ');
+			return b;
+		}
+
+		Buffer & repeat(Buffer &b, uint32_t count, char c)
+		{
+			for (uint32_t i=0; i<count; ++i)
+				array::push_back(b, c);
+			return b;
+		}
+	}
+}
+#pragma once
+
+#include "collection_types.h"
+#include "array.h"
+
+#include <string.h>
+#include <stdio.h>
+
+namespace foundation
+{
+	/// Functions for operating on an Array<char> as a stream of characters,
+	/// useful for string formatting, etc.
+	namespace string_stream
+	{
+		typedef Array<char> Buffer;
+
+		/// Dumps the item to the stream using a default formatting.
+		Buffer & operator<<(Buffer &b, char c);
+		Buffer & operator<<(Buffer &b, const char *s);
+		Buffer & operator<<(Buffer &b, float f);
+		Buffer & operator<<(Buffer &b, int32_t i);
+		Buffer & operator<<(Buffer &b, uint32_t i);
+		Buffer & operator<<(Buffer &b, uint64_t i);
+
+		/// Uses printf to print formatted data to the stream.
+		Buffer & printf(Buffer &b, const char *format, ...);
+
+		/// Pushes the raw data to the stream.
+		Buffer & push(Buffer &b, const char *data, uint32_t n);
+
+		/// Pads the stream with spaces until it is aligned at the specified column.
+		/// Can be used to column align data. (Assumes each char is 1 space wide,
+		/// i.e. does not work with UTF-8 data.)
+		Buffer & tab(Buffer &b, uint32_t column);
+
+		/// Adds the specified number of c to the stream.
+		Buffer & repeat(Buffer &b, uint32_t count, char c);
+
+		/// Returns the stream as a C-string. There will always be a \0 character
+		/// at the end of the returned string. You don't have to explicitly add it
+		/// to the buffer.
+		const char *c_str(Buffer &b);
+	}
+
+	namespace string_stream_internal
+	{
+		using namespace string_stream;
+
+		template <typename T>
+		inline Buffer &printf_small(Buffer &b, const char *fmt, const T &t)
+		{
+			char s[32];
+			snprintf(s, 32, fmt, t);
+			return (b << s);
+		}
+	}
+
+	namespace string_stream
+	{
+		inline Buffer & operator<<(Buffer &b, char c)
+		{
+			array::push_back(b, c);
+			return b;
+		}
+
+		inline Buffer & operator<<(Buffer &b, const char *s)
+		{
+			return push(b, s, strlen(s));
+		}
+
+		inline Buffer & operator<<(Buffer &b, float f)
+		{
+			return string_stream_internal::printf_small(b, "%g", f);
+		}
+
+		inline Buffer & operator<<(Buffer &b, int32_t i)
+		{
+			return string_stream_internal::printf_small(b, "%d", i);
+		}
+
+		inline Buffer & operator<<(Buffer &b, uint32_t i)
+		{
+			return string_stream_internal::printf_small(b, "%u", i);
+		}
+
+		inline Buffer & operator<<(Buffer &b, uint64_t i)
+		{
+			return string_stream_internal::printf_small(b, "%01llx", i);
+		}
+
+		inline Buffer & push(Buffer &b, const char *data, uint32_t n)
+		{
+			unsigned int end = array::size(b);
+			array::resize(b, end + n);
+			memcpy(array::begin(b) + end, data, n);
+			return b;
+		}
+
+		inline const char *c_str(Buffer &b)
+		{
+			// Ensure there is a \0 at the end of the buffer.
+			array::push_back(b, '\0');
+			array::pop_back(b);
+			return array::begin(b);
+		}
+	}
+}
+#include "string_stream.h"
 #include "murmur_hash.h"
 #include "hash.h"
 #include "temp_allocator.h"
 		memory_globals::shutdown();
 	}
 
-	void test_multi_hash() {
+	void test_multi_hash()
+	{
 		memory_globals::init();
 		{
 			TempAllocator128 ta;
 			ASSERT(*value == buffer[i]);
 		}
 	}
+
+	void test_string_stream()
+	{
+		memory_globals::init();
+		{
+			using namespace string_stream;
+
+			TempAllocator1024 ta;
+			Buffer ss(ta);
+
+			ss << "Name"; 			tab(ss, 20);	ss << "Score\n";
+			repeat(ss, 10, '-');	tab(ss, 20);	repeat(ss, 10, '-'); ss << "\n";
+			ss << "Niklas"; 		tab(ss, 20);	printf(ss, "%.2f", 2.7182818284f); ss << "\n";
+			ss << "Jim"; 			tab(ss, 20);	printf(ss, "%.2f", 3.14159265f); ss << "\n";
+
+			ASSERT(
+				0 == strcmp(c_str(ss),
+					"Name                Score\n"
+					"----------          ----------\n"
+					"Niklas              2.72\n"
+					"Jim                 3.14\n"
+				)
+			);
+		}
+		memory_globals::shutdown();
+	}
 }
 
 int main(int, char **)
 	test_multi_hash();
 	test_murmur_hash();
 	test_pointer_arithmetic();
+	test_string_stream();
 	return 0;
 }
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.