File: CTypeList.cpp

package info (click to toggle)
vcmi 1.1.0%2Bdfsg-1
  • links: PTS, VCS
  • area: contrib
  • in suites: bookworm
  • size: 14,672 kB
  • sloc: cpp: 181,738; sh: 220; python: 178; ansic: 69; objc: 66; xml: 59; makefile: 34
file content (141 lines) | stat: -rw-r--r-- 3,454 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * CTypeList.cpp, part of VCMI engine
 *
 * Authors: listed in file AUTHORS in main folder
 *
 * License: GNU General Public License v2.0 or later
 * Full text of license available in license.txt file, in main folder
 *
 */
#include "StdInc.h"
#include "CTypeList.h"

#include "../registerTypes/RegisterTypes.h"

VCMI_LIB_NAMESPACE_BEGIN

extern template void registerTypes<CTypeList>(CTypeList & s);

CTypeList typeList;

CTypeList::CTypeList()
{
	registerTypes(*this);
}

CTypeList::TypeInfoPtr CTypeList::registerType(const std::type_info *type)
{
	if(auto typeDescr = getTypeDescriptor(type, false))
		return typeDescr;  //type found, return ptr to structure

	//type not found - add it to the list and return given ID
	auto newType = std::make_shared<TypeDescriptor>();
	newType->typeID = static_cast<ui16>(typeInfos.size() + 1);
	newType->name = type->name();
	typeInfos[type] = newType;

	return newType;
}

ui16 CTypeList::getTypeID(const std::type_info *type, bool throws) const
{
	auto descriptor = getTypeDescriptor(type, throws);
	if (descriptor == nullptr)
	{
		return 0;
	}
	return descriptor->typeID;
}

CTypeList::TypeInfoPtr CTypeList::getTypeDescriptor(ui16 typeID) const
{
	auto found = std::find_if(typeInfos.begin(), typeInfos.end(), [typeID](const std::pair<const std::type_info *, TypeInfoPtr> & p) -> bool
		{
			return p.second->typeID == typeID;
		});

	if(found != typeInfos.end())
	{
		return found->second;
	}

	return TypeInfoPtr();
}

std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to) const
{
	if(!strcmp(from->name, to->name))
		return std::vector<CTypeList::TypeInfoPtr>();

	// Perform a simple BFS in the class hierarchy.

	auto BFS = [&](bool upcast)
	{
		std::map<TypeInfoPtr, TypeInfoPtr> previous;
		std::queue<TypeInfoPtr> q;
		q.push(to);
		while(q.size())
		{
			auto typeNode = q.front();
			q.pop();
			for(auto & weakNode : (upcast ? typeNode->parents : typeNode->children) )
			{
				auto nodeBase = weakNode.lock();
				if(!previous.count(nodeBase))
				{
					previous[nodeBase] = typeNode;
					q.push(nodeBase);
				}
			}
		}

		std::vector<TypeInfoPtr> ret;

		if(!previous.count(from))
			return ret;

		ret.push_back(from);
		TypeInfoPtr ptr = from;
		do
		{
			ptr = previous.at(ptr);
			ret.push_back(ptr);
		} while(ptr != to);

		return ret;
	};

	// Try looking both up and down.
	auto ret = BFS(true);
	if(ret.empty())
		ret = BFS(false);

	if(ret.empty())
		THROW_FORMAT("Cannot find relation between types %s and %s. Were they (and all classes between them) properly registered?", from->name % to->name);

	return ret;
}

std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(const std::type_info *from, const std::type_info *to) const
{
	//This additional if is needed because getTypeDescriptor might fail if type is not registered
	// (and if casting is not needed, then registereing should no  be required)
	if(!strcmp(from->name(), to->name()))
		return std::vector<CTypeList::TypeInfoPtr>();

	return castSequence(getTypeDescriptor(from), getTypeDescriptor(to));
}

CTypeList::TypeInfoPtr CTypeList::getTypeDescriptor(const std::type_info *type, bool throws) const
{
	auto i = typeInfos.find(type);
	if(i != typeInfos.end())
		return i->second; //type found, return ptr to structure

	if(!throws)
		return nullptr;

	THROW_FORMAT("Cannot find type descriptor for type %s. Was it registered?", type->name());
}

VCMI_LIB_NAMESPACE_END