amuse/lib/Common.cpp

425 lines
19 KiB
C++
Raw Normal View History

#include "amuse/Common.hpp"
#ifndef _WIN32
#include <cstdio>
#include <memory>
#endif
#include <logvisor/logvisor.hpp>
2018-08-07 07:09:23 +00:00
using namespace std::literals;
2018-12-08 05:20:09 +00:00
namespace amuse {
static logvisor::Module Log("amuse");
2018-12-08 05:20:09 +00:00
bool Copy(const SystemChar* from, const SystemChar* to) {
#if _WIN32
2018-12-08 05:20:09 +00:00
return CopyFileW(from, to, FALSE) != 0;
#else
2018-12-08 05:20:09 +00:00
FILE* fi = fopen(from, "rb");
if (!fi)
return false;
FILE* fo = fopen(to, "wb");
if (!fo) {
fclose(fi);
2018-12-08 05:20:09 +00:00
return false;
}
std::unique_ptr<uint8_t[]> buf(new uint8_t[65536]);
size_t readSz = 0;
while ((readSz = fread(buf.get(), 1, 65536, fi)))
fwrite(buf.get(), 1, readSz, fo);
fclose(fi);
fclose(fo);
struct stat theStat;
if (::stat(from, &theStat))
return true;
2018-08-28 03:48:53 +00:00
#if __APPLE__
2018-12-08 05:20:09 +00:00
struct timespec times[] = {theStat.st_atimespec, theStat.st_mtimespec};
2018-09-25 22:39:22 +00:00
#elif __SWITCH__
2018-12-08 05:20:09 +00:00
struct timespec times[] = {theStat.st_atime, theStat.st_mtime};
2018-08-28 03:48:53 +00:00
#else
2018-12-08 05:20:09 +00:00
struct timespec times[] = {theStat.st_atim, theStat.st_mtim};
2018-08-28 03:48:53 +00:00
#endif
2018-12-08 05:20:09 +00:00
utimensat(AT_FDCWD, to, times, 0);
return true;
#endif
}
2018-12-08 05:20:09 +00:00
#define DEFINE_ID_TYPE(type, typeName) \
thread_local NameDB* type::CurNameDB = nullptr; \
template <> \
template <> \
void type##DNA<athena::Endian::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) { \
2018-12-08 05:20:09 +00:00
id = reader.readUint16Little(); \
} \
template <> \
template <> \
void type##DNA<athena::Endian::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) { \
2019-07-20 04:23:25 +00:00
writer.writeUint16Little(id.id); \
2018-12-08 05:20:09 +00:00
} \
template <> \
template <> \
void type##DNA<athena::Endian::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz) { \
2018-12-08 05:20:09 +00:00
sz += 2; \
} \
template <> \
template <> \
void type##DNA<athena::Endian::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader) { \
2018-12-08 05:20:09 +00:00
_read(reader); \
} \
template <> \
template <> \
void type##DNA<athena::Endian::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer) { \
2018-12-08 05:20:09 +00:00
_write(writer); \
} \
template <> \
template <> \
void type##DNA<athena::Endian::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) { \
2018-12-08 05:20:09 +00:00
id = reader.readUint16Big(); \
} \
template <> \
template <> \
void type##DNA<athena::Endian::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) { \
2019-07-20 04:23:25 +00:00
writer.writeUint16Big(id.id); \
2018-12-08 05:20:09 +00:00
} \
template <> \
template <> \
void type##DNA<athena::Endian::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz) { \
2018-12-08 05:20:09 +00:00
sz += 2; \
} \
template <> \
template <> \
void type##DNA<athena::Endian::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader) { \
2018-12-08 05:20:09 +00:00
_read(reader); \
} \
template <> \
template <> \
void type##DNA<athena::Endian::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer) { \
2018-12-08 05:20:09 +00:00
_write(writer); \
} \
template <athena::Endian DNAE> \
void type##DNA<DNAE>::_read(athena::io::YAMLDocReader& r) { \
2019-10-01 07:34:12 +00:00
std::string name = r.readString(); \
2018-12-08 05:20:09 +00:00
if (!type::CurNameDB) \
2020-04-11 22:49:30 +00:00
Log.report(logvisor::Fatal, FMT_STRING("Unable to resolve " typeName " name {}, no database present"), name); \
2018-12-08 05:20:09 +00:00
if (name.empty()) { \
id.id = 0xffff; \
return; \
} \
id = type::CurNameDB->resolveIdFromName(name); \
} \
template <athena::Endian DNAE> \
void type##DNA<DNAE>::_write(athena::io::YAMLDocWriter& w) { \
if (!type::CurNameDB) \
2020-04-11 22:49:30 +00:00
Log.report(logvisor::Fatal, FMT_STRING("Unable to resolve " typeName " ID {}, no database present"), id); \
2018-12-08 05:20:09 +00:00
if (id.id == 0xffff) \
return; \
std::string_view name = type::CurNameDB->resolveNameFromId(id); \
if (!name.empty()) \
2019-10-01 07:34:12 +00:00
w.writeString(name); \
2018-12-08 05:20:09 +00:00
} \
template <athena::Endian DNAE> \
2019-10-01 07:34:12 +00:00
std::string_view type##DNA<DNAE>::DNAType() { \
return "amuse::" #type "DNA"sv; \
2018-12-08 05:20:09 +00:00
} \
template struct type##DNA<athena::Endian::Big>; \
template struct type##DNA<athena::Endian::Little>;
2018-07-15 06:10:50 +00:00
DEFINE_ID_TYPE(ObjectId, "object")
DEFINE_ID_TYPE(SoundMacroId, "SoundMacro")
DEFINE_ID_TYPE(SampleId, "sample")
DEFINE_ID_TYPE(TableId, "table")
DEFINE_ID_TYPE(KeymapId, "keymap")
DEFINE_ID_TYPE(LayersId, "layers")
DEFINE_ID_TYPE(SongId, "song")
DEFINE_ID_TYPE(SFXId, "sfx")
2018-07-17 04:48:38 +00:00
DEFINE_ID_TYPE(GroupId, "group")
2018-07-15 06:10:50 +00:00
2018-12-08 05:20:09 +00:00
template <>
template <>
void PageObjectIdDNA<athena::Endian::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) {
2018-12-08 05:20:09 +00:00
id = reader.readUint16Little();
}
template <>
template <>
void PageObjectIdDNA<athena::Endian::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) {
2019-07-20 04:23:25 +00:00
writer.writeUint16Little(id.id);
2018-12-08 05:20:09 +00:00
}
template <>
template <>
void PageObjectIdDNA<athena::Endian::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz) {
2018-12-08 05:20:09 +00:00
sz += 2;
}
template <>
template <>
void PageObjectIdDNA<athena::Endian::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader) {
2018-12-08 05:20:09 +00:00
_read(reader);
}
template <>
template <>
void PageObjectIdDNA<athena::Endian::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer) {
2018-12-08 05:20:09 +00:00
_write(writer);
}
template <>
template <>
void PageObjectIdDNA<athena::Endian::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) {
2018-12-08 05:20:09 +00:00
id = reader.readUint16Big();
}
template <>
template <>
void PageObjectIdDNA<athena::Endian::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) {
2019-07-20 04:23:25 +00:00
writer.writeUint16Big(id.id);
2018-12-08 05:20:09 +00:00
}
template <>
template <>
void PageObjectIdDNA<athena::Endian::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz) {
2018-12-08 05:20:09 +00:00
sz += 2;
}
template <>
template <>
void PageObjectIdDNA<athena::Endian::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader) {
2018-12-08 05:20:09 +00:00
_read(reader);
}
template <>
template <>
void PageObjectIdDNA<athena::Endian::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer) {
2018-12-08 05:20:09 +00:00
_write(writer);
}
template <athena::Endian DNAE>
2018-12-08 05:20:09 +00:00
void PageObjectIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r) {
2019-10-01 07:34:12 +00:00
std::string name = r.readString();
2018-12-08 05:20:09 +00:00
if (!KeymapId::CurNameDB || !LayersId::CurNameDB)
2020-04-11 22:49:30 +00:00
Log.report(logvisor::Fatal, FMT_STRING("Unable to resolve keymap or layers name {}, no database present"), name);
2018-12-08 05:20:09 +00:00
if (name.empty()) {
id.id = 0xffff;
return;
}
auto search = KeymapId::CurNameDB->m_stringToId.find(name);
if (search == KeymapId::CurNameDB->m_stringToId.cend()) {
search = LayersId::CurNameDB->m_stringToId.find(name);
if (search == LayersId::CurNameDB->m_stringToId.cend()) {
search = SoundMacroId::CurNameDB->m_stringToId.find(name);
if (search == SoundMacroId::CurNameDB->m_stringToId.cend()) {
2020-04-11 22:49:30 +00:00
Log.report(logvisor::Error, FMT_STRING("Unable to resolve name {}"), name);
2018-07-15 06:10:50 +00:00
id.id = 0xffff;
return;
2018-12-08 05:20:09 +00:00
}
2018-07-15 06:10:50 +00:00
}
2018-12-08 05:20:09 +00:00
}
id = search->second;
}
template <athena::Endian DNAE>
2018-12-08 05:20:09 +00:00
void PageObjectIdDNA<DNAE>::_write(athena::io::YAMLDocWriter& w) {
if (!KeymapId::CurNameDB || !LayersId::CurNameDB)
2020-04-11 22:49:30 +00:00
Log.report(logvisor::Fatal, FMT_STRING("Unable to resolve keymap or layers ID {}, no database present"), id);
2018-12-08 05:20:09 +00:00
if (id.id == 0xffff)
return;
if (id.id & 0x8000) {
std::string_view name = LayersId::CurNameDB->resolveNameFromId(id);
if (!name.empty())
2019-10-01 07:34:12 +00:00
w.writeString(name);
2018-12-08 05:20:09 +00:00
} else if (id.id & 0x4000) {
std::string_view name = KeymapId::CurNameDB->resolveNameFromId(id);
if (!name.empty())
2019-10-01 07:34:12 +00:00
w.writeString(name);
2018-12-08 05:20:09 +00:00
} else {
std::string_view name = SoundMacroId::CurNameDB->resolveNameFromId(id);
if (!name.empty())
2019-10-01 07:34:12 +00:00
w.writeString(name);
2018-12-08 05:20:09 +00:00
}
}
template <athena::Endian DNAE>
2019-10-01 07:34:12 +00:00
std::string_view PageObjectIdDNA<DNAE>::DNAType() {
return "amuse::PageObjectIdDNA"sv;
}
template struct PageObjectIdDNA<athena::Endian::Big>;
template struct PageObjectIdDNA<athena::Endian::Little>;
2018-12-08 05:20:09 +00:00
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Little>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) {
2018-12-08 05:20:09 +00:00
step = reader.readUint16Little();
}
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Little>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) {
2018-12-08 05:20:09 +00:00
writer.writeUint16Little(step);
}
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Little>::Enumerate<BigDNA::BinarySize>(size_t& sz) {
2018-12-08 05:20:09 +00:00
sz += 2;
}
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Little>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader) {
2019-10-01 07:34:12 +00:00
step = reader.readUint16();
2018-12-08 05:20:09 +00:00
}
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Little>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer) {
2019-10-01 07:34:12 +00:00
writer.writeUint16(step);
2018-12-08 05:20:09 +00:00
}
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Big>::Enumerate<BigDNA::Read>(athena::io::IStreamReader& reader) {
2018-12-08 05:20:09 +00:00
step = reader.readUint16Big();
}
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Big>::Enumerate<BigDNA::Write>(athena::io::IStreamWriter& writer) {
2018-12-08 05:20:09 +00:00
writer.writeUint16Big(step);
}
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Big>::Enumerate<BigDNA::BinarySize>(size_t& sz) {
2018-12-08 05:20:09 +00:00
sz += 2;
}
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Big>::Enumerate<BigDNA::ReadYaml>(athena::io::YAMLDocReader& reader) {
2019-10-01 07:34:12 +00:00
step = reader.readUint16();
2018-12-08 05:20:09 +00:00
}
template <>
template <>
void SoundMacroStepDNA<athena::Endian::Big>::Enumerate<BigDNA::WriteYaml>(athena::io::YAMLDocWriter& writer) {
2019-10-01 07:34:12 +00:00
writer.writeUint16(step);
2018-07-28 04:34:29 +00:00
}
template <athena::Endian DNAE>
2019-10-01 07:34:12 +00:00
std::string_view SoundMacroStepDNA<DNAE>::DNAType() {
return "amuse::SoundMacroStepDNA"sv;
2018-07-28 04:34:29 +00:00
}
template struct SoundMacroStepDNA<athena::Endian::Big>;
template struct SoundMacroStepDNA<athena::Endian::Little>;
2018-07-28 04:34:29 +00:00
2018-12-08 05:20:09 +00:00
ObjectId NameDB::generateId(Type tp) const {
uint16_t maxMatch = 0;
if (tp == Type::Layer)
maxMatch = 0x8000;
else if (tp == Type::Keymap)
maxMatch = 0x4000;
for (const auto& p : m_idToString)
2019-07-20 04:23:25 +00:00
if (p.first.id >= maxMatch)
maxMatch = p.first.id + 1;
2018-12-08 05:20:09 +00:00
return maxMatch;
}
2018-12-08 05:20:09 +00:00
std::string NameDB::generateName(ObjectId id, Type tp) {
switch (tp) {
case Type::SoundMacro:
2020-04-11 22:49:30 +00:00
return fmt::format(FMT_STRING("macro{}"), id);
2018-12-08 05:20:09 +00:00
case Type::Table:
2020-04-11 22:49:30 +00:00
return fmt::format(FMT_STRING("table{}"), id);
2018-12-08 05:20:09 +00:00
case Type::Keymap:
2020-04-11 22:49:30 +00:00
return fmt::format(FMT_STRING("keymap{}"), id);
2018-12-08 05:20:09 +00:00
case Type::Layer:
2020-04-11 22:49:30 +00:00
return fmt::format(FMT_STRING("layers{}"), id);
2018-12-08 05:20:09 +00:00
case Type::Song:
2020-04-11 22:49:30 +00:00
return fmt::format(FMT_STRING("song{}"), id);
2018-12-08 05:20:09 +00:00
case Type::SFX:
2020-04-11 22:49:30 +00:00
return fmt::format(FMT_STRING("sfx{}"), id);
2018-12-08 05:20:09 +00:00
case Type::Group:
2020-04-11 22:49:30 +00:00
return fmt::format(FMT_STRING("group{}"), id);
2018-12-08 05:20:09 +00:00
case Type::Sample:
2020-04-11 22:49:30 +00:00
return fmt::format(FMT_STRING("sample{}"), id);
2018-12-08 05:20:09 +00:00
default:
2020-04-11 22:49:30 +00:00
return fmt::format(FMT_STRING("obj{}"), id);
2018-12-08 05:20:09 +00:00
}
}
2018-12-08 05:20:09 +00:00
std::string NameDB::generateDefaultName(Type tp) const { return generateName(generateId(tp), tp); }
2018-08-10 06:19:23 +00:00
2018-12-08 05:20:09 +00:00
std::string_view NameDB::registerPair(std::string_view str, ObjectId id) {
auto string = std::string(str);
m_stringToId.insert_or_assign(string, id);
return m_idToString.emplace(id, std::move(string)).first->second;
}
2018-12-08 05:20:09 +00:00
std::string_view NameDB::resolveNameFromId(ObjectId id) const {
auto search = m_idToString.find(id);
if (search == m_idToString.cend()) {
2020-04-11 22:49:30 +00:00
Log.report(logvisor::Error, FMT_STRING("Unable to resolve ID {}"), id);
2018-12-08 05:20:09 +00:00
return ""sv;
}
return search->second;
}
2018-12-08 05:20:09 +00:00
ObjectId NameDB::resolveIdFromName(std::string_view str) const {
auto search = m_stringToId.find(std::string(str));
if (search == m_stringToId.cend()) {
2020-04-11 22:49:30 +00:00
Log.report(logvisor::Error, FMT_STRING("Unable to resolve name {}"), str);
2018-12-08 05:20:09 +00:00
return {};
}
return search->second;
}
2018-12-08 05:20:09 +00:00
void NameDB::remove(ObjectId id) {
auto search = m_idToString.find(id);
if (search == m_idToString.cend())
return;
auto search2 = m_stringToId.find(search->second);
if (search2 == m_stringToId.cend())
return;
m_idToString.erase(search);
m_stringToId.erase(search2);
2018-08-09 07:42:17 +00:00
}
2018-12-08 05:20:09 +00:00
void NameDB::rename(ObjectId id, std::string_view str) {
auto search = m_idToString.find(id);
if (search == m_idToString.cend())
return;
if (search->second == str)
return;
auto search2 = m_stringToId.find(search->second);
if (search2 == m_stringToId.cend())
return;
2018-08-28 03:48:53 +00:00
#if __APPLE__
2018-12-08 05:20:09 +00:00
std::swap(m_stringToId[std::string(str)], search2->second);
m_stringToId.erase(search2);
2018-08-28 03:48:53 +00:00
#else
2018-12-08 05:20:09 +00:00
auto nh = m_stringToId.extract(search2);
nh.key() = str;
m_stringToId.insert(std::move(nh));
2018-08-28 03:48:53 +00:00
#endif
2018-12-08 05:20:09 +00:00
search->second = str;
2018-08-09 07:42:17 +00:00
}
2018-12-08 05:20:09 +00:00
template <>
void LittleUInt24::Enumerate<LittleDNA::Read>(athena::io::IStreamReader& reader) {
union {
atUint32 val;
char bytes[4];
} data = {};
reader.readBytesToBuf(data.bytes, 3);
val = SLittle(data.val);
}
2018-12-08 05:20:09 +00:00
template <>
void LittleUInt24::Enumerate<LittleDNA::Write>(athena::io::IStreamWriter& writer) {
union {
atUint32 val;
char bytes[4];
} data;
data.val = SLittle(val);
writer.writeBytes(data.bytes, 3);
}
2018-12-08 05:20:09 +00:00
template <>
void LittleUInt24::Enumerate<LittleDNA::BinarySize>(size_t& sz) {
sz += 3;
}
2018-12-08 05:20:09 +00:00
template <>
void LittleUInt24::Enumerate<LittleDNA::ReadYaml>(athena::io::YAMLDocReader& reader) {
2019-10-01 07:34:12 +00:00
val = reader.readUint32();
}
2018-12-08 05:20:09 +00:00
template <>
void LittleUInt24::Enumerate<LittleDNA::WriteYaml>(athena::io::YAMLDocWriter& writer) {
2019-10-01 07:34:12 +00:00
writer.writeUint32(val);
}
2019-10-01 07:34:12 +00:00
std::string_view LittleUInt24::DNAType() { return "amuse::LittleUInt24"sv; }
2018-12-08 05:20:09 +00:00
} // namespace amuse