Anonymous avatar Anonymous committed cacbbdd

Basic array type added.

Comments (0)

Files changed (9)

+syntax: glob
+*.o
+unit_test
+#pragma once
+
+#include "collection_types.h"
+#include "memory.h"
+
+#include <memory>
+
+namespace array
+{
+	template<typename T> inline uint32_t size(const Array<T> &a) 		{return a._size;}
+	template<typename T> inline bool any(const Array<T> &a) 			{return a._size != 0;}
+	template<typename T> inline bool empty(const Array<T> &a) 			{return a._size == 0;}
+	template<typename T> inline uint32_t capacity(const Array<T> &a)	{return a._capacity;}
+
+	template<typename T> inline T* begin(Array<T> &a) 					{return a._data;}
+	template<typename T> inline const T* begin(const Array<T> &a) 		{return a._data;}
+	template<typename T> inline T* end(Array<T> &a) 					{return a._data + a._size;}
+	template<typename T> inline const T* end(const Array<T> &a) 		{return a._data + a._size;}
+	
+	template<typename T> inline T& front(Array<T> &a) 					{return a._data[0];}
+	template<typename T> inline const T& front(const Array<T> &a) 		{return a._data[0];}
+	template<typename T> inline T& back(Array<T> &a) 					{return a._data[a._size-1];}
+	template<typename T> inline const T& back(const Array<T> &a) 		{return a._data[a._size-1];}
+
+	template <typename T> void resize(Array<T> &a, uint32_t new_size)
+	{
+		if (new_size > a._capacity)
+			grow(a, new_size);
+		a._size = new_size;
+	}
+
+	template<typename T> void set_capacity(Array<T> &a, uint32_t new_capacity)
+	{
+		if (new_capacity == a._capacity)
+			return;
+
+		if (new_capacity < a._size)
+			resize(a, new_capacity);
+
+		T *new_data = 0;
+		if (new_capacity > 0) {
+			new_data = (T *)a._allocator->allocate(sizeof(T)*new_capacity, alignof(T));
+			memcpy(new_data, a._data, sizeof(T)*a._size);
+		}
+		a._allocator->deallocate(a._data);
+		a._data = new_data;
+		a._capacity = new_capacity;
+	}
+
+	template<typename T> void grow(Array<T> &a, uint32_t min_capacity = 0)
+	{
+		uint32_t new_capacity = a._capacity*2 + 10;
+		if (new_capacity < min_capacity)
+			new_capacity = min_capacity;
+		set_capacity(a, new_capacity);
+	}
+
+	template<typename T> inline void push_back(Array<T> &a, const T &item)
+	{
+		if (a._size + 1 > a._capacity)
+			grow(a);
+		a._data[a._size++] = item;
+	}
+
+	template<typename T> inline void pop_back(Array<T> &a)
+	{
+		a._size--;
+	}
+}
+
+template <typename T>
+inline Array<T>::Array(Allocator &allocator) : _allocator(&allocator), _size(0), _capacity(0), _data(NULL) {}
+
+template <typename T>
+inline Array<T>::~Array()
+{
+	_allocator->deallocate(_data);
+}
+
+template <typename T>
+Array<T>::Array(const Array<T> &other) : _allocator(other._allocator), _size(0), _capacity(0), _data(0)
+{
+	const uint32_t n = other._size;
+	array::set_capacity(*this, n);
+	memcpy(_data, other._data, sizeof(T) * n);
+	_size = n;
+}
+
+template <typename T>
+Array<T> &Array<T>::operator=(const Array<T> &other)
+{
+	const uint32_t n = other._size;
+	array::resize(*this, n);
+	memcpy(_data, other._data, sizeof(T)*n);
+	return *this;
+}
+
+template <typename T>
+inline T & Array<T>::operator[](uint32_t i)
+{
+	return _data[i];
+}
+
+template <typename T>
+inline const T & Array<T>::operator[](uint32_t i) const
+{
+	return _data[i];
+}

collection_types.h

