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) {
453 template <
typename TTargetType>
454 requires(!IsStdFixedArray<TTargetType> && !IsOptional<TTargetType> && !IsEnum<TTargetType> && !IsVector<TTargetType> && !IsMap<TTargetType> && !IsSharedPointer<TTargetType> && !IsStarPointer<TTargetType>)
455 TTargetType
convertMapValueToArg(
const std::any &anyValue,
const string &argName,
size_t argIndex) {
456 auto &x =
typeid(TTargetType);
457 LOG_TRACE(
"convertMapValueToArg - i: " +
to_string(argIndex) +
" name:" + argName +
" requested: " + x.name() +
" in any: " + anyValue.type().name());
459 using TTargetTypeCleaned = std::remove_cvref_t<TTargetType>;
461 return std::any_cast<TTargetTypeCleaned>(anyValue);
462 }
catch (std::exception &e) {
463 if constexpr (std::is_arithmetic_v<TTargetTypeCleaned>) {
464 if (anyValue.type() ==
typeid(
unsigned long long)) {
465 return static_cast<TTargetTypeCleaned
>(std::any_cast<unsigned long long>(anyValue));
468 if (anyValue.type() ==
typeid(double)) {
469 return static_cast<TTargetTypeCleaned
>(std::any_cast<double>(anyValue));
472 LOG_ERROR(
string(
"cannot cast to ") +
getClassName(
typeid(TTargetTypeCleaned),
false) +
" name=" + argName +
" - " +
string(e.what()));
473 throw runtime_error(
string(
"cannot cast to ") +
getClassName(
typeid(TTargetTypeCleaned),
false) +
" name=" + argName);
477 #define COMMAND_REGISTER(COMMAND_REGISTER_className, ...) \
478 class CSC_DLL_IMPORTEXPORT __##COMMAND_REGISTER_className##AutoParseMetadataInit { \
479 inline static void *registerCommand() { \
480 string commandId = COMMAND_REGISTER_className::COMMAND_ID; \
481 auto builder = [commandId](const map<string, any> &commandParams, const vector<string> ¶mNames) { \
482 return createInstance<COMMAND_REGISTER_className __VA_OPT__(, ) __VA_ARGS__>(commandParams, paramNames); \
484 registerCommandTypeBuilder(typeid(COMMAND_REGISTER_className), builder); \
485 CscCommandAutoParseMetadata::registerCommand(commandId, #COMMAND_REGISTER_className, [commandId, builder](CscCommandParseContext ¶ms) { \
486 map<string, any> commandParams = parseCommandParametersAsMap(commandId, params.arguments, params.knowledgeId, true); \
487 const CscCommandDataTypeMetadata *commandParamsInfo = CscCommandDataTypeMetadata::getCommandMetadata(commandId); \
488 return ptr<COMMAND_REGISTER_className>(builder(commandParams, commandParamsInfo->getParamNames())); \
493 inline static void *__metadata = registerCommand(); \
496 #define USER_COMMAND_REGISTER(COMMAND_REGISTER_className, ...) \
497 class CSC_USER_DLL_EXPORT __##COMMAND_REGISTER_className##AutoParseMetadataInit { \
498 inline static void *registerCommand() { \
499 string commandId = COMMAND_REGISTER_className::COMMAND_ID; \
500 auto builder = [commandId](const map<string, any> &commandParams, const vector<string> ¶mNames) { \
501 return createInstance<COMMAND_REGISTER_className __VA_OPT__(, ) __VA_ARGS__>(commandParams, paramNames); \
503 registerCommandTypeBuilder(typeid(COMMAND_REGISTER_className), builder); \
504 CscCommandAutoParseMetadata::registerCommand(commandId, #COMMAND_REGISTER_className, [commandId, builder](CscCommandParseContext ¶ms) { \
505 map<string, any> commandParams = parseCommandParametersAsMap(commandId, params.arguments, params.knowledgeId, true); \
506 const CscCommandDataTypeMetadata *commandParamsInfo = CscCommandDataTypeMetadata::getCommandMetadata(commandId); \
507 return ptr<COMMAND_REGISTER_className>(builder(commandParams, commandParamsInfo->getParamNames())); \
512 inline static void *__metadata = registerCommand(); \
515 #define COMMAND_TYPE_BUILDER(PREFIX, COMMAND_REGISTER_className, ...) \
517 static bool __##PREFIX##__##COMMAND_REGISTER_className##initialized = ([]() { \
518 auto builder = [](const map<string, any> &commandParams, const vector<string> ¶mNames) { \
519 return createInstance<COMMAND_REGISTER_className, __VA_ARGS__>(commandParams, paramNames); \
521 registerCommandTypeBuilder(typeid(COMMAND_REGISTER_className), builder); \