1 // Filename: File.cpp
2 #include "util/HashGenerator.h"
3 #include "dc/DistributedType.h"
4 #include "dc/Class.h"
5 #include "dc/Field.h"
6 
7 #include "File.h"
8 namespace dclass   // open namespace
9 {
10 
11 
12 typedef std::unordered_map<std::string, DistributedType*>::value_type TypeName;
13 
14 // constructor
File()15 File::File()
16 {
17 }
18 
19 //destructor
~File()20 File::~File()
21 {
22     for(auto it = m_classes.begin(); it != m_classes.end(); ++it) {
23         delete(*it);
24     }
25     for(auto it = m_structs.begin(); it != m_structs.end(); ++it) {
26         delete(*it);
27     }
28     for(auto it = m_imports.begin(); it != m_imports.end(); ++it) {
29         delete(*it);
30     }
31 
32     m_classes.clear();
33     m_structs.clear();
34     m_imports.clear();
35     m_types_by_id.clear();
36     m_types_by_name.clear();
37     m_fields_by_id.clear();
38     m_keywords.clear();
39 }
40 
41 // get_class_by_id returns the requested class or nullptr if there is no such class.
get_class_by_id(unsigned int id)42 Class* File::get_class_by_id(unsigned int id)
43 {
44     DistributedType* dt = get_type_by_id(id);
45     if(dt == nullptr) {
46         return nullptr;
47     }
48     if(dt->as_struct() == nullptr) {
49         return nullptr;
50     }
51     return dt->as_struct()->as_class();
52 }
get_class_by_id(unsigned int id) const53 const Class* File::get_class_by_id(unsigned int id) const
54 {
55     const DistributedType* dt = get_type_by_id(id);
56     if(dt == nullptr) {
57         return nullptr;
58     }
59     if(dt->as_struct() == nullptr) {
60         return nullptr;
61     }
62     return dt->as_struct()->as_class();
63 }
64 // get_class_by_name returns the requested class or nullptr if there is no such class.
get_class_by_name(const std::string & name)65 Class* File::get_class_by_name(const std::string &name)
66 {
67     DistributedType* dt = get_type_by_name(name);
68     if(dt == nullptr) {
69         return nullptr;
70     }
71     if(dt->as_struct() == nullptr) {
72         return nullptr;
73     }
74     return dt->as_struct()->as_class();
75 }
get_class_by_name(const std::string & name) const76 const Class* File::get_class_by_name(const std::string &name) const
77 {
78     const DistributedType* dt = get_type_by_name(name);
79     if(dt == nullptr) {
80         return nullptr;
81     }
82     if(dt->as_struct() == nullptr) {
83         return nullptr;
84     }
85     return dt->as_struct()->as_class();
86 }
87 
88 // add_class adds the newly-allocated class to the file.
89 //     Returns false if there is a name conflict.
90 //     The File becomes the owner of the pointer and will delete it when it destructs.
add_class(Class * cls)91 bool File::add_class(Class *cls)
92 {
93     // Classes have to have a name
94     if(cls->get_name().empty()) {
95         return false;
96     }
97 
98     // A Class can't share a name with any other type.
99     bool inserted = m_types_by_name.insert(TypeName(cls->get_name(), cls)).second;
100     if(!inserted) {
101         return false;
102     }
103 
104     cls->set_id(m_types_by_id.size());
105     m_types_by_id.push_back(cls);
106     m_classes.push_back(cls);
107     return true;
108 }
109 
110 // add_struct adds the newly-allocated struct to the file.
111 //     Returns false if there is a name conflict.
112 //     The File becomes the owner of the pointer and will delete it when it destructs.
add_struct(Struct * strct)113 bool File::add_struct(Struct *strct)
114 {
115     // Structs have to have a name
116     if(strct->get_name().empty()) {
117         return false;
118     }
119 
120     // A Struct can't share a name with any other type.
121     bool inserted = m_types_by_name.insert(TypeName(strct->get_name(), strct)).second;
122     if(!inserted) {
123         return false;
124     }
125 
126     strct->set_id(m_types_by_id.size());
127     m_types_by_id.push_back(strct);
128     m_structs.push_back(strct);
129     return true;
130 }
131 
132 // add_typedef adds the alias <name> to the file for the type <type>.
133 //     Returns false if there is a name conflict.
add_typedef(const std::string & name,DistributedType * type)134 bool File::add_typedef(const std::string& name, DistributedType* type)
135 {
136     // Typedefs can't use the empty string as a name
137     if(name.empty()) {
138         return false;
139     }
140 
141     // A type alias can't share a name with any other type.
142     return m_types_by_name.insert(TypeName(name, type)).second;
143 }
144 
145 // add_import adds a newly-allocated import to the file.
146 //     Imports with duplicate modules are combined.
add_import(Import * import)147 void File::add_import(Import* import)
148 {
149     // TODO: Combine duplicates
150     m_imports.push_back(import);
151 }
152 
153 // add_keyword adds a keyword with the name <keyword> to the list of declared keywords.
add_keyword(const std::string & keyword)154 void File::add_keyword(const std::string &keyword)
155 {
156     if(!has_keyword(keyword)) {
157         m_keywords.push_back(keyword);
158     }
159 }
160 
161 // add_field gives the field a unique id within the file.
add_field(Field * field)162 void File::add_field(Field *field)
163 {
164     field->set_id((unsigned int)m_fields_by_id.size());
165     m_fields_by_id.push_back(field);
166 }
167 
get_hash() const168 uint32_t File::get_hash() const
169 {
170     HashGenerator hashgen;
171     generate_hash(hashgen);
172     return hashgen.get_hash();
173 }
174 
175 // generate_hash accumulates the properties of this file into the hash.
generate_hash(HashGenerator & hashgen) const176 void File::generate_hash(HashGenerator& hashgen) const
177 {
178     hashgen.add_int(m_classes.size());
179     for(auto it = m_classes.begin(); it != m_classes.end(); ++it) {
180         (*it)->generate_hash(hashgen);
181     }
182 
183     hashgen.add_int(m_structs.size());
184     for(auto it = m_structs.begin(); it != m_structs.end(); ++it) {
185         (*it)->generate_hash(hashgen);
186     }
187 
188     hashgen.add_int(m_keywords.size());
189     for(auto it = m_keywords.begin(); it != m_keywords.end(); ++it) {
190         hashgen.add_string(*it);
191     }
192 }
193 
194 
195 } // close namespace dclass
196