+#pragma once
+
+#include "types.h"
+#include "memory_types.h"
+
+template<typename T> struct Array
+{
+	Array(Allocator &a);
+	~Array();
+	Array(const Array &other);
+	Array &operator=(const Array &other);
+	
+	T &operator[](uint32_t i);
+	const T &operator[](uint32_t i) const;
+
+	Allocator *_allocator;
+	uint32_t _size;
+	uint32_t _capacity;
+	T *_data;
+};
 		}
 
 		virtual void deallocate(void *p) {
+			if (!p)
+				return;
+
 			Header *h = header(p);
 			_total_allocated -= h->size;
 			free(h);
+#pragma once
+
+#include "types.h"
 #include "memory_types.h"
-#include <stdint.h>
 
 /// Base class for memory allocators.
 ///
 	/// Default alignment for memory allocations.
 	static const uint32_t DEFAULT_ALIGN = 4;
 
+	Allocator() {}
 	virtual ~Allocator() {}
 	
 	virtual void *allocate(uint32_t size, uint32_t align = DEFAULT_ALIGN) = 0;
 	virtual void deallocate(void *p) = 0;
 	virtual uint32_t allocated_size(void *p) = 0;
 	virtual uint32_t total_allocated() = 0;
+
+private:
+    Allocator(const Allocator& other);
+    Allocator& operator=(const Allocator& other);
 };
 
 #define MAKE_NEW(a, T, ...)		(new ((a).allocate(sizeof(T), alignof(T))) T(__VA_ARGS__))
+#pragma once
+
 class Allocator;
 EXEC = "unit_test"
 FLAGS = "-Wall -Wextra"
 
-OBJECTS = ['unit_test.o', 'memory.o']
+OBJECTS = %w(unit_test.o memory.o)
+HEADERS = %w(array.h collection_types.h memory.h memory_types.h types.h)
 
 # tasks
 
 
 file EXEC => OBJECTS do
 	sh "#{COMPILER} #{FLAGS} #{OBJECTS.join(" ")} -o #{EXEC}"
-end
+end
+
+# dependencies
+
+file 'unit_test.o' => %w(unit_test.cpp) + HEADERS
+file 'memory.o' => %w(memory.cpp) + %w(types.h memory_types.h memory.h)
+#pragma once
+
+#include <stdint.h>
+
+#ifndef alignof
+	#define alignof(x) __alignof(x)
+#endif
+#include "array.h"
 #include "memory.h"
 
 #include <stdio.h>
 #include <assert.h>
 
-#define CHECK(x) assert(x)
+#define ASSERT(x) assert(x)
 
 namespace {
 	void test_memory() {
 		Allocator &a = memory_globals::default_allocator();
 
 		void *p = a.allocate(100);
-		CHECK(a.allocated_size(p) >= 100);
-		CHECK(a.total_allocated() >= 100);
+		ASSERT(a.allocated_size(p) >= 100);
+		ASSERT(a.total_allocated() >= 100);
 		void *q = a.allocate(100);
-		CHECK(a.allocated_size(q) >= 100);
-		CHECK(a.total_allocated() >= 200);
+		ASSERT(a.allocated_size(q) >= 100);
+		ASSERT(a.total_allocated() >= 200);
 
 		a.deallocate(p);
 		a.deallocate(q);
 
-		CHECK(a.total_allocated() == 0);
+		ASSERT(a.total_allocated() == 0);
+
+		memory_globals::shutdown();
+	}
+
+	void test_array() {
+		memory_globals::init();
+		Allocator &a = memory_globals::default_allocator();
+
+		{
+			Array<int> v(a);
+
+			ASSERT(array::size(v) == 0);
+			array::push_back(v, 3);
+			ASSERT(array::size(v) == 1);
+			ASSERT(v[0] == 3);
+
+			Array<int> v2(v);
+			ASSERT(v2[0] == 3);
+			v2[0] = 5;
+			ASSERT(v[0] == 3);
+			ASSERT(v2[0] == 5);
+			v2 = v;
+			ASSERT(v2[0] == 3);
+			
+			ASSERT(array::end(v) - array::begin(v) == array::size(v));
+			ASSERT(*array::begin(v) == 3);
+			array::pop_back(v);
+			ASSERT(array::empty(v));
+
+			for (int i=0; i<100; ++i)
+				array::push_back(v, i);
+			ASSERT(array::size(v) == 100);
+		}
+
+		ASSERT(a.total_allocated() == 0);
+
 
 		memory_globals::shutdown();
 	}
 int main(int, char **)
 {
 	test_memory();
+	test_array();
+	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.