Преглед изворни кода

src: use ListNode instead of Array to keep track of lists of some heap-allocated objects

Daniele Bartolini пре 7 година
родитељ
комит
cd891b451c
10 измењених фајлова са 91 додато и 39 уклоњено
  1. 9 0
      src/core/containers/types.h
  2. 1 0
      src/core/types.h
  3. 22 16
      src/device/device.cpp
  4. 3 3
      src/device/device.h
  5. 2 0
      src/world/gui.cpp
  6. 1 0
      src/world/gui.h
  7. 3 0
      src/world/level.cpp
  8. 1 0
      src/world/level.h
  9. 44 18
      src/world/world.cpp
  10. 5 2
      src/world/world.h

+ 9 - 0
src/core/containers/types.h

@@ -166,4 +166,13 @@ struct SortMap
 	SortMap(Allocator& a);
 };
 
+/// Node in an intrusive linked list.
+///
+/// @ingroup Containers
+struct ListNode
+{
+	ListNode* next;
+	ListNode* prev;
+};
+
 } // namespace crown

+ 1 - 0
src/core/types.h

@@ -53,6 +53,7 @@ typedef double   f64;
 #endif
 
 #define countof(arr) (sizeof(arr)/sizeof(arr[0]))
+#define container_of(ptr, type, member) ((char*)ptr - offsetof(type, member))
 
 #define CE_NOOP(...) do { (void)0; } while (0)
 #define CE_UNUSED(x) do { (void)(x); } while (0)

+ 22 - 16
src/device/device.cpp

@@ -226,12 +226,13 @@ Device::Device(const DeviceOptions& opts, ConsoleServer& cs)
 	, _pipeline(NULL)
 	, _display(NULL)
 	, _window(NULL)
-	, _worlds(default_allocator())
 	, _width(0)
 	, _height(0)
 	, _quit(false)
 	, _paused(false)
 {
+	_worlds.next = &_worlds;
+	_worlds.prev = &_worlds;
 }
 
 bool Device::process_events(bool vsync)
