/* PIP - Platform Independent Primitives Code model generator Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "stream.h" #include "pitranslator.h" bool writeClassStreamMembersOut(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple) { PIVector ml; for (const PICodeParser::Member & m: e->members) { if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; ml << m; } bool is_union = e->type == "union"; PISet used_id; for (const PICodeParser::Member & m: ml) { if (is_union && m.isBitfield()) continue; if (m.attributes[PICodeParser::Static]) continue; if (m.meta.value("id") == "-") continue; ++cnt; if (m.meta.contains("id")) cnt = m.meta.value("id").toInt(); if (used_id[cnt]) { piCerr << "Error with \"%1\" stream operator: ID %2 already used"_tr("pip_cmg").arg(e->name).arg(cnt); return false; } if (m.dims.isEmpty()) { if (simple) { rt.ts << "\ts << "; if (rt.parser.isEnum(m.type)) rt.ts << "(int)"; rt.ts << "v." << m.name << ";\n"; } else { rt.ts << "\tcs.add(" << cnt << ", "; if (rt.parser.isEnum(m.type)) rt.ts << "(int)"; rt.ts << "v." << m.name << ");\n"; } } else { PIString ptype = m.type.left(m.type.find('[')).trim(); PIString size = m.dims[0]; for (int i = 1; i < m.dims.size_s(); ++i) { size += " * "; size += m.dims[i]; } if (simple) { rt.ts << "\tfor (int i = 0; i < " << size << "; ++i)\n"; rt.ts << "\t\ts << ((const " << ptype << " *)(v." << m.name << "))[i];\n"; } else { rt.ts << "\tcs << cs.chunk(" << cnt << ", PIVector<" << ptype << " >((const " << ptype << " *)(v." << m.name << "), "; rt.ts << size << "));\n"; } } if (is_union) break; } if (is_union) return true; for (const PICodeParser::Entity * ce: e->children) { if (ce->has_name) continue; if (!writeClassStreamMembersOut(rt, ce, cnt, simple)) return false; } return true; } bool writeClassStreamMembersIn(Runtime & rt, const PICodeParser::Entity * e, int & cnt, bool simple) { PIVector ml; for (const PICodeParser::Member & m: e->members) { if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; ml << m; } bool is_union = e->type == "union"; PISet used_id; for (const PICodeParser::Member & m: ml) { if (is_union && m.isBitfield()) continue; if (m.attributes[PICodeParser::Static]) continue; if (m.meta.value("id") == "-") continue; ++cnt; if (m.meta.contains("id")) cnt = m.meta.value("id").toInt(); if (used_id[cnt]) { piCerr << "Error with \"%1\" stream operator: ID %2 already used"_tr("pip_cmg").arg(e->name).arg(cnt); return false; } used_id << cnt; if (m.dims.isEmpty()) { bool is_enum = rt.parser.isEnum(m.type); if (simple) { rt.ts << "\t"; if (is_enum) rt.ts << "{int i; "; rt.ts << "s >> "; if (is_enum) rt.ts << "i;"; else rt.ts << "v." << m.name << ";"; if (is_enum) rt.ts << " v." << m.name << " = (" << m.type << ")i;}"; rt.ts << "\n"; } else { rt.ts << "\t\tcase " << cnt << ":"; if (is_enum) rt.ts << " {int i;"; rt.ts << " cs.get("; if (is_enum) rt.ts << "i"; else rt.ts << "v." << m.name; rt.ts << ");"; if (is_enum) rt.ts << " v." << m.name << " = (" << m.type << ")i;}"; rt.ts << " break;\n"; } } else { PIString ptype = m.type.left(m.type.find('[')).trim(); PIString size = m.dims[0]; for (int i = 1; i < m.dims.size_s(); ++i) { size += " * "; size += m.dims[i]; } if (simple) { rt.ts << "\tfor (int i = 0; i < " << size << "; ++i)\n"; rt.ts << "\t\ts >> ((" << ptype << " *)(v." << m.name << "))[i];\n"; } else { rt.ts << "\t\tcase " << cnt << ": {\n\t\t\tPIVector<" << ptype << " > d; cs.get(d);\n"; rt.ts << "\t\t\tint cnt = piMini(d.size_s(), " << size << ");\n"; rt.ts << "\t\t\tfor (int i = 0; i < cnt; ++i)\n"; rt.ts << "\t\t\t\t((" << ptype << " *)(v." << m.name << "))[i] = d[i];\n"; rt.ts << "\t\t\t}\n"; rt.ts << "\t\t\tbreak;\n"; } } if (is_union) break; } if (is_union) return true; for (const PICodeParser::Entity * ce: e->children) { if (ce->has_name) continue; if (!writeClassStreamMembersIn(rt, ce, cnt, simple)) return false; } return true; } bool needClassStream(const PICodeParser::Entity * e) { if (e->meta.contains("no-stream")) return false; for (const PICodeParser::Member & m: e->members) { if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; if (m.attributes[PICodeParser::Static]) continue; if (m.meta.value("id") == "-") continue; return true; } return false; } bool makeClassStream(Runtime & rt, const PICodeParser::Entity * e) { if (!needClassStream(e)) return true; bool simple = e->meta.contains("simple-stream"); rt.ts << "\nBINARY_STREAM_WRITE(" << e->name << ") {\n"; if (!simple) rt.ts << "\tPIChunkStream cs;\n"; int cnt = 0; if (!writeClassStreamMembersOut(rt, e, cnt, simple)) return false; if (!simple) rt.ts << "\ts << cs.data();\n"; rt.ts << "\treturn s;\n}\n"; rt.ts << "BINARY_STREAM_READ (" << e->name << ") {\n"; if (!simple) { // ts << "\tif (s.size_s() < 4) return s;\n"; rt.ts << "\tPIChunkStream cs;\n"; rt.ts << "\tcs.extract(s);\n"; rt.ts << "\twhile (!cs.atEnd()) {\n"; rt.ts << "\t\tswitch (cs.read()) {\n"; } cnt = 0; if (!writeClassStreamMembersIn(rt, e, cnt, simple)) return false; if (!simple) rt.ts << "\t\t}\n\t}\n"; rt.ts << "\treturn s;\n}\n"; return true; }