1 #ifndef CscCommandAutoParse_h
2 #define CscCommandAutoParse_h
6 #include "../FunctionCommandWrapper.h"
12 class CscCommandAutoParseMetadata;
18 static map<CommandTypeId, const CscCommandAutoParseMetadata *> &commandAutoParseMetadataById();
20 static map<string, const CscCommandAutoParseMetadata *> &commandAutoParseMetadataByFunctionName();
30 static optional<const CscCommandAutoParseMetadata *> getForCommandId(
const CommandTypeId &commandId);
32 static vector<CommandTypeId> getSupportedCommandIds();
35 static void unregisterCommand(
const CommandTypeId &commandId);
37 static vector<string> getCommandFunctionNames();
40 typedef function<
void *(
const map<string, any> ¶msValues,
const vector<string> ¶mNames)>
CommandTypeBuilder;
42 static map<const std::type_info *, CommandTypeBuilder> theMap;
48 auto it = builders.find(&type);
49 if (it != builders.end()) {
50 auto autoParseLogger = CscLogger::getForCategory(
"CommandAutoParse");
51 autoParseLogger->debug(
"replace existing command data type builder: " +
getClassName(type,
true));
55 builders.emplace(&type, builder);
60 auto it = builders.find(&type);
61 if (it != builders.end()) {
71 #define COMMAND_FUNCTION(COMMAND_FUNCTION_paramsClassPrefix, COMMAND_FUNCTION_commandId) \
73 COMMAND_FUNCTION_paramsClassPrefix##CommandResult cscCommand_##COMMAND_FUNCTION_paramsClassPrefix(ptr<COMMAND_FUNCTION_paramsClassPrefix##CommandParams> params, CscEnvironmentSimulator &environmentSimulator); \
75 static FunctionCommand get##COMMAND_FUNCTION_paramsClassPrefix##Command(ptr<COMMAND_FUNCTION_paramsClassPrefix##CommandParams> params) { \
77 return [params](CscEnvironmentSimulator &environmentSimulator) { \
78 auto result = cscCommand_##COMMAND_FUNCTION_paramsClassPrefix(params, environmentSimulator); \
79 return result.toRawResult(); \
82 class CSC_DLL_IMPORTEXPORT __##COMMAND_FUNCTION_paramsClassPrefix##AutoParseMetadataInit { \
83 inline static const CscCommandAutoParseMetadata *__metadata = CscCommandAutoParseMetadata::registerCommand(COMMAND_FUNCTION_commandId, #COMMAND_FUNCTION_paramsClassPrefix, [](CscCommandParseContext ¶ms) { \
84 string commandId = COMMAND_FUNCTION_commandId; \
85 ptr<COMMAND_FUNCTION_paramsClassPrefix##CommandParams> paramsObject = parseCommandParameters<COMMAND_FUNCTION_paramsClassPrefix##CommandParams>(commandId, params.arguments, params.knowledgeId); \
86 FunctionCommand functionCommand = get##COMMAND_FUNCTION_paramsClassPrefix##Command(paramsObject); \
87 ptr<CscEntityReflexion> entityReflexion = params.getEntityReflexionFromParameter(); \
88 return newptr<FunctionCommandWrapper>(entityReflexion, commandId, functionCommand, params.originalCommandString, params.arguments); \
109 template <typename TArray>
116 template <typename TTargetType>
122 return (TEnum)(convertMapValueToArg<unsigned long long>(anyValue, argName, argIndex));
125 #define TRY_ANY_CAST(targetType, varName, outVarName, parentName) \
127 outVarName = std::any_cast<targetType>(varName); \
128 } catch (std::exception & e) { \
129 LOG_ERROR(string("cannot cast to ") + getClassName(typeid(targetType), false) + " name=" + parentName + " - " + string(e.what())); \
130 throw runtime_error(string("cannot cast to ") + getClassName(typeid(targetType), false) + " name=" + parentName); \
133 template <IsOptional TOptional>
135 using TElement =
typename TOptional::value_type;
136 if (anyValue.type() ==
typeid(TOptional)) {
137 return any_cast<TOptional>(anyValue);
140 if (anyValue.type() ==
typeid(optional<any>)) {
141 auto theOptional = any_cast<optional<any>>(anyValue);
142 if (theOptional.has_value()) {
143 result = convertMapValueToArg<TElement>(theOptional.value(), argName, argIndex);
145 }
else if (anyValue.has_value()) {
146 result = convertMapValueToArg<TElement>(anyValue, argName, argIndex);
152 template <
typename TNumber>
154 const type_info &numberType =
typeid(TNumber);
156 if (numberType ==
typeid(
char)) {
158 int temp = std::stoi(strValue);
159 return static_cast<char>(temp);
160 }
else if (numberType ==
typeid(
unsigned char)) {
162 unsigned int temp = std::stoul(strValue);
163 return static_cast<unsigned char>(temp);
164 }
else if (numberType ==
typeid(
short)) {
165 short temp = std::stoi(strValue);
167 }
else if (numberType ==
typeid(
unsigned short)) {
168 unsigned short temp =
static_cast<unsigned short>(std::stoul(strValue));
170 }
else if (numberType ==
typeid(
int)) {
171 int temp = std::stoi(strValue);
173 }
else if (numberType ==
typeid(
unsigned int)) {
174 unsigned int temp = std::stoul(strValue);
176 }
else if (numberType ==
typeid(
long)) {
177 long temp = std::stol(strValue);
179 }
else if (numberType ==
typeid(
unsigned long)) {
180 unsigned long temp = std::stoul(strValue);
182 }
else if (numberType ==
typeid(
long long)) {
183 long long temp = std::stoll(strValue);
185 }
else if (numberType ==
typeid(
unsigned long long)) {
186 unsigned long long temp = std::stoull(strValue);
188 }
else if (numberType ==
typeid(
float)) {
189 float temp = std::stof(strValue);
191 }
else if (numberType ==
typeid(
double)) {
192 double temp = std::stod(strValue);
194 }
else if (numberType ==
typeid(
long double)) {
195 long double temp = std::stold(strValue);
199 throw std::logic_error(
"Unhandled numeric type during conversion.");
201 }
catch (
const std::exception &e) {
206 template <IsMap TMap>
208 using K =
typename TMap::key_type;
209 using V =
typename TMap::mapped_type;
211 if (!anyValue.has_value()) {
215 if (anyValue.type() ==
typeid(TMap)) {
223 unsigned mapValueIndex = 0;
224 if constexpr (std::is_arithmetic_v<K> || std::is_enum_v<K>) {
225 if (anyValue.type() ==
typeid(map<string, any>)) {
226 auto mapAny = any_cast<map<string, any>>(anyValue);
227 for (
auto it : mapAny) {
228 if constexpr (std::is_enum_v<K>) {
229 result[(K)getNumberFromString<unsigned>(it.first)] = convertMapValueToArg<V>(it.second,
"mapValues", mapValueIndex++);
231 result[getNumberFromString<K>(it.first)] = convertMapValueToArg<V>(it.second,
"mapValues", mapValueIndex++);
235 using MapByInt = map<int, any>;
238 for (
auto it : mapAny) {
239 result[(K)it.first] = convertMapValueToArg<V>(it.second,
"mapValues", mapValueIndex++);
243 using MapByString = map<string, any>;
246 for (
auto it : mapAny) {
247 result[it.first] = convertMapValueToArg<V>(it.second,
"mapValues", mapValueIndex++);
253 template <IsVector TVector>
255 using TElement =
typename TVector::value_type;
256 if (anyValue.type() ==
typeid(TVector)) {
257 return any_cast<TVector>(anyValue);
260 vector<any> vectorAny;
263 unsigned elementIndex = 0;
264 for (
auto it : vectorAny) {
265 result.push_back(convertMapValueToArg<TElement>(it,
"elements", elementIndex++));
269 template <
typename TArray>
272 using TElement =
typename TArray::value_type;
273 if (anyValue.type() ==
typeid(TArray)) {
274 return any_cast<TArray>(anyValue);
276 vector<any> vectorAny;
279 for (
size_t i = 0;
i < result.size();
i++) {
280 if (
i >= vectorAny.size()) {
284 result[
i] = convertMapValueToArg<TElement>(vectorAny.at(
i),
"elements",
i);
290 template <
typename Tuple,
typename Map, std::size_t... Is>
291 Tuple
extractArgsHelper(
const Map ¶mMap,
const std::vector<std::string> ¶mNames, std::index_sequence<Is...>) {
292 return std::make_tuple(
294 (Is >= paramNames.size() || paramMap.find(paramNames[Is]) == paramMap.end() ? any() : paramMap.at(paramNames[Is])),
295 Is >= paramNames.size() ? (
"?param" +
to_string(Is)) : paramNames[Is], Is)...);
298 template <
typename Tuple>
299 Tuple
extractArgs(
const std::map<std::string, std::any> ¶mMap,
const std::vector<std::string> ¶mNames) {
304 template <
typename T,
typename... Params>
305 T *
createInstance(
const std::map<std::string, std::any> ¶mMap,
const std::vector<std::string> ¶mNames) {
306 using ArgsTuple = std::tuple<std::decay_t<Params>...>;
309 auto argsTuple = extractArgs<ArgsTuple>(paramMap, paramNames);
314 return new T(std::forward<decltype(args)>(args)...);
321 template <
typename T>
323 return anyValue.type() ==
typeid(T *);
325 template <
typename T>
327 return anyValue.type() ==
typeid(std::shared_ptr<T>);
330 template <
typename TObject>
332 using TObjectCleaned = std::remove_cvref_t<TObject>;
333 return std::is_same_v<TObjectCleaned, CscEntityReflexion> || std::is_same_v<TObjectCleaned, CscEntityModel> || std::is_same_v<TObjectCleaned, CscObjectModel> || std::is_same_v<TObjectCleaned, CscPlaceModel>;
336 template <
typename T>
339 if (!anyValue.has_value()) {
342 if (anyValue.type() ==
typeid(optional<any>)) {
343 optional<any> optionalValue = any_cast<optional<any>>(anyValue);
344 if (!optionalValue.has_value()) {
347 return convertMapValueToArg<T>(optionalValue.value(), argName, argIndex);
350 using CleanT = std::remove_cvref_t<T>;
351 using TPointee = std::remove_cvref_t<typename PointeeType<CleanT>::pointee_type>;
353 if constexpr (std::is_arithmetic_v<TPointee> || std::is_same_v<TPointee, string> || std::is_same_v<TPointee, bool>) {
354 if (anyValue.type() ==
typeid(TPointee)) {
357 return new TPointee(outValue);
361 if (doesAnyContainStarPointer<TPointee>(anyValue)) {
362 TPointee *outValue =
nullptr;
366 if (doesAnyContainStarPointer<const TPointee>(anyValue)) {
367 const TPointee *outValue =
nullptr;
368 TRY_ANY_CAST(
const TPointee *, anyValue, outValue, argName)
371 if constexpr (IsMap<TPointee> || IsVector<TPointee> || IsOptional<TPointee>) {
372 return new TPointee(convertMapValueToArg<TPointee>(anyValue, argName, argIndex));
375 if constexpr (!isCommandBuiltinObjectType<TPointee>()) {
376 const std::type_info &pointerTypeId =
typeid(TPointee);
379 LOG_TRACE(argName +
" type is " + typeName +
" *");
381 optional<CommandTypeBuilder> builder = {};
382 if (commandParamsInfo) {
383 using MapAnyType = map<string, any>;
384 MapAnyType commandParams;
385 TRY_ANY_CAST(MapAnyType, anyValue, commandParams, argName);
388 void *result = builder.value()(commandParams, commandParamsInfo->getParamNames());
389 return static_cast<TPointee *
>(result);
392 if constexpr (std::is_default_constructible_v<TPointee>) {
394 return new TPointee{};
396 LOG_WARN(
"cannot find metadata or builder for type: " + typeName +
" hasMetadata=" +
boolToString(commandParamsInfo) +
" - hasBuilder=" +
boolToString(builder.has_value()) +
" - return NULL")
402 template <typename T>
405 if (!anyValue.has_value()) {
408 if (anyValue.type() ==
typeid(optional<any>)) {
409 optional<any> optionalValue = any_cast<optional<any>>(anyValue);
410 if (!optionalValue.has_value()) {
413 return convertMapValueToArg<T>(optionalValue.value(), argName, argIndex);
416 using CleanT = std::remove_cvref_t<T>;
418 using TPointee = std::remove_cvref_t<TPointeeOriginal>;
420 if (doesAnyContainSharedPtr<TPointee>(anyValue)) {
423 return std::dynamic_pointer_cast<TPointeeOriginal>(outValue);
425 if (doesAnyContainSharedPtr<const TPointee>(anyValue)) {
428 return std::dynamic_pointer_cast<TPointeeOriginal>(std::const_pointer_cast<TPointee>(outValue));
430 if constexpr (std::is_arithmetic_v<TPointee> || std::is_same_v<TPointee, string> || std::is_same_v<TPointee, bool>) {
431 if (anyValue.type() ==
typeid(TPointee)) {
434 return newptr<TPointee>(outValue);
437 if constexpr (IsMap<TPointee> || IsVector<TPointee> || IsOptional<TPointee>) {
438 return newptr<TPointee>(convertMapValueToArg<TPointee>(anyValue, argName, argIndex));
440 if constexpr (!isCommandBuiltinObjectType<TPointee>()) {
441 const std::type_info &pointerTypeId =
typeid(std::remove_cv_t<std::remove_reference_t<TPointee>>);
444 TPointee *obj = convertMapValueToArg<TPointee *>(anyValue, argName, argIndex);
445 if (obj ==
nullptr) {
454 using CleanT = std::remove_cvref_t<T>;
456 if constexpr (isCommandBuiltinObjectType<CleanT>()) {
459 const std::type_info &typeId =
typeid(CleanT);
463 if (!commandParamsInfo) {
473 using MapAnyType = map<string, any>;
474 if (anyValue.type() !=
typeid(MapAnyType)) {
475 LOG_WARN(
"builder found for " + typeName +
" but any does not contain map<string,any>, has: "
476 +
string(anyValue.type().name()));
480 MapAnyType commandParams;
481 TRY_ANY_CAST(MapAnyType, anyValue, commandParams, argName);
483 void *result = builder.value()(commandParams, commandParamsInfo->
getParamNames());
489 CleanT *typedResult =
static_cast<CleanT*
>(result);
490 CleanT value = std::move(*typedResult);
495 template <
typename TTargetType>
496 requires(!IsStdFixedArray<TTargetType> && !IsOptional<TTargetType> && !IsEnum<TTargetType>
497 && !IsVector<TTargetType> && !IsMap<TTargetType>
498 && !IsSharedPointer<TTargetType> && !IsStarPointer<TTargetType>)
499 TTargetType
convertMapValueToArg(
const std::any &anyValue,
const string &argName,
size_t argIndex) {
500 using TTargetTypeCleaned = std::remove_cvref_t<TTargetType>;
503 +
" requested: " +
typeid(TTargetTypeCleaned).name()
504 +
" in any: " + anyValue.type().name());
507 if (anyValue.type() ==
typeid(TTargetTypeCleaned)) {
509 return std::any_cast<TTargetTypeCleaned>(anyValue);
510 }
catch (
const std::bad_any_cast&) {
516 if constexpr (std::is_arithmetic_v<TTargetTypeCleaned>) {
517 if (anyValue.type() ==
typeid(
unsigned long long)) {
518 return static_cast<TTargetTypeCleaned
>(std::any_cast<unsigned long long>(anyValue));
520 if (anyValue.type() ==
typeid(double)) {
521 return static_cast<TTargetTypeCleaned
>(std::any_cast<double>(anyValue));
526 if constexpr (std::is_class_v<TTargetTypeCleaned>
527 && !std::is_same_v<TTargetTypeCleaned, std::string>) {
528 auto built = tryBuildFromBuilder<TTargetTypeCleaned>(anyValue, argName);
530 return std::move(*built);
537 +
" - any contains: " +
string(anyValue.type().name()));
538 throw runtime_error(
"cannot cast to " +
getClassName(
typeid(TTargetTypeCleaned),
false) +
" name=" + argName);
541 #define COMMAND_REGISTER(COMMAND_REGISTER_className, ...) \
542 class CSC_DLL_IMPORTEXPORT __##COMMAND_REGISTER_className##AutoParseMetadataInit { \
543 inline static void *registerCommand() { \
544 string commandId = COMMAND_REGISTER_className::COMMAND_ID; \
545 auto builder = [commandId](const map<string, any> &commandParams, const vector<string> ¶mNames) { \
546 return createInstance<COMMAND_REGISTER_className __VA_OPT__(, ) __VA_ARGS__>(commandParams, paramNames); \
548 registerCommandTypeBuilder(typeid(COMMAND_REGISTER_className), builder); \
549 CscCommandAutoParseMetadata::registerCommand(commandId, #COMMAND_REGISTER_className, [commandId, builder](CscCommandParseContext ¶ms) { \
550 map<string, any> commandParams = parseCommandParametersAsMap(commandId, params.arguments, params.knowledgeId, true); \
551 const CscCommandDataTypeMetadata *commandParamsInfo = CscCommandDataTypeMetadata::getCommandMetadata(commandId); \
552 return ptr<COMMAND_REGISTER_className>(builder(commandParams, commandParamsInfo->getParamNames())); \
557 inline static void *__metadata = registerCommand(); \
560 #define USER_COMMAND_REGISTER(COMMAND_REGISTER_className, ...) \
561 class CSC_USER_DLL_EXPORT __##COMMAND_REGISTER_className##AutoParseMetadataInit { \
562 inline static void *registerCommand() { \
563 string commandId = COMMAND_REGISTER_className::COMMAND_ID; \
564 auto builder = [commandId](const map<string, any> &commandParams, const vector<string> ¶mNames) { \
565 return createInstance<COMMAND_REGISTER_className __VA_OPT__(, ) __VA_ARGS__>(commandParams, paramNames); \
567 registerCommandTypeBuilder(typeid(COMMAND_REGISTER_className), builder); \
568 CscCommandAutoParseMetadata::registerCommand(commandId, #COMMAND_REGISTER_className, [commandId, builder](CscCommandParseContext ¶ms) { \
569 map<string, any> commandParams = parseCommandParametersAsMap(commandId, params.arguments, params.knowledgeId, true); \
570 const CscCommandDataTypeMetadata *commandParamsInfo = CscCommandDataTypeMetadata::getCommandMetadata(commandId); \
571 return ptr<COMMAND_REGISTER_className>(builder(commandParams, commandParamsInfo->getParamNames())); \
576 inline static void *__metadata = registerCommand(); \
579 #define COMMAND_TYPE_BUILDER(PREFIX, COMMAND_REGISTER_className, ...) \
581 static bool __##PREFIX##__##COMMAND_REGISTER_className##initialized = ([]() { \
582 auto builder = [](const map<string, any> &commandParams, const vector<string> ¶mNames) { \
583 return createInstance<COMMAND_REGISTER_className, __VA_ARGS__>(commandParams, paramNames); \
585 registerCommandTypeBuilder(typeid(COMMAND_REGISTER_className), builder); \