@@ -636,31 +637,36 @@ void Device::render(World& world, UnitId camera_unit)
 
 World* Device::create_world()
 {
-	World* w = CE_NEW(default_allocator(), World)(default_allocator()
+	World* world = CE_NEW(default_allocator(), World)(default_allocator()
 		, *_resource_manager
 		, *_shader_manager
 		, *_material_manager
 		, *_unit_manager
 		, *_lua_environment
 		);
-	array::push_back(_worlds, w);
-	return w;
+
+	ListNode* node = &world->_node;
+	ListNode* prev = &_worlds;
+	ListNode* next = _worlds.next;
+
+	node->next = next;
+	node->prev = prev;
+	next->prev = node;
+	prev->next = node;
+
+	return world;
 }
 
-void Device::destroy_world(World& w)
+void Device::destroy_world(World& world)
 {
-	for (u32 i = 0, n = array::size(_worlds); i < n; ++i)
-	{
-		if (&w == _worlds[i])
-		{
-			CE_DELETE(default_allocator(), &w);
-			_worlds[i] = _worlds[n-1];
-			array::pop_back(_worlds);
-			return;
-		}
-	}
+	ListNode* node = &world._node;
+
+	node->next->prev = node->prev;
+	node->prev->next = node->next;
+	node->next = NULL;
+	node->prev = NULL;
 
-	CE_FATAL("World not found");
+	CE_DELETE(default_allocator(), &world);
 }
 
 ResourcePackage* Device::create_resource_package(StringId64 id)

+ 3 - 3
src/device/device.h

@@ -55,7 +55,7 @@ struct Device
 	Pipeline* _pipeline;
 	Display* _display;
 	Window* _window;
-	Array<World*> _worlds;
+	ListNode _worlds;
 
 	u16 _width;
 	u16 _height;
@@ -97,8 +97,8 @@ struct Device
 	/// Creates a new world.
 	World* create_world();
 
-	/// Destroys the world @a w.
-	void destroy_world(World& w);
+	/// Destroys the @a world.
+	void destroy_world(World& world);
 
 	/// Returns the resource package @a id.
 	ResourcePackage* create_resource_package(StringId64 id);

+ 2 - 0
src/world/gui.cpp

@@ -27,6 +27,8 @@ Gui::Gui(GuiBuffer& gb, ResourceManager& rm, ShaderManager& sm, MaterialManager&
 	, _material_manager(&mm)
 	, _world(MATRIX4X4_IDENTITY)
 {
+	_node.next = NULL;
+	_node.prev = NULL;
 }
 
 Gui::~Gui()

+ 1 - 0
src/world/gui.h

@@ -111,6 +111,7 @@ struct Gui
 	ShaderManager* _shader_manager;
 	MaterialManager* _material_manager;
 	Matrix4x4 _world;
+	ListNode _node;
 
 	///
 	Gui(GuiBuffer& gb, ResourceManager& rm, ShaderManager& sm, MaterialManager& mm);

+ 3 - 0
src/world/level.cpp

@@ -24,6 +24,9 @@ Level::Level(Allocator& a, UnitManager& um, World& w, const LevelResource& lr)
 Level::~Level()
 {
 	_marker = 0;
+
+	_node.next = NULL;
+	_node.prev = NULL;
 }
 
 void Level::load(const Vector3& pos, const Quaternion& rot)

+ 1 - 0
src/world/level.h

@@ -24,6 +24,7 @@ struct Level
 	World* _world;
 	const LevelResource* _resource;
 	Array<UnitId> _unit_lookup;
+	ListNode _node;
 
 	///
 	Level(Allocator& a, UnitManager& um, World& w, const LevelResource& lr);

+ 44 - 18
src/world/world.cpp

@@ -41,12 +41,10 @@ World::World(Allocator& a, ResourceManager& rm, ShaderManager& sm, MaterialManag
 	, _sound_world(NULL)
 	, _animation_state_machine(NULL)
 	, _units(a)
-	, _levels(a)
 	, _camera(a)
 	, _camera_map(a)
 	, _events(a)
 	, _gui_buffer(sm)
-	, _guis(a)
 {
 	_lines = create_debug_line(true);
 	_scene_graph   = CE_NEW(*_allocator, SceneGraph)(*_allocator, um);
@@ -57,16 +55,32 @@ World::World(Allocator& a, ResourceManager& rm, ShaderManager& sm, MaterialManag
 	_animation_state_machine = CE_NEW(*_allocator, AnimationStateMachine)(*_allocator, rm, um);
 
 	_gui_buffer.create();
+
+	_guis.next = &_guis;
+	_guis.prev = &_guis;
+	_levels.next = &_levels;
+	_levels.prev = &_levels;
+
+	_node.next = NULL;
+	_node.prev = NULL;
 }
 
 World::~World()
 {
-	for (u32 i = 0; i < array::size(_levels); ++i)
-		CE_DELETE(*_allocator, _levels[i]);
+	// Destroy loaded levels
+	ListNode* cur = _levels.next;
+	while (cur != &_levels)
+	{
+		Level* level = (Level*)container_of(cur, Level, _node);
+		cur = cur->next;
+		CE_DELETE(*_allocator, level);
+	}
 
+	// Destroy units
 	for (u32 i = 0; i < array::size(_units); ++i)
 		_unit_manager->destroy(_units[i]);
 
+	// Destroy subsystems
 	CE_DELETE(*_allocator, _animation_state_machine);
 	CE_DELETE(*_allocator, _script_world);
 	CE_DELETE(*_allocator, _sound_world);
@@ -503,24 +517,29 @@ Gui* World::create_screen_gui()
 		, *_shader_manager
 		, *_material_manager
 		);
-	array::push_back(_guis, gui);
+
+	ListNode* node = &gui->_node;
+	ListNode* prev = &_guis;
+	ListNode* next = _guis.next;
+
+	node->next = next;
+	node->prev = prev;
+	next->prev = node;
+	prev->next = node;
+
 	return gui;
 }
 
 void World::destroy_gui(Gui& gui)
 {
-	for (u32 i = 0, n = array::size(_guis); i < n; ++i)
-	{
-		if (_guis[i] == &gui)
-		{
-			CE_DELETE(*_allocator, &gui);
-			_guis[i] = _guis[n-1];
-			array::pop_back(_guis);
-			return;
-		}
-	}
+	ListNode* node = &gui._node;
+
+	node->next->prev = node->prev;
+	node->prev->next = node->next;
+	node->next = NULL;
+	node->prev = NULL;
 
-	CE_FATAL("Gui not found");
+	CE_DELETE(*_allocator, &gui);
 }
 
 Level* World::load_level(StringId64 name, const Vector3& pos, const Quaternion& rot)
@@ -530,9 +549,16 @@ Level* World::load_level(StringId64 name, const Vector3& pos, const Quaternion&
 	Level* level = CE_NEW(*_allocator, Level)(*_allocator, *_unit_manager, *this, *lr);
 	level->load(pos, rot);
 
-	array::push_back(_levels, level);
-	post_level_loaded_event();
+	ListNode* node = &level->_node;
+	ListNode* prev = &_levels;
+	ListNode* next = _levels.next;
+
+	node->next = next;
+	node->prev = prev;
+	next->prev = node;
+	prev->next = node;
 
+	post_level_loaded_event();
 	return level;
 }
 

+ 5 - 2
src/world/world.h

@@ -59,13 +59,16 @@ struct World
 	AnimationStateMachine* _animation_state_machine;
 
 	Array<UnitId> _units;
-	Array<Level*> _levels;
 	Array<Camera> _camera;
 	HashMap<UnitId, u32> _camera_map;
 
 	EventStream _events;
 	GuiBuffer _gui_buffer;
-	Array<Gui*> _guis;
+
+	ListNode _guis;
+	ListNode _levels;
+
+	ListNode _node;
 
 	CameraInstance camera_make_instance(u32 i) { CameraInstance inst = { i }; return inst; }