typed treebuilder for primitives and containers

This commit is contained in:
Jake Hillion 2023-03-20 13:06:37 -07:00
parent 76f525f43d
commit c434988b43
34 changed files with 939 additions and 499 deletions

View File

@ -5,10 +5,10 @@
[types]
containers = [
"PWD/types/array_type.toml",
"PWD/types/string_type.toml",
# "PWD/types/string_type.toml",
"PWD/types/cxx11_string_type.toml",
"PWD/types/folly_iobuf_type.toml",
"PWD/types/folly_iobuf_queue_type.toml",
# "PWD/types/folly_iobuf_type.toml",
# "PWD/types/folly_iobuf_queue_type.toml",
"PWD/types/set_type.toml",
"PWD/types/unordered_set_type.toml",
"PWD/types/seq_type.toml",
@ -25,25 +25,28 @@ containers = [
"PWD/types/priority_queue_container_adapter_type.toml",
"PWD/types/ref_wrapper_type.toml",
"PWD/types/multi_map_type.toml",
"PWD/types/folly_small_heap_vector_map.toml",
"PWD/types/folly_optional_type.toml",
# "PWD/types/folly_small_heap_vector_map.toml",
# "PWD/types/folly_optional_type.toml",
"PWD/types/optional_type.toml",
"PWD/types/try_type.toml",
"PWD/types/fb_string_type.toml",
"PWD/types/small_vec_type.toml",
"PWD/types/f14_fast_map.toml",
"PWD/types/f14_node_map.toml",
"PWD/types/f14_vector_map.toml",
"PWD/types/f14_fast_set.toml",
"PWD/types/f14_node_set.toml",
"PWD/types/f14_vector_set.toml",
# "PWD/types/try_type.toml",
# "PWD/types/fb_string_type.toml",
# "PWD/types/small_vec_type.toml",
# "PWD/types/f14_fast_map.toml",
# "PWD/types/f14_node_map.toml",
# "PWD/types/f14_vector_map.toml",
# "PWD/types/f14_fast_set.toml",
# "PWD/types/f14_node_set.toml",
# "PWD/types/f14_vector_set.toml",
"PWD/types/sorted_vec_set_type.toml",
"PWD/types/map_seq_type.toml",
"PWD/types/boost_bimap_type.toml",
"PWD/types/repeated_field_type.toml",
"PWD/types/repeated_ptr_field_type.toml",
"PWD/types/caffe2_blob_type.toml",
# "PWD/types/map_seq_type.toml",
# "PWD/types/boost_bimap_type.toml",
# "PWD/types/repeated_field_type.toml",
# "PWD/types/repeated_ptr_field_type.toml",
# "PWD/types/caffe2_blob_type.toml",
"PWD/types/std_variant.toml",
"PWD/types/thrift_isset_type.toml",
# "PWD/types/thrift_isset_type.toml",
"PWD/types/weak_ptr_type.toml",
]
[codegen]
default_namespaces = ["namespace std"]

View File

@ -154,6 +154,15 @@ std::unique_ptr<ContainerInfo> ContainerInfo::loadFromFile(
return nullptr;
}
// std::string outputType;
// if (std::optional<std::string> str =
// (*codegen)["outputType"].value<std::string>()) {
// func = std::move(*str);
// } else {
// LOG(ERROR) << "`codegen.outputType` is a required field";
// return nullptr;
// }
return std::unique_ptr<ContainerInfo>(new ContainerInfo{
std::move(typeName),
std::move(matcher),
@ -166,8 +175,9 @@ std::unique_ptr<ContainerInfo> ContainerInfo::loadFromFile(
underlyingContainerIndex,
{
std::move(decl),
std::move(func),
.outputType = "",
.decl = std::move(decl),
.func = std::move(func),
},
});
}

View File

@ -28,6 +28,7 @@ const char* containerTypeEnumToStr(ContainerTypeEnum ty);
struct ContainerInfo {
struct Codegen {
std::string outputType;
std::string decl;
std::string func;
};

View File

@ -134,13 +134,6 @@ const std::string typedValueFunc = R"(
} // namespace
void FuncGen::DeclareGetSize(std::string& testCode, const std::string& type) {
boost::format fmt =
boost::format("void getSizeType(const %1% &t, size_t& returnArg);\n") %
type;
testCode.append(fmt.str());
}
void FuncGen::DeclareTopLevelGetSize(std::string& testCode,
const std::string& type) {
boost::format fmt = boost::format("void getSizeType(const %1% &t);\n") % type;
@ -158,6 +151,59 @@ void FuncGen::DeclareEncodeData(std::string& testCode) {
void FuncGen::DeclareEncodeDataSize(std::string& testCode) {
testCode.append("size_t EncodeVarintSize(uint64_t val);\n");
}
void FuncGen::DeclareBasicTypeHandlers(std::string& testCode) {
testCode.append(R"(
template <typename DB, typename T>
struct TypeHandler {
private:
static auto choose_type() {
if constexpr(std::is_pointer_v<T>) {
return std::type_identity<StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::Sum<DB,
StaticTypes::Unit<DB>,
typename TypeHandler<DB, std::remove_pointer_t<T>>::type
>>>();
} else {
return std::type_identity<StaticTypes::Unit<DB>>();
}
}
public:
using type = typename decltype(choose_type())::type;
static StaticTypes::Unit<DB> getSizeType(
const T& t,
typename TypeHandler<DB, T>::type returnArg) {
if constexpr(std::is_pointer_v<T>) {
JLOG("ptr val @");
JLOGPTR(t);
auto r0 = returnArg.write((uintptr_t)t);
if (t && pointers.add((uintptr_t)t)) {
return r0.template delegate<1>([&t](auto ret) {
if constexpr (!std::is_void<std::remove_pointer_t<T>>::value) {
return TypeHandler<DB, std::remove_pointer_t<T>>::getSizeType(*t, ret);
} else {
return ret;
}
});
} else {
return r0.template delegate<0>(std::identity());
}
} else {
return returnArg;
}
}
};
template <typename DB>
class TypeHandler<DB, void> {
public:
using type = StaticTypes::Unit<DB>;
};
)");
}
void FuncGen::DefineEncodeData(std::string& testCode) {
std::string func = R"(
size_t EncodeVarint(uint64_t val, uint8_t* buf) {
@ -245,6 +291,7 @@ void FuncGen::DefineTopLevelGetSizeRef(std::string& testCode,
{
pointers.initialize();
pointers.add((uintptr_t)&t);
auto data = reinterpret_cast<uintptr_t*>(dataBase);
data[0] = oidMagicId;
data[1] = cookieValue;
@ -254,9 +301,21 @@ void FuncGen::DefineTopLevelGetSizeRef(std::string& testCode,
OIInternal::StoreData((uintptr_t)(&t), dataSegOffset);
JLOG("%1% @");
JLOGPTR(&t);
OIInternal::getSizeType(t, dataSegOffset);
OIInternal::StoreData((uintptr_t)123456789, dataSegOffset);
OIInternal::StoreData((uintptr_t)123456789, dataSegOffset);
using DataBufferType = OIInternal::TypeHandler<DataBuffer::DataSegment, OIInternal::__ROOT_TYPE__>::type;
DataBufferType db = DataBuffer::DataSegment(dataSegOffset);
StaticTypes::Unit<DataBuffer::DataSegment> out = OIInternal::getSizeType<DataBuffer::DataSegment>(t, db);
StaticTypes::Unit<DataBuffer::DataSegment> final = out.template cast<StaticTypes::Pair<
DataBuffer::DataSegment,
StaticTypes::VarInt<DataBuffer::DataSegment>,
StaticTypes::VarInt<DataBuffer::DataSegment>
>>()
.write(123456789)
.write(123456789);
dataSegOffset = final.bust() - dataBase;
data[2] = dataSegOffset;
dataBase += dataSegOffset;
}
@ -289,58 +348,29 @@ void FuncGen::DefineTopLevelGetSizeRefRet(std::string& testCode,
testCode.append(fmt.str());
}
void FuncGen::DefineTopLevelGetSizeSmartPtr(std::string& testCode,
const std::string& rawType) {
std::string func = R"(
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-attributes"
/* RawType: %1% */
void __attribute__((used, retain)) getSize_%2$016x(const OIInternal::__ROOT_TYPE__& t)
#pragma GCC diagnostic pop
{
pointers.initialize();
auto data = reinterpret_cast<uintptr_t*>(dataBase);
data[0] = oidMagicId;
data[1] = cookieValue;
data[2] = 0;
size_t dataSegOffset = 3 * sizeof(uintptr_t);
OIInternal::StoreData((uintptr_t)(&t), dataSegOffset);
OIInternal::getSizeType(t, dataSegOffset);
OIInternal::StoreData((uintptr_t)123456789, dataSegOffset);
OIInternal::StoreData((uintptr_t)123456789, dataSegOffset);
data[2] = dataSegOffset;
dataBase += dataSegOffset;
}
)";
boost::format fmt =
boost::format(func) % rawType % std::hash<std::string>{}(rawType);
testCode.append(fmt.str());
}
bool FuncGen::DeclareGetSizeFuncs(std::string& testCode,
const ContainerInfoRefSet& containerInfo,
bool chaseRawPointers) {
testCode.append(R"(template<typename DB, typename T>
StaticTypes::Unit<DB>
getSizeType(const T &t, typename TypeHandler<DB, T>::type returnArg) {
JLOG("obj @");
JLOGPTR(&t);
return TypeHandler<DB, T>::getSizeType(t, returnArg);
}
)");
for (const ContainerInfo& cInfo : containerInfo) {
std::string ctype = cInfo.typeName;
ctype = ctype.substr(0, ctype.find("<", 0));
auto& decl = cInfo.codegen.decl;
LOG(ERROR) << "got here 0 decl";
boost::format fmt = boost::format(decl) % ctype;
LOG(ERROR) << "got here 1 decl";
testCode.append(fmt.str());
}
if (chaseRawPointers) {
testCode.append(
"template<typename T, typename = "
"std::enable_if_t<!std::is_pointer_v<std::decay_t<T>>>>\n");
} else {
testCode.append("template<typename T>\n");
}
testCode.append("void getSizeType(const T &t, size_t& returnArg);");
return true;
}
@ -352,24 +382,12 @@ bool FuncGen::DefineGetSizeFuncs(std::string& testCode,
ctype = ctype.substr(0, ctype.find("<", 0));
auto& func = cInfo.codegen.func;
LOG(ERROR) << "got here 0 func";
boost::format fmt = boost::format(func) % ctype;
LOG(ERROR) << "got here 1 func";
testCode.append(fmt.str());
}
if (chaseRawPointers) {
testCode.append("template<typename T, typename C>\n");
} else {
testCode.append("template<typename T>\n");
}
testCode.append(R"(
void getSizeType(const T &t, size_t& returnArg) {
JLOG("obj @");
JLOGPTR(&t);
SAVE_SIZE(sizeof(T));
}
)");
return true;
}

View File

@ -37,6 +37,8 @@ class FuncGen {
static void DeclareEncodeDataSize(std::string& testCode);
static void DefineEncodeDataSize(std::string& testCode);
static void DeclareBasicTypeHandlers(std::string& testCode);
bool DeclareGetSizeFuncs(std::string& testCode,
const ContainerInfoRefSet& containerInfo,
bool chaseRawPointers);
@ -46,8 +48,6 @@ class FuncGen {
static void DeclareGetContainer(std::string& testCode);
static void DeclareGetSize(std::string& testCode, const std::string& type);
static void DeclareTopLevelGetSize(std::string& testCode,
const std::string& type);
static void DefineTopLevelGetObjectSize(std::string& testCode,
@ -60,9 +60,6 @@ class FuncGen {
static void DefineTopLevelGetSizeRefRet(std::string& testCode,
const std::string& type);
static void DefineTopLevelGetSizeSmartPtr(std::string& testCode,
const std::string& rawType);
static void DefineGetSizeTypedValueFunc(std::string& testCode,
const std::string& ctype);
};

View File

@ -1695,22 +1695,28 @@ void OICodeGen::getFuncDefClassMembers(
code += ">;\n";
}
if (members.size() == 0) {
code += "return returnArg;\n";
return;
}
code += "auto r1 = returnArg";
for (std::size_t i = 0; i < members.size(); ++i) {
if (captureThriftIsset && i < members.size() - 1) {
// Capture Thrift's isset value for each field, except __isset itself,
// which we assume comes last
assert(members[i].member_name != "__isset");
std::string issetIdxStr =
"thrift_data::isset_indexes[" + std::to_string(i) + "]";
code += "{\n";
code += " if (&thrift_data::isset_indexes != nullptr &&\n";
code += " " + issetIdxStr + " != -1) {\n";
code += " SAVE_DATA(t.__isset.get(" + issetIdxStr + "));\n";
code += " } else {\n";
code += " SAVE_DATA(-1);\n";
code += " }\n";
code += "}\n";
}
// if (captureThriftIsset && i < members.size() - 1) {
// // Capture Thrift's isset value for each field, except __isset itself,
// // which we assume comes last
// assert(members[i].member_name != "__isset");
// std::string issetIdxStr =
// "thrift_data::isset_indexes[" + std::to_string(i) + "]";
// code += "{\n";
// code += " if (&thrift_data::isset_indexes != nullptr &&\n";
// code += " " + issetIdxStr + " != -1) {\n";
// code += " SAVE_DATA(t.__isset.get(" + issetIdxStr + "));\n";
// code += " } else {\n";
// code += " SAVE_DATA(-1);\n";
// code += " }\n";
// code += "}\n";
// }
const auto& member = members[i];
std::string memberName = member.member_name;
@ -1721,19 +1727,33 @@ void OICodeGen::getFuncDefClassMembers(
if (memberName.empty()) {
continue;
}
/*
* Check if the member is a bit field (bitFieldSize > 0).
* If it is a bit field, we can't get its address with operator&.
* If it is *NOT* a bit field, then we can print its address.
*/
if (member.bit_field_size > 0) {
code += "JLOG(\"" + memberName + " (bit_field)\\n\");\n";
} else {
code += "JLOG(\"" + memberName + " @\");\n";
code += "JLOGPTR(&t." + memberName + ");\n";
}
code += "getSizeType(t." + memberName + ", returnArg);\n";
if (i != members.size() - 1) {
code += "\n .delegate([&t](auto ret) {\n";
/*
* Check if the member is a bit field (bitFieldSize > 0).
* If it is a bit field, we can't get its address with operator&.
* If it is *NOT* a bit field, then we can print its address.
*/
if (member.bit_field_size > 0) {
code += " JLOG(\"" + memberName + " (bit_field)\\n\");\n";
} else {
code += " JLOG(\"" + memberName + " @\");\n";
code += " JLOGPTR(&t." + memberName + ");\n";
}
code += " return OIInternal::getSizeType<DB>(t." + memberName +
", ret);\n";
code += " })";
} else {
code += ";\n";
if (member.bit_field_size > 0) {
code += " JLOG(\"" + memberName + " (bit_field)\\n\");\n";
} else {
code += " JLOG(\"" + memberName + " @\");\n";
code += " JLOGPTR(&t." + memberName + ");\n";
}
code += " return OIInternal::getSizeType<DB>(t." + memberName + ", r1);\n";
}
}
}
@ -1753,6 +1773,48 @@ void OICodeGen::enumerateDescendants(drgn_type* type, drgn_type* baseType) {
}
}
std::string OICodeGen::getFuncDefTreeBuilderType(drgn_type* type,
const std::string& typeName) {
if (drgn_type_kind(type) == DRGN_TYPE_TYPEDEF) {
// Handle case where parent is a typedef
return getFuncDefTreeBuilderType(drgnUnderlyingType(type), typeName);
}
std::string out;
size_t count = 0;
const auto& members = classMembersMap[type];
std::unordered_map<std::string, int> memberNames;
for (std::size_t i = 0; i < members.size(); ++i) {
const auto& member = members[i];
std::string memberName = member.member_name;
std::replace(memberName.begin(), memberName.end(), '.', '_');
deduplicateMemberName(memberNames, memberName);
if (memberName.empty()) {
continue;
}
if (i != members.size() - 1) {
out += "StaticTypes::Pair<DB, ";
count++;
}
out +=
(boost::format("typename TypeHandler<DB, decltype(%1%::%2%)>::type") %
typeName % memberName)
.str();
if (i != members.size() - 1) {
out += ", ";
}
}
out += std::string(count, '>');
if (!out.empty()) {
return out;
}
return "StaticTypes::Unit<DB>";
}
void OICodeGen::getFuncDefinitionStr(std::string& code, drgn_type* type,
const std::string& typeName) {
if (classMembersMap.find(type) == classMembersMap.end()) {
@ -1764,13 +1826,24 @@ void OICodeGen::getFuncDefinitionStr(std::string& code, drgn_type* type,
funcName = "getSizeTypeConcrete";
}
code +=
"void " + funcName + "(const " + typeName + "& t, size_t& returnArg) {\n";
auto typeStaticType = getFuncDefTreeBuilderType(type, typeName);
code += (boost::format(R"(
template <typename DB>
struct TypeHandler<DB, %1%> {
using type = %3%;
static StaticTypes::Unit<DB> %2%(
const %1% &t,
typename TypeHandler<DB, %1%>::type returnArg) {
)") % typeName %
funcName % typeStaticType)
.str();
std::unordered_map<std::string, int> memberNames;
getFuncDefClassMembers(code, type, memberNames);
code += "}\n";
code += " }\n";
if (isDynamic(type)) {
enumerateDescendants(type, type);
@ -1810,8 +1883,10 @@ void OICodeGen::getFuncDefinitionStr(std::string& code, drgn_type* type,
"& t, size_t& returnArg);\n";
}
code += std::string("void getSizeType(const ") + typeName +
std::string("& t, size_t& returnArg) {\n");
code += "template <typename DB>\n";
code += std::string("StaticTypes::Unit<DB> getSizeType(const ") + typeName +
std::string("& t, typename TypeHandler<" + typeName +
">::type returnArg) {\n");
// The Itanium C++ ABI defines that the vptr must appear at the zero-offset
// position in any class in which they are present.
code += " auto *vptr = *reinterpret_cast<uintptr_t * const *>(&t);\n";
@ -1846,6 +1921,8 @@ void OICodeGen::getFuncDefinitionStr(std::string& code, drgn_type* type,
code += " getSizeTypeConcrete(t, returnArg);\n";
code += "}\n";
}
code += "\n};";
}
std::string OICodeGen::templateTransformType(const std::string& typeName) {
@ -3231,6 +3308,7 @@ bool OICodeGen::generateJitCode(std::string& code) {
std::string functionsCode;
functionsCode.append("namespace OIInternal {\nnamespace {\n");
functionsCode.append("// functions -----\n");
funcGen.DeclareBasicTypeHandlers(functionsCode);
if (!funcGen.DeclareGetSizeFuncs(functionsCode, containerTypesFuncDef,
config.chaseRawPointers)) {
LOG(ERROR) << "declaring get size for containers failed";
@ -3246,18 +3324,6 @@ bool OICodeGen::generateJitCode(std::string& code) {
)");
}
for (auto& e : structDefType) {
if (drgn_type_kind(e) != DRGN_TYPE_UNION) {
auto typeName = getNameForType(e);
if (!typeName.has_value()) {
return false;
}
funcGen.DeclareGetSize(functionsCode, *typeName);
}
}
if (config.useDataSegment || config.chaseRawPointers) {
funcGen.DeclareStoreData(functionsCode);
}
@ -3275,28 +3341,6 @@ bool OICodeGen::generateJitCode(std::string& code) {
return false;
}
if (config.chaseRawPointers) {
functionsCode.append(R"(
template<typename T>
void getSizeType(const T* s_ptr, size_t& returnArg)
{
JLOG("ptr val @");
JLOGPTR(s_ptr);
StoreData((uintptr_t)(s_ptr), returnArg);
if (s_ptr && pointers.add((uintptr_t)s_ptr)) {
getSizeType(*(s_ptr), returnArg);
}
}
void getSizeType(const void *s_ptr, size_t& returnArg)
{
JLOG("void ptr @");
JLOGPTR(s_ptr);
StoreData((uintptr_t)(s_ptr), returnArg);
}
)");
}
for (auto& e : structDefType) {
auto name = getNameForType(e);
@ -3364,7 +3408,8 @@ bool OICodeGen::generateJitCode(std::string& code) {
if (rootTypeStr.starts_with("unique_ptr") ||
rootTypeStr.starts_with("LowPtr") ||
rootTypeStr.starts_with("shared_ptr")) {
funcGen.DefineTopLevelGetSizeSmartPtr(functionsCode, rawTypeName);
// funcGen.DefineTopLevelGetSizeSmartPtr(functionsCode, rawTypeName);
funcGen.DefineTopLevelGetSizeRef(functionsCode, rawTypeName);
} else {
funcGen.DefineTopLevelGetSizeRef(functionsCode, rawTypeName);
}

View File

@ -228,6 +228,7 @@ class OICodeGen {
bool& ifStub);
bool getContainerTemplateParams(drgn_type* type, bool& ifStub);
void enumerateDescendants(drgn_type* type, drgn_type* baseType);
std::string getFuncDefTreeBuilderType(drgn_type* type, const std::string&);
void getFuncDefinitionStr(std::string& code, drgn_type* type,
const std::string& typeName);
std::optional<uint64_t> getDrgnTypeSize(drgn_type* type);

View File

@ -14,6 +14,9 @@ R"(
#include <cstdint>
#include <utility>
#include <variant>
#include <functional>
#include <type_traits>
#include <unistd.h>
// clang-format on
@ -21,7 +24,7 @@ R"(
#define C10_USING_CUSTOM_GENERATED_MACROS
// These globals are set by oid, see end of OIDebugger::compileCode()
extern uintptr_t dataBase;
extern uint8_t* dataBase;
extern size_t dataSize;
extern uintptr_t cookieValue;
extern int logFile;
@ -154,4 +157,185 @@ template <>
struct DummySizedOperator<0> {
};
namespace ObjectIntrospection {
namespace DataBuffer {
class DataBuffer {
protected:
void write_byte(uint8_t);
};
class DataSegment: public DataBuffer {
public:
DataSegment(size_t offset) : buf(dataBase + offset) {}
void write_byte(uint8_t byte) {
if (buf > (dataBase + dataSize * 8)) {
// TODO: fail
}
*buf = byte;
buf++;
}
// TODO: REMOVE ME
uint8_t* bust() {
return buf;
}
private:
uint8_t* buf;
};
} // namespace DataBuffer
namespace RuntimeTypes {
class Unit {};
class VarInt {
};
using Dynamic = std::variant<
std::reference_wrapper<const Unit>,
std::reference_wrapper<const VarInt>>;
} // namespace RuntimeTypes
namespace StaticTypes {
template <typename DataBuffer>
class Unit {
public:
Unit(DataBuffer db) : _buf(db) {}
static RuntimeTypes::Dynamic describe() {
static auto singleton = RuntimeTypes::Unit();
return RuntimeTypes::Dynamic(singleton);
}
// TODO: REMOVE ME
uint8_t* bust() {
return _buf.bust();
}
template <typename T>
T cast() {
return T(_buf);
}
Unit<DataBuffer>
delegate(std::function<Unit<DataBuffer>(Unit<DataBuffer>)> cb) {
return cb(*this);
}
private:
DataBuffer _buf;
};
template <typename DataBuffer>
class VarInt {
public:
VarInt(DataBuffer db) : _buf(db) {}
static RuntimeTypes::Dynamic describe() {
static auto singleton = RuntimeTypes::VarInt();
return RuntimeTypes::Dynamic(singleton);
}
Unit<DataBuffer> write(uint64_t val) {
while (val >= 128) {
_buf.write_byte(0x80 | (val & 0x7f));
val >>= 7;
}
_buf.write_byte(uint8_t(val));
return Unit<DataBuffer>(_buf);
}
private:
DataBuffer _buf;
};
template <typename DataBuffer, typename T1, typename T2>
class Pair {
public:
Pair(DataBuffer db) : _buf(db) {}
template <class U>
T2 write(U val) {
Unit<DataBuffer> second = T1(_buf).write(val);
return second.template cast<T2>();
}
T2 delegate(std::function<Unit<DataBuffer>(T1)> cb) {
T1 first = T1(_buf);
Unit<DataBuffer> second = cb(first);
return second.template cast<T2>();
}
private:
DataBuffer _buf;
};
template <typename DataBuffer, typename... Types>
class Sum {
private:
template <size_t I, typename... Elements>
struct Selector;
template <size_t I, typename Head, typename... Tail>
struct Selector<I, Head, Tail...> {
using type = typename std::conditional<I == 0, Head, typename Selector<I - 1, Tail...>::type>::type;
};
template<size_t I>
struct Selector<I> {
using type = int;
};
public:
Sum(DataBuffer db) : _buf(db) {}
template <size_t I = 0>
typename Selector<I, Types...>::type write() {
Pair<DataBuffer, VarInt<DataBuffer>, typename Selector<I, Types...>::type> buf(_buf);
return buf.write(I);
}
template <size_t I = 0>
Unit<DataBuffer> delegate(std::function<Unit<DataBuffer>(typename Selector<I, Types...>::type)> cb) {
auto tail = write<I>();
return cb(tail);
}
private:
DataBuffer _buf;
};
template <typename DataBuffer, typename T>
class ListContents {
public:
ListContents(DataBuffer db) : _buf(db) {}
ListContents<DataBuffer, T> delegate(std::function<Unit<DataBuffer>(T)> cb) {
T head = T(_buf);
Unit<DataBuffer> tail = cb(head);
return tail.template cast<ListContents<DataBuffer, T>>();
}
Unit<DataBuffer> finish() {
return { _buf };
}
private:
DataBuffer _buf;
};
template <typename DataBuffer, typename T>
using List = Pair<DataBuffer, VarInt<DataBuffer>, ListContents<DataBuffer, T>>;
} // namespace StaticTypes
} // namespace ObjectIntrospection
using namespace ObjectIntrospection;
)"

View File

@ -28,13 +28,7 @@
#include "PaddingHunter.h"
#include "SymbolService.h"
#define DEFINE_TYPE_VERSION(Type, size, version) \
static_assert( \
sizeof(Type) == size, \
"Type `" #Type \
"` has changed, please update the `size` parameter and increment the " \
"`version` parameter of the corresponding invocation " \
"of `DEFINE_TYPE_VERSION` in " __FILE__); \
#define DEFINE_TYPE_VERSION(Type, size, version) \
BOOST_CLASS_VERSION(Type, version)
DEFINE_TYPE_VERSION(PaddingInfo, 120, 3)

View File

@ -427,8 +427,7 @@ TreeBuilder::Node TreeBuilder::process(NodeID id, Variable variable) {
auto innerTypeKind = drgn_type_kind(entry->second);
if (innerTypeKind != DRGN_TYPE_FUNCTION) {
node.pointer = next();
if (innerTypeKind == DRGN_TYPE_VOID ||
!shouldProcess(*node.pointer)) {
if (innerTypeKind == DRGN_TYPE_VOID || next() == 0) {
break;
}
}
@ -626,7 +625,7 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
node.pointer = next();
containerStats.length = *node.pointer ? 1 : 0;
containerStats.capacity = 1;
if (!shouldProcess(*node.pointer)) {
if (next() == 0) {
return;
}
break;

View File

@ -3,7 +3,9 @@ definitions = '''
int a;
char b;
long long c;
int d;
};
struct EmptyStruct {};
class SimpleClass {
int a;
char b;
@ -21,13 +23,22 @@ definitions = '''
param_types = ["const SimpleStruct&"]
setup = "return {};"
expect_json = '''[{
"staticSize":16,
"staticSize":24,
"dynamicSize":0,
"members":[
{"name":"a", "staticSize":4, "dynamicSize":0},
{"name":"b", "staticSize":1, "dynamicSize":0},
{"name":"c", "staticSize":8, "dynamicSize":0}
{"name":"c", "staticSize":8, "dynamicSize":0},
{"name":"d", "staticSize":4, "dynamicSize":0}
]}]'''
[cases.empty_struct]
param_types = ["const EmptyStruct&"]
setup = "return {};"
expect_json = '''[{
"staticSize":1,
"dynamicSize":0,
"NOT": "members"
}]'''
[cases.class]
param_types = ["const SimpleClass&"]
setup = "return {};"

View File

@ -10,21 +10,26 @@ replaceTemplateParamIndex = []
[codegen]
decl = """
template<typename T, long unsigned int N>
void getSizeType(const %1%<T, N> &container, size_t& returnArg);
template<typename DB, typename T0, long unsigned int N>
struct TypeHandler<DB, %1%<T0, N>> {
using type = StaticTypes::List<DB, typename TypeHandler<DB, T0>::type>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0, N> &container,
typename TypeHandler<DB, %1%<T0,N>>::type returnArg) {
auto tail = returnArg.write(container.size());
for (auto & it: container) {
tail = tail.delegate([&it](auto ret) {
return TypeHandler<DB, T0>::getSizeType(it, ret);
});
}
return tail.finish();
}
};
"""
func = """
template<typename T, long unsigned int N>
void getSizeType(const %1%<T,N> &container, size_t& returnArg)
{
SAVE_DATA((uintptr_t)container.size());
SAVE_SIZE(sizeof(container));
for (auto & it: container) {
// undo the static size that has already been added per-element
SAVE_SIZE(-sizeof(it));
getSizeType(it, returnArg);
}
}
// DummyFunc %1%
"""

View File

@ -10,22 +10,31 @@ allocatorIndex = 1
[codegen]
decl = """
template<typename T, typename Allocator>
void getSizeType(const %1%<T, Allocator> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1>
struct TypeHandler<DB, %1% <T0, T1>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::List<DB, typename TypeHandler<DB, T0>::type>>;
static StaticTypes::Unit<DB> getSizeType(
const %1% <T0, T1> & container,
typename TypeHandler<DB, %1% <T0, T1>>::type returnArg) {
auto tail = returnArg.write((uintptr_t)&container)
.write(container.size());
// The double ampersand is needed otherwise this loop doesn't work with
// vector<bool>
for (auto&& it : container) {
tail = tail.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it, ret);
});
}
return tail.finish();
}
};
"""
func = """
template<typename T, typename Allocator>
void getSizeType(const %1%<T, Allocator> &container, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<T>));
SAVE_DATA((uintptr_t)&container);
SAVE_DATA((uintptr_t)container.size());
// The double ampersand is needed otherwise this loop doesn't work with vector<bool>
for (auto&& it: container) {
getSizeType(it, returnArg);
}
}
// DummyFunc %1%
"""

View File

@ -10,26 +10,23 @@ replaceTemplateParamIndex = []
[codegen]
decl = """
template<typename T>
void getSizeType(const %1%<T> &t, size_t& returnArg);
template <typename DB, typename T0>
struct TypeHandler<DB, %1% <T0>> {
using type =
StaticTypes::Pair<DB, StaticTypes::VarInt<DB>, StaticTypes::VarInt<DB>>;
static StaticTypes::Unit<DB> getSizeType(
const %1% <T0> & container,
typename TypeHandler<DB, %1% <T0>>::type returnArg) {
bool sso = ((uintptr_t)container.data() <
(uintptr_t)(&container + sizeof(%1% <T0>))) &&
((uintptr_t)container.data() >= (uintptr_t)&container);
return returnArg.write(container.capacity()).write(container.size());
}
};
"""
func = """
template<typename T>
void getSizeType(const %1%<T> &t, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<T>));
SAVE_DATA((uintptr_t)t.capacity());
SAVE_DATA((uintptr_t)t.size());
// Test for small string optimisation - whether the underlying string is
// contained within the string object.
SAVE_SIZE(
(((uintptr_t)t.data() < (uintptr_t)(&t + sizeof(%1%<T>)))
&&
((uintptr_t)t.data() >= (uintptr_t)&t))
? 0 : (t.capacity() * sizeof(T))
);
}
// DummyFunc %1%
"""

View File

@ -10,22 +10,31 @@ allocatorIndex = 1
[codegen]
decl = """
template<typename T, typename Allocator>
void getSizeType(const %1%<T, Allocator> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1>
struct TypeHandler<DB, %1%<T0, T1>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::List<DB, typename TypeHandler<DB, T0>::type>>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0, T1>& container,
typename TypeHandler<DB, %1%<T0, T1>>::type returnArg) {
auto tail = returnArg.write((uintptr_t)&container)
.write(container.size());
// The double ampersand is needed otherwise this loop doesn't work with
// vector<bool>
for (auto&& it : container) {
tail = tail.delegate([&it](auto ret) {
return TypeHandler<DB, T0>::getSizeType(it, ret);
});
}
return tail.finish();
}
};
"""
func = """
template<typename T, typename Allocator>
void getSizeType(const %1%<T, Allocator> &container, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<T>));
SAVE_DATA((uintptr_t)&container);
SAVE_DATA((uintptr_t)container.size());
// The double ampersand is needed otherwise this loop doesn't work with vector<bool>
for (auto&& it: container) {
getSizeType(it, returnArg);
}
}
// DummyFunc %1%
"""

View File

@ -10,22 +10,31 @@ allocatorIndex = 1
[codegen]
decl = """
template<typename T, typename Allocator>
void getSizeType(const %1%<T, Allocator> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1>
struct TypeHandler<DB, %1% <T0, T1>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::List<DB, typename TypeHandler<DB, T0>::type>>;
static StaticTypes::Unit<DB> getSizeType(
const %1% <T0, T1> & container,
typename TypeHandler<DB, %1% <T0, T1>>::type returnArg) {
auto tail = returnArg.write((uintptr_t)&container)
.write(container.size());
// The double ampersand is needed otherwise this loop doesn't work with
// vector<bool>
for (auto&& it : container) {
tail = tail.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it, ret);
});
}
return tail.finish();
}
};
"""
func = """
template<typename T, typename Allocator>
void getSizeType(const %1%<T, Allocator> &container, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<T>));
SAVE_DATA((uintptr_t)&container);
SAVE_DATA((uintptr_t)container.size());
// The double ampersand is needed otherwise this loop doesn't work with vector<bool>
for (auto&& it: container) {
getSizeType(it, returnArg);
}
}
// DummyFunc %1%
"""

View File

@ -9,22 +9,33 @@ allocatorIndex = 3
[codegen]
decl = """
template<class Key, class T, class Compare, class Allocator>
void getSizeType(const %1%<Key,T,Compare,Allocator> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1, typename T2, typename T3>
struct TypeHandler<DB, %1%<T0, T1, T2, T3>> {
using type = StaticTypes::List<DB, StaticTypes::Pair<DB,
typename TypeHandler<DB, T0>::type,
typename TypeHandler<DB, T1>::type
>>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0, T1, T2, T3>& container,
typename TypeHandler<DB, %1%<T0, T1, T2, T3>>::type returnArg) {
auto tail = returnArg.write(container.size());
// The double ampersand is needed otherwise this loop doesn't work with
// vector<bool>
for (auto&& it : container) {
tail = tail.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it.second, ret.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it.first, ret);
}));
});
}
return tail.finish();
}
};
"""
func = """
template<class Key, class T, class Compare, class Allocator>
void getSizeType(const %1%<Key,T,Compare,Allocator> &container, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<Key,T,Compare,Allocator>));
SAVE_DATA((uintptr_t)container.size());
for (auto const& it : container)
{
getSizeType(it.first, returnArg);
getSizeType(it.second, returnArg);
}
}
// DummyFunc %1%
"""

View File

@ -10,20 +10,27 @@ replaceTemplateParamIndex = []
[codegen]
decl = """
template<typename T>
void getSizeType(const %1%<T> &s_ptr, size_t& returnArg);
template <typename DB, typename T0>
struct TypeHandler<DB, %1%<T0>> {
using type = StaticTypes::Sum<DB,
StaticTypes::Unit<DB>,
typename TypeHandler<DB, T0>::type
>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0>& container,
typename TypeHandler<DB, %1%<T0>>::type returnArg) {
if (container) {
return returnArg.template delegate<1>([&container](auto ret) {
return OIInternal::getSizeType<DB>(*container, ret);
});
} else {
return returnArg.template delegate<0>(std::identity());
}
}
};
"""
func = """
template <typename T>
void getSizeType(const %1%<T>& s_ptr, size_t& returnArg) {
if (s_ptr) {
SAVE_SIZE(sizeof(%1%<T>) - sizeof(T));
SAVE_DATA(true);
getSizeType(*s_ptr, returnArg);
} else {
SAVE_SIZE(sizeof(%1%<T>));
SAVE_DATA(false);
}
}
// DummyFunc %1%
"""

View File

@ -10,17 +10,25 @@ replaceTemplateParamIndex = []
[codegen]
decl = """
template<typename P, typename Q>
void getSizeType(const %1%<P,Q> &p, size_t& returnArg);
template <typename DB, typename T0, typename T1>
struct TypeHandler<DB, %1%<T0, T1>> {
using type = StaticTypes::Pair<DB,
typename TypeHandler<DB, T0>::type,
typename TypeHandler<DB, T1>::type>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0, T1> & container,
typename TypeHandler<DB, %1%<T0, T1>>::type returnArg) {
return OIInternal::getSizeType<DB>(
container.second,
returnArg.delegate([&container](auto ret) {
return OIInternal::getSizeType<DB>(container.first, ret);
})
);
}
};
"""
func = """
template<typename P, typename Q>
void getSizeType(const %1%<P,Q> &p, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<P,Q>) - sizeof(P) - sizeof(Q));
getSizeType(p.first, returnArg);
getSizeType(p.second, returnArg);
}
// DummyFunc %1%
"""

View File

@ -10,22 +10,23 @@ underlyingContainerIndex = 1
[codegen]
decl = """
template<class T, class Container>
void getSizeType(const %1%<T, Container> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1>
struct TypeHandler<DB, %1%<T0, T1>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
typename TypeHandler<DB, T1>::type>;
static StaticTypes::Unit<DB> getSizeType(
const %1% <T0, T1> & container,
typename TypeHandler<DB, %1% <T0, T1>>::type returnArg) {
auto tail = returnArg.write((uintptr_t)&container);
const T1 &underlyingContainer = get_container(container);
return OIInternal::getSizeType<DB>(underlyingContainer, tail);
}
};
"""
func = """
template<class T, class Container>
void getSizeType(const %1%<T, Container> &containerAdapter, size_t& returnArg)
{
SAVE_DATA((uintptr_t)&containerAdapter);
// Only record the overhead of this container adapter - don't count the
// underlying container as that will be taken care of in its own
// getSizeType() function
SAVE_SIZE(sizeof(%1%<T, Container>) - sizeof(Container));
const Container &container = get_container(containerAdapter);
getSizeType(container, returnArg);
}
// DummyFunc %1%
"""

View File

@ -10,22 +10,23 @@ underlyingContainerIndex = 1
[codegen]
decl = """
template<class T, class Container>
void getSizeType(const %1%<T, Container> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1>
struct TypeHandler<DB, %1%<T0, T1>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
typename TypeHandler<DB, T1>::type>;
static StaticTypes::Unit<DB> getSizeType(
const %1% <T0, T1> & container,
typename TypeHandler<DB, %1% <T0, T1>>::type returnArg) {
auto tail = returnArg.write((uintptr_t)&container);
const T1 &underlyingContainer = get_container(container);
return OIInternal::getSizeType<DB>(underlyingContainer, tail);
}
};
"""
func = """
template<class T, class Container>
void getSizeType(const %1%<T, Container> &containerAdapter, size_t& returnArg)
{
SAVE_DATA((uintptr_t)&containerAdapter);
// Only record the overhead of this container adapter - don't count the
// underlying container as that will be taken care of in its own
// getSizeType() function
SAVE_SIZE(sizeof(%1%<T, Container>) - sizeof(Container));
const Container &container = get_container(containerAdapter);
getSizeType(container, returnArg);
}
// DummyFunc %1%
"""

View File

@ -10,16 +10,22 @@ replaceTemplateParamIndex = []
[codegen]
decl = """
template<typename T>
void getSizeType(const %1%<T> &s_ptr, size_t& returnArg);
template <typename DB, typename T0>
struct TypeHandler<DB, %1%<T0>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
typename TypeHandler<DB, T0>::type
>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0>& container,
typename TypeHandler<DB, %1%<T0>>::type returnArg) {
auto r0 = returnArg.write((uintptr_t)&(container.get()));
return OIInternal::getSizeType<DB>(container.get(), r0);
}
};
"""
func = """
template<typename T>
void getSizeType(const %1%<T> &ref, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<T>));
SAVE_DATA((uintptr_t)&(ref.get()));
getSizeType(ref.get(), returnArg);
}
// DummyFunc %1%
"""

View File

@ -10,25 +10,34 @@ allocatorIndex = 1
[codegen]
decl = """
template<typename T>
void getSizeType(const %1%<T> &container, size_t& returnArg);
template <typename DB, typename T0>
struct TypeHandler<DB, %1% <T0>> {
using type = StaticTypes::Pair<
DB, StaticTypes::VarInt<DB>,
StaticTypes::Pair<
DB, StaticTypes::VarInt<DB>,
StaticTypes::List<DB, typename TypeHandler<DB, T0>::type>>>;
static StaticTypes::Unit<DB> getSizeType(
const %1% <T0> & container,
typename TypeHandler<DB, %1% <T0>>::type returnArg) {
auto tail = returnArg.write((uintptr_t)&container)
.write(container.capacity())
.write(container.size());
// The double ampersand is needed otherwise this loop doesn't work with
// vector<bool>
for (auto&& it : container) {
tail = tail.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it, ret);
});
}
return tail.finish();
}
};
"""
func = """
template<typename T>
void getSizeType(const %1%<T> &container, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<T>));
SAVE_DATA((uintptr_t)&container);
SAVE_DATA((uintptr_t)container.capacity());
SAVE_DATA((uintptr_t)container.size());
SAVE_SIZE((container.capacity() - container.size()) * sizeof(T));
// The double ampersand is needed otherwise this loop doesn't work with vector<bool>
for (auto&& it: container) {
getSizeType(it, returnArg);
}
}
// DummyDecl %1%
"""

View File

@ -10,8 +10,31 @@ allocatorIndex = 2
[codegen]
decl = """
template<typename Key, typename Compare, typename Alloc>
void getSizeType(const %1%<Key, Compare, Alloc> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1, typename T2>
struct TypeHandler<DB, %1% <T0, T1, T2>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::List<DB, typename TypeHandler<DB, T0>::type>>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0, T1, T2>& container,
typename TypeHandler<DB, %1%<T0, T1, T2>>::type returnArg) {
constexpr size_t nodeSize = sizeof(typename %1%<T0, T1, T2>::node_type);
auto tail = returnArg.write(nodeSize)
.write(container.size());
// The double ampersand is needed otherwise this loop doesn't work with
// vector<bool>
for (auto&& it : container) {
tail = tail.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it, ret);
});
}
return tail.finish();
}
};
"""
func = """

View File

@ -10,22 +10,37 @@ replaceTemplateParamIndex = []
[codegen]
decl = """
template<typename T>
void getSizeType(const %1%<T> &s_ptr, size_t& returnArg);
template <typename DB, typename T0>
struct TypeHandler<DB, %1%<T0>> {
using type = typename std::conditional<
std::is_void<T0>::value,
StaticTypes::Unit<DB>,
StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::Sum<DB,
StaticTypes::Unit<DB>,
typename TypeHandler<DB, T0>::type
>>>::type;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0>& container,
typename TypeHandler<DB, %1%<T0>>::type returnArg) {
if constexpr (!std::is_void<T0>::value) {
auto r0 = returnArg.write((uintptr_t)(container.get()));
if (container && pointers.add((uintptr_t)(container.get()))) {
return r0.template delegate<1>([&container](auto ret) {
return OIInternal::getSizeType<DB>(*(container.get()), ret);
});
} else {
return r0.template delegate<0>(std::identity());
}
} else {
return returnArg;
}
}
};
"""
func = """
template<typename T>
void getSizeType(const %1%<T> &s_ptr, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<T>));
if constexpr (!std::is_void<T>::value) {
SAVE_DATA((uintptr_t)(s_ptr.get()));
if (s_ptr && pointers.add((uintptr_t)(s_ptr.get()))) {
getSizeType(*(s_ptr.get()), returnArg);
}
}
}
// DummyFunc %1%
"""

View File

@ -8,20 +8,22 @@ underlyingContainerIndex = 4
[codegen]
decl = """
template <class T, class Compare, class Allocator, class GrowthPolicy, class Container>
void getSizeType(const %1%<T,Compare, Allocator, GrowthPolicy, Container> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1, typename T2, typename T3, typename T4>
struct TypeHandler<DB, %1%<T0, T1, T2, T3, T4>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
typename TypeHandler<DB, T4>::type>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0, T1, T2, T3, T4>& container,
typename TypeHandler<DB, %1%<T0, T1, T2, T3, T4>>::type returnArg) {
auto tail = returnArg.write((uintptr_t)&container);
const T4 &underlyingContainer = container.get_container();
return OIInternal::getSizeType<DB>(underlyingContainer, tail);
}
};
"""
func = """
template <class T, class Compare, class Allocator, class GrowthPolicy, class Container>
void getSizeType(const %1%<T,Compare, Allocator, GrowthPolicy, Container> &containerAdapter, size_t& returnArg)
{
SAVE_DATA((uintptr_t)&containerAdapter);
// Underlying container is grabbed by recursion, store only the exclusive size.
SAVE_SIZE(sizeof(%1%<T,Compare, Allocator, GrowthPolicy, Container>) - sizeof(Container));
const Container &container = containerAdapter.get_container();
getSizeType(container, returnArg);
}
// DummyFunc %1%
"""

View File

@ -10,22 +10,23 @@ underlyingContainerIndex = 1
[codegen]
decl = """
template<class T, class Container>
void getSizeType(const %1%<T, Container> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1>
struct TypeHandler<DB, %1%<T0, T1>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
typename TypeHandler<DB, T1>::type>;
static StaticTypes::Unit<DB> getSizeType(
const %1% <T0, T1> & container,
typename TypeHandler<DB, %1% <T0, T1>>::type returnArg) {
auto tail = returnArg.write((uintptr_t)&container);
const T1 &underlyingContainer = get_container(container);
return OIInternal::getSizeType<DB>(underlyingContainer, tail);
}
};
"""
func = """
template<class T, class Container>
void getSizeType(const %1%<T, Container> &containerAdapter, size_t& returnArg)
{
SAVE_DATA((uintptr_t)&containerAdapter);
// Only record the overhead of this container adapter - don't count the
// underlying container as that will be taken care of in its own
// getSizeType() function
SAVE_SIZE(sizeof(%1%<T, Container>) - sizeof(Container));
const Container &container = get_container(containerAdapter);
getSizeType(container, returnArg);
}
// DummyFunc %1%
"""

View File

@ -10,26 +10,37 @@ allocatorIndex = 3
[codegen]
decl = """
template<class K, class T, class C, class A>
void getSizeType(const %1%<K, T, C, A> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1, typename T2, typename T3>
struct TypeHandler<DB, %1%<T0, T1, T2, T3>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::List<DB, StaticTypes::Pair<DB,
typename TypeHandler<DB, T0>::type,
typename TypeHandler<DB, T1>::type
>>>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0, T1, T2, T3>& container,
typename TypeHandler<DB, %1%<T0, T1, T2, T3>>::type returnArg) {
constexpr size_t nodeSize = sizeof(typename %1%<T0, T1, T2, T3>::node_type);
auto tail = returnArg.write(nodeSize).write(container.size());
// The double ampersand is needed otherwise this loop doesn't work with
// vector<bool>
for (const auto& it : container) {
tail = tail.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it.second, ret.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it.first, ret);
}));
});
}
return tail.finish();
}
};
"""
func = """
template<class K, class T, class C, class A>
void getSizeType(const %1%<K, T, C, A> &container, size_t& returnArg)
{
constexpr size_t nodeSize = sizeof(typename %1%<K, T, C, A>::node_type);
size_t numElems = container.size();
SAVE_SIZE(sizeof(%1%<K, T, C, A>) + (nodeSize * numElems));
SAVE_DATA((uintptr_t)nodeSize);
SAVE_DATA((uintptr_t)numElems);
for (auto const& it : container)
{
getSizeType(it.first, returnArg);
getSizeType(it.second, returnArg);
}
}
// DummyFunc %1%
"""

View File

@ -10,28 +10,41 @@ allocatorIndex = 4
[codegen]
decl = """
template<class K, class T, class H, class KE, class A>
void getSizeType(const %1%<K, T, H, KE, A> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1, typename T2, typename T3, typename T4>
struct TypeHandler<DB, %1%<T0, T1, T2, T3, T4>> {
using type = StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::List<DB, StaticTypes::Pair<DB,
typename TypeHandler<DB, T0>::type,
typename TypeHandler<DB, T1>::type
>>>>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0, T1, T2, T3, T4>& container,
typename TypeHandler<DB, %1%<T0, T1, T2, T3, T4>>::type returnArg) {
constexpr size_t nodeSize = sizeof(typename %1%<T0, T1, T2, T3, T4>::node_type);
auto tail = returnArg.write(nodeSize)
.write(container.bucket_count())
.write(container.size());
// The double ampersand is needed otherwise this loop doesn't work with
// vector<bool>
for (const auto& it : container) {
tail = tail.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it.second, ret.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it.first, ret);
}));
});
}
return tail.finish();
}
};
"""
func = """
template<class K, class T, class H, class KE, class A>
void getSizeType(const %1%<K, T, H, KE, A> &container, size_t& returnArg)
{
constexpr size_t nodeSize = sizeof(typename %1%<K, T, H, KE, A>::node_type);
size_t bucketCount = container.bucket_count();
size_t numElems = container.size();
SAVE_SIZE(sizeof(%1%<K, T, H, KE, A>) + (nodeSize * numElems) + (bucketCount * sizeof(uintptr_t)));
SAVE_DATA((uintptr_t)nodeSize);
SAVE_DATA((uintptr_t)bucketCount);
SAVE_DATA((uintptr_t)numElems);
for (auto const& it : container)
{
getSizeType(it.first, returnArg);
getSizeType(it.second, returnArg);
}
}
// DummyFunc %1%
"""

View File

@ -6,29 +6,36 @@ ns = ["namespace std"]
[codegen]
decl = """
template<class... Types>
void getSizeType(const %1%<Types...> &container, size_t& returnArg);
template <typename DB, typename... Types>
struct TypeHandler<DB, %1%<Types...>> {
using type = StaticTypes::Sum<DB, typename TypeHandler<DB, Types>::type..., StaticTypes::Unit<DB>>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<Types...>& container,
typename TypeHandler<DB, %1%<Types...>>::type returnArg) {
return getSizeTypeRecursive(container, returnArg);
}
private:
template <size_t I = 0>
static StaticTypes::Unit<DB> getSizeTypeRecursive(
const %1%<Types...>& container,
typename TypeHandler<DB, %1%<Types...>>::type returnArg) {
if constexpr (I < sizeof...(Types)) {
if (I == container.index()) {
return returnArg.template delegate<I>([&container](auto ret) {
return OIInternal::getSizeType<DB>(std::get<I>(container), ret);
});
} else {
return getSizeTypeRecursive<I+1>(container, returnArg);
}
} else {
return returnArg.template delegate<sizeof...(Types)>(std::identity());
}
}
};
"""
func = """
template<class... Types>
void getSizeType(const %1%<Types...> &container, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<Types...>));
SAVE_DATA(container.index());
// This check should be `container.valueless_by_exception()` but it doesn't
// work with the variable sized integers used in `std::variant`. For fewer
// than 256 options it uses a `uint8_t` index but checks against -1 of
// `uintptr_t`. Manually check for any out of bounds indices as a workaround.
if (container.index() >= sizeof...(Types)) {
return;
}
std::visit([&returnArg](auto &&arg) {
// Account for inline contents
SAVE_SIZE(-sizeof(arg));
getSizeType(arg, returnArg);
}, container);
}
// DummyFunc %1%
"""

View File

@ -10,18 +10,22 @@ replaceTemplateParamIndex = []
[codegen]
decl = """
template<typename T>
void getSizeType(const %1%<T> &t, size_t& returnArg);
template <typename DB, typename T0>
struct TypeHandler<DB, %1%<T0>> {
using type = StaticTypes::VarInt;
};
template<typename T0>
Unit getSizeType(const %1%<T0> &t, TypeHandler<%1%<T0>> returnArg);
"""
func = """
template<typename T>
void getSizeType(const %1%<T> &t, size_t& returnArg)
template<typename T0>
Unit getSizeType(const %1%<T0> &t, TypeHandler<%1%<T0>> returnArg)
{
SAVE_SIZE(sizeof(%1%<T>));
SAVE_SIZE(sizeof(%1%<T0>));
SAVE_DATA((uintptr_t)t.capacity());
SAVE_DATA((uintptr_t)t.size());
return returnArg.write(t.capacity());
// Test for small string optimisation - whether the underlying string is
// contained within the string object.

View File

@ -10,22 +10,37 @@ replaceTemplateParamIndex = []
[codegen]
decl = """
template<typename T, class Deleter>
void getSizeType(const %1%<T,Deleter> &s_ptr, size_t& returnArg);
template <typename DB, typename T0, typename T1>
struct TypeHandler<DB, %1%<T0,T1>> {
using type = typename std::conditional<
std::is_void<T0>::value,
StaticTypes::Unit<DB>,
StaticTypes::Pair<DB,
StaticTypes::VarInt<DB>,
StaticTypes::Sum<DB,
StaticTypes::Unit<DB>,
typename TypeHandler<DB, T0>::type
>>>::type;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0,T1>& container,
typename TypeHandler<DB, %1%<T0,T1>>::type returnArg) {
if constexpr (!std::is_void<T0>::value) {
auto r0 = returnArg.write((uintptr_t)(container.get()));
if (container && pointers.add((uintptr_t)(container.get()))) {
return r0.template delegate<1>([&container](auto ret) {
return OIInternal::getSizeType<DB>(*(container.get()), ret);
});
} else {
return r0.template delegate<0>(std::identity());
}
} else {
return returnArg;
}
}
};
"""
func = """
template<typename T, class Deleter>
void getSizeType(const %1%<T,Deleter> &s_ptr, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<T,Deleter>));
if constexpr (!std::is_void<T>::value) {
SAVE_DATA((uintptr_t)(s_ptr.get()));
if (s_ptr && pointers.add((uintptr_t)(s_ptr.get()))) {
getSizeType(*(s_ptr.get()), returnArg);
}
}
}
// DummyFunc %1%
"""

View File

@ -10,26 +10,36 @@ allocatorIndex = 3
[codegen]
decl = """
template <typename Key, typename Hasher, typename KeyEqual, typename Alloc>
void getSizeType(const %1%<Key, Hasher, KeyEqual, Alloc> &container, size_t& returnArg);
template <typename DB, typename T0, typename T1, typename T2, typename T3>
struct TypeHandler<DB, %1%<T0, T1, T2, T3>> {
using type = StaticTypes::Pair<
DB, StaticTypes::VarInt<DB>,
StaticTypes::Pair<
DB, StaticTypes::VarInt<DB>,
StaticTypes::List<DB, typename TypeHandler<DB, T0>::type>>>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0, T1, T2, T3>& container,
typename TypeHandler<DB, %1%<T0, T1, T2, T3>>::type returnArg) {
constexpr size_t nodeSize = sizeof(typename %1%<T0, T1, T2, T3>::node_type);
auto tail = returnArg.write(nodeSize)
.write(container.bucket_count())
.write(container.size());
// The double ampersand is needed otherwise this loop doesn't work with
// vector<bool>
for (auto&& it : container) {
tail = tail.delegate([&it](auto ret) {
return OIInternal::getSizeType<DB>(it, ret);
});
}
return tail.finish();
}
};
"""
func = """
template <typename Key, typename Hasher, typename KeyEqual, typename Alloc>
void getSizeType(const %1%<Key, Hasher, KeyEqual, Alloc> &container, size_t& returnArg)
{
constexpr size_t nodeSize = sizeof(typename %1%<Key, Hasher, KeyEqual, Alloc>::node_type);
size_t bucketCount = container.bucket_count();
size_t numElems = container.size();
SAVE_SIZE(sizeof(%1%<Key, Hasher, KeyEqual, Alloc>) + (numElems * nodeSize) + (bucketCount * sizeof(uintptr_t)));
SAVE_DATA((uintptr_t)nodeSize);
SAVE_DATA((uintptr_t)bucketCount);
SAVE_DATA((uintptr_t)numElems);
// The double ampersand is needed otherwise this loop doesn't work with vector<bool>
for (auto&& it: container) {
getSizeType(it, returnArg);
}
}
// DummyFunc %1%
"""

View File

@ -8,15 +8,19 @@ replaceTemplateParamIndex = []
[codegen]
decl = """
template<typename T>
void getSizeType(const %1%<T> &s_ptr, size_t& returnArg);
template <typename DB, typename T0>
struct TypeHandler<DB, %1%<T0>> {
using type = StaticTypes::Unit<DB>;
static StaticTypes::Unit<DB> getSizeType(
const %1%<T0>& container,
typename TypeHandler<DB, %1%<T0>>::type returnArg) {
return returnArg;
}
};
"""
# Weak pointers do not have ownership, so let's not follow them (for now)
func = """
template<typename T>
void getSizeType(const %1%<T> &s_ptr, size_t& returnArg)
{
SAVE_SIZE(sizeof(%1%<T>));
}
// DummyFunc %1%
"""