From db00d95bbe76ffe726e1d7627d24acbfe2018c72 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Tue, 4 Feb 2025 11:44:08 +0100 Subject: [PATCH 01/24] [arcane:launcher,utils] Add a generic help (with option --help or -h) --- arcane/src/arcane/launcher/ArcaneLauncher.cc | 23 +++++++++ arcane/src/arcane/launcher/ArcaneLauncher.h | 20 ++++++++ arcane/src/arcane/launcher/GeneralHelp.cc | 49 +++++++++++++++++++ arcane/src/arcane/launcher/GeneralHelp.h | 31 ++++++++++++ arcane/src/arcane/launcher/srcs.cmake | 2 + .../src/arcane/utils/CommandLineArguments.cc | 47 ++++++++++++++++-- .../src/arcane/utils/CommandLineArguments.h | 6 +++ 7 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 arcane/src/arcane/launcher/GeneralHelp.cc create mode 100644 arcane/src/arcane/launcher/GeneralHelp.h diff --git a/arcane/src/arcane/launcher/ArcaneLauncher.cc b/arcane/src/arcane/launcher/ArcaneLauncher.cc index e0a540f7ee..2ef3ec0cb1 100644 --- a/arcane/src/arcane/launcher/ArcaneLauncher.cc +++ b/arcane/src/arcane/launcher/ArcaneLauncher.cc @@ -15,6 +15,7 @@ #include "arcane/launcher/IDirectExecutionContext.h" #include "arcane/launcher/DirectSubDomainExecutionContext.h" +#include "arcane/launcher/GeneralHelp.h" #include "arcane/utils/Property.h" #include "arcane/utils/FatalErrorException.h" @@ -417,6 +418,28 @@ _notifyRemoveStandaloneSubDomain() /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +bool ArcaneLauncher:: +needHelp() +{ + return applicationInfo().commandLineArguments().needHelp(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ArcaneLauncher:: +printHelp() +{ + if (applicationInfo().commandLineArguments().needHelp()) { + GeneralHelp::printHelp(); + return true; + } + return false; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + } // End namespace Arcane /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/launcher/ArcaneLauncher.h b/arcane/src/arcane/launcher/ArcaneLauncher.h index 77f89489f5..3db38871b0 100644 --- a/arcane/src/arcane/launcher/ArcaneLauncher.h +++ b/arcane/src/arcane/launcher/ArcaneLauncher.h @@ -212,6 +212,26 @@ class ARCANE_LAUNCHER_EXPORT ArcaneLauncher */ static StandaloneSubDomain createStandaloneSubDomain(const String& case_file_name); + /*! + * \brief Demande d'aide avec l'option "--help" ou "-h". + * + * Méthode permettant de savoir si l'utilisateur a demandée l'aide + * avec l'option "--help" ou "-h". + * + * \return true si l'aide a été demandée. + */ + static bool needHelp(); + + /*! + * \brief Affichage de l'aide générique Arcane. + * + * Méthode permettant d'afficher l'aide générique Arcane si + * l'utilisateur l'a demandée avec l'option "--help" ou "-h". + * + * \return true si l'aide a été demandée. + */ + static bool printHelp(); + public: /*! diff --git a/arcane/src/arcane/launcher/GeneralHelp.cc b/arcane/src/arcane/launcher/GeneralHelp.cc new file mode 100644 index 0000000000..f46af3e077 --- /dev/null +++ b/arcane/src/arcane/launcher/GeneralHelp.cc @@ -0,0 +1,49 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* GeneralHelp.cc (C) 2000-2025 */ +/* */ +/* Classe gérant le message d'aide générique. */ +/*---------------------------------------------------------------------------*/ + +#include "arcane/launcher/GeneralHelp.h" +#include "arcane/utils/ApplicationInfo.h" +#include "arcane/core/ApplicationBuildInfo.h" + +#include +#include + +namespace Arcane +{ +void GeneralHelp:: +printHelp() +{ + ApplicationInfo& infos = ArcaneMain::defaultApplicationInfo(); + const CommandLineArguments& args = infos.commandLineArguments(); + + std::cout << infos.codeName() << " v" << infos.codeVersion() << std::endl; + std::cout << std::endl; + std::cout << "Usage:" << std::endl; + std::cout << " " << *args.commandLineArgv()[0] << " [OPTIONS] dataset.arc" << std::endl; + std::cout << std::endl; + std::cout << "General options:" << std::endl; + std::cout << " -h, --help Give this help list" << std::endl; + std::cout << std::endl; + std::cout << "Arcane option usage: -A,Option1=Value,Option2=Value" << std::endl; + std::cout << " and/or" << std::endl; + std::cout << " -A,Option1=Value -A,Option2=Value" << std::endl; + std::cout << std::endl; + std::cout << "Arcane options:" << std::endl; + std::cout << " -A,T= Nombre de tâches concurrentes à exécuter (default=1)" << std::endl; + std::cout << " -A,S= Nombre de sous-domaines en mémoire partagée" << std::endl; + std::cout << " -A,R= Nombre de sous-domaines répliqués (default=1)" << std::endl; + std::cout << " -A,P= Nombre de processus à utiliser pour les sous-domaines. Cette valeur est normalement calculée automatiquement en fonction des paramètres MPI. Elle n'est utile que si on souhaite utiliser moins de processus pour le partitionnement de domaine que ceux alloués pour le calcul." << std::endl; + std::cout << " -A,AcceleratorRuntime= Runtime accélérateur à utiliser. Les deux valeurs possibles sont cuda ou hip. Il faut avoir compiler Arcane avec le support des accélérateurs pour que cette option soit accessible. " << std::endl; + std::cout << " -A,MaxIteration= Nombre maximum d'itérations à effectuer pour l'exécution. Si le nombre d'itérations spécifié par cette variable est atteint, le calcul s'arrête." << std::endl; +} + +} diff --git a/arcane/src/arcane/launcher/GeneralHelp.h b/arcane/src/arcane/launcher/GeneralHelp.h new file mode 100644 index 0000000000..ddd058cc5f --- /dev/null +++ b/arcane/src/arcane/launcher/GeneralHelp.h @@ -0,0 +1,31 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* GeneralHelp.h (C) 2000-2025 */ +/* */ +/* Classe gérant le message d'aide générique. */ +/*---------------------------------------------------------------------------*/ +#ifndef ARCANE_LAUNCHER_GENERALHELP_H +#define ARCANE_LAUNCHER_GENERALHELP_H +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#include "arcane/launcher/LauncherGlobal.h" + +namespace Arcane +{ +class ARCANE_LAUNCHER_EXPORT GeneralHelp +{ +public: + static void printHelp(); +}; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#endif diff --git a/arcane/src/arcane/launcher/srcs.cmake b/arcane/src/arcane/launcher/srcs.cmake index dfb0f8a6f2..d23aaa6bfc 100644 --- a/arcane/src/arcane/launcher/srcs.cmake +++ b/arcane/src/arcane/launcher/srcs.cmake @@ -6,6 +6,8 @@ set( ARCANE_SOURCES DirectExecutionContext.cc DirectSubDomainExecutionContext.h DirectSubDomainExecutionContext.cc + GeneralHelp.h + GeneralHelp.cc LauncherGlobal.h StandaloneAcceleratorMng.h StandaloneAcceleratorMng.cc diff --git a/arcane/src/arcane/utils/CommandLineArguments.cc b/arcane/src/arcane/utils/CommandLineArguments.cc index 2be21846c6..5a168308d9 100644 --- a/arcane/src/arcane/utils/CommandLineArguments.cc +++ b/arcane/src/arcane/utils/CommandLineArguments.cc @@ -47,12 +47,22 @@ class CommandLineArguments::Impl }; public: Impl(int* argc,char*** argv) - : m_nb_ref(0), m_args(), m_argc(argc), m_argv(argv), m_need_destroy(false) + : m_nb_ref(0) + , m_args() + , m_argc(argc) + , m_argv(argv) + , m_need_destroy(false) + , m_need_help(false) { } Impl(const StringList& aargs) - : m_nb_ref(0), m_args(aargs), m_argc(nullptr), m_argv(nullptr), m_need_destroy(true) + : m_nb_ref(0) + , m_args(aargs) + , m_argc(nullptr) + , m_argv(nullptr) + , m_need_destroy(true) + , m_need_help(false) { Integer nb_arg = aargs.count(); m_argc_orig = new int; @@ -70,7 +80,12 @@ class CommandLineArguments::Impl } Impl() - : m_nb_ref(0), m_args(), m_argc(nullptr), m_argv(nullptr), m_need_destroy(true) + : m_nb_ref(0) + , m_args() + , m_argc(nullptr) + , m_argv(nullptr) + , m_need_destroy(true) + , m_need_help(false) { m_argc_orig = new int; m_argc = m_argc_orig; @@ -110,8 +125,17 @@ class CommandLineArguments::Impl // -A,x=b,y=c StringList args; command_line_args.fillArgs(args); - for( Integer i=0, n=args.count(); i m_nb_ref; StringList m_args; @@ -143,6 +172,7 @@ class CommandLineArguments::Impl char*** m_argv_orig = nullptr; char* m_argv0 = nullptr; bool m_need_destroy; + bool m_need_help; ParameterList m_parameter_list; }; @@ -273,6 +303,15 @@ parameters() const /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +bool CommandLineArguments:: +needHelp() const +{ + return m_p->needHelp(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + } // End namespace Arcane /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/CommandLineArguments.h b/arcane/src/arcane/utils/CommandLineArguments.h index 2c5bdf8a1d..91fda1a71c 100644 --- a/arcane/src/arcane/utils/CommandLineArguments.h +++ b/arcane/src/arcane/utils/CommandLineArguments.h @@ -94,6 +94,12 @@ class ARCANE_UTILS_EXPORT CommandLineArguments //! Liste des paramètres ParameterList& parameters(); + /*! + * \brief Méthode permettant de savoir si l'utilisateur a demandé + * de l'aide dans la ligne de commande. + */ + bool needHelp() const; + private: Arccore::ReferenceCounter m_p; From 64251d421441920d3e198960d4f63a9f02496fdd Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Tue, 4 Feb 2025 11:50:08 +0100 Subject: [PATCH 02/24] [arcane:core] Add the symbol replacing process in options --- arcane/src/arcane/core/CaseOptionService.cc | 19 ++++++++++++++++++- arcane/src/arcane/core/CaseOptionSimple.cc | 9 +++++++++ .../core/internal/StringVariableReplace.cc | 17 +++++++++++++++-- .../core/internal/StringVariableReplace.h | 3 +-- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/arcane/src/arcane/core/CaseOptionService.cc b/arcane/src/arcane/core/CaseOptionService.cc index c0aeebf5d9..c5c6cd39df 100644 --- a/arcane/src/arcane/core/CaseOptionService.cc +++ b/arcane/src/arcane/core/CaseOptionService.cc @@ -17,6 +17,8 @@ #include "arcane/utils/Enumerator.h" #include "arcane/utils/NotImplementedException.h" #include "arcane/utils/FatalErrorException.h" +#include "arcane/utils/ApplicationInfo.h" +#include "arcane/utils/CommandLineArguments.h" #include "arcane/core/IApplication.h" #include "arcane/core/IServiceFactory.h" @@ -28,6 +30,7 @@ #include "arcane/core/ICaseDocument.h" #include "arcane/core/ICaseMng.h" #include "arcane/core/internal/ICaseOptionListInternal.h" +#include "arcane/core/internal/StringVariableReplace.h" #include @@ -187,7 +190,17 @@ _readPhase1() } XmlNode element = col->rootElement(); - String mesh_name = meshName(); + const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); + + String mesh_name = element.attrValue("mesh-name"); + if (mesh_name.null()) { + mesh_name = meshName(); + } + else { + // Dans un else : Le remplacement de symboles ne s'applique pas pour les valeurs par défault du .axl. + mesh_name = StringVariableReplace::replaceWithCmdLineArgs(params, mesh_name, true); + } + tm->info(5) << "** CaseOptionService::read() ELEMENT <" << rootTagName() << "> " << col->rootElement().name() << " full=" << col->rootElement().xpathFullName() << " is_present=" << col->isPresent() @@ -221,6 +234,10 @@ _readPhase1() } str_val = m_default_value; } + else { + // Dans un else : Le remplacement de symboles ne s'applique pas pour les valeurs par défault du .axl. + str_val = StringVariableReplace::replaceWithCmdLineArgs(params, str_val, true); + } if (str_val.null() && !isOptional()){ CaseOptionError::addOptionNotFoundError(doc,A_FUNCINFO,"@name",element); return; diff --git a/arcane/src/arcane/core/CaseOptionSimple.cc b/arcane/src/arcane/core/CaseOptionSimple.cc index 20f98ce30d..2019786055 100644 --- a/arcane/src/arcane/core/CaseOptionSimple.cc +++ b/arcane/src/arcane/core/CaseOptionSimple.cc @@ -16,7 +16,10 @@ #include "arcane/utils/ValueConvert.h" #include "arcane/utils/ITraceMng.h" #include "arcane/utils/FatalErrorException.h" +#include +#include +#include "arcane/core/IApplication.h" #include "arcane/core/CaseOptionException.h" #include "arcane/core/CaseOptionBuildInfo.h" #include "arcane/core/XmlNodeList.h" @@ -29,6 +32,7 @@ #include "arcane/core/IPhysicalUnitSystem.h" #include "arcane/core/IStandardFunction.h" #include "arcane/core/ICaseDocumentVisitor.h" +#include "arcane/core/internal/StringVariableReplace.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -127,6 +131,11 @@ _search(bool is_phase1) } } + { + const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); + velem.setValue(StringVariableReplace::replaceWithCmdLineArgs(params, velem.value(), true)); + } + m_element = velem; m_function = 0; diff --git a/arcane/src/arcane/core/internal/StringVariableReplace.cc b/arcane/src/arcane/core/internal/StringVariableReplace.cc index a354df49ba..41b9af7234 100644 --- a/arcane/src/arcane/core/internal/StringVariableReplace.cc +++ b/arcane/src/arcane/core/internal/StringVariableReplace.cc @@ -14,11 +14,15 @@ /* Exemple : @mon_symbole@ */ /*---------------------------------------------------------------------------*/ +#include "arcane/core/internal/StringVariableReplace.h" + +#include "arcane/utils/CommandLineArguments.h" #include "arcane/utils/PlatformUtils.h" #include "arcane/utils/SmallArray.h" #include "arcane/utils/StringBuilder.h" - -#include "arcane/core/internal/StringVariableReplace.h" +#include "arcane/utils/String.h" +#include "arcane/utils/FatalErrorException.h" +#include "arcane/utils/List.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -29,6 +33,15 @@ namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +String StringVariableReplace:: +replaceWithCmdLineArgs(StringView string_with_symbols, bool fatal_if_not_found, bool fatal_if_invalid) +{ + StringList args; + platform::fillCommandLineArguments(args); + const CommandLineArguments cla{ args }; + return replaceWithCmdLineArgs(cla.parameters(), string_with_symbols, fatal_if_not_found, fatal_if_invalid); +} + /*! * \brief Méthode permettant de remplacer les symboles de la chaine de * caractères \a string_with_symbols par leurs valeurs définies dans la liste diff --git a/arcane/src/arcane/core/internal/StringVariableReplace.h b/arcane/src/arcane/core/internal/StringVariableReplace.h index 9afe8fb870..af0049612c 100644 --- a/arcane/src/arcane/core/internal/StringVariableReplace.h +++ b/arcane/src/arcane/core/internal/StringVariableReplace.h @@ -22,8 +22,6 @@ #include "arcane/utils/ParameterList.h" -#include "arcane/core/VariableTypes.h" - /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -37,6 +35,7 @@ class ARCANE_CORE_EXPORT StringVariableReplace { public: + static String replaceWithCmdLineArgs(StringView string_with_symbols, bool fatal_if_not_found = false, bool fatal_if_invalid = true); static String replaceWithCmdLineArgs(const ParameterList& parameter_list, StringView string_with_symbols, bool fatal_if_not_found = false, bool fatal_if_invalid = true); private: From 09281e2439e1cb1863209c3135de715ec4fac52a Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Tue, 4 Feb 2025 14:57:43 +0100 Subject: [PATCH 03/24] [arcane:core] Add option replacement with command line - For OptionSimple value, OptionService name and mesh-name - Syntax : -A,say-hello/test-option=1 --- arcane/src/arcane/core/CaseOptionService.cc | 39 +++++++++++++++++++-- arcane/src/arcane/core/CaseOptionSimple.cc | 27 +++++++++++++- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/arcane/src/arcane/core/CaseOptionService.cc b/arcane/src/arcane/core/CaseOptionService.cc index c5c6cd39df..3ff96808cd 100644 --- a/arcane/src/arcane/core/CaseOptionService.cc +++ b/arcane/src/arcane/core/CaseOptionService.cc @@ -191,8 +191,26 @@ _readPhase1() XmlNode element = col->rootElement(); const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); + ICaseDocumentFragment* doc = caseDocumentFragment(); + + String mesh_name; + { + String path = element.xpathFullName() + "/@mesh-name"; + + // On retire le "//case/" ou le "//cas/" du début. + StringView sv; + if (doc->language() == "fr") + sv = path.view().subView(6); + else + sv = path.view().subView(7); + + String reference_input = params.getParameterOrNull(sv); + if (!reference_input.null()) + mesh_name = reference_input; + else + mesh_name = element.attrValue("mesh-name"); + } - String mesh_name = element.attrValue("mesh-name"); if (mesh_name.null()) { mesh_name = meshName(); } @@ -213,9 +231,24 @@ _readPhase1() if (_setMeshHandleAndCheckDisabled(mesh_name)) return; - ICaseDocumentFragment* doc = caseDocumentFragment(); + String str_val; + { + String path = element.xpathFullName() + "/@name"; + + // On retire le "//case/" ou le "//cas/" du début. + StringView sv; + if (doc->language() == "fr") + sv = path.view().subView(6); + else + sv = path.view().subView(7); + + String reference_input = params.getParameterOrNull(sv); + if (!reference_input.null()) + str_val = reference_input; + else + str_val = element.attrValue("name"); + } - String str_val = element.attrValue("name"); //cerr << "** STR_VAL <" << str_val << " - " << m_default_value << ">\n"; if (str_val.null()){ diff --git a/arcane/src/arcane/core/CaseOptionSimple.cc b/arcane/src/arcane/core/CaseOptionSimple.cc index 2019786055..8e73116641 100644 --- a/arcane/src/arcane/core/CaseOptionSimple.cc +++ b/arcane/src/arcane/core/CaseOptionSimple.cc @@ -131,8 +131,33 @@ _search(bool is_phase1) } } + // Liste des options de la ligne de commande. + const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); { - const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); + String path; + if (velem.null()) + path = rootElement().xpathFullName() + "/" + name(); + else + path = velem.xpathFullName(); + + // On retire le "//case/" ou le "//cas/" du début. + StringView sv; + if (doc->language() == "fr") + sv = path.view().subView(6); + else + sv = path.view().subView(7); + + String reference_input = params.getParameterOrNull(sv); + if (!reference_input.null()) { + // Si l'utilisateur a spécifié une option qui n'est pas présente dans le + // jeu de données, on doit la créer. + if (velem.null()) { + velem = rootElement().createElement(name()); + } + velem.setValue(reference_input); + } + } + if (!velem.null()) { velem.setValue(StringVariableReplace::replaceWithCmdLineArgs(params, velem.value(), true)); } From e1b154898aa4935fd87436fe1ff26ba32c6cfdcf Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Tue, 4 Feb 2025 15:19:43 +0100 Subject: [PATCH 04/24] [arcane:impl,launcher] Remove now useless string replacement in ArcaneCaseMeshService --- arcane/src/arcane/impl/ArcaneCaseMeshService.cc | 4 ++-- arcane/src/arcane/launcher/ArcaneLauncher.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arcane/src/arcane/impl/ArcaneCaseMeshService.cc b/arcane/src/arcane/impl/ArcaneCaseMeshService.cc index e0097393bf..d08f225326 100644 --- a/arcane/src/arcane/impl/ArcaneCaseMeshService.cc +++ b/arcane/src/arcane/impl/ArcaneCaseMeshService.cc @@ -115,8 +115,8 @@ createMesh(const String& default_name) options()->configList()->xpathFullName(), options()->generator.rootTagName(), options()->filename.name()); - if (has_filename){ - m_mesh_file_name = StringVariableReplace::replaceWithCmdLineArgs(m_sub_domain->applicationInfo().commandLineArguments().parameters(), options()->filename().view()); + if (has_filename) { + m_mesh_file_name = options()->filename(); if (m_mesh_file_name.empty()) ARCANE_FATAL("Invalid filename '{0}' in option '{1}'", m_mesh_file_name,options()->filename.xpathFullName()); diff --git a/arcane/src/arcane/launcher/ArcaneLauncher.h b/arcane/src/arcane/launcher/ArcaneLauncher.h index 3db38871b0..38d65ad407 100644 --- a/arcane/src/arcane/launcher/ArcaneLauncher.h +++ b/arcane/src/arcane/launcher/ArcaneLauncher.h @@ -215,7 +215,7 @@ class ARCANE_LAUNCHER_EXPORT ArcaneLauncher /*! * \brief Demande d'aide avec l'option "--help" ou "-h". * - * Méthode permettant de savoir si l'utilisateur a demandée l'aide + * Méthode permettant de savoir si l'utilisateur a demandé l'aide * avec l'option "--help" ou "-h". * * \return true si l'aide a été demandée. From de6e1d9d1320a8a2133c5198d4dd910a38639e00 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Wed, 5 Feb 2025 16:59:34 +0100 Subject: [PATCH 05/24] [arcane:core,tests] Add name and mesh-name replacement for MultiService options and add a new test --- arcane/src/arcane/core/CaseOptionService.cc | 102 +++++++++++--- arcane/src/arcane/core/CaseOptions.h | 2 + arcane/src/arcane/tests/CMakeLists.txt | 35 +++++ .../testCaseOptions-commandLineReplace.arc | 127 ++++++++++++++++++ 4 files changed, 245 insertions(+), 21 deletions(-) create mode 100644 arcane/tests/testCaseOptions-commandLineReplace.arc diff --git a/arcane/src/arcane/core/CaseOptionService.cc b/arcane/src/arcane/core/CaseOptionService.cc index 3ff96808cd..241328d148 100644 --- a/arcane/src/arcane/core/CaseOptionService.cc +++ b/arcane/src/arcane/core/CaseOptionService.cc @@ -193,6 +193,8 @@ _readPhase1() const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); ICaseDocumentFragment* doc = caseDocumentFragment(); + // TODO AH : Si l'on met un "mesh-name" dans le .axl puis que l'utilisateur met un "mesh-name" dans le .arc, qui gagne ? + // Cas où un service agit sur deux maillages ? String mesh_name; { String path = element.xpathFullName() + "/@mesh-name"; @@ -401,44 +403,92 @@ multiAllocate(const XmlNodeList& elem_list) Integer size = elem_list.size(); - if (size==0) + if (size == 0) return; - m_services_name.resize(size); - ITraceMng* tm = traceMng(); - m_container->allocate(size); - m_allocated_options.resize(size); IApplication* app = caseMng()->application(); XmlNode parent_element = configList()->parentElement(); + const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); ICaseDocumentFragment* doc = caseDocumentFragment(); - String mesh_name = meshName(); - if (_setMeshHandleAndCheckDisabled(mesh_name)) - return; + m_container->allocate(size); - for( Integer index=0; indexlanguage() == "fr") + sv = path.view().subView(6); + else + sv = path.view().subView(7); + + String reference_input = params.getParameterOrNull(sv); + if (!reference_input.null()) + mesh_name = reference_input; + else + mesh_name = element.attrValue("mesh-name"); + } + + if (mesh_name.null()) { + mesh_name = meshName(); + } + else { + // Dans un else : Le remplacement de symboles ne s'applique pas pour les valeurs par défault du .axl. + mesh_name = StringVariableReplace::replaceWithCmdLineArgs(params, mesh_name, true); + } + + String str_val; + { + String path = element.xpathFullName() + "/@name"; + + // On retire le "//case/" ou le "//cas/" du début. + StringView sv; + if (doc->language() == "fr") + sv = path.view().subView(6); + else + sv = path.view().subView(7); + + String reference_input = params.getParameterOrNull(sv); + if (!reference_input.null()) + str_val = reference_input; + else + str_val = element.attrValue("name"); + } tm->info(5) << "CaseOptionMultiServiceImpl name=" << name() << " index=" << index << " v=" << str_val << " default_value='" << _defaultValue() << "'" << " mesh=" << meshHandle().meshName(); - - if (str_val.null()) + + if (str_val.null()) { str_val = _defaultValue(); + } + else { + // Dans un else : Le remplacement de symboles ne s'applique pas pour les valeurs par défault du .axl. + str_val = StringVariableReplace::replaceWithCmdLineArgs(params, str_val, true); + } if (str_val.null()) - throw CaseOptionException("get_value","@name",element); + throw CaseOptionException("get_value", "@name", element); + // TODO: regarder si on ne peut pas créer directement un CaseOptionService. - CaseOptions* coptions = new CaseOptions(configList(),name(),parent_element,false,true); + auto* coptions = new CaseOptions(configList(), name(), parent_element, false, true); + if (coptions->_setMeshHandleAndCheckDisabled(mesh_name)) { + delete coptions; + continue; + } coptions->configList()->_internalApi()->setRootElement(element); - bool is_found = _tryCreateService(m_container,app,str_val,index,coptions); + bool is_found = _tryCreateService(m_container, app, str_val, index, coptions); - if (!is_found){ + if (!is_found) { tm->info(5) << "CaseOptionMultiServiceImpl name=" << name() << " index=" << index << " service not found"; @@ -447,12 +497,22 @@ multiAllocate(const XmlNodeList& elem_list) // Recherche les noms des implémentations valides StringUniqueArray valid_names; getAvailableNames(valid_names); - CaseOptionError::addError(doc,A_FUNCINFO,element.xpathFullName(), + CaseOptionError::addError(doc, A_FUNCINFO, element.xpathFullName(), String::format("Unable to find a service named '{0}' (valid values:{1})", - str_val,valid_names),true); + str_val, valid_names), + true); } + m_services_name[index] = str_val; m_allocated_options[index] = coptions; + + index++; } + + m_container->allocate(index); + + m_allocated_options.resize(index); + m_services_name.resize(index); + if (m_notify_functor) m_notify_functor->executeFunctor(); } diff --git a/arcane/src/arcane/core/CaseOptions.h b/arcane/src/arcane/core/CaseOptions.h index 4c033f5ff2..b916ab2181 100644 --- a/arcane/src/arcane/core/CaseOptions.h +++ b/arcane/src/arcane/core/CaseOptions.h @@ -186,6 +186,8 @@ class ARCANE_CORE_EXPORT CaseOptions protected: + friend class CaseOptionMultiServiceImpl; + void _setTranslatedName(); bool _setMeshHandleAndCheckDisabled(const String& mesh_name); diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index d48da2c906..7dec4056f2 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -331,6 +331,41 @@ endif() ARCANE_ADD_TEST_SEQUENTIAL(caseoptions testCaseOptions-1.arc) arcane_add_test_sequential(caseoptions_specificentrypoint testCaseOptions-specific-entry-point.arc "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2") + +arcane_add_test_sequential(caseoptions_commandlinereplace testCaseOptions-commandLineReplace.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,TestId=1" + "-A,SimpleRealUnit2=0.0" + "-A,case-options-tester/simple-real=3.0" + "-A,case-options-tester/simple-real-unit=4.2" + "-A,SimpleRealUnit2=0.0" + "-A,case-options-tester/simple-realarray-unit=\"2.2 2.3 0.1 3.5\"" + "-A,case-options-tester/simple-real2=\"3.5 7.2\"" + "-A,SimpleReal3=\"1.2 4.7 7.9\"" + "-A,case-options-tester/simple-real2x2=\"3.1 3.0 2.9 2.7\"" + "-A,case-options-tester/simple-real3x3=\"3.3 3.2 2.1 1.1 0.3 0.5 7.2 7.1 4.0\"" + "-A,case-options-tester/simple-integer=4" + "-A,case-options-tester/simple-int32=-23" + "-A,case-options-tester/simple-int64=454653457457455474" + "-A,case-options-tester/simple-bool=true" + "-A,case-options-tester/simple-string=toto" + "-A,SimpleStringMultiple=toto2" + "-A,case-options-tester/simple-string-multiple[2]=toto3" + "-A,case-options-tester/simple-string-multiple[3]=\"\"" + "-A,case-options-tester/simple-real-array=\"3.0 4.1 5.6\"" + "-A,case-options-tester/simple-real-array-multi[1]=\"4.0 1.1 7.3\"" + "-A,case-options-tester/simple-integer-array=\"4 5 6 7\"" + "-A,case-options-tester/simple-int32-array=\"-23 32 -32\"" + "-A,case-options-tester/simple-int64-array=\"454653457457455474 -453463634634634634\"" + "-A,case-options-tester/simple-bool-array=\"true false false true\"" + "-A,case-options-tester/simple-string-array=\"toto titi tata tutu tete\"" + "-A,case-options-tester/simple-enum=enum1" + "-A,PostProcessor1FrName=Ensight7PostProcessor" + "-A,case-options-tester/post-processor1-fr[0]/nb-temps-par-fichier=1" + "-A,case-options-tester/post-processor1-fr[0]/fichier-binaire=false" +) + if(UDUNITS_FOUND) ARCANE_ADD_TEST_SEQUENTIAL(caseoptions_unit testCaseOptions-2.arc) endif() diff --git a/arcane/tests/testCaseOptions-commandLineReplace.arc b/arcane/tests/testCaseOptions-commandLineReplace.arc new file mode 100644 index 0000000000..82074aed90 --- /dev/null +++ b/arcane/tests/testCaseOptions-commandLineReplace.arc @@ -0,0 +1,127 @@ + + + + Test Arcane 1 + Test Arcane 1 + CaseOptionsTester2 + + + + + + 422 + + + + + + @TestId@ + 20 + @SimpleRealUnit2@ + @SimpleReal3@ + + toto1 + @SimpleStringMultiple@ + + 3.0 4.1 5.6 + + 4.5 + + enum1 + + + + + + + + 9 + false + + + + 12 + false + + + + 5 + false + + + + 32 + false + + + 32 + false + + + 64 + false + + + + 3 + 5.2 + 2.3 + 3.0 2.0 4.0 + 4 + enum2 + enum1 + + 2.0 3.0 + 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 + + + + true + 1. + 4 + enum1 + enum1 + + + true + 3 + 4 + enum1 + enum1 + + 3 + 4 + enum1 + enum1 + + 5 + 3 + + + + 5 + 7 + enum2 + enum2 + + 12 + 4 + + + + enum1 + + 5.2 + + + 5.2 + + + 4.9xs + + + 4.9xs + + + + From aac70e4489db1d1e0834c83bc2a2f182a160d4c7 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Tue, 11 Feb 2025 12:48:49 +0100 Subject: [PATCH 06/24] [arcane:core,utils,tests] Add ParameterCaseOption class to manage options in command line - Add it in CaseOptionSimple(Multi) and CaseOptionService(Multi). --- arcane/src/arcane/core/CaseOptionBase.cc | 16 + arcane/src/arcane/core/CaseOptionBase.h | 5 +- arcane/src/arcane/core/CaseOptionList.cc | 14 +- arcane/src/arcane/core/CaseOptionService.cc | 154 +++--- arcane/src/arcane/core/CaseOptionSimple.cc | 120 +++-- arcane/src/arcane/core/ICaseOptionList.h | 4 + arcane/src/arcane/tests/CMakeLists.txt | 49 +- arcane/src/arcane/tests/CaseOptionsTester.axl | 2 +- .../src/arcane/utils/ParameterCaseOption.cc | 461 ++++++++++++++++++ arcane/src/arcane/utils/ParameterCaseOption.h | 88 ++++ arcane/src/arcane/utils/srcs.cmake | 2 + .../testCaseOptions-commandLineReplace.arc | 6 +- 12 files changed, 775 insertions(+), 146 deletions(-) create mode 100644 arcane/src/arcane/utils/ParameterCaseOption.cc create mode 100644 arcane/src/arcane/utils/ParameterCaseOption.h diff --git a/arcane/src/arcane/core/CaseOptionBase.cc b/arcane/src/arcane/core/CaseOptionBase.cc index de2ed7af40..62620a8783 100644 --- a/arcane/src/arcane/core/CaseOptionBase.cc +++ b/arcane/src/arcane/core/CaseOptionBase.cc @@ -54,6 +54,7 @@ class CaseOptionBasePrivate String m_default_value; //!< Valeur par défaut Integer m_min_occurs; //!< Nombre minimum d'occurences Integer m_max_occurs; //!< Nombre maximum d'occurences (-1 == unbounded) + bool m_is_optional; bool m_is_initialized; //!< \a true si initialisé bool m_is_override_default; //!< \a true si la valeur par défaut est surchargée //! Liste des noms d'options par langue. @@ -77,6 +78,7 @@ CaseOptionBasePrivate(const CaseOptionBuildInfo& cob) , m_default_value(m_axl_default_value) , m_min_occurs(cob.minOccurs()) , m_max_occurs(cob.maxOccurs()) +, m_is_optional(cob.isOptional()) , m_is_initialized(false) , m_is_override_default(false) { @@ -227,6 +229,15 @@ maxOccurs() const /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +bool CaseOptionBase:: +isOptional() const +{ + return m_p->m_is_optional; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + void CaseOptionBase:: _setTranslatedName() { @@ -349,6 +360,11 @@ _checkMinMaxOccurs(Integer nb_occur) { Integer min_occurs = m_p->m_min_occurs; Integer max_occurs = m_p->m_max_occurs; + bool is_optional = m_p->m_is_optional; + + if (nb_occur == 0 && is_optional) { + return; + } if (nb_occurmultiAllocate(m_root_element_list); + // Ces vérifications sont faites dans multiAllocate(). + //Integer s = m_root_element_list.size(); + //_checkMinMaxOccurs(s); + //if (s!=0) + m_case_option_multi->multiAllocate(m_root_element_list); // Récupère les options créées lors de l'appel à 'multiAllocate' et // les ajoute à la liste. Integer nb_children = m_case_option_multi->nbChildren(); diff --git a/arcane/src/arcane/core/CaseOptionService.cc b/arcane/src/arcane/core/CaseOptionService.cc index 241328d148..3a5968fa79 100644 --- a/arcane/src/arcane/core/CaseOptionService.cc +++ b/arcane/src/arcane/core/CaseOptionService.cc @@ -31,6 +31,7 @@ #include "arcane/core/ICaseMng.h" #include "arcane/core/internal/ICaseOptionListInternal.h" #include "arcane/core/internal/StringVariableReplace.h" +#include "arcane/utils/ParameterCaseOption.h" #include @@ -193,20 +194,11 @@ _readPhase1() const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); ICaseDocumentFragment* doc = caseDocumentFragment(); - // TODO AH : Si l'on met un "mesh-name" dans le .axl puis que l'utilisateur met un "mesh-name" dans le .arc, qui gagne ? - // Cas où un service agit sur deux maillages ? + ParameterCaseOption pco{ caseMng() }; + String mesh_name; { - String path = element.xpathFullName() + "/@mesh-name"; - - // On retire le "//case/" ou le "//cas/" du début. - StringView sv; - if (doc->language() == "fr") - sv = path.view().subView(6); - else - sv = path.view().subView(7); - - String reference_input = params.getParameterOrNull(sv); + String reference_input = pco.getParameterOrNull(element.xpathFullName(), "@mesh-name", 1); if (!reference_input.null()) mesh_name = reference_input; else @@ -235,16 +227,7 @@ _readPhase1() String str_val; { - String path = element.xpathFullName() + "/@name"; - - // On retire le "//case/" ou le "//cas/" du début. - StringView sv; - if (doc->language() == "fr") - sv = path.view().subView(6); - else - sv = path.view().subView(7); - - String reference_input = params.getParameterOrNull(sv); + String reference_input = pco.getParameterOrNull(element.xpathFullName(), "@name", 1); if (!reference_input.null()) str_val = reference_input; else @@ -401,41 +384,78 @@ multiAllocate(const XmlNodeList& elem_list) if (!m_container) ARCANE_FATAL("null 'm_container'. did you called setContainer() method ?"); + const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); + ParameterCaseOption pco{ caseMng() }; + + XmlNode parent_element = configList()->parentElement(); + + // !!! En XML, on commence par 1 et non 0. + UniqueArray option_in_param; + + pco.indexesInParam(String::format("{0}/{1}", parent_element.xpathFullName(), name()), option_in_param, true); + Integer size = elem_list.size(); - if (size == 0) + bool is_optional = configList()->isOptional(); + + if (size == 0 && option_in_param.empty() && is_optional) { return; + } + + Integer min_occurs = configList()->minOccurs(); + Integer max_occurs = configList()->maxOccurs(); + + Integer max_in_param = 0; + + if (!option_in_param.empty()) { + max_in_param = option_in_param[0]; + for (Integer index : option_in_param) { + if (index > max_in_param) + max_in_param = index; + } + if (max_occurs >= 0) { + if (max_in_param > max_occurs) { + ARCANE_FATAL("Max in param > max_occurs"); + } + } + } + + if (max_occurs >= 0) { + if (size > max_occurs) { + ARCANE_FATAL("Nb in XmlNodeList > max_occurs"); + } + } + + Integer final_size = std::max(size, std::max(min_occurs, max_in_param)); ITraceMng* tm = traceMng(); IApplication* app = caseMng()->application(); - XmlNode parent_element = configList()->parentElement(); - const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); ICaseDocumentFragment* doc = caseDocumentFragment(); - m_container->allocate(size); + m_container->allocate(final_size); - m_allocated_options.resize(size); - m_services_name.resize(size); + m_allocated_options.resize(final_size); + m_services_name.resize(final_size); + + for (Integer index = 0; index < final_size; ++index) { + XmlNode element; - Integer index = 0; - for (const XmlNode& element : elem_list) { String mesh_name; - { - String path = element.xpathFullName() + "/@mesh-name"; - - // On retire le "//case/" ou le "//cas/" du début. - StringView sv; - if (doc->language() == "fr") - sv = path.view().subView(6); - else - sv = path.view().subView(7); - - String reference_input = params.getParameterOrNull(sv); - if (!reference_input.null()) - mesh_name = reference_input; - else - mesh_name = element.attrValue("mesh-name"); + String str_val; + + if (option_in_param.contains(index + 1)) { + mesh_name = pco.getParameterOrNull(String::format("{0}/{1}", parent_element.xpathFullName(), name()), "@mesh-name", index + 1); + str_val = pco.getParameterOrNull(String::format("{0}/{1}", parent_element.xpathFullName(), name()), "@name", index + 1); + } + if (index < size && (mesh_name.null() || str_val.null())) { + element = elem_list[index]; + if (!element.null()) { + if (mesh_name.null()) + mesh_name = element.attrValue("mesh-name"); + if (str_val.null()) + str_val = element.attrValue("name"); + } } if (mesh_name.null()) { @@ -446,29 +466,6 @@ multiAllocate(const XmlNodeList& elem_list) mesh_name = StringVariableReplace::replaceWithCmdLineArgs(params, mesh_name, true); } - String str_val; - { - String path = element.xpathFullName() + "/@name"; - - // On retire le "//case/" ou le "//cas/" du début. - StringView sv; - if (doc->language() == "fr") - sv = path.view().subView(6); - else - sv = path.view().subView(7); - - String reference_input = params.getParameterOrNull(sv); - if (!reference_input.null()) - str_val = reference_input; - else - str_val = element.attrValue("name"); - } - tm->info(5) << "CaseOptionMultiServiceImpl name=" << name() - << " index=" << index - << " v=" << str_val - << " default_value='" << _defaultValue() << "'" - << " mesh=" << meshHandle().meshName(); - if (str_val.null()) { str_val = _defaultValue(); } @@ -476,8 +473,20 @@ multiAllocate(const XmlNodeList& elem_list) // Dans un else : Le remplacement de symboles ne s'applique pas pour les valeurs par défault du .axl. str_val = StringVariableReplace::replaceWithCmdLineArgs(params, str_val, true); } + if (element.null()) { + element = parent_element.createElement(name()); + + element.setAttrValue("mesh-name", mesh_name); + element.setAttrValue("name", str_val); + } + + tm->info(5) << "CaseOptionMultiServiceImpl name=" << name() + << " index=" << index + << " v=" << str_val + << " default_value='" << _defaultValue() << "'" + << " mesh=" << meshHandle().meshName(); if (str_val.null()) - throw CaseOptionException("get_value", "@name", element); + throw CaseOptionException("get_value", "@name"); // TODO: regarder si on ne peut pas créer directement un CaseOptionService. auto* coptions = new CaseOptions(configList(), name(), parent_element, false, true); @@ -504,15 +513,8 @@ multiAllocate(const XmlNodeList& elem_list) } m_services_name[index] = str_val; m_allocated_options[index] = coptions; - - index++; } - m_container->allocate(index); - - m_allocated_options.resize(index); - m_services_name.resize(index); - if (m_notify_functor) m_notify_functor->executeFunctor(); } diff --git a/arcane/src/arcane/core/CaseOptionSimple.cc b/arcane/src/arcane/core/CaseOptionSimple.cc index 8e73116641..45cd99068f 100644 --- a/arcane/src/arcane/core/CaseOptionSimple.cc +++ b/arcane/src/arcane/core/CaseOptionSimple.cc @@ -16,8 +16,9 @@ #include "arcane/utils/ValueConvert.h" #include "arcane/utils/ITraceMng.h" #include "arcane/utils/FatalErrorException.h" -#include -#include +#include "arcane/utils/ApplicationInfo.h" +#include "arcane/utils/CommandLineArguments.h" +#include "arcane/utils/ParameterCaseOption.h" #include "arcane/core/IApplication.h" #include "arcane/core/CaseOptionException.h" @@ -132,22 +133,11 @@ _search(bool is_phase1) } // Liste des options de la ligne de commande. - const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); { - String path; - if (velem.null()) - path = rootElement().xpathFullName() + "/" + name(); - else - path = velem.xpathFullName(); + const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); + ParameterCaseOption pco{ caseMng() }; - // On retire le "//case/" ou le "//cas/" du début. - StringView sv; - if (doc->language() == "fr") - sv = path.view().subView(6); - else - sv = path.view().subView(7); - - String reference_input = params.getParameterOrNull(sv); + String reference_input = pco.getParameterOrNull(String::format("{0}/{1}", rootElement().xpathFullName(), velem_name), 1, false); if (!reference_input.null()) { // Si l'utilisateur a spécifié une option qui n'est pas présente dans le // jeu de données, on doit la créer. @@ -156,9 +146,9 @@ _search(bool is_phase1) } velem.setValue(reference_input); } - } - if (!velem.null()) { - velem.setValue(StringVariableReplace::replaceWithCmdLineArgs(params, velem.value(), true)); + if (!velem.null()) { + velem.setValue(StringVariableReplace::replaceWithCmdLineArgs(params, velem.value(), true)); + } } m_element = velem; @@ -664,43 +654,97 @@ _allowPhysicalUnit() * Si la valeur n'est pas présente dans le jeu de donnée, regarde s'il * existe une valeur par défaut et utilise cette dernière. */ -template void CaseOptionMultiSimpleT:: +template +void CaseOptionMultiSimpleT:: _search(bool is_phase1) { if (!is_phase1) return; - XmlNodeList elem_list = rootElement().children(name()); + const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); + ParameterCaseOption pco{ caseMng() }; + + // !!! En XML, on commence par 1 et non 0. + UniqueArray option_in_param; + + pco.indexesInParam(String::format("{0}/{1}", rootElement().xpathFullName(), name()), option_in_param, false); + + XmlNodeList elem_list = rootElement().children(name()); Integer asize = elem_list.size(); - _checkMinMaxOccurs(asize); - if (asize==0) + + bool is_optional = isOptional(); + + if (asize == 0 && option_in_param.empty() && is_optional) { return; + } + + Integer min_occurs = minOccurs(); + Integer max_occurs = maxOccurs(); + + Integer max_in_param = 0; + + if (!option_in_param.empty()) { + max_in_param = option_in_param[0]; + for (Integer index : option_in_param) { + if (index > max_in_param) + max_in_param = index; + } + if (max_occurs >= 0) { + if (max_in_param > max_occurs) { + ARCANE_FATAL("Max in param > max_occurs"); + } + } + } + + if (max_occurs >= 0) { + if (asize > max_occurs) { + ARCANE_FATAL("Nb in XmlNodeList > max_occurs"); + } + } + + Integer final_size = std::max(asize, std::max(min_occurs, max_in_param)); const Type* old_value = m_view.data(); delete[] old_value; using Type = typename CaseOptionTraitsT::ContainerType; - Type* ptr_value = new Type[asize]; - m_view = ArrayViewType(asize,ptr_value); - this->_setArray(ptr_value,asize); + Type* ptr_value = new Type[final_size]; + m_view = ArrayViewType(final_size, ptr_value); + this->_setArray(ptr_value, final_size); //cerr << "** MULTI SEARCH " << size << endl; - for( Integer i=0; i::collapse(str_val); - bool is_bad = builtInGetValue(val,str_val); + bool is_bad = builtInGetValue(val, str_val); if (is_bad) - CaseOptionError::addInvalidTypeError(caseDocumentFragment(),A_FUNCINFO, - name(),rootElement(),str_val,typeToName(val)); + CaseOptionError::addInvalidTypeError(caseDocumentFragment(), A_FUNCINFO, + name(), rootElement(), str_val, typeToName(val)); //throw CaseOptionException("get_value",name(),rootElement(),str_val,typeToName(val)); //ptr_value[i] = val; - _copyCaseOptionValue(ptr_value[i],val); + _copyCaseOptionValue(ptr_value[i], val); } } diff --git a/arcane/src/arcane/core/ICaseOptionList.h b/arcane/src/arcane/core/ICaseOptionList.h index 61485808ad..067b70f096 100644 --- a/arcane/src/arcane/core/ICaseOptionList.h +++ b/arcane/src/arcane/core/ICaseOptionList.h @@ -72,6 +72,10 @@ class ARCANE_CORE_EXPORT ICaseOptionList virtual bool isPresent() const =0; //! Indique si l'option est optionnelle virtual bool isOptional() const =0; + //! Nombre minimum d'occurences + virtual Integer minOccurs() const = 0; + //! Nombre maximum d'occurences + virtual Integer maxOccurs() const = 0; //! Applique le visiteur \a visitor virtual void visit(ICaseDocumentVisitor* visitor) =0; //! Nom complet au format XPath correspondant à rootElement() diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index 7dec4056f2..8802432b4d 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -337,33 +337,36 @@ arcane_add_test_sequential(caseoptions_commandlinereplace testCaseOptions-comman "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" "-A,TestId=1" "-A,SimpleRealUnit2=0.0" - "-A,case-options-tester/simple-real=3.0" - "-A,case-options-tester/simple-real-unit=4.2" + "-A,//case-options-tester/simple-real=3.0" + "-A,//case-options-tester/simple-real-unit=4.2" "-A,SimpleRealUnit2=0.0" - "-A,case-options-tester/simple-realarray-unit=\"2.2 2.3 0.1 3.5\"" - "-A,case-options-tester/simple-real2=\"3.5 7.2\"" + "-A,//case-options-tester/simple-realarray-unit=\"2.2 2.3 0.1 3.5\"" + "-A,//case-options-tester/simple-real2=\"3.5 7.2\"" "-A,SimpleReal3=\"1.2 4.7 7.9\"" - "-A,case-options-tester/simple-real2x2=\"3.1 3.0 2.9 2.7\"" - "-A,case-options-tester/simple-real3x3=\"3.3 3.2 2.1 1.1 0.3 0.5 7.2 7.1 4.0\"" - "-A,case-options-tester/simple-integer=4" - "-A,case-options-tester/simple-int32=-23" - "-A,case-options-tester/simple-int64=454653457457455474" - "-A,case-options-tester/simple-bool=true" - "-A,case-options-tester/simple-string=toto" + "-A,//case-options-tester/simple-real2x2=\"3.1 3.0 2.9 2.7\"" + "-A,//case-options-tester/simple-real3x3=\"3.3 3.2 2.1 1.1 0.3 0.5 7.2 7.1 4.0\"" + "-A,//case-options-tester/simple-integer=4" + "-A,//case-options-tester/simple-int32=-23" + "-A,//case-options-tester/simple-int64=454653457457455474" + "-A,//case-options-tester/simple-bool=true" + "-A,//case-options-tester/simple-string=toto" "-A,SimpleStringMultiple=toto2" - "-A,case-options-tester/simple-string-multiple[2]=toto3" - "-A,case-options-tester/simple-string-multiple[3]=\"\"" - "-A,case-options-tester/simple-real-array=\"3.0 4.1 5.6\"" - "-A,case-options-tester/simple-real-array-multi[1]=\"4.0 1.1 7.3\"" - "-A,case-options-tester/simple-integer-array=\"4 5 6 7\"" - "-A,case-options-tester/simple-int32-array=\"-23 32 -32\"" - "-A,case-options-tester/simple-int64-array=\"454653457457455474 -453463634634634634\"" - "-A,case-options-tester/simple-bool-array=\"true false false true\"" - "-A,case-options-tester/simple-string-array=\"toto titi tata tutu tete\"" - "-A,case-options-tester/simple-enum=enum1" + "-A,//case-options-tester/simple-string-multiple[3]=toto3" + "-A,//case-options-tester/simple-string-multiple[4]=\"\"" + "-A,//case-options-tester/simple-real-array=\"3.0 4.1 5.6\"" + "-A,//case-options-tester/simple-real-array-multi[2]=\"4.0 1.1 7.3\"" + "-A,//case-options-tester/simple-integer-array=\"4 5 6 7\"" + "-A,//case-options-tester/simple-int32-array=\"-23 32 -32\"" + "-A,//case-options-tester/simple-int64-array=\"454653457457455474 -453463634634634634\"" + "-A,//case-options-tester/simple-bool-array=\"true false false true\"" + "-A,//case-options-tester/simple-string-array=\"toto titi tata tutu tete\"" + "-A,//case-options-tester/simple-enum=enum1" "-A,PostProcessor1FrName=Ensight7PostProcessor" - "-A,case-options-tester/post-processor1-fr[0]/nb-temps-par-fichier=1" - "-A,case-options-tester/post-processor1-fr[0]/fichier-binaire=false" + "-A,//case-options-tester/post-processor1/fileset-size=1" + "-A,//case-options-tester/post-processor1/binary-file=false" + "-A,//case-options-tester/post-processor1[3]/@name=VtkHdfV2PostProcessor" + "-A,//case-options-tester/post-processor1[4]/@name=UCDPostProcessor" + "-A,//case-options-tester/post-processor2[2]/@mesh-name=Mesh1" ) if(UDUNITS_FOUND) diff --git a/arcane/src/arcane/tests/CaseOptionsTester.axl b/arcane/src/arcane/tests/CaseOptionsTester.axl index 0be2cb1f26..0021877581 100644 --- a/arcane/src/arcane/tests/CaseOptionsTester.axl +++ b/arcane/src/arcane/tests/CaseOptionsTester.axl @@ -130,7 +130,7 @@ SimpleStringMultiple diff --git a/arcane/src/arcane/utils/ParameterCaseOption.cc b/arcane/src/arcane/utils/ParameterCaseOption.cc new file mode 100644 index 0000000000..8499d103e3 --- /dev/null +++ b/arcane/src/arcane/utils/ParameterCaseOption.cc @@ -0,0 +1,461 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* ParameterCaseOption.cc (C) 2000-2025 */ +/* */ +/* TODO. */ +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#include "arcane/utils/ParameterCaseOption.h" + +#include "arcane/utils/ApplicationInfo.h" +#include "arcane/utils/CommandLineArguments.h" +#include "arcane/utils/ParameterList.h" +#include "arcane/core/IApplication.h" +#include "arcane/core/ICaseDocument.h" +#include "arcane/utils/ValueConvert.h" +#include "arcane/utils/String.h" +#include "arcane/utils/StringDictionary.h" +#include "arcane/utils/Array.h" +#include "arcane/utils/FatalErrorException.h" +#include "arccore/trace/ITraceMng.h" + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +namespace Arcane +{ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterCaseOption:: +ParameterCaseOption(ICaseMng* case_mng) +: m_case_mng(case_mng) +{ + m_lang = m_case_mng->caseDocumentFragment()->language(); + + m_case_mng->application()->applicationInfo().commandLineArguments().parameters().fillParameters(m_param_names, m_values); + + Integer size = m_param_names.count(); + + m_params_view.reserve(size); + m_values_view.reserve(size); + + Integer true_size = 0; + for (Integer i = 0; i < m_param_names.count(); ++i) { + const String& param = m_param_names[i]; + if (param.startsWith("//")) { + m_params_view.add(param.view().subView(2)); + m_values_view.add(m_values[i].view()); + true_size++; + } + } + m_params_view.resize(true_size); + m_values_view.resize(true_size); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +// xpath_before_index[index]/xpath_after_index +String ParameterCaseOption:: +getParameterOrNull(const String& xpath_before_index, const String& xpath_after_index, Integer index) +{ + if (index <= 0) { + ARCANE_FATAL("Index in XML start at 1"); + } + + StringView xpath_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); + + String xpath_with_index_attr = String::format("{0}[{1}]/{2}", xpath_view, index, xpath_after_index); + + if (index > 1) { + Integer index_value = _getValueIndex(xpath_with_index_attr); + if (index_value == -1) + return {}; + return m_values_view[index_value]; + } + + String xpath_with_attr = String::format("{0}/{1}", xpath_view, xpath_after_index); + for (Integer i = 0; i < m_params_view.size(); ++i) { + if (m_params_view[i] == xpath_with_index_attr.view() || m_params_view[i] == xpath_with_attr.view()) { + return m_values_view[i]; + } + } + return {}; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +String ParameterCaseOption:: +getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_elems_after_index) +{ + if (index <= 0) { + ARCANE_FATAL("Index in XML start at 1"); + } + + StringView xpath_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); + + String xpath_with_index_attr = String::format("{0}[{1}]", xpath_view, index); + + + if (allow_elems_after_index) { + StringView before_view_with_attr = xpath_with_index_attr.view(); + if (index > 1) { + for (Integer i = 0; i < m_params_view.size(); ++i) { + StringView param = m_params_view[i]; + if (param.size()-before_view_with_attr.size() >= 0) { + StringView begin = param.subView(0, before_view_with_attr.size()); + if (begin == before_view_with_attr) { + return m_values_view[i]; + } + } + } + return {}; + } + + for (Integer i = 0; i < m_params_view.size(); ++i) { + StringView param = m_params_view[i]; + if (param.size()-xpath_view.size() >= 0) { + StringView begin = param.subView(0, xpath_view.size()); + if (begin == xpath_view) { + return m_values_view[i]; + } + } + if (param.size()-before_view_with_attr.size() >= 0) { + StringView begin = param.subView(0, before_view_with_attr.size()); + if (begin == before_view_with_attr) { + return m_values_view[i]; + } + } + } + return {}; + + } + else { + if (index > 1) { + for (Integer i = 0; i < m_params_view.size(); ++i) { + if (m_params_view[i] == xpath_with_index_attr.view()) { + return m_values_view[i]; + } + } + return {}; + } + + for (Integer i = 0; i < m_params_view.size(); ++i) { + if (m_params_view[i] == xpath_view || m_params_view[i] == xpath_with_index_attr.view()) { + return m_values_view[i]; + } + } + } + return {}; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +String ParameterCaseOption:: +getParameterOrNull(const String& full_xpath) +{ + Integer index_value = _getValueIndex(_removeUselessPartInXpath(full_xpath)); + if (index_value == -1) return {}; + return m_values_view[index_value]; +} + + + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterCaseOption:: +exist(const String& full_xpath) +{ + StringView xpath = _removeUselessPartInXpath(full_xpath); + + for (auto param : m_params_view) { + if (param == xpath) { + return true; + } + } + return false; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterCaseOption:: +existAnyIndex(const String& xpath_before_index, const String& xpath_after_index) +{ + StringView before_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); + StringView after_view = xpath_after_index.view(); + + for (auto param : m_params_view) { + // > 0 car il doit y avoir au moins un "/" entre les deux. + if (param.size()-after_view.size()-before_view.size() > 0) { + StringView begin = param.subView(0, before_view.size()); + if (begin == before_view) { + StringView end = param.subView(param.size()-after_view.size(), after_view.size()); + if (end == after_view) { + // Le "-1" : On retire le "/" à la fin du between. + StringView between = param.subView(before_view.size(), param.size()-after_view.size()-before_view.size()-1); + if (_hasOnlyIndex(between)){ + return true; + } + } + } + } + } + return false; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterCaseOption:: +existAnyIndex(const String& full_xpath) +{ + StringView xpath_view = _removeIndexAtEnd(_removeUselessPartInXpath(full_xpath)); + + for (auto param : m_params_view) { + if (_removeIndexAtEnd(param) == xpath_view) { + return true; + } + } + return false; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterCaseOption:: +indexesInParam(const String& xpath_before_index, const String& xpath_after_index, UniqueArray& indexes) +{ + StringView before_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); + StringView after_view = xpath_after_index.view(); + + // m_case_mng->traceMng()->info() << "full_xpath : " << xpath_view + // << " -- name_view : " << name_view + // << " -- m_params_view.size() : " << m_params_view.size() + // ; + + for (auto param : m_params_view) { + // > 0 car il doit y avoir au moins un "/" entre les deux. + if (param.size()-after_view.size()-before_view.size() > 0) { + StringView begin = param.subView(0, before_view.size()); + if (begin == before_view) { + StringView end = param.subView(param.size()-after_view.size(), after_view.size()); + if (end == after_view) { + // Le "-1" : On retire le "/" à la fin du between. + StringView between = param.subView(before_view.size(), param.size()-after_view.size()-before_view.size()-1); + if (_hasOnlyIndex(between)){ + Integer index = _getIndexAtBegin(between); + if (indexes.contains(index)) { + // TODO Warning : Doublon + } + else { + indexes.add(index); + } + } + } + } + } + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterCaseOption:: +indexesInParam(const String& xpath_before_index, UniqueArray& indexes, bool allow_elems_after_index) +{ + StringView before_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); + + for (auto param : m_params_view) { + // > 0 car il doit y avoir au moins un "/" entre les deux. + if (param.size()-before_view.size() > 0) { + StringView begin = param.subView(0, before_view.size()); + if (begin == before_view) { + StringView end = param.subView(before_view.size()); + if (allow_elems_after_index || _hasOnlyIndex(end)){ + Integer index = _getIndexAtBegin(end); + if (indexes.contains(index)) { + // TODO Warning : Doublon + } + else { + indexes.add(index); + } + } + } + } + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Integer ParameterCaseOption:: +count(const String& xpath_before_index, const String& xpath_after_index) +{ + UniqueArray indexes; + indexesInParam(xpath_before_index, xpath_after_index, indexes); + return indexes.size(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Integer ParameterCaseOption:: +count(const String& xpath_before_index) +{ + UniqueArray indexes; + indexesInParam(xpath_before_index, indexes, false); + return indexes.size(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +StringView ParameterCaseOption:: +_removeUselessPartInXpath(StringView xpath) +{ + if (m_lang == "fr") + return xpath.subView(6); + return xpath.subView(7); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +StringView ParameterCaseOption:: +_removeIndexAtEnd(StringView xpath) +{ + Span bytes_span = xpath.bytes(); + if (bytes_span[bytes_span.size()-1] == ']') { + // bytes_span.size()-3 car on ne peut pas avoir de crochets vides : "[]". + // i >= 2 car il y a forcément quelque chose avant les crochets. + for (Integer i = bytes_span.size()-3; i >= 2; --i) { + if (bytes_span[i] == '[') { + return StringView{bytes_span.subSpan(0, i)}; + } + } + ARCANE_FATAL("Bad xpath"); + } + return xpath; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Integer ParameterCaseOption:: +_getIndexAtEnd(StringView xpath) +{ + if (xpath.size() == 0) return 1; + Span bytes_span = xpath.bytes(); + if (bytes_span[bytes_span.size() - 1] == ']') { + // bytes_span.size()-3 car on ne peut pas avoir de crochets vides : "[]". + // i >= 2 car il y a forcément quelque chose avant les crochets. + for (Integer i = bytes_span.size() - 3; i >= 2; --i) { + if (bytes_span[i] == '[') { + StringView index_str = bytes_span.subSpan(i + 1, bytes_span.size() - 1 - i - 1); + Integer index = 0; + bool is_bad = builtInGetValue(index, index_str); + if (is_bad) { + ARCANE_FATAL("Invalid index"); + } + if (index < 1) { + ARCANE_FATAL("Index in XML start at 1"); + } + return index; + } + } + ARCANE_FATAL("Bad xpath"); + } + return 1; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Integer ParameterCaseOption:: +_getIndexAtBegin(StringView xpath) +{ + if (xpath.size() == 0) return 1; + Span bytes_span = xpath.bytes(); + if (bytes_span[0] == '[') { + for (Integer i = 2; i < bytes_span.size(); ++i) { + if (bytes_span[i] == ']') { + StringView index_str = bytes_span.subSpan(1, i-1); + Integer index = 0; + bool is_bad = builtInGetValue(index, index_str); + if (is_bad) { + ARCANE_FATAL("Invalid index"); + } + if (index < 1) { + ARCANE_FATAL("Index in XML start at 1"); + } + return index; + } + } + ARCANE_FATAL("Bad xpath"); + } + return 1; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Integer ParameterCaseOption:: +_getValueIndex(StringView xpath) +{ + for (Integer i = 0; i < m_params_view.size(); ++i) { + if (m_params_view[i] == xpath) { + return i; + } + } + return -1; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterCaseOption:: +_hasOnlyIndex(StringView xpath_part) +{ + // xpath_before_index=0 (xpath_part="") + if (xpath_part.size() == 0) return true; + Span bytes_span = xpath_part.bytes(); + + // xpath_before_index[0]=0 (xpath_part="[0]") + if (bytes_span.size() < 3) return false; + // xpath_before_indextruc[0]=0 (xpath_part="truc[0]") + if (bytes_span[0] != '[') return false; + + // xpath_before_index[0]/xpath_after_index=0 (xpath_part="[0]") + for (Integer i = 2; i < bytes_span.size(); ++i) { + if (bytes_span[i] == ']') { + return (i == bytes_span.size()-1); + } + } + + // xpath_before_index[0]/truc/xpath_after_index=0 (xpath_part="[0]/truc/") + // xpath_before_index[0]/truc[0]/xpath_after_index=0 (xpath_part="[0]/truc[0]/") + return false; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} // End namespace Arcane + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/ParameterCaseOption.h b/arcane/src/arcane/utils/ParameterCaseOption.h new file mode 100644 index 0000000000..7fe77bf507 --- /dev/null +++ b/arcane/src/arcane/utils/ParameterCaseOption.h @@ -0,0 +1,88 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* ParameterCaseOption.h (C) 2000-2025 */ +/* */ +/* TODO. */ +/*---------------------------------------------------------------------------*/ +#ifndef ARCANE_UTILS_PARAMETERCASEOPTION_H +#define ARCANE_UTILS_PARAMETERCASEOPTION_H +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#include "arcane/core/ICaseMng.h" +#include "arcane/utils/UtilsTypes.h" +#include "arcane/utils/String.h" +#include "arcane/utils/List.h" + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +namespace Arcane +{ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +class ARCANE_UTILS_EXPORT +ParameterCaseOption +{ + + public: + + ParameterCaseOption(ICaseMng* case_mng); + ~ParameterCaseOption()=default; + + public: + + String getParameterOrNull(const String& xpath_before_index, const String& xpath_after_index, Integer index); + String getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_elems_after_index); + String getParameterOrNull(const String& full_xpath); + + bool exist(const String& full_xpath); + + bool existAnyIndex(const String& xpath_before_index, const String& xpath_after_index); + bool existAnyIndex(const String& full_xpath); + + void indexesInParam(const String& xpath_before_index, const String& xpath_after_index, UniqueArray& indexes); + void indexesInParam(const String& xpath_before_index, UniqueArray& indexes, bool allow_elems_after_index); + + Integer count(const String& xpath_before_index, const String& xpath_after_index); + Integer count(const String& xpath_before_index); + + private: + + StringView _removeUselessPartInXpath(StringView xpath); + StringView _removeIndexAtEnd(StringView xpath); + Integer _getIndexAtEnd(StringView xpath); + Integer _getIndexAtBegin(StringView xpath); + + + Integer _getValueIndex(StringView xpath); + + bool _hasOnlyIndex(StringView xpath_part); + + + private: + + StringList m_param_names; + StringList m_values; + UniqueArray m_params_view; + UniqueArray m_values_view; + String m_lang; + ICaseMng* m_case_mng; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} // End namespace Arcane + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#endif diff --git a/arcane/src/arcane/utils/srcs.cmake b/arcane/src/arcane/utils/srcs.cmake index 4ade74bd08..dd317f0f34 100644 --- a/arcane/src/arcane/utils/srcs.cmake +++ b/arcane/src/arcane/utils/srcs.cmake @@ -117,6 +117,8 @@ set(ARCANE_SOURCES ParallelFatalErrorException.h ParallelLoopOptions.h ParallelLoopOptions.cc + ParameterCaseOption.h + ParameterCaseOption.cc PerfCounterMng.cc PerfCounterMng.h PlatformUtils.cc diff --git a/arcane/tests/testCaseOptions-commandLineReplace.arc b/arcane/tests/testCaseOptions-commandLineReplace.arc index 82074aed90..0e5e4ddbb7 100644 --- a/arcane/tests/testCaseOptions-commandLineReplace.arc +++ b/arcane/tests/testCaseOptions-commandLineReplace.arc @@ -34,9 +34,9 @@ - - 9 - false + + true + 50 From 09367460d61518ab6d1a71902c38525c254d1523 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Tue, 11 Feb 2025 13:40:11 +0100 Subject: [PATCH 07/24] [arcane:core,tests] Add 'optional' attribute in .axl when there are minOccurs/maxOccurs - If opt with optional=true/minOccurs=3 : - 0 opt => 0 opt after read - 1 opt => 3 opt after read (1 in .arc / 2 default) - 2 opt => 3 opt after read (2 in .arc / 1 default) - &c - If opt with optional=false/minOccurs=3 : - 0 opt => 3 opt after read (0 in .arc / 3 default) - 1 opt => 3 opt after read (1 in .arc / 2 default) - 2 opt => 3 opt after read (2 in .arc / 1 default) - &c --- arcane/src/arcane/core/CaseOptionSimple.h | 1 + arcane/src/arcane/tests/CaseOptionsTester.axl | 1 + 2 files changed, 2 insertions(+) diff --git a/arcane/src/arcane/core/CaseOptionSimple.h b/arcane/src/arcane/core/CaseOptionSimple.h index f8d05177b9..2eda02f0be 100644 --- a/arcane/src/arcane/core/CaseOptionSimple.h +++ b/arcane/src/arcane/core/CaseOptionSimple.h @@ -385,6 +385,7 @@ class CaseOptionMultiSimpleT const T& value(Integer index) const { return this->operator[](index); } Integer size() const { return ArrayView::size(); } ARCANE_CORE_EXPORT void visit(ICaseDocumentVisitor* visitor) const override; + bool isPresent() const { return !m_view.empty(); } protected: diff --git a/arcane/src/arcane/tests/CaseOptionsTester.axl b/arcane/src/arcane/tests/CaseOptionsTester.axl index 0021877581..a964d33599 100644 --- a/arcane/src/arcane/tests/CaseOptionsTester.axl +++ b/arcane/src/arcane/tests/CaseOptionsTester.axl @@ -130,6 +130,7 @@ From 6a494787e377a83ae14f44534f967360f7a73ed6 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Tue, 11 Feb 2025 13:41:16 +0100 Subject: [PATCH 08/24] [arcane:core] Add ParameterCaseOption support in CaseOptionExtended --- arcane/src/arcane/core/CaseOptionExtended.cc | 80 +++++++++++++++++--- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/arcane/src/arcane/core/CaseOptionExtended.cc b/arcane/src/arcane/core/CaseOptionExtended.cc index 8a60e1e046..9848735fd5 100644 --- a/arcane/src/arcane/core/CaseOptionExtended.cc +++ b/arcane/src/arcane/core/CaseOptionExtended.cc @@ -15,12 +15,19 @@ #include "arcane/utils/ITraceMng.h" #include "arcane/utils/FatalErrorException.h" +#include "arcane/utils/ApplicationInfo.h" +#include "arcane/utils/CommandLineArguments.h" +#include "arcane/utils/ParameterList.h" +#include "arcane/utils/ParameterCaseOption.h" +#include "arcane/core/IApplication.h" +#include "arcane/core/ICaseMng.h" #include "arcane/core/CaseOptionError.h" #include "arcane/core/ICaseDocumentVisitor.h" #include "arcane/core/XmlNodeList.h" #include "arcane/core/ICaseOptionList.h" #include "arcane/core/MeshHandle.h" +#include "arcane/core/internal/StringVariableReplace.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -41,25 +48,76 @@ namespace Arcane void CaseOptionMultiExtended:: _search(bool is_phase1) { - XmlNodeList elem_list = rootElement().children(name()); ITraceMng* tm = traceMng(); + const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); + ParameterCaseOption pco{ caseMng() }; + + // !!! En XML, on commence par 1 et non 0. + UniqueArray option_in_param; + pco.indexesInParam(String::format("{0}/{1}", rootElement().xpathFullName(), name()), option_in_param, false); + + XmlNodeList elem_list = rootElement().children(name()); Integer size = elem_list.size(); - _checkMinMaxOccurs(size); - if (size==0) + bool is_optional = isOptional(); + + if (size == 0 && option_in_param.empty() && is_optional) { return; + } + + Integer min_occurs = minOccurs(); + Integer max_occurs = maxOccurs(); - if (is_phase1){ - _allocate(size); - m_values.resize(size); + Integer max_in_param = 0; + + if (!option_in_param.empty()) { + max_in_param = option_in_param[0]; + for (Integer index : option_in_param) { + if (index > max_in_param) + max_in_param = index; + } + if (max_occurs >= 0) { + if (max_in_param > max_occurs) { + ARCANE_FATAL("Max in param > max_occurs"); + } + } + } + + if (max_occurs >= 0) { + if (size > max_occurs) { + ARCANE_FATAL("Nb in XmlNodeList > max_occurs"); + } + } + + Integer final_size = std::max(size, std::max(min_occurs, max_in_param)); + + if (is_phase1) { + _allocate(final_size); + m_values.resize(final_size); } else{ //cerr << "** MULTI SEARCH " << size << endl; - for( Integer i=0; i Date: Wed, 12 Feb 2025 14:11:29 +0100 Subject: [PATCH 09/24] [arcane:core] Remove multiple String creation --- arcane/src/arcane/core/CaseOptionService.cc | 7 ++++--- arcane/src/arcane/core/CaseOptionSimple.cc | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arcane/src/arcane/core/CaseOptionService.cc b/arcane/src/arcane/core/CaseOptionService.cc index 3a5968fa79..04f737f93e 100644 --- a/arcane/src/arcane/core/CaseOptionService.cc +++ b/arcane/src/arcane/core/CaseOptionService.cc @@ -389,10 +389,11 @@ multiAllocate(const XmlNodeList& elem_list) XmlNode parent_element = configList()->parentElement(); + String full_xpath = String::format("{0}/{1}", parent_element.xpathFullName(), name()); // !!! En XML, on commence par 1 et non 0. UniqueArray option_in_param; - pco.indexesInParam(String::format("{0}/{1}", parent_element.xpathFullName(), name()), option_in_param, true); + pco.indexesInParam(full_xpath, option_in_param, true); Integer size = elem_list.size(); @@ -445,8 +446,8 @@ multiAllocate(const XmlNodeList& elem_list) String str_val; if (option_in_param.contains(index + 1)) { - mesh_name = pco.getParameterOrNull(String::format("{0}/{1}", parent_element.xpathFullName(), name()), "@mesh-name", index + 1); - str_val = pco.getParameterOrNull(String::format("{0}/{1}", parent_element.xpathFullName(), name()), "@name", index + 1); + mesh_name = pco.getParameterOrNull(full_xpath, "@mesh-name", index + 1); + str_val = pco.getParameterOrNull(full_xpath, "@name", index + 1); } if (index < size && (mesh_name.null() || str_val.null())) { element = elem_list[index]; diff --git a/arcane/src/arcane/core/CaseOptionSimple.cc b/arcane/src/arcane/core/CaseOptionSimple.cc index 45cd99068f..d0fb85c4c0 100644 --- a/arcane/src/arcane/core/CaseOptionSimple.cc +++ b/arcane/src/arcane/core/CaseOptionSimple.cc @@ -664,10 +664,11 @@ _search(bool is_phase1) const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); ParameterCaseOption pco{ caseMng() }; + String full_xpath = String::format("{0}/{1}", rootElement().xpathFullName(), name()); // !!! En XML, on commence par 1 et non 0. UniqueArray option_in_param; - pco.indexesInParam(String::format("{0}/{1}", rootElement().xpathFullName(), name()), option_in_param, false); + pco.indexesInParam(full_xpath, option_in_param, false); XmlNodeList elem_list = rootElement().children(name()); Integer asize = elem_list.size(); @@ -716,7 +717,7 @@ _search(bool is_phase1) String str_val; if (option_in_param.contains(i + 1)) { - str_val = pco.getParameterOrNull(String::format("{0}/{1}", rootElement().xpathFullName(), name()), i + 1, false); + str_val = pco.getParameterOrNull(full_xpath, i + 1, false); } else if (i < asize) { XmlNode velem = elem_list[i]; From 02b234f2c24c917c096e465ce723e404f04c64ff Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Wed, 12 Feb 2025 16:08:18 +0100 Subject: [PATCH 10/24] [arcane:utils] Create new structs 'ParameterCaseOptionLine/Part' to improve extensibility of ParameterCaseOption --- .../src/arcane/utils/ParameterCaseOption.cc | 155 ++++++++++++++++++ arcane/src/arcane/utils/ParameterCaseOption.h | 5 +- 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/arcane/src/arcane/utils/ParameterCaseOption.cc b/arcane/src/arcane/utils/ParameterCaseOption.cc index 8499d103e3..ff1ab65200 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.cc +++ b/arcane/src/arcane/utils/ParameterCaseOption.cc @@ -34,9 +34,144 @@ namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +struct ParameterOptionPart +{ + StringView m_part; + Integer m_index; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +class ParameterOptionLine +{ + public: + + explicit ParameterOptionLine(const StringView line) + { + Span span_line(line.bytes()); + Integer begin = 0; + Integer size = 0; + Integer index_begin = -1; + + // aaa[0] + for (Integer i = 0; i < span_line.size(); ++i) { + if (span_line[i] == '[') { + index_begin = i + 1; + size = i - begin; + ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); + ARCANE_ASSERT(index_begin < span_line.size(), ("Invalid option (']' not found)")); + } + else if (span_line[i] == ']') { + ARCANE_ASSERT(index_begin != i, ("Invalid option ('[]' found without integer)")); + ARCANE_ASSERT(index_begin != -1, ("Invalid option (']' found without '[')")); + + StringView index_str = line.subView(index_begin, i - index_begin); + Integer index; + bool is_bad = builtInGetValue(index, index_str); + if (is_bad) { + ARCANE_FATAL("Invalid index"); + } + m_parts.add({ line.subView(begin, size), index }); + } + else if (span_line[i] == '/') { + ARCANE_ASSERT(i + 1 != span_line.size(), ("Invalid option ('/' found at the end of the param option)")); + + if (index_begin == -1) { + size = i - begin; + ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); + + m_parts.add({ line.subView(begin, size), 1 }); + } + + begin = i + 1; + size = 0; + index_begin = -1; + } + } + if (index_begin == -1) { + size = span_line.size() - begin; + ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); + + m_parts.add({ line.subView(begin, size), 1 }); + } + m_parts.shrink(); + } + + public: + + ParameterOptionPart getPart(Integer index) + { + return m_parts[index]; + } + + Integer nbPart() + { + return m_parts.size(); + } + + private: + + UniqueArray m_parts; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +class ParameterCaseOptionLine +{ + public: + + ParameterCaseOptionLine(StringView line, StringView value) + : m_line(line) + , m_value(value) + {} + + ParameterOptionLine getLine() + { + return m_line; + } + + StringView getValue() const + { + return m_value; + } + + private: + + ParameterOptionLine m_line; + StringView m_value; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +class ParameterCaseOptionMultiLine +{ + public: + + void addOption(StringView line, StringView value) + { + m_lines.add({ line, value }); + } + + ParameterCaseOptionLine getOption(Integer index) + { + return m_lines[index]; + } + + private: + + UniqueArray m_lines; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + ParameterCaseOption:: ParameterCaseOption(ICaseMng* case_mng) : m_case_mng(case_mng) +, m_lines(new ParameterCaseOptionMultiLine) { m_lang = m_case_mng->caseDocumentFragment()->language(); @@ -53,11 +188,31 @@ ParameterCaseOption(ICaseMng* case_mng) if (param.startsWith("//")) { m_params_view.add(param.view().subView(2)); m_values_view.add(m_values[i].view()); + + m_lines->addOption(param.view().subView(2), m_values[i].view()); + true_size++; } } m_params_view.resize(true_size); m_values_view.resize(true_size); + + ITraceMng* tm = case_mng->traceMng(); + tm->info() << "Try with : " << m_params_view[2]; + ParameterCaseOptionLine pa(m_lines->getOption(2)); + ParameterOptionLine line = pa.getLine(); + for (Integer i = 0; i < line.nbPart(); ++i) { + tm->info() << "i : " << i << " -- elem : " << line.getPart(i).m_part << " -- index : " << line.getPart(i).m_index; + } + tm->info() << "Value : " << pa.getValue(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterCaseOption::~ParameterCaseOption() +{ + delete m_lines; } /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/ParameterCaseOption.h b/arcane/src/arcane/utils/ParameterCaseOption.h index 7fe77bf507..f27d150df3 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.h +++ b/arcane/src/arcane/utils/ParameterCaseOption.h @@ -28,6 +28,8 @@ namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +class ParameterCaseOptionMultiLine; + class ARCANE_UTILS_EXPORT ParameterCaseOption { @@ -35,7 +37,7 @@ ParameterCaseOption public: ParameterCaseOption(ICaseMng* case_mng); - ~ParameterCaseOption()=default; + ~ParameterCaseOption(); public: @@ -75,6 +77,7 @@ ParameterCaseOption UniqueArray m_values_view; String m_lang; ICaseMng* m_case_mng; + ParameterCaseOptionMultiLine* m_lines; }; /*---------------------------------------------------------------------------*/ From a7ffe262515398325137733a5f5b1df68806d1ae Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Fri, 14 Feb 2025 11:40:57 +0100 Subject: [PATCH 11/24] [arcane:utils,tests] Replace old methods in ParameterCaseOption with new methods using ParameterOption classes --- arcane/src/arcane/tests/CMakeLists.txt | 4 +- .../src/arcane/utils/ParameterCaseOption.cc | 656 +++++++++--------- arcane/src/arcane/utils/ParameterCaseOption.h | 16 +- .../testCaseOptions-commandLineReplace.arc | 2 - 4 files changed, 345 insertions(+), 333 deletions(-) diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index 8802432b4d..ec6c1c03bf 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -363,10 +363,12 @@ arcane_add_test_sequential(caseoptions_commandlinereplace testCaseOptions-comman "-A,//case-options-tester/simple-enum=enum1" "-A,PostProcessor1FrName=Ensight7PostProcessor" "-A,//case-options-tester/post-processor1/fileset-size=1" - "-A,//case-options-tester/post-processor1/binary-file=false" + "-A,//case-options-tester/post-processor1[1]/binary-file=false" "-A,//case-options-tester/post-processor1[3]/@name=VtkHdfV2PostProcessor" "-A,//case-options-tester/post-processor1[4]/@name=UCDPostProcessor" "-A,//case-options-tester/post-processor2[2]/@mesh-name=Mesh1" + "-A,//case-options-tester/complex1/simple-real-2=3" + "-A,//case-options-tester/complex1/simple-real-2-multi[2]=2.3" ) if(UDUNITS_FOUND) diff --git a/arcane/src/arcane/utils/ParameterCaseOption.cc b/arcane/src/arcane/utils/ParameterCaseOption.cc index ff1ab65200..c94a14c85d 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.cc +++ b/arcane/src/arcane/utils/ParameterCaseOption.cc @@ -19,27 +19,94 @@ #include "arcane/core/IApplication.h" #include "arcane/core/ICaseDocument.h" #include "arcane/utils/ValueConvert.h" -#include "arcane/utils/String.h" -#include "arcane/utils/StringDictionary.h" #include "arcane/utils/Array.h" #include "arcane/utils/FatalErrorException.h" -#include "arccore/trace/ITraceMng.h" +#include "arcane/utils/ITraceMng.h" +#include "arcane/utils/Ref.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +namespace +{ +const Arcane::String ANY_TAG_STR = "/"; +const Arcane::StringView ANY_TAG = ANY_TAG_STR.view(); +constexpr Arcane::Integer ANY_INDEX = -1; +constexpr Arcane::Integer GET_INDEX = -2; +} // namespace + namespace Arcane { /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -struct ParameterOptionPart +class ParameterOptionPart { - StringView m_part; + public: + + ParameterOptionPart() + : m_tag(ANY_TAG) + , m_index(ANY_INDEX) + {} + + explicit ParameterOptionPart(const StringView tag) + : m_tag(tag) + , m_index(1) + { + ARCANE_ASSERT(tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbiden")); + } + + ParameterOptionPart(const StringView tag, const Integer index) + : m_tag(tag) + , m_index(index) + { + ARCANE_ASSERT(index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbiden")); + } + + public: + + StringView tag() const + { + return m_tag; + } + Integer index() const + { + return m_index; + } + void setTag(const StringView tag) + { + ARCANE_ASSERT(m_index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbiden")); + m_tag = tag; + } + void setIndex(const Integer index) + { + m_index = index; + } + bool isAny() const + { + return (m_tag == ANY_TAG && m_index == ANY_INDEX); + } + bool operator==(const ParameterOptionPart& other) const + { + return (m_tag == other.m_tag || m_tag == ANY_TAG || other.m_tag == ANY_TAG) && + (m_index == other.m_index || m_index == ANY_INDEX || other.m_index == ANY_INDEX || m_index == GET_INDEX || other.m_index == GET_INDEX); + } + + private: + + StringView m_tag; Integer m_index; }; +std::ostream& operator<<(std::ostream& o, const ParameterOptionPart& h) +{ + o << (h.tag() == ANY_TAG ? "ANY" : h.tag()) + << "[" << (h.index() == ANY_INDEX ? "ANY" : (h.index() == GET_INDEX ? "GET" : std::to_string(h.index()))) + << "]"; + return o; +} + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -53,6 +120,8 @@ class ParameterOptionLine Integer begin = 0; Integer size = 0; Integer index_begin = -1; + // On interdit les options qui s'appliquent à toutes les caseoptions. + bool have_a_no_any = false; // aaa[0] for (Integer i = 0; i < span_line.size(); ++i) { @@ -72,16 +141,23 @@ class ParameterOptionLine if (is_bad) { ARCANE_FATAL("Invalid index"); } - m_parts.add({ line.subView(begin, size), index }); + m_parts.add(makeRef(new ParameterOptionPart(line.subView(begin, size), index))); + have_a_no_any = true; } + else if (span_line[i] == '/') { ARCANE_ASSERT(i + 1 != span_line.size(), ("Invalid option ('/' found at the end of the param option)")); if (index_begin == -1) { size = i - begin; - ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); - - m_parts.add({ line.subView(begin, size), 1 }); + // Cas ou on a un any_tag any_index ("truc1//truc2"). + if (size == 0) { + m_parts.add(makeRef(new ParameterOptionPart())); + } + else { + m_parts.add(makeRef(new ParameterOptionPart(line.subView(begin, size)))); + have_a_no_any = true; + } } begin = i + 1; @@ -90,31 +166,117 @@ class ParameterOptionLine } } if (index_begin == -1) { - size = span_line.size() - begin; + size = static_cast(span_line.size()) - begin; ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); - m_parts.add({ line.subView(begin, size), 1 }); + m_parts.add(makeRef(new ParameterOptionPart(line.subView(begin, size)))); + have_a_no_any = true; + } + if (!have_a_no_any) { + ARCANE_FATAL("Invalid option"); } - m_parts.shrink(); } public: - ParameterOptionPart getPart(Integer index) + // On ne doit pas bloquer les multiples ParameterOptionPart(ANY) : + // Construction par iteration : aaaa/bb/ANY/ANY/cc + void addPart(ParameterOptionPart* part) + { + m_parts.add(makeRef(part)); + } + + ParameterOptionPart* part(const Integer index) const + { + if (index >= m_parts.size()) { + if (m_parts[m_parts.size() - 1]->isAny()) { + return lastPart(); + } + ARCANE_FATAL("Invalid index"); + } + return m_parts[index].get(); + } + + ParameterOptionPart* lastPart() const { - return m_parts[index]; + return m_parts[m_parts.size() - 1].get(); } - Integer nbPart() + Integer nbPart() const { return m_parts.size(); } + bool getIndexes(const ParameterOptionLine& with_get_index, ArrayView indexes) const + { + if (!operator==(with_get_index)) + return false; + + Integer index = 0; + for (Integer i = 0; i < with_get_index.nbPart(); ++i) { + if (with_get_index.part(i)->index() == GET_INDEX) { + Integer index_tag = part(i)->index(); + if (index_tag == ANY_INDEX) + return false; + indexes[index++] = index_tag; + } + } + return true; + } + + Integer nbIndexToGet() const + { + Integer count = 0; + for (const auto& elem : m_parts) { + if (elem->index() == GET_INDEX) { + count++; + } + } + return count; + } + + public: + + bool operator==(const ParameterOptionLine& other) const + { + Integer nb_iter = 0; + if (lastPart()->isAny()) { + nb_iter = nbPart() - 1; + } + else if (other.lastPart()->isAny()) { + nb_iter = other.nbPart() - 1; + } + else if (nbPart() != other.nbPart()) { + return false; + } + else { + nb_iter = nbPart(); + } + + for (Integer i = 0; i < nb_iter; ++i) { + if (*part(i) != *other.part(i)) { + return false; + } + } + return true; + } + private: - UniqueArray m_parts; + UniqueArray> m_parts; }; +std::ostream& operator<<(std::ostream& o, const ParameterOptionLine& h) +{ + Integer nb_part = h.nbPart(); + if (nb_part != 0) + o << *(h.part(0)); + for (Integer i = 1; i < nb_part; ++i) { + o << "/" << *(h.part(i)); + } + return o; +} + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -127,7 +289,7 @@ class ParameterCaseOptionLine , m_value(value) {} - ParameterOptionLine getLine() + ParameterOptionLine getLine() const { return m_line; } @@ -137,6 +299,11 @@ class ParameterCaseOptionLine return m_value; } + bool operator==(const ParameterOptionLine& line) const + { + return m_line == line; + } + private: ParameterOptionLine m_line; @@ -160,6 +327,44 @@ class ParameterCaseOptionMultiLine return m_lines[index]; } + std::optional getValueOrNull(const ParameterOptionLine& line) + { + for (const auto& elem : m_lines) { + if (elem == line) + return elem.getValue(); + } + return {}; + } + + bool exist(const ParameterOptionLine& line) + { + for (const auto& elem : m_lines) { + if (elem == line) + return true; + } + return false; + } + + Integer existAndCount(const ParameterOptionLine& line) + { + Integer count = 0; + for (const auto& elem : m_lines) { + if (elem == line) + count++; + } + return count; + } + + void getIndexesOfLine(const ParameterOptionLine& line, UniqueArray& indexes) + { + UniqueArray new_indexes(line.nbIndexToGet()); + for (const auto& elem : m_lines) { + if (elem.getLine().getIndexes(line, new_indexes)) { + indexes.addRange(new_indexes); + } + } + } + private: UniqueArray m_lines; @@ -177,34 +382,15 @@ ParameterCaseOption(ICaseMng* case_mng) m_case_mng->application()->applicationInfo().commandLineArguments().parameters().fillParameters(m_param_names, m_values); - Integer size = m_param_names.count(); - - m_params_view.reserve(size); - m_values_view.reserve(size); - - Integer true_size = 0; + //Integer d_count = 0; for (Integer i = 0; i < m_param_names.count(); ++i) { const String& param = m_param_names[i]; if (param.startsWith("//")) { - m_params_view.add(param.view().subView(2)); - m_values_view.add(m_values[i].view()); - m_lines->addOption(param.view().subView(2), m_values[i].view()); - - true_size++; + //m_case_mng->traceMng()->info() << "AddOption : " << m_lines->getOption(d_count).getLine() << " = " << m_lines->getOption(d_count).getValue(); + //d_count++; } } - m_params_view.resize(true_size); - m_values_view.resize(true_size); - - ITraceMng* tm = case_mng->traceMng(); - tm->info() << "Try with : " << m_params_view[2]; - ParameterCaseOptionLine pa(m_lines->getOption(2)); - ParameterOptionLine line = pa.getLine(); - for (Integer i = 0; i < line.nbPart(); ++i) { - tm->info() << "i : " << i << " -- elem : " << line.getPart(i).m_part << " -- index : " << line.getPart(i).m_index; - } - tm->info() << "Value : " << pa.getValue(); } /*---------------------------------------------------------------------------*/ @@ -222,27 +408,26 @@ ParameterCaseOption::~ParameterCaseOption() String ParameterCaseOption:: getParameterOrNull(const String& xpath_before_index, const String& xpath_after_index, Integer index) { + // m_case_mng->traceMng()->info() << "getParameterOrNull(SSI)"; + // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index + // << " -- xpath_after_index : " << xpath_after_index + // << " -- index : " << index; if (index <= 0) { ARCANE_FATAL("Index in XML start at 1"); } - StringView xpath_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); - - String xpath_with_index_attr = String::format("{0}[{1}]/{2}", xpath_view, index, xpath_after_index); + ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; + line.lastPart()->setIndex(index); + line.addPart(new ParameterOptionPart(xpath_after_index.view())); - if (index > 1) { - Integer index_value = _getValueIndex(xpath_with_index_attr); - if (index_value == -1) - return {}; - return m_values_view[index_value]; - } + // m_case_mng->traceMng()->info() << "Line : " << line; - String xpath_with_attr = String::format("{0}/{1}", xpath_view, xpath_after_index); - for (Integer i = 0; i < m_params_view.size(); ++i) { - if (m_params_view[i] == xpath_with_index_attr.view() || m_params_view[i] == xpath_with_attr.view()) { - return m_values_view[i]; - } + std::optional value = m_lines->getValueOrNull(line); + if (value.has_value()) { + // m_case_mng->traceMng()->info() << "Ret : " << value.value(); + return value.value(); } + // m_case_mng->traceMng()->info() << "Ret : {}"; return {}; } @@ -252,64 +437,26 @@ getParameterOrNull(const String& xpath_before_index, const String& xpath_after_i String ParameterCaseOption:: getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_elems_after_index) { + // m_case_mng->traceMng()->info() << "getParameterOrNull(SIB)"; + // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index + // << " -- index : " << index + // << " -- allow_elems_after_index : " << allow_elems_after_index; if (index <= 0) { ARCANE_FATAL("Index in XML start at 1"); } - - StringView xpath_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); - - String xpath_with_index_attr = String::format("{0}[{1}]", xpath_view, index); - - + ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; + line.lastPart()->setIndex(index); if (allow_elems_after_index) { - StringView before_view_with_attr = xpath_with_index_attr.view(); - if (index > 1) { - for (Integer i = 0; i < m_params_view.size(); ++i) { - StringView param = m_params_view[i]; - if (param.size()-before_view_with_attr.size() >= 0) { - StringView begin = param.subView(0, before_view_with_attr.size()); - if (begin == before_view_with_attr) { - return m_values_view[i]; - } - } - } - return {}; - } - - for (Integer i = 0; i < m_params_view.size(); ++i) { - StringView param = m_params_view[i]; - if (param.size()-xpath_view.size() >= 0) { - StringView begin = param.subView(0, xpath_view.size()); - if (begin == xpath_view) { - return m_values_view[i]; - } - } - if (param.size()-before_view_with_attr.size() >= 0) { - StringView begin = param.subView(0, before_view_with_attr.size()); - if (begin == before_view_with_attr) { - return m_values_view[i]; - } - } - } - return {}; - + line.addPart(new ParameterOptionPart()); } - else { - if (index > 1) { - for (Integer i = 0; i < m_params_view.size(); ++i) { - if (m_params_view[i] == xpath_with_index_attr.view()) { - return m_values_view[i]; - } - } - return {}; - } - for (Integer i = 0; i < m_params_view.size(); ++i) { - if (m_params_view[i] == xpath_view || m_params_view[i] == xpath_with_index_attr.view()) { - return m_values_view[i]; - } - } + // m_case_mng->traceMng()->info() << "Line : " << line; + std::optional value = m_lines->getValueOrNull(line); + if (value.has_value()) { + // m_case_mng->traceMng()->info() << "Ret : " << value.value(); + return value.value(); } + // m_case_mng->traceMng()->info() << "Ret : {}"; return {}; } @@ -319,12 +466,20 @@ getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_e String ParameterCaseOption:: getParameterOrNull(const String& full_xpath) { - Integer index_value = _getValueIndex(_removeUselessPartInXpath(full_xpath)); - if (index_value == -1) return {}; - return m_values_view[index_value]; -} + // m_case_mng->traceMng()->info() << "getParameterOrNull(S)"; + // m_case_mng->traceMng()->info() << "full_xpath : " << full_xpath; + const ParameterOptionLine line{ _removeUselessPartInXpath(full_xpath.view()) }; + // m_case_mng->traceMng()->info() << "Line : " << line; + std::optional value = m_lines->getValueOrNull(line); + if (value.has_value()) { + // m_case_mng->traceMng()->info() << "Ret : " << value.value(); + return value.value(); + } + // m_case_mng->traceMng()->info() << "Ret : {}"; + return {}; +} /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -332,14 +487,14 @@ getParameterOrNull(const String& full_xpath) bool ParameterCaseOption:: exist(const String& full_xpath) { - StringView xpath = _removeUselessPartInXpath(full_xpath); + // m_case_mng->traceMng()->info() << "exist(S)"; + // m_case_mng->traceMng()->info() << "full_xpath : " << full_xpath; + const ParameterOptionLine line{ _removeUselessPartInXpath(full_xpath.view()) }; - for (auto param : m_params_view) { - if (param == xpath) { - return true; - } - } - return false; + // m_case_mng->traceMng()->info() << "Line : " << line; + // m_case_mng->traceMng()->info() << "Ret : " << m_lines->exist(line); + + return m_lines->exist(line); } /*---------------------------------------------------------------------------*/ @@ -348,26 +503,19 @@ exist(const String& full_xpath) bool ParameterCaseOption:: existAnyIndex(const String& xpath_before_index, const String& xpath_after_index) { - StringView before_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); - StringView after_view = xpath_after_index.view(); - - for (auto param : m_params_view) { - // > 0 car il doit y avoir au moins un "/" entre les deux. - if (param.size()-after_view.size()-before_view.size() > 0) { - StringView begin = param.subView(0, before_view.size()); - if (begin == before_view) { - StringView end = param.subView(param.size()-after_view.size(), after_view.size()); - if (end == after_view) { - // Le "-1" : On retire le "/" à la fin du between. - StringView between = param.subView(before_view.size(), param.size()-after_view.size()-before_view.size()-1); - if (_hasOnlyIndex(between)){ - return true; - } - } - } - } - } - return false; + // m_case_mng->traceMng()->info() << "existAnyIndex(SS)"; + // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index + // << " -- xpath_after_index : " << xpath_after_index; + + ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; + line.lastPart()->setIndex(ANY_INDEX); + + line.addPart(new ParameterOptionPart(xpath_after_index.view())); + + // m_case_mng->traceMng()->info() << "Line : " << line; + // m_case_mng->traceMng()->info() << "Ret : " << m_lines->exist(line); + + return m_lines->exist(line); } /*---------------------------------------------------------------------------*/ @@ -376,14 +524,16 @@ existAnyIndex(const String& xpath_before_index, const String& xpath_after_index) bool ParameterCaseOption:: existAnyIndex(const String& full_xpath) { - StringView xpath_view = _removeIndexAtEnd(_removeUselessPartInXpath(full_xpath)); + // m_case_mng->traceMng()->info() << "existAnyIndex(S)"; + // m_case_mng->traceMng()->info() << "full_xpath : " << full_xpath; - for (auto param : m_params_view) { - if (_removeIndexAtEnd(param) == xpath_view) { - return true; - } - } - return false; + ParameterOptionLine line{ _removeUselessPartInXpath(full_xpath.view()) }; + line.lastPart()->setIndex(ANY_INDEX); + + // m_case_mng->traceMng()->info() << "Line : " << line; + // m_case_mng->traceMng()->info() << "Ret : " << m_lines->exist(line); + + return m_lines->exist(line); } /*---------------------------------------------------------------------------*/ @@ -392,36 +542,19 @@ existAnyIndex(const String& full_xpath) void ParameterCaseOption:: indexesInParam(const String& xpath_before_index, const String& xpath_after_index, UniqueArray& indexes) { - StringView before_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); - StringView after_view = xpath_after_index.view(); - - // m_case_mng->traceMng()->info() << "full_xpath : " << xpath_view - // << " -- name_view : " << name_view - // << " -- m_params_view.size() : " << m_params_view.size() - // ; - - for (auto param : m_params_view) { - // > 0 car il doit y avoir au moins un "/" entre les deux. - if (param.size()-after_view.size()-before_view.size() > 0) { - StringView begin = param.subView(0, before_view.size()); - if (begin == before_view) { - StringView end = param.subView(param.size()-after_view.size(), after_view.size()); - if (end == after_view) { - // Le "-1" : On retire le "/" à la fin du between. - StringView between = param.subView(before_view.size(), param.size()-after_view.size()-before_view.size()-1); - if (_hasOnlyIndex(between)){ - Integer index = _getIndexAtBegin(between); - if (indexes.contains(index)) { - // TODO Warning : Doublon - } - else { - indexes.add(index); - } - } - } - } - } - } + // m_case_mng->traceMng()->info() << "indexesInParam(SSU)"; + // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index + // << " -- xpath_after_index : " << xpath_after_index + // << " -- indexes : " << indexes; + + ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; + line.lastPart()->setIndex(GET_INDEX); + line.addPart(new ParameterOptionPart(xpath_after_index.view())); + + // m_case_mng->traceMng()->info() << "Line : " << line; + + m_lines->getIndexesOfLine(line, indexes); + // m_case_mng->traceMng()->info() << "indexes : " << indexes; } /*---------------------------------------------------------------------------*/ @@ -430,26 +563,20 @@ indexesInParam(const String& xpath_before_index, const String& xpath_after_index void ParameterCaseOption:: indexesInParam(const String& xpath_before_index, UniqueArray& indexes, bool allow_elems_after_index) { - StringView before_view = _removeIndexAtEnd(_removeUselessPartInXpath(xpath_before_index)); - - for (auto param : m_params_view) { - // > 0 car il doit y avoir au moins un "/" entre les deux. - if (param.size()-before_view.size() > 0) { - StringView begin = param.subView(0, before_view.size()); - if (begin == before_view) { - StringView end = param.subView(before_view.size()); - if (allow_elems_after_index || _hasOnlyIndex(end)){ - Integer index = _getIndexAtBegin(end); - if (indexes.contains(index)) { - // TODO Warning : Doublon - } - else { - indexes.add(index); - } - } - } - } + // m_case_mng->traceMng()->info() << "indexesInParam(SUB)"; + // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index + // << " -- indexes : " << indexes + // << " -- allow_elems_after_index : " << allow_elems_after_index; + + ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; + line.lastPart()->setIndex(GET_INDEX); + if (allow_elems_after_index) { + line.addPart(new ParameterOptionPart()); } + + // m_case_mng->traceMng()->info() << "Line : " << line; + m_lines->getIndexesOfLine(line, indexes); + // m_case_mng->traceMng()->info() << "indexes : " << indexes; } /*---------------------------------------------------------------------------*/ @@ -458,9 +585,17 @@ indexesInParam(const String& xpath_before_index, UniqueArray& indexes, Integer ParameterCaseOption:: count(const String& xpath_before_index, const String& xpath_after_index) { - UniqueArray indexes; - indexesInParam(xpath_before_index, xpath_after_index, indexes); - return indexes.size(); + // m_case_mng->traceMng()->info() << "count(SS)"; + // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index + // << " -- xpath_after_index : " << xpath_after_index; + + ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; + line.lastPart()->setIndex(ANY_INDEX); + line.addPart(new ParameterOptionPart(xpath_after_index.view())); + // m_case_mng->traceMng()->info() << "Line : " << line; + // m_case_mng->traceMng()->info() << "Ret : " << m_lines->existAndCount(line); + + return m_lines->existAndCount(line); } /*---------------------------------------------------------------------------*/ @@ -469,9 +604,15 @@ count(const String& xpath_before_index, const String& xpath_after_index) Integer ParameterCaseOption:: count(const String& xpath_before_index) { - UniqueArray indexes; - indexesInParam(xpath_before_index, indexes, false); - return indexes.size(); + // m_case_mng->traceMng()->info() << "count(S)"; + // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index; + + ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; + line.lastPart()->setIndex(ANY_INDEX); + // m_case_mng->traceMng()->info() << "Line : " << line; + // m_case_mng->traceMng()->info() << "Ret : " << m_lines->existAndCount(line); + + return m_lines->existAndCount(line); } /*---------------------------------------------------------------------------*/ @@ -480,7 +621,7 @@ count(const String& xpath_before_index) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -StringView ParameterCaseOption:: +inline StringView ParameterCaseOption:: _removeUselessPartInXpath(StringView xpath) { if (m_lang == "fr") @@ -491,125 +632,6 @@ _removeUselessPartInXpath(StringView xpath) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -StringView ParameterCaseOption:: -_removeIndexAtEnd(StringView xpath) -{ - Span bytes_span = xpath.bytes(); - if (bytes_span[bytes_span.size()-1] == ']') { - // bytes_span.size()-3 car on ne peut pas avoir de crochets vides : "[]". - // i >= 2 car il y a forcément quelque chose avant les crochets. - for (Integer i = bytes_span.size()-3; i >= 2; --i) { - if (bytes_span[i] == '[') { - return StringView{bytes_span.subSpan(0, i)}; - } - } - ARCANE_FATAL("Bad xpath"); - } - return xpath; -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -Integer ParameterCaseOption:: -_getIndexAtEnd(StringView xpath) -{ - if (xpath.size() == 0) return 1; - Span bytes_span = xpath.bytes(); - if (bytes_span[bytes_span.size() - 1] == ']') { - // bytes_span.size()-3 car on ne peut pas avoir de crochets vides : "[]". - // i >= 2 car il y a forcément quelque chose avant les crochets. - for (Integer i = bytes_span.size() - 3; i >= 2; --i) { - if (bytes_span[i] == '[') { - StringView index_str = bytes_span.subSpan(i + 1, bytes_span.size() - 1 - i - 1); - Integer index = 0; - bool is_bad = builtInGetValue(index, index_str); - if (is_bad) { - ARCANE_FATAL("Invalid index"); - } - if (index < 1) { - ARCANE_FATAL("Index in XML start at 1"); - } - return index; - } - } - ARCANE_FATAL("Bad xpath"); - } - return 1; -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -Integer ParameterCaseOption:: -_getIndexAtBegin(StringView xpath) -{ - if (xpath.size() == 0) return 1; - Span bytes_span = xpath.bytes(); - if (bytes_span[0] == '[') { - for (Integer i = 2; i < bytes_span.size(); ++i) { - if (bytes_span[i] == ']') { - StringView index_str = bytes_span.subSpan(1, i-1); - Integer index = 0; - bool is_bad = builtInGetValue(index, index_str); - if (is_bad) { - ARCANE_FATAL("Invalid index"); - } - if (index < 1) { - ARCANE_FATAL("Index in XML start at 1"); - } - return index; - } - } - ARCANE_FATAL("Bad xpath"); - } - return 1; -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -Integer ParameterCaseOption:: -_getValueIndex(StringView xpath) -{ - for (Integer i = 0; i < m_params_view.size(); ++i) { - if (m_params_view[i] == xpath) { - return i; - } - } - return -1; -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -bool ParameterCaseOption:: -_hasOnlyIndex(StringView xpath_part) -{ - // xpath_before_index=0 (xpath_part="") - if (xpath_part.size() == 0) return true; - Span bytes_span = xpath_part.bytes(); - - // xpath_before_index[0]=0 (xpath_part="[0]") - if (bytes_span.size() < 3) return false; - // xpath_before_indextruc[0]=0 (xpath_part="truc[0]") - if (bytes_span[0] != '[') return false; - - // xpath_before_index[0]/xpath_after_index=0 (xpath_part="[0]") - for (Integer i = 2; i < bytes_span.size(); ++i) { - if (bytes_span[i] == ']') { - return (i == bytes_span.size()-1); - } - } - - // xpath_before_index[0]/truc/xpath_after_index=0 (xpath_part="[0]/truc/") - // xpath_before_index[0]/truc[0]/xpath_after_index=0 (xpath_part="[0]/truc[0]/") - return false; -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - } // End namespace Arcane /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/ParameterCaseOption.h b/arcane/src/arcane/utils/ParameterCaseOption.h index f27d150df3..9f7f18839a 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.h +++ b/arcane/src/arcane/utils/ParameterCaseOption.h @@ -14,11 +14,12 @@ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -#include "arcane/core/ICaseMng.h" #include "arcane/utils/UtilsTypes.h" #include "arcane/utils/String.h" #include "arcane/utils/List.h" +#include "arcane/core/ICaseMng.h" + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -58,23 +59,12 @@ ParameterCaseOption private: - StringView _removeUselessPartInXpath(StringView xpath); - StringView _removeIndexAtEnd(StringView xpath); - Integer _getIndexAtEnd(StringView xpath); - Integer _getIndexAtBegin(StringView xpath); - - - Integer _getValueIndex(StringView xpath); - - bool _hasOnlyIndex(StringView xpath_part); - + inline StringView _removeUselessPartInXpath(StringView xpath); private: StringList m_param_names; StringList m_values; - UniqueArray m_params_view; - UniqueArray m_values_view; String m_lang; ICaseMng* m_case_mng; ParameterCaseOptionMultiLine* m_lines; diff --git a/arcane/tests/testCaseOptions-commandLineReplace.arc b/arcane/tests/testCaseOptions-commandLineReplace.arc index 0e5e4ddbb7..52df3abd98 100644 --- a/arcane/tests/testCaseOptions-commandLineReplace.arc +++ b/arcane/tests/testCaseOptions-commandLineReplace.arc @@ -63,9 +63,7 @@ - 3 5.2 - 2.3 3.0 2.0 4.0 4 enum2 From e00a1082c032e6bda2ad743002bffdd0cbb9b317 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Fri, 14 Feb 2025 12:30:19 +0100 Subject: [PATCH 12/24] [arcane:utils] Rename ParameterOption classes and methods --- .../src/arcane/utils/ParameterCaseOption.cc | 213 +++++++++--------- arcane/src/arcane/utils/ParameterCaseOption.h | 7 +- 2 files changed, 116 insertions(+), 104 deletions(-) diff --git a/arcane/src/arcane/utils/ParameterCaseOption.cc b/arcane/src/arcane/utils/ParameterCaseOption.cc index c94a14c85d..1dcfb9edba 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.cc +++ b/arcane/src/arcane/utils/ParameterCaseOption.cc @@ -16,14 +16,15 @@ #include "arcane/utils/ApplicationInfo.h" #include "arcane/utils/CommandLineArguments.h" #include "arcane/utils/ParameterList.h" -#include "arcane/core/IApplication.h" -#include "arcane/core/ICaseDocument.h" #include "arcane/utils/ValueConvert.h" #include "arcane/utils/Array.h" #include "arcane/utils/FatalErrorException.h" #include "arcane/utils/ITraceMng.h" #include "arcane/utils/Ref.h" +#include "arcane/core/IApplication.h" +#include "arcane/core/ICaseDocument.h" + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -41,23 +42,23 @@ namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -class ParameterOptionPart +class ParameterOptionAddrPart { public: - ParameterOptionPart() + ParameterOptionAddrPart() : m_tag(ANY_TAG) , m_index(ANY_INDEX) {} - explicit ParameterOptionPart(const StringView tag) + explicit ParameterOptionAddrPart(const StringView tag) : m_tag(tag) , m_index(1) { ARCANE_ASSERT(tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbiden")); } - ParameterOptionPart(const StringView tag, const Integer index) + ParameterOptionAddrPart(const StringView tag, const Integer index) : m_tag(tag) , m_index(index) { @@ -87,11 +88,16 @@ class ParameterOptionPart { return (m_tag == ANY_TAG && m_index == ANY_INDEX); } - bool operator==(const ParameterOptionPart& other) const + bool operator==(const ParameterOptionAddrPart& other) const { return (m_tag == other.m_tag || m_tag == ANY_TAG || other.m_tag == ANY_TAG) && (m_index == other.m_index || m_index == ANY_INDEX || other.m_index == ANY_INDEX || m_index == GET_INDEX || other.m_index == GET_INDEX); } + // TODO AH : À supprimer lors du passage en C++20. + bool operator!=(const ParameterOptionAddrPart& other) const + { + return !operator==(other); + } private: @@ -99,7 +105,7 @@ class ParameterOptionPart Integer m_index; }; -std::ostream& operator<<(std::ostream& o, const ParameterOptionPart& h) +std::ostream& operator<<(std::ostream& o, const ParameterOptionAddrPart& h) { o << (h.tag() == ANY_TAG ? "ANY" : h.tag()) << "[" << (h.index() == ANY_INDEX ? "ANY" : (h.index() == GET_INDEX ? "GET" : std::to_string(h.index()))) @@ -110,11 +116,11 @@ std::ostream& operator<<(std::ostream& o, const ParameterOptionPart& h) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -class ParameterOptionLine +class ParameterOptionAddr { public: - explicit ParameterOptionLine(const StringView line) + explicit ParameterOptionAddr(const StringView line) { Span span_line(line.bytes()); Integer begin = 0; @@ -141,7 +147,7 @@ class ParameterOptionLine if (is_bad) { ARCANE_FATAL("Invalid index"); } - m_parts.add(makeRef(new ParameterOptionPart(line.subView(begin, size), index))); + m_parts.add(makeRef(new ParameterOptionAddrPart(line.subView(begin, size), index))); have_a_no_any = true; } @@ -152,10 +158,10 @@ class ParameterOptionLine size = i - begin; // Cas ou on a un any_tag any_index ("truc1//truc2"). if (size == 0) { - m_parts.add(makeRef(new ParameterOptionPart())); + m_parts.add(makeRef(new ParameterOptionAddrPart())); } else { - m_parts.add(makeRef(new ParameterOptionPart(line.subView(begin, size)))); + m_parts.add(makeRef(new ParameterOptionAddrPart(line.subView(begin, size)))); have_a_no_any = true; } } @@ -169,7 +175,7 @@ class ParameterOptionLine size = static_cast(span_line.size()) - begin; ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); - m_parts.add(makeRef(new ParameterOptionPart(line.subView(begin, size)))); + m_parts.add(makeRef(new ParameterOptionAddrPart(line.subView(begin, size)))); have_a_no_any = true; } if (!have_a_no_any) { @@ -179,43 +185,45 @@ class ParameterOptionLine public: - // On ne doit pas bloquer les multiples ParameterOptionPart(ANY) : + // On ne doit pas bloquer les multiples ParameterOptionAddrPart(ANY) : // Construction par iteration : aaaa/bb/ANY/ANY/cc - void addPart(ParameterOptionPart* part) + void addAddrPart(ParameterOptionAddrPart* part) { m_parts.add(makeRef(part)); } - ParameterOptionPart* part(const Integer index) const + ParameterOptionAddrPart* addrPart(const Integer index) const { if (index >= m_parts.size()) { if (m_parts[m_parts.size() - 1]->isAny()) { - return lastPart(); + return lastAddrPart(); } ARCANE_FATAL("Invalid index"); } return m_parts[index].get(); } - ParameterOptionPart* lastPart() const + ParameterOptionAddrPart* lastAddrPart() const { return m_parts[m_parts.size() - 1].get(); } - Integer nbPart() const + Integer nbAddrPart() const { return m_parts.size(); } - bool getIndexes(const ParameterOptionLine& with_get_index, ArrayView indexes) const + bool getIndexes(const ParameterOptionAddr& addr_with_get_index, ArrayView indexes) const { - if (!operator==(with_get_index)) + if (!operator==(addr_with_get_index)) return false; + ARCANE_ASSERT(indexes.size() == addr_with_get_index.nbIndexToGet(), ("ArrayView too small")); + Integer index = 0; - for (Integer i = 0; i < with_get_index.nbPart(); ++i) { - if (with_get_index.part(i)->index() == GET_INDEX) { - Integer index_tag = part(i)->index(); + for (Integer i = 0; i < addr_with_get_index.nbAddrPart(); ++i) { + if (addr_with_get_index.addrPart(i)->index() == GET_INDEX) { + Integer index_tag = addrPart(i)->index(); if (index_tag == ANY_INDEX) return false; indexes[index++] = index_tag; @@ -237,24 +245,24 @@ class ParameterOptionLine public: - bool operator==(const ParameterOptionLine& other) const + bool operator==(const ParameterOptionAddr& other) const { Integer nb_iter = 0; - if (lastPart()->isAny()) { - nb_iter = nbPart() - 1; + if (lastAddrPart()->isAny()) { + nb_iter = nbAddrPart() - 1; } - else if (other.lastPart()->isAny()) { - nb_iter = other.nbPart() - 1; + else if (other.lastAddrPart()->isAny()) { + nb_iter = other.nbAddrPart() - 1; } - else if (nbPart() != other.nbPart()) { + else if (nbAddrPart() != other.nbAddrPart()) { return false; } else { - nb_iter = nbPart(); + nb_iter = nbAddrPart(); } for (Integer i = 0; i < nb_iter; ++i) { - if (*part(i) != *other.part(i)) { + if (*addrPart(i) != *other.addrPart(i)) { return false; } } @@ -263,16 +271,16 @@ class ParameterOptionLine private: - UniqueArray> m_parts; + UniqueArray> m_parts; }; -std::ostream& operator<<(std::ostream& o, const ParameterOptionLine& h) +std::ostream& operator<<(std::ostream& o, const ParameterOptionAddr& h) { - Integer nb_part = h.nbPart(); + Integer nb_part = h.nbAddrPart(); if (nb_part != 0) - o << *(h.part(0)); + o << *(h.addrPart(0)); for (Integer i = 1; i < nb_part; ++i) { - o << "/" << *(h.part(i)); + o << "/" << *(h.addrPart(i)); } return o; } @@ -280,86 +288,86 @@ std::ostream& operator<<(std::ostream& o, const ParameterOptionLine& h) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -class ParameterCaseOptionLine +class ParameterOptionElement { public: - ParameterCaseOptionLine(StringView line, StringView value) - : m_line(line) + ParameterOptionElement(StringView addr, StringView value) + : m_addr(addr) , m_value(value) {} - ParameterOptionLine getLine() const + ParameterOptionAddr addr() const { - return m_line; + return m_addr; } - StringView getValue() const + StringView value() const { return m_value; } - bool operator==(const ParameterOptionLine& line) const + bool operator==(const ParameterOptionAddr& addr) const { - return m_line == line; + return m_addr == addr; } private: - ParameterOptionLine m_line; + ParameterOptionAddr m_addr; StringView m_value; }; /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -class ParameterCaseOptionMultiLine +class ParameterOptionElementsCollection { public: - void addOption(StringView line, StringView value) + void addOption(StringView addr, StringView value) { - m_lines.add({ line, value }); + m_elements.add({ addr, value }); } - ParameterCaseOptionLine getOption(Integer index) + ParameterOptionElement element(Integer index) { - return m_lines[index]; + return m_elements[index]; } - std::optional getValueOrNull(const ParameterOptionLine& line) + std::optional value(const ParameterOptionAddr& addr) { - for (const auto& elem : m_lines) { - if (elem == line) - return elem.getValue(); + for (const auto& elem : m_elements) { + if (elem == addr) + return elem.value(); } return {}; } - bool exist(const ParameterOptionLine& line) + bool isExistAddr(const ParameterOptionAddr& addr) { - for (const auto& elem : m_lines) { - if (elem == line) + for (const auto& elem : m_elements) { + if (elem == addr) return true; } return false; } - Integer existAndCount(const ParameterOptionLine& line) + Integer countAddr(const ParameterOptionAddr& addr) { Integer count = 0; - for (const auto& elem : m_lines) { - if (elem == line) + for (const auto& elem : m_elements) { + if (elem == addr) count++; } return count; } - void getIndexesOfLine(const ParameterOptionLine& line, UniqueArray& indexes) + void getIndexesOfLine(const ParameterOptionAddr& line, UniqueArray& indexes) { UniqueArray new_indexes(line.nbIndexToGet()); - for (const auto& elem : m_lines) { - if (elem.getLine().getIndexes(line, new_indexes)) { + for (const auto& elem : m_elements) { + if (elem.addr().getIndexes(line, new_indexes)) { indexes.addRange(new_indexes); } } @@ -367,7 +375,7 @@ class ParameterCaseOptionMultiLine private: - UniqueArray m_lines; + UniqueArray m_elements; }; /*---------------------------------------------------------------------------*/ @@ -376,7 +384,7 @@ class ParameterCaseOptionMultiLine ParameterCaseOption:: ParameterCaseOption(ICaseMng* case_mng) : m_case_mng(case_mng) -, m_lines(new ParameterCaseOptionMultiLine) +, m_lines(new ParameterOptionElementsCollection) { m_lang = m_case_mng->caseDocumentFragment()->language(); @@ -396,7 +404,8 @@ ParameterCaseOption(ICaseMng* case_mng) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -ParameterCaseOption::~ParameterCaseOption() +ParameterCaseOption:: +~ParameterCaseOption() { delete m_lines; } @@ -416,13 +425,13 @@ getParameterOrNull(const String& xpath_before_index, const String& xpath_after_i ARCANE_FATAL("Index in XML start at 1"); } - ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; - line.lastPart()->setIndex(index); - line.addPart(new ParameterOptionPart(xpath_after_index.view())); + ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; + addr.lastAddrPart()->setIndex(index); + addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); // m_case_mng->traceMng()->info() << "Line : " << line; - std::optional value = m_lines->getValueOrNull(line); + std::optional value = m_lines->value(addr); if (value.has_value()) { // m_case_mng->traceMng()->info() << "Ret : " << value.value(); return value.value(); @@ -444,14 +453,14 @@ getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_e if (index <= 0) { ARCANE_FATAL("Index in XML start at 1"); } - ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; - line.lastPart()->setIndex(index); + ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; + addr.lastAddrPart()->setIndex(index); if (allow_elems_after_index) { - line.addPart(new ParameterOptionPart()); + addr.addAddrPart(new ParameterOptionAddrPart()); } // m_case_mng->traceMng()->info() << "Line : " << line; - std::optional value = m_lines->getValueOrNull(line); + std::optional value = m_lines->value(addr); if (value.has_value()) { // m_case_mng->traceMng()->info() << "Ret : " << value.value(); return value.value(); @@ -468,11 +477,11 @@ getParameterOrNull(const String& full_xpath) { // m_case_mng->traceMng()->info() << "getParameterOrNull(S)"; // m_case_mng->traceMng()->info() << "full_xpath : " << full_xpath; - const ParameterOptionLine line{ _removeUselessPartInXpath(full_xpath.view()) }; + const ParameterOptionAddr addr{ _removeUselessPartInXpath(full_xpath.view()) }; // m_case_mng->traceMng()->info() << "Line : " << line; - std::optional value = m_lines->getValueOrNull(line); + std::optional value = m_lines->value(addr); if (value.has_value()) { // m_case_mng->traceMng()->info() << "Ret : " << value.value(); return value.value(); @@ -489,12 +498,12 @@ exist(const String& full_xpath) { // m_case_mng->traceMng()->info() << "exist(S)"; // m_case_mng->traceMng()->info() << "full_xpath : " << full_xpath; - const ParameterOptionLine line{ _removeUselessPartInXpath(full_xpath.view()) }; + const ParameterOptionAddr addr{ _removeUselessPartInXpath(full_xpath.view()) }; // m_case_mng->traceMng()->info() << "Line : " << line; // m_case_mng->traceMng()->info() << "Ret : " << m_lines->exist(line); - return m_lines->exist(line); + return m_lines->isExistAddr(addr); } /*---------------------------------------------------------------------------*/ @@ -507,15 +516,15 @@ existAnyIndex(const String& xpath_before_index, const String& xpath_after_index) // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index // << " -- xpath_after_index : " << xpath_after_index; - ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; - line.lastPart()->setIndex(ANY_INDEX); + ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; + addr.lastAddrPart()->setIndex(ANY_INDEX); - line.addPart(new ParameterOptionPart(xpath_after_index.view())); + addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); // m_case_mng->traceMng()->info() << "Line : " << line; // m_case_mng->traceMng()->info() << "Ret : " << m_lines->exist(line); - return m_lines->exist(line); + return m_lines->isExistAddr(addr); } /*---------------------------------------------------------------------------*/ @@ -527,13 +536,13 @@ existAnyIndex(const String& full_xpath) // m_case_mng->traceMng()->info() << "existAnyIndex(S)"; // m_case_mng->traceMng()->info() << "full_xpath : " << full_xpath; - ParameterOptionLine line{ _removeUselessPartInXpath(full_xpath.view()) }; - line.lastPart()->setIndex(ANY_INDEX); + ParameterOptionAddr addr{ _removeUselessPartInXpath(full_xpath.view()) }; + addr.lastAddrPart()->setIndex(ANY_INDEX); // m_case_mng->traceMng()->info() << "Line : " << line; // m_case_mng->traceMng()->info() << "Ret : " << m_lines->exist(line); - return m_lines->exist(line); + return m_lines->isExistAddr(addr); } /*---------------------------------------------------------------------------*/ @@ -547,13 +556,13 @@ indexesInParam(const String& xpath_before_index, const String& xpath_after_index // << " -- xpath_after_index : " << xpath_after_index // << " -- indexes : " << indexes; - ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; - line.lastPart()->setIndex(GET_INDEX); - line.addPart(new ParameterOptionPart(xpath_after_index.view())); + ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; + addr.lastAddrPart()->setIndex(GET_INDEX); + addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); // m_case_mng->traceMng()->info() << "Line : " << line; - m_lines->getIndexesOfLine(line, indexes); + m_lines->getIndexesOfLine(addr, indexes); // m_case_mng->traceMng()->info() << "indexes : " << indexes; } @@ -568,14 +577,14 @@ indexesInParam(const String& xpath_before_index, UniqueArray& indexes, // << " -- indexes : " << indexes // << " -- allow_elems_after_index : " << allow_elems_after_index; - ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; - line.lastPart()->setIndex(GET_INDEX); + ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; + addr.lastAddrPart()->setIndex(GET_INDEX); if (allow_elems_after_index) { - line.addPart(new ParameterOptionPart()); + addr.addAddrPart(new ParameterOptionAddrPart()); } // m_case_mng->traceMng()->info() << "Line : " << line; - m_lines->getIndexesOfLine(line, indexes); + m_lines->getIndexesOfLine(addr, indexes); // m_case_mng->traceMng()->info() << "indexes : " << indexes; } @@ -589,13 +598,13 @@ count(const String& xpath_before_index, const String& xpath_after_index) // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index // << " -- xpath_after_index : " << xpath_after_index; - ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; - line.lastPart()->setIndex(ANY_INDEX); - line.addPart(new ParameterOptionPart(xpath_after_index.view())); + ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; + addr.lastAddrPart()->setIndex(ANY_INDEX); + addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); // m_case_mng->traceMng()->info() << "Line : " << line; // m_case_mng->traceMng()->info() << "Ret : " << m_lines->existAndCount(line); - return m_lines->existAndCount(line); + return m_lines->countAddr(addr); } /*---------------------------------------------------------------------------*/ @@ -607,12 +616,12 @@ count(const String& xpath_before_index) // m_case_mng->traceMng()->info() << "count(S)"; // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index; - ParameterOptionLine line{ _removeUselessPartInXpath(xpath_before_index.view()) }; - line.lastPart()->setIndex(ANY_INDEX); + ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; + addr.lastAddrPart()->setIndex(ANY_INDEX); // m_case_mng->traceMng()->info() << "Line : " << line; // m_case_mng->traceMng()->info() << "Ret : " << m_lines->existAndCount(line); - return m_lines->existAndCount(line); + return m_lines->countAddr(addr); } /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/ParameterCaseOption.h b/arcane/src/arcane/utils/ParameterCaseOption.h index 9f7f18839a..14eea9e260 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.h +++ b/arcane/src/arcane/utils/ParameterCaseOption.h @@ -29,7 +29,10 @@ namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -class ParameterCaseOptionMultiLine; +class ParameterOptionElementsCollection; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ class ARCANE_UTILS_EXPORT ParameterCaseOption @@ -67,7 +70,7 @@ ParameterCaseOption StringList m_values; String m_lang; ICaseMng* m_case_mng; - ParameterCaseOptionMultiLine* m_lines; + ParameterOptionElementsCollection* m_lines; }; /*---------------------------------------------------------------------------*/ From 9ab9895f2946479c3be7217d01279b23c2ddfebc Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Fri, 14 Feb 2025 14:24:53 +0100 Subject: [PATCH 13/24] [arcane:utils] Add doc for ParameterOption classes --- .../src/arcane/utils/ParameterCaseOption.cc | 343 +++++++++++------- arcane/src/arcane/utils/ParameterCaseOption.h | 256 ++++++++++++- 2 files changed, 466 insertions(+), 133 deletions(-) diff --git a/arcane/src/arcane/utils/ParameterCaseOption.cc b/arcane/src/arcane/utils/ParameterCaseOption.cc index 1dcfb9edba..71f340ae01 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.cc +++ b/arcane/src/arcane/utils/ParameterCaseOption.cc @@ -7,7 +7,8 @@ /*---------------------------------------------------------------------------*/ /* ParameterCaseOption.cc (C) 2000-2025 */ /* */ -/* TODO. */ +/* Classe représentant l'ensemble des paramètres pouvant modifier les */ +/* options du jeu de données. */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -42,27 +43,54 @@ namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +/*! + * \brief Classe représentant une partie d'une adresse d'option du jeu de données. + * À noter qu'en XML, l'index commence à 1 et non à 0. + * + * Un tag spécial nommé ANY_TAG représente n'importe quel tag. + * Deux index spéciaux sont aussi disponibles : + * - ANY_INDEX : Représente n'importe quel index, + * - GET_INDEX : Représente un index à récupérer (voir la classe ParameterOptionAddr). + * Ces élements sont utiles pour l'opérateur ==. + * À noter que ANY_TAG ne peut pas être définit sans ANY_INDEX. + * Aussi, le tag ne peut pas être vide. + */ class ParameterOptionAddrPart { public: + /*! + * \brief Constructeur. Définit le tag en ANY_TAG et l'index en ANY_INDEX. + */ ParameterOptionAddrPart() : m_tag(ANY_TAG) , m_index(ANY_INDEX) {} + /*! + * \brief Constructeur. Définit l'index à 1. + * \param tag Le tag de cette partie d'adresse. Ce tag ne peut pas être ANY_TAG. + */ explicit ParameterOptionAddrPart(const StringView tag) : m_tag(tag) , m_index(1) { - ARCANE_ASSERT(tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbiden")); + ARCANE_ASSERT(tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbidden")); + ARCANE_ASSERT(!tag.empty(), ("tag is empty")); } + /*! + * \brief Constructeur. + * \param tag Le tag de cette partie d'adresse. Ce tag ne peut pas être ANY_TAG + * si l'index n'est pas ANY_INDEX. + * \param index L'index de cette partie d'adresse. + */ ParameterOptionAddrPart(const StringView tag, const Integer index) : m_tag(tag) , m_index(index) { - ARCANE_ASSERT(index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbiden")); + ARCANE_ASSERT(index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbidden")); + ARCANE_ASSERT(!tag.empty(), ("tag is empty")); } public: @@ -75,19 +103,32 @@ class ParameterOptionAddrPart { return m_index; } + + //! Si l'index est ANY_INDEX, le tag ne peut pas être ANY_TAG. void setTag(const StringView tag) { - ARCANE_ASSERT(m_index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbiden")); + ARCANE_ASSERT(m_index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbidden")); + ARCANE_ASSERT(!tag.empty(), ("tag is empty")); + m_tag = tag; } void setIndex(const Integer index) { m_index = index; } + + //! isAny si ANY_TAG et ANY_INDEX. bool isAny() const { return (m_tag == ANY_TAG && m_index == ANY_INDEX); } + + /*! + * \brief Opérateur d'égalité. + * Le tag ANY_TAG est égal à tous les tags. + * L'index ANY_INDEX est égal à tous les index. + * L'index GET_INDEX est égal à tous les index. + */ bool operator==(const ParameterOptionAddrPart& other) const { return (m_tag == other.m_tag || m_tag == ANY_TAG || other.m_tag == ANY_TAG) && @@ -116,13 +157,38 @@ std::ostream& operator<<(std::ostream& o, const ParameterOptionAddrPart& h) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +/*! + * \brief Classe représentant une adresse d'option du jeu de données. + * Cette adresse doit être de la forme : "tag/tag[index]/tag" + * Les parties de l'adresse sans index auront l'index par défaut (=1). + * + * Cette adresse doit obéir à certaines règles : + * - elle ne doit pas être vide, + * - elle ne doit pas représenter l'ensemble des options ("/"), + * - ses tags peuvent être vides ssi l'index est vide (voir après), + * - l'index spécial ANY_INDEX ne peut être présent que si le tag est non vide, + * - l'adresse peut terminer par un attribut ("\@name"), + * - l'adresse donnée au constructeur ne peut pas terminer par un ANY_TAG (mais + * ANY_TAG peut être ajouté après avec la méthode addAddrPart()), + * + * Dans une chaine de caractères : + * - le motif ANY_TAG[ANY_INDEX] peut être défini avec "//" : + * -> "tag/tag//tag" sera convertie ainsi : "tag[1]/tag[1]/ANY_TAG[ANY_INDEX]/tag[1]". + * - l'index ANY_INDEX peut être défini avec un index vide "[]" : + * -> "tag/tag[]/\@attr" sera convertie ainsi : "tag[1]/tag[ANY_INDEX]/\@attr[1]", + * -> le motif "tag/[]/tag" est interdit. + */ class ParameterOptionAddr { public: - explicit ParameterOptionAddr(const StringView line) + /*! + * \brief Constructeur. + * \param addr_str_view L'adresse à convertir. + */ + explicit ParameterOptionAddr(const StringView addr_str_view) { - Span span_line(line.bytes()); + Span span_line(addr_str_view.bytes()); Integer begin = 0; Integer size = 0; Integer index_begin = -1; @@ -138,17 +204,23 @@ class ParameterOptionAddr ARCANE_ASSERT(index_begin < span_line.size(), ("Invalid option (']' not found)")); } else if (span_line[i] == ']') { - ARCANE_ASSERT(index_begin != i, ("Invalid option ('[]' found without integer)")); ARCANE_ASSERT(index_begin != -1, ("Invalid option (']' found without '[')")); - StringView index_str = line.subView(index_begin, i - index_begin); - Integer index; - bool is_bad = builtInGetValue(index, index_str); - if (is_bad) { - ARCANE_FATAL("Invalid index"); + // Motif spécial "[]" (= ANY_INDEX) + if (index_begin == i) { + m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size), ANY_INDEX))); + have_a_no_any = true; + } + else { + StringView index_str = addr_str_view.subView(index_begin, i - index_begin); + Integer index; + bool is_bad = builtInGetValue(index, index_str); + if (is_bad) { + ARCANE_FATAL("Invalid index"); + } + m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size), index))); + have_a_no_any = true; } - m_parts.add(makeRef(new ParameterOptionAddrPart(line.subView(begin, size), index))); - have_a_no_any = true; } else if (span_line[i] == '/') { @@ -161,7 +233,7 @@ class ParameterOptionAddr m_parts.add(makeRef(new ParameterOptionAddrPart())); } else { - m_parts.add(makeRef(new ParameterOptionAddrPart(line.subView(begin, size)))); + m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size)))); have_a_no_any = true; } } @@ -175,7 +247,7 @@ class ParameterOptionAddr size = static_cast(span_line.size()) - begin; ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); - m_parts.add(makeRef(new ParameterOptionAddrPart(line.subView(begin, size)))); + m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size)))); have_a_no_any = true; } if (!have_a_no_any) { @@ -187,20 +259,34 @@ class ParameterOptionAddr // On ne doit pas bloquer les multiples ParameterOptionAddrPart(ANY) : // Construction par iteration : aaaa/bb/ANY/ANY/cc + /*! + * \brief Méthode permettant d'ajouter une partie à la fin de l'adresse actuelle. + * \param part Un pointeur vers la nouvelle partie. Attention, on récupère la + * propriété de l'objet (on gère le delete). + */ void addAddrPart(ParameterOptionAddrPart* part) { m_parts.add(makeRef(part)); } - ParameterOptionAddrPart* addrPart(const Integer index) const + /*! + * \brief Méthode permettant de récupérer une partie de l'adresse. + * Si l'adresse termine par un ANY_TAG[ANY_INDEX], tous index donnés en paramètre + * supérieur au nombre de partie de l'adresse retournera le dernier élément de + * l'adresse ("ANY_TAG[ANY_INDEX]"). + * + * \param index_of_part L'index de la partie à récupérer. + * \return La partie de l'adresse. + */ + ParameterOptionAddrPart* addrPart(const Integer index_of_part) const { - if (index >= m_parts.size()) { + if (index_of_part >= m_parts.size()) { if (m_parts[m_parts.size() - 1]->isAny()) { return lastAddrPart(); } ARCANE_FATAL("Invalid index"); } - return m_parts[index].get(); + return m_parts[index_of_part].get(); } ParameterOptionAddrPart* lastAddrPart() const @@ -208,17 +294,46 @@ class ParameterOptionAddr return m_parts[m_parts.size() - 1].get(); } + /*! + * \brief Méthode permettant de récupérer le nombre de partie de l'adresse. + * Les parties égales à "ANY_TAG[ANY_INDEX]" sont comptées. + * + * \return Le nombre de partie de l'adresse. + */ Integer nbAddrPart() const { return m_parts.size(); } - bool getIndexes(const ParameterOptionAddr& addr_with_get_index, ArrayView indexes) const + /*! + * \brief Méthode permettant de récupérer un ou plusieurs indices dans l'adresse. + * + * Le fonctionnement de cette méthode est simple. + * Nous avons l'adresse suivante : "aaa[1]/bbb[2]/ccc[4]/\@name[1]". + * L'adresse en paramètre est la suivante : "aaa[1]/bbb[GET_INDEX]/ccc[4]/\@name[1]". + * L'indice ajouté dans la vue en paramètre sera 2. + * + * Si l'adresse en paramètre est : "aaa[1]/bbb[GET_INDEX]/ccc[GET_INDEX]/\@name[1]". + * Les indices ajoutés dans la vue seront 2 et 4. + * + * En revanche, un "GET_INDEX" ne peut pas être utilisé sur un "ANY_INDEX" (return false). + * Exemple : si l'on a : "aaa[1]/bbb[ANY_INDEX]/ccc[4]/\@name[1]". + * Et si l'adresse en paramètre est : "aaa[1]/bbb[GET_INDEX]/ccc[GET_INDEX]/\@name[1]". + * Le booléen retourné sera false. + * + * Pour avoir la bonne taille de la vue, un appel à la méthode "nbIndexToGetInAddr()" + * peut être effectué. + * + * \param addr_with_get_index L'adresse contenant des indices "GET_INDEX". + * \param indexes [OUT] La vue dans laquelle sera ajouté le ou les indices (la taille devra être correct). + * \return true si la vue a pu être remplie correctement. + */ + bool getIndexInAddr(const ParameterOptionAddr& addr_with_get_index, ArrayView indexes) const { if (!operator==(addr_with_get_index)) return false; - ARCANE_ASSERT(indexes.size() == addr_with_get_index.nbIndexToGet(), ("ArrayView too small")); + ARCANE_ASSERT(indexes.size() == addr_with_get_index.nbIndexToGetInAddr(), ("ArrayView too small")); Integer index = 0; for (Integer i = 0; i < addr_with_get_index.nbAddrPart(); ++i) { @@ -232,7 +347,11 @@ class ParameterOptionAddr return true; } - Integer nbIndexToGet() const + /*! + * \brief Méthode permettant de savoir combien il y a de "GET_INDEX" dans l'adresse. + * \return Le nombre de "GET_INDEX". + */ + Integer nbIndexToGetInAddr() const { Integer count = 0; for (const auto& elem : m_parts) { @@ -245,6 +364,15 @@ class ParameterOptionAddr public: + /*! + * \brief Opérateur d'égalité. + * Cet opérateur tient compte des ANY_TAG / ANY_INDEX. + * L'adresse "aaa[1]/bbb[2]/ANY_TAG[ANY_INDEX]" + * sera éqale à l'adresse "aaa[1]/bbb[2]/ccc[5]/ddd[7]" + * ou à l'adresse "aaa[1]/bbb[ANY_INDEX]/ccc[5]/ddd[7]" + * ou à l'adresse "aaa[1]/bbb[2]" + * mais pas à l'adresse "aaa[1]" + */ bool operator==(const ParameterOptionAddr& other) const { Integer nb_iter = 0; @@ -288,11 +416,15 @@ std::ostream& operator<<(std::ostream& o, const ParameterOptionAddr& h) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +/*! + * \brief Classe représentant un élément XML (une option Arcane). + * Cet élement a une adresse et une valeur. + */ class ParameterOptionElement { public: - ParameterOptionElement(StringView addr, StringView value) + ParameterOptionElement(const StringView addr, const StringView value) : m_addr(addr) , m_value(value) {} @@ -321,20 +453,26 @@ class ParameterOptionElement /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +/*! + * \brief Classe représentant un ensemble d'éléments XML (un ensemble d'options Arcane). + */ class ParameterOptionElementsCollection { public: - void addOption(StringView addr, StringView value) + void addElement(StringView addr, StringView value) { m_elements.add({ addr, value }); } - ParameterOptionElement element(Integer index) - { - return m_elements[index]; - } + // ParameterOptionElement element(const Integer index) + // { + // return m_elements[index]; + // } + // Un StringView "vide" est éqal à un StringView "nul". + // Comme on travaille avec des String et que la distinction + // vide/nul est importante, on passe par un std::optional. std::optional value(const ParameterOptionAddr& addr) { for (const auto& elem : m_elements) { @@ -344,6 +482,12 @@ class ParameterOptionElementsCollection return {}; } + /*! + * \brief Méthode permettant de savoir si une adresse est présente dans la liste d'éléments. + * Les ANY_TAG/ANY_INDEX sont pris en compte. + * \param addr L'adresse à rechercher. + * \return true si l'adresse est trouvé. + */ bool isExistAddr(const ParameterOptionAddr& addr) { for (const auto& elem : m_elements) { @@ -353,6 +497,13 @@ class ParameterOptionElementsCollection return false; } + /*! + * \brief Méthode permettant de savoir combien de fois une adresse est présente dans la liste d'élements. + * Méthode particulièrement utile avec les ANY_TAG/ANY_INDEX. + * + * \param addr L'adresse à rechercher. + * \return Le nombre de correspondances trouvé. + */ Integer countAddr(const ParameterOptionAddr& addr) { Integer count = 0; @@ -363,11 +514,32 @@ class ParameterOptionElementsCollection return count; } - void getIndexesOfLine(const ParameterOptionAddr& line, UniqueArray& indexes) + /*! + * \brief Méthode permettant de récupérer un ou plusieurs indices dans la liste d'adresses. + * + * Le fonctionnement de cette méthode est simple. + * Nous avons les adresses suivantes : "aaa[1]/bbb[2]/ccc[1]/\@name[1]". + * "aaa[1]/bbb[2]/ccc[2]/\@name[1]". + * "ddd[1]/eee[2]". + * "fff[1]/ggg[2]/hhh[4]". + * L'adresse en paramètre est la suivante : "aaa[1]/bbb[2]/ccc[GET_INDEX]/\@name[1]". + * Les indices ajoutés dans le tableau en paramètre seront 1 et 2. + * + * Attention : Avoir une adresse en entrée avec plusieurs "GET_INDEX" est autorisé mais + * ça peut être dangereux si le nombre d'indices trouvé par adresse est différent pour + * chaque adresse (s'il y a deux "GET_INDEX" mais que dans une des adresses, il n'y a + * pas deux correspondances, ces éventuelles correspondances ne seront pas prises en + * compte). + * + * \param addr_with_get_index L'adresse contenant des indices "GET_INDEX". + * \param indexes [OUT] Le tableau dans lequel sera ajouté le ou les indices (le tableau + * n'est pas effacé avant utilisation). + */ + void getIndexInAddr(const ParameterOptionAddr& addr_with_get_index, UniqueArray& indexes) { - UniqueArray new_indexes(line.nbIndexToGet()); + UniqueArray new_indexes(addr_with_get_index.nbIndexToGetInAddr()); for (const auto& elem : m_elements) { - if (elem.addr().getIndexes(line, new_indexes)) { + if (elem.addr().getIndexInAddr(addr_with_get_index, new_indexes)) { indexes.addRange(new_indexes); } } @@ -390,13 +562,10 @@ ParameterCaseOption(ICaseMng* case_mng) m_case_mng->application()->applicationInfo().commandLineArguments().parameters().fillParameters(m_param_names, m_values); - //Integer d_count = 0; for (Integer i = 0; i < m_param_names.count(); ++i) { const String& param = m_param_names[i]; if (param.startsWith("//")) { - m_lines->addOption(param.view().subView(2), m_values[i].view()); - //m_case_mng->traceMng()->info() << "AddOption : " << m_lines->getOption(d_count).getLine() << " = " << m_lines->getOption(d_count).getValue(); - //d_count++; + m_lines->addElement(param.view().subView(2), m_values[i].view()); } } } @@ -413,14 +582,9 @@ ParameterCaseOption:: /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -// xpath_before_index[index]/xpath_after_index String ParameterCaseOption:: -getParameterOrNull(const String& xpath_before_index, const String& xpath_after_index, Integer index) +getParameterOrNull(const String& xpath_before_index, const String& xpath_after_index, Integer index) const { - // m_case_mng->traceMng()->info() << "getParameterOrNull(SSI)"; - // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index - // << " -- xpath_after_index : " << xpath_after_index - // << " -- index : " << index; if (index <= 0) { ARCANE_FATAL("Index in XML start at 1"); } @@ -429,14 +593,9 @@ getParameterOrNull(const String& xpath_before_index, const String& xpath_after_i addr.lastAddrPart()->setIndex(index); addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); - // m_case_mng->traceMng()->info() << "Line : " << line; - std::optional value = m_lines->value(addr); - if (value.has_value()) { - // m_case_mng->traceMng()->info() << "Ret : " << value.value(); + if (value.has_value()) return value.value(); - } - // m_case_mng->traceMng()->info() << "Ret : {}"; return {}; } @@ -444,12 +603,8 @@ getParameterOrNull(const String& xpath_before_index, const String& xpath_after_i /*---------------------------------------------------------------------------*/ String ParameterCaseOption:: -getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_elems_after_index) +getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_elems_after_index) const { - // m_case_mng->traceMng()->info() << "getParameterOrNull(SIB)"; - // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index - // << " -- index : " << index - // << " -- allow_elems_after_index : " << allow_elems_after_index; if (index <= 0) { ARCANE_FATAL("Index in XML start at 1"); } @@ -459,13 +614,9 @@ getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_e addr.addAddrPart(new ParameterOptionAddrPart()); } - // m_case_mng->traceMng()->info() << "Line : " << line; std::optional value = m_lines->value(addr); - if (value.has_value()) { - // m_case_mng->traceMng()->info() << "Ret : " << value.value(); + if (value.has_value()) return value.value(); - } - // m_case_mng->traceMng()->info() << "Ret : {}"; return {}; } @@ -473,20 +624,13 @@ getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_e /*---------------------------------------------------------------------------*/ String ParameterCaseOption:: -getParameterOrNull(const String& full_xpath) +getParameterOrNull(const String& full_xpath) const { - // m_case_mng->traceMng()->info() << "getParameterOrNull(S)"; - // m_case_mng->traceMng()->info() << "full_xpath : " << full_xpath; const ParameterOptionAddr addr{ _removeUselessPartInXpath(full_xpath.view()) }; - // m_case_mng->traceMng()->info() << "Line : " << line; - std::optional value = m_lines->value(addr); - if (value.has_value()) { - // m_case_mng->traceMng()->info() << "Ret : " << value.value(); + if (value.has_value()) return value.value(); - } - // m_case_mng->traceMng()->info() << "Ret : {}"; return {}; } @@ -496,13 +640,7 @@ getParameterOrNull(const String& full_xpath) bool ParameterCaseOption:: exist(const String& full_xpath) { - // m_case_mng->traceMng()->info() << "exist(S)"; - // m_case_mng->traceMng()->info() << "full_xpath : " << full_xpath; const ParameterOptionAddr addr{ _removeUselessPartInXpath(full_xpath.view()) }; - - // m_case_mng->traceMng()->info() << "Line : " << line; - // m_case_mng->traceMng()->info() << "Ret : " << m_lines->exist(line); - return m_lines->isExistAddr(addr); } @@ -510,20 +648,13 @@ exist(const String& full_xpath) /*---------------------------------------------------------------------------*/ bool ParameterCaseOption:: -existAnyIndex(const String& xpath_before_index, const String& xpath_after_index) +existAnyIndex(const String& xpath_before_index, const String& xpath_after_index) const { - // m_case_mng->traceMng()->info() << "existAnyIndex(SS)"; - // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index - // << " -- xpath_after_index : " << xpath_after_index; - ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; addr.lastAddrPart()->setIndex(ANY_INDEX); addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); - // m_case_mng->traceMng()->info() << "Line : " << line; - // m_case_mng->traceMng()->info() << "Ret : " << m_lines->exist(line); - return m_lines->isExistAddr(addr); } @@ -531,17 +662,11 @@ existAnyIndex(const String& xpath_before_index, const String& xpath_after_index) /*---------------------------------------------------------------------------*/ bool ParameterCaseOption:: -existAnyIndex(const String& full_xpath) +existAnyIndex(const String& full_xpath) const { - // m_case_mng->traceMng()->info() << "existAnyIndex(S)"; - // m_case_mng->traceMng()->info() << "full_xpath : " << full_xpath; - - ParameterOptionAddr addr{ _removeUselessPartInXpath(full_xpath.view()) }; + const ParameterOptionAddr addr{ _removeUselessPartInXpath(full_xpath.view()) }; addr.lastAddrPart()->setIndex(ANY_INDEX); - // m_case_mng->traceMng()->info() << "Line : " << line; - // m_case_mng->traceMng()->info() << "Ret : " << m_lines->exist(line); - return m_lines->isExistAddr(addr); } @@ -549,60 +674,39 @@ existAnyIndex(const String& full_xpath) /*---------------------------------------------------------------------------*/ void ParameterCaseOption:: -indexesInParam(const String& xpath_before_index, const String& xpath_after_index, UniqueArray& indexes) +indexesInParam(const String& xpath_before_index, const String& xpath_after_index, UniqueArray& indexes) const { - // m_case_mng->traceMng()->info() << "indexesInParam(SSU)"; - // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index - // << " -- xpath_after_index : " << xpath_after_index - // << " -- indexes : " << indexes; - ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; addr.lastAddrPart()->setIndex(GET_INDEX); addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); - // m_case_mng->traceMng()->info() << "Line : " << line; - - m_lines->getIndexesOfLine(addr, indexes); - // m_case_mng->traceMng()->info() << "indexes : " << indexes; + m_lines->getIndexInAddr(addr, indexes); } /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ void ParameterCaseOption:: -indexesInParam(const String& xpath_before_index, UniqueArray& indexes, bool allow_elems_after_index) +indexesInParam(const String& xpath_before_index, UniqueArray& indexes, bool allow_elems_after_index) const { - // m_case_mng->traceMng()->info() << "indexesInParam(SUB)"; - // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index - // << " -- indexes : " << indexes - // << " -- allow_elems_after_index : " << allow_elems_after_index; - ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; addr.lastAddrPart()->setIndex(GET_INDEX); if (allow_elems_after_index) { addr.addAddrPart(new ParameterOptionAddrPart()); } - // m_case_mng->traceMng()->info() << "Line : " << line; - m_lines->getIndexesOfLine(addr, indexes); - // m_case_mng->traceMng()->info() << "indexes : " << indexes; + m_lines->getIndexInAddr(addr, indexes); } /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ Integer ParameterCaseOption:: -count(const String& xpath_before_index, const String& xpath_after_index) +count(const String& xpath_before_index, const String& xpath_after_index) const { - // m_case_mng->traceMng()->info() << "count(SS)"; - // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index - // << " -- xpath_after_index : " << xpath_after_index; - ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; addr.lastAddrPart()->setIndex(ANY_INDEX); addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); - // m_case_mng->traceMng()->info() << "Line : " << line; - // m_case_mng->traceMng()->info() << "Ret : " << m_lines->existAndCount(line); return m_lines->countAddr(addr); } @@ -611,15 +715,10 @@ count(const String& xpath_before_index, const String& xpath_after_index) /*---------------------------------------------------------------------------*/ Integer ParameterCaseOption:: -count(const String& xpath_before_index) +count(const String& xpath_before_index) const { - // m_case_mng->traceMng()->info() << "count(S)"; - // m_case_mng->traceMng()->info() << "xpath_before_index : " << xpath_before_index; - - ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; + const ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; addr.lastAddrPart()->setIndex(ANY_INDEX); - // m_case_mng->traceMng()->info() << "Line : " << line; - // m_case_mng->traceMng()->info() << "Ret : " << m_lines->existAndCount(line); return m_lines->countAddr(addr); } @@ -631,7 +730,7 @@ count(const String& xpath_before_index) /*---------------------------------------------------------------------------*/ inline StringView ParameterCaseOption:: -_removeUselessPartInXpath(StringView xpath) +_removeUselessPartInXpath(StringView xpath) const { if (m_lang == "fr") return xpath.subView(6); diff --git a/arcane/src/arcane/utils/ParameterCaseOption.h b/arcane/src/arcane/utils/ParameterCaseOption.h index 14eea9e260..3c0e371d8e 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.h +++ b/arcane/src/arcane/utils/ParameterCaseOption.h @@ -7,10 +7,13 @@ /*---------------------------------------------------------------------------*/ /* ParameterCaseOption.h (C) 2000-2025 */ /* */ -/* TODO. */ +/* Classe représentant l'ensemble des paramètres pouvant modifier les */ +/* options du jeu de données . */ /*---------------------------------------------------------------------------*/ + #ifndef ARCANE_UTILS_PARAMETERCASEOPTION_H #define ARCANE_UTILS_PARAMETERCASEOPTION_H + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -34,6 +37,10 @@ class ParameterOptionElementsCollection; /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +/*! + * \brief Classe représentant l'ensemble des paramètres pouvant modifier + * les options du jeu de données. + */ class ARCANE_UTILS_EXPORT ParameterCaseOption { @@ -45,24 +52,251 @@ ParameterCaseOption public: - String getParameterOrNull(const String& xpath_before_index, const String& xpath_after_index, Integer index); - String getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_elems_after_index); - String getParameterOrNull(const String& full_xpath); + /*! + * \brief Méthode permettant de récupérer la valeur d'une option. + * + * L'adresse de l'option est reformée comme ceci : + * xpath_before_index[index]/xpath_after_index + * + * xpath_before_index doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin (mais il sera remplacé + * par celui passé en paramètre). + * + * xpath_after_index doit être de la forme suivante : + * ddd/eee + * - pas de "/" au début ni à la fin. + * + * Les indices sont des indices XML et ces indices commencent par 1. + * + * \param xpath_before_index L'adresse avant indice. + * \param xpath_after_index L'adresse après indice. + * \param index L'indice à mettre entre les deux parties de l'adresse. + * \return La valeur si trouvée, sinon chaîne null. + */ + String getParameterOrNull(const String& xpath_before_index, const String& xpath_after_index, Integer index) const; + + /*! + * \brief Méthode permettant de récupérer la valeur d'une option. + * + * L'adresse de l'option est reformée comme ceci : + * xpath_before_index[index] + * + * xpath_before_index doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin (mais il sera remplacé + * par celui passé en paramètre). + * + * Si le paramètre allow_elems_after_index est activé, les adresses de la forme : + * xpath_before_index[index]/aaa/bbb + * seront aussi recherchées. + * + * Les indices sont des indices XML et ces indices commencent par 1. + * + * \param xpath_before_index L'adresse avant indice. + * \param index L'indice à mettre après l'adresse. + * \param allow_elems_after_index Doit-on vérifier la présence d'éléments après l'indice ? + * \return La valeur si trouvée, sinon chaîne null. + */ + String getParameterOrNull(const String& xpath_before_index, Integer index, bool allow_elems_after_index) const; + + /*! + * \brief Méthode permettant de récupérer la valeur d'une option. + * + * L'adresse doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin. + * + * Les indices sont des indices XML et ces indices commencent par 1. + * + * \param full_xpath L'adresse à rechercher. + * \return La valeur si trouvée, sinon chaîne null. + */ + String getParameterOrNull(const String& full_xpath) const; + /*! + * \brief Méthode permettant de savoir si une option est présente. + * + * L'adresse doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin. + * + * Les indices sont des indices XML et ces indices commencent par 1. + * + * \param full_xpath L'adresse à rechercher. + * \return true si l'adresse est trouvée dans la liste. + */ bool exist(const String& full_xpath); - bool existAnyIndex(const String& xpath_before_index, const String& xpath_after_index); - bool existAnyIndex(const String& full_xpath); + /*! + * \brief Méthode permettant de savoir si une option est présente. + * + * L'adresse de l'option est reformée comme ceci : + * xpath_before_index[ANY_INDEX]/xpath_after_index + * + * xpath_before_index doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin (mais il sera remplacé + * par ANY_INDEX). + * + * xpath_after_index doit être de la forme suivante : + * ddd/eee + * - pas de "/" au début ni à la fin. + * + * Les indices sont des indices XML et ces indices commencent par 1. + * L'indice ANY_INDEX est un indice spécial désignant tous les indices. + * + * \param xpath_before_index L'adresse avant indice. + * \param xpath_after_index L'adresse après indice. + * \return true si l'adresse est trouvée dans la liste. + */ + bool existAnyIndex(const String& xpath_before_index, const String& xpath_after_index) const; + + /*! + * \brief Méthode permettant de savoir si une option est présente. + * + * L'adresse de l'option est reformée comme ceci : + * full_xpath[ANY_INDEX] + * + * L'adresse doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin (mais il sera remplacé + * par ANY_INDEX). + * + * Les indices sont des indices XML et ces indices commencent par 1. + * L'indice ANY_INDEX est un indice spécial désignant tous les indices. + * + * \param full_xpath L'adresse à rechercher. + * \return true si l'adresse est trouvée dans la liste. + */ + bool existAnyIndex(const String& full_xpath) const; + + /*! + * \brief Méthode permettant de récupérer le ou les indices de l'option. + * + * L'adresse de l'option est reformée comme ceci : + * xpath_before_index[GET_INDEX]/xpath_after_index + * + * xpath_before_index doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin (mais il sera remplacé + * par GET_INDEX). + * + * xpath_after_index doit être de la forme suivante : + * ddd/eee + * - pas de "/" au début ni à la fin. + * + * Les indices sont des indices XML et ces indices commencent par 1. + * L'indice GET_INDEX est un indice spécial désignant les indices que l'on souhaite récupérer. + * + * \param xpath_before_index L'adresse avant indice. + * \param xpath_after_index L'adresse après indice. + * \param indexes Le tableau qui contiendra l'ensemble des indices trouvés + * (ce tableau n'est pas effacé avant utilisation). + */ + void indexesInParam(const String& xpath_before_index, const String& xpath_after_index, UniqueArray& indexes) const; + + /*! + * \brief Méthode permettant de récupérer le ou les indices de l'option. + * + * L'adresse de l'option est reformée comme ceci : + * xpath_before_index[GET_INDEX] + * + * xpath_before_index doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin (mais il sera remplacé + * par GET_INDEX). + * + * Si le paramètre allow_elems_after_index est activé, les adresses de la forme : + * xpath_before_index[GET_INDEX]/aaa/bbb + * seront aussi recherchées. + * + * Les indices sont des indices XML et ces indices commencent par 1. + * L'indice GET_INDEX est un indice spécial désignant les indices que l'on souhaite récupérer. + * + * \param xpath_before_index L'adresse avant indice. + * \param indexes Le tableau qui contiendra l'ensemble des indices trouvés + * \param allow_elems_after_index Doit-on vérifier la présence d'éléments après l'indice ? + * (ce tableau n'est pas effacé avant utilisation). + */ + void indexesInParam(const String& xpath_before_index, UniqueArray& indexes, bool allow_elems_after_index) const; - void indexesInParam(const String& xpath_before_index, const String& xpath_after_index, UniqueArray& indexes); - void indexesInParam(const String& xpath_before_index, UniqueArray& indexes, bool allow_elems_after_index); + /*! + * \brief Méthode permettant de connaitre le nombre d'indices de l'option. + * + * L'adresse de l'option est reformée comme ceci : + * xpath_before_index[GET_INDEX]/xpath_after_index + * + * xpath_before_index doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin (mais il sera remplacé + * par GET_INDEX). + * + * xpath_after_index doit être de la forme suivante : + * ddd/eee + * - pas de "/" au début ni à la fin. + * + * Les indices sont des indices XML et ces indices commencent par 1. + * L'indice GET_INDEX est un indice spécial désignant les indices que l'on souhaite récupérer. + * + * \param xpath_before_index L'adresse avant indice. + * \param xpath_after_index L'adresse après indice. + * \return Le nombre d'indices de l'option. + */ + Integer count(const String& xpath_before_index, const String& xpath_after_index) const; - Integer count(const String& xpath_before_index, const String& xpath_after_index); - Integer count(const String& xpath_before_index); + /*! + * \brief Méthode permettant de connaitre le nombre d'indices de l'option. + * + * L'adresse de l'option est reformée comme ceci : + * xpath_before_index[GET_INDEX] + * + * xpath_before_index doit être de la forme suivante : + * //case/aaa/bbb[2]/ccc + * - le "//case/" au début (ou "//cas/" en français"), + * - une succession de tags avec possiblement leurs indices, + * - pas de "/" à la fin, + * - un indice peut être mise à la fin (mais il sera remplacé + * par GET_INDEX). + * + * Les indices sont des indices XML et ces indices commencent par 1. + * L'indice GET_INDEX est un indice spécial désignant les indices que l'on souhaite récupérer. + * + * \param xpath_before_index L'adresse avant indice. + * \return Le nombre d'indices de l'option. + */ + Integer count(const String& xpath_before_index) const; private: - inline StringView _removeUselessPartInXpath(StringView xpath); + inline StringView _removeUselessPartInXpath(StringView xpath) const; private: From 67b6f00fedba0cb6541937920824308c835be198 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Sat, 15 Feb 2025 15:54:43 +0100 Subject: [PATCH 14/24] [arcane:core,utils] Move ParameterOption classes to internal/ParameterOption.cc/.h - Parameters are parsed once time now (at each options before) --- arcane/src/arcane/core/CaseOptionExtended.cc | 3 +- arcane/src/arcane/core/CaseOptionService.cc | 4 +- arcane/src/arcane/core/CaseOptionSimple.cc | 4 +- .../src/arcane/utils/ParameterCaseOption.cc | 571 +----------------- arcane/src/arcane/utils/ParameterCaseOption.h | 18 +- arcane/src/arcane/utils/ParameterList.cc | 57 +- arcane/src/arcane/utils/ParameterList.h | 11 + .../arcane/utils/internal/ParameterOption.cc | 470 ++++++++++++++ .../arcane/utils/internal/ParameterOption.h | 323 ++++++++++ arcane/src/arcane/utils/srcs.cmake | 2 + 10 files changed, 885 insertions(+), 578 deletions(-) create mode 100644 arcane/src/arcane/utils/internal/ParameterOption.cc create mode 100644 arcane/src/arcane/utils/internal/ParameterOption.h diff --git a/arcane/src/arcane/core/CaseOptionExtended.cc b/arcane/src/arcane/core/CaseOptionExtended.cc index 9848735fd5..51545f2eaf 100644 --- a/arcane/src/arcane/core/CaseOptionExtended.cc +++ b/arcane/src/arcane/core/CaseOptionExtended.cc @@ -27,6 +27,7 @@ #include "arcane/core/XmlNodeList.h" #include "arcane/core/ICaseOptionList.h" #include "arcane/core/MeshHandle.h" +#include "arcane/core/ICaseDocument.h" #include "arcane/core/internal/StringVariableReplace.h" /*---------------------------------------------------------------------------*/ @@ -50,7 +51,7 @@ _search(bool is_phase1) { ITraceMng* tm = traceMng(); const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); - ParameterCaseOption pco{ caseMng() }; + const ParameterCaseOption pco{ params.getParameterCaseOption(caseDocumentFragment()->language()) }; // !!! En XML, on commence par 1 et non 0. UniqueArray option_in_param; diff --git a/arcane/src/arcane/core/CaseOptionService.cc b/arcane/src/arcane/core/CaseOptionService.cc index 04f737f93e..3b04962f4b 100644 --- a/arcane/src/arcane/core/CaseOptionService.cc +++ b/arcane/src/arcane/core/CaseOptionService.cc @@ -194,7 +194,7 @@ _readPhase1() const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); ICaseDocumentFragment* doc = caseDocumentFragment(); - ParameterCaseOption pco{ caseMng() }; + const ParameterCaseOption pco{ params.getParameterCaseOption(doc->language()) }; String mesh_name; { @@ -385,7 +385,7 @@ multiAllocate(const XmlNodeList& elem_list) ARCANE_FATAL("null 'm_container'. did you called setContainer() method ?"); const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); - ParameterCaseOption pco{ caseMng() }; + const ParameterCaseOption pco{ params.getParameterCaseOption(caseDocumentFragment()->language()) }; XmlNode parent_element = configList()->parentElement(); diff --git a/arcane/src/arcane/core/CaseOptionSimple.cc b/arcane/src/arcane/core/CaseOptionSimple.cc index d0fb85c4c0..c753d83c50 100644 --- a/arcane/src/arcane/core/CaseOptionSimple.cc +++ b/arcane/src/arcane/core/CaseOptionSimple.cc @@ -135,7 +135,7 @@ _search(bool is_phase1) // Liste des options de la ligne de commande. { const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); - ParameterCaseOption pco{ caseMng() }; + const ParameterCaseOption pco{ params.getParameterCaseOption(doc->language()) }; String reference_input = pco.getParameterOrNull(String::format("{0}/{1}", rootElement().xpathFullName(), velem_name), 1, false); if (!reference_input.null()) { @@ -662,7 +662,7 @@ _search(bool is_phase1) return; const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); - ParameterCaseOption pco{ caseMng() }; + const ParameterCaseOption pco{ params.getParameterCaseOption(caseDocumentFragment()->language()) }; String full_xpath = String::format("{0}/{1}", rootElement().xpathFullName(), name()); // !!! En XML, on commence par 1 et non 0. diff --git a/arcane/src/arcane/utils/ParameterCaseOption.cc b/arcane/src/arcane/utils/ParameterCaseOption.cc index 71f340ae01..357e013e6f 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.cc +++ b/arcane/src/arcane/utils/ParameterCaseOption.cc @@ -7,577 +7,36 @@ /*---------------------------------------------------------------------------*/ /* ParameterCaseOption.cc (C) 2000-2025 */ /* */ -/* Classe représentant l'ensemble des paramètres pouvant modifier les */ -/* options du jeu de données. */ +/* Classe permettant d'interroger les paramètres pour savoir si des options */ +/* du jeu de données doivent être modifiées par ceux-ci. */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ #include "arcane/utils/ParameterCaseOption.h" #include "arcane/utils/ApplicationInfo.h" -#include "arcane/utils/CommandLineArguments.h" -#include "arcane/utils/ParameterList.h" #include "arcane/utils/ValueConvert.h" #include "arcane/utils/Array.h" #include "arcane/utils/FatalErrorException.h" #include "arcane/utils/ITraceMng.h" #include "arcane/utils/Ref.h" -#include "arcane/core/IApplication.h" -#include "arcane/core/ICaseDocument.h" +#include "arcane/utils/internal/ParameterOption.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -namespace -{ -const Arcane::String ANY_TAG_STR = "/"; -const Arcane::StringView ANY_TAG = ANY_TAG_STR.view(); -constexpr Arcane::Integer ANY_INDEX = -1; -constexpr Arcane::Integer GET_INDEX = -2; -} // namespace - namespace Arcane { /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -/*! - * \brief Classe représentant une partie d'une adresse d'option du jeu de données. - * À noter qu'en XML, l'index commence à 1 et non à 0. - * - * Un tag spécial nommé ANY_TAG représente n'importe quel tag. - * Deux index spéciaux sont aussi disponibles : - * - ANY_INDEX : Représente n'importe quel index, - * - GET_INDEX : Représente un index à récupérer (voir la classe ParameterOptionAddr). - * Ces élements sont utiles pour l'opérateur ==. - * À noter que ANY_TAG ne peut pas être définit sans ANY_INDEX. - * Aussi, le tag ne peut pas être vide. - */ -class ParameterOptionAddrPart -{ - public: - - /*! - * \brief Constructeur. Définit le tag en ANY_TAG et l'index en ANY_INDEX. - */ - ParameterOptionAddrPart() - : m_tag(ANY_TAG) - , m_index(ANY_INDEX) - {} - - /*! - * \brief Constructeur. Définit l'index à 1. - * \param tag Le tag de cette partie d'adresse. Ce tag ne peut pas être ANY_TAG. - */ - explicit ParameterOptionAddrPart(const StringView tag) - : m_tag(tag) - , m_index(1) - { - ARCANE_ASSERT(tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbidden")); - ARCANE_ASSERT(!tag.empty(), ("tag is empty")); - } - - /*! - * \brief Constructeur. - * \param tag Le tag de cette partie d'adresse. Ce tag ne peut pas être ANY_TAG - * si l'index n'est pas ANY_INDEX. - * \param index L'index de cette partie d'adresse. - */ - ParameterOptionAddrPart(const StringView tag, const Integer index) - : m_tag(tag) - , m_index(index) - { - ARCANE_ASSERT(index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbidden")); - ARCANE_ASSERT(!tag.empty(), ("tag is empty")); - } - - public: - - StringView tag() const - { - return m_tag; - } - Integer index() const - { - return m_index; - } - - //! Si l'index est ANY_INDEX, le tag ne peut pas être ANY_TAG. - void setTag(const StringView tag) - { - ARCANE_ASSERT(m_index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbidden")); - ARCANE_ASSERT(!tag.empty(), ("tag is empty")); - - m_tag = tag; - } - void setIndex(const Integer index) - { - m_index = index; - } - - //! isAny si ANY_TAG et ANY_INDEX. - bool isAny() const - { - return (m_tag == ANY_TAG && m_index == ANY_INDEX); - } - - /*! - * \brief Opérateur d'égalité. - * Le tag ANY_TAG est égal à tous les tags. - * L'index ANY_INDEX est égal à tous les index. - * L'index GET_INDEX est égal à tous les index. - */ - bool operator==(const ParameterOptionAddrPart& other) const - { - return (m_tag == other.m_tag || m_tag == ANY_TAG || other.m_tag == ANY_TAG) && - (m_index == other.m_index || m_index == ANY_INDEX || other.m_index == ANY_INDEX || m_index == GET_INDEX || other.m_index == GET_INDEX); - } - // TODO AH : À supprimer lors du passage en C++20. - bool operator!=(const ParameterOptionAddrPart& other) const - { - return !operator==(other); - } - - private: - - StringView m_tag; - Integer m_index; -}; - -std::ostream& operator<<(std::ostream& o, const ParameterOptionAddrPart& h) -{ - o << (h.tag() == ANY_TAG ? "ANY" : h.tag()) - << "[" << (h.index() == ANY_INDEX ? "ANY" : (h.index() == GET_INDEX ? "GET" : std::to_string(h.index()))) - << "]"; - return o; -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -/*! - * \brief Classe représentant une adresse d'option du jeu de données. - * Cette adresse doit être de la forme : "tag/tag[index]/tag" - * Les parties de l'adresse sans index auront l'index par défaut (=1). - * - * Cette adresse doit obéir à certaines règles : - * - elle ne doit pas être vide, - * - elle ne doit pas représenter l'ensemble des options ("/"), - * - ses tags peuvent être vides ssi l'index est vide (voir après), - * - l'index spécial ANY_INDEX ne peut être présent que si le tag est non vide, - * - l'adresse peut terminer par un attribut ("\@name"), - * - l'adresse donnée au constructeur ne peut pas terminer par un ANY_TAG (mais - * ANY_TAG peut être ajouté après avec la méthode addAddrPart()), - * - * Dans une chaine de caractères : - * - le motif ANY_TAG[ANY_INDEX] peut être défini avec "//" : - * -> "tag/tag//tag" sera convertie ainsi : "tag[1]/tag[1]/ANY_TAG[ANY_INDEX]/tag[1]". - * - l'index ANY_INDEX peut être défini avec un index vide "[]" : - * -> "tag/tag[]/\@attr" sera convertie ainsi : "tag[1]/tag[ANY_INDEX]/\@attr[1]", - * -> le motif "tag/[]/tag" est interdit. - */ -class ParameterOptionAddr -{ - public: - - /*! - * \brief Constructeur. - * \param addr_str_view L'adresse à convertir. - */ - explicit ParameterOptionAddr(const StringView addr_str_view) - { - Span span_line(addr_str_view.bytes()); - Integer begin = 0; - Integer size = 0; - Integer index_begin = -1; - // On interdit les options qui s'appliquent à toutes les caseoptions. - bool have_a_no_any = false; - - // aaa[0] - for (Integer i = 0; i < span_line.size(); ++i) { - if (span_line[i] == '[') { - index_begin = i + 1; - size = i - begin; - ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); - ARCANE_ASSERT(index_begin < span_line.size(), ("Invalid option (']' not found)")); - } - else if (span_line[i] == ']') { - ARCANE_ASSERT(index_begin != -1, ("Invalid option (']' found without '[')")); - - // Motif spécial "[]" (= ANY_INDEX) - if (index_begin == i) { - m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size), ANY_INDEX))); - have_a_no_any = true; - } - else { - StringView index_str = addr_str_view.subView(index_begin, i - index_begin); - Integer index; - bool is_bad = builtInGetValue(index, index_str); - if (is_bad) { - ARCANE_FATAL("Invalid index"); - } - m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size), index))); - have_a_no_any = true; - } - } - - else if (span_line[i] == '/') { - ARCANE_ASSERT(i + 1 != span_line.size(), ("Invalid option ('/' found at the end of the param option)")); - - if (index_begin == -1) { - size = i - begin; - // Cas ou on a un any_tag any_index ("truc1//truc2"). - if (size == 0) { - m_parts.add(makeRef(new ParameterOptionAddrPart())); - } - else { - m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size)))); - have_a_no_any = true; - } - } - - begin = i + 1; - size = 0; - index_begin = -1; - } - } - if (index_begin == -1) { - size = static_cast(span_line.size()) - begin; - ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); - - m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size)))); - have_a_no_any = true; - } - if (!have_a_no_any) { - ARCANE_FATAL("Invalid option"); - } - } - - public: - - // On ne doit pas bloquer les multiples ParameterOptionAddrPart(ANY) : - // Construction par iteration : aaaa/bb/ANY/ANY/cc - /*! - * \brief Méthode permettant d'ajouter une partie à la fin de l'adresse actuelle. - * \param part Un pointeur vers la nouvelle partie. Attention, on récupère la - * propriété de l'objet (on gère le delete). - */ - void addAddrPart(ParameterOptionAddrPart* part) - { - m_parts.add(makeRef(part)); - } - - /*! - * \brief Méthode permettant de récupérer une partie de l'adresse. - * Si l'adresse termine par un ANY_TAG[ANY_INDEX], tous index donnés en paramètre - * supérieur au nombre de partie de l'adresse retournera le dernier élément de - * l'adresse ("ANY_TAG[ANY_INDEX]"). - * - * \param index_of_part L'index de la partie à récupérer. - * \return La partie de l'adresse. - */ - ParameterOptionAddrPart* addrPart(const Integer index_of_part) const - { - if (index_of_part >= m_parts.size()) { - if (m_parts[m_parts.size() - 1]->isAny()) { - return lastAddrPart(); - } - ARCANE_FATAL("Invalid index"); - } - return m_parts[index_of_part].get(); - } - - ParameterOptionAddrPart* lastAddrPart() const - { - return m_parts[m_parts.size() - 1].get(); - } - - /*! - * \brief Méthode permettant de récupérer le nombre de partie de l'adresse. - * Les parties égales à "ANY_TAG[ANY_INDEX]" sont comptées. - * - * \return Le nombre de partie de l'adresse. - */ - Integer nbAddrPart() const - { - return m_parts.size(); - } - - /*! - * \brief Méthode permettant de récupérer un ou plusieurs indices dans l'adresse. - * - * Le fonctionnement de cette méthode est simple. - * Nous avons l'adresse suivante : "aaa[1]/bbb[2]/ccc[4]/\@name[1]". - * L'adresse en paramètre est la suivante : "aaa[1]/bbb[GET_INDEX]/ccc[4]/\@name[1]". - * L'indice ajouté dans la vue en paramètre sera 2. - * - * Si l'adresse en paramètre est : "aaa[1]/bbb[GET_INDEX]/ccc[GET_INDEX]/\@name[1]". - * Les indices ajoutés dans la vue seront 2 et 4. - * - * En revanche, un "GET_INDEX" ne peut pas être utilisé sur un "ANY_INDEX" (return false). - * Exemple : si l'on a : "aaa[1]/bbb[ANY_INDEX]/ccc[4]/\@name[1]". - * Et si l'adresse en paramètre est : "aaa[1]/bbb[GET_INDEX]/ccc[GET_INDEX]/\@name[1]". - * Le booléen retourné sera false. - * - * Pour avoir la bonne taille de la vue, un appel à la méthode "nbIndexToGetInAddr()" - * peut être effectué. - * - * \param addr_with_get_index L'adresse contenant des indices "GET_INDEX". - * \param indexes [OUT] La vue dans laquelle sera ajouté le ou les indices (la taille devra être correct). - * \return true si la vue a pu être remplie correctement. - */ - bool getIndexInAddr(const ParameterOptionAddr& addr_with_get_index, ArrayView indexes) const - { - if (!operator==(addr_with_get_index)) - return false; - - ARCANE_ASSERT(indexes.size() == addr_with_get_index.nbIndexToGetInAddr(), ("ArrayView too small")); - - Integer index = 0; - for (Integer i = 0; i < addr_with_get_index.nbAddrPart(); ++i) { - if (addr_with_get_index.addrPart(i)->index() == GET_INDEX) { - Integer index_tag = addrPart(i)->index(); - if (index_tag == ANY_INDEX) - return false; - indexes[index++] = index_tag; - } - } - return true; - } - - /*! - * \brief Méthode permettant de savoir combien il y a de "GET_INDEX" dans l'adresse. - * \return Le nombre de "GET_INDEX". - */ - Integer nbIndexToGetInAddr() const - { - Integer count = 0; - for (const auto& elem : m_parts) { - if (elem->index() == GET_INDEX) { - count++; - } - } - return count; - } - - public: - - /*! - * \brief Opérateur d'égalité. - * Cet opérateur tient compte des ANY_TAG / ANY_INDEX. - * L'adresse "aaa[1]/bbb[2]/ANY_TAG[ANY_INDEX]" - * sera éqale à l'adresse "aaa[1]/bbb[2]/ccc[5]/ddd[7]" - * ou à l'adresse "aaa[1]/bbb[ANY_INDEX]/ccc[5]/ddd[7]" - * ou à l'adresse "aaa[1]/bbb[2]" - * mais pas à l'adresse "aaa[1]" - */ - bool operator==(const ParameterOptionAddr& other) const - { - Integer nb_iter = 0; - if (lastAddrPart()->isAny()) { - nb_iter = nbAddrPart() - 1; - } - else if (other.lastAddrPart()->isAny()) { - nb_iter = other.nbAddrPart() - 1; - } - else if (nbAddrPart() != other.nbAddrPart()) { - return false; - } - else { - nb_iter = nbAddrPart(); - } - - for (Integer i = 0; i < nb_iter; ++i) { - if (*addrPart(i) != *other.addrPart(i)) { - return false; - } - } - return true; - } - - private: - - UniqueArray> m_parts; -}; - -std::ostream& operator<<(std::ostream& o, const ParameterOptionAddr& h) -{ - Integer nb_part = h.nbAddrPart(); - if (nb_part != 0) - o << *(h.addrPart(0)); - for (Integer i = 1; i < nb_part; ++i) { - o << "/" << *(h.addrPart(i)); - } - return o; -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -/*! - * \brief Classe représentant un élément XML (une option Arcane). - * Cet élement a une adresse et une valeur. - */ -class ParameterOptionElement -{ - public: - - ParameterOptionElement(const StringView addr, const StringView value) - : m_addr(addr) - , m_value(value) - {} - - ParameterOptionAddr addr() const - { - return m_addr; - } - - StringView value() const - { - return m_value; - } - - bool operator==(const ParameterOptionAddr& addr) const - { - return m_addr == addr; - } - - private: - - ParameterOptionAddr m_addr; - StringView m_value; -}; - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -/*! - * \brief Classe représentant un ensemble d'éléments XML (un ensemble d'options Arcane). - */ -class ParameterOptionElementsCollection -{ - public: - - void addElement(StringView addr, StringView value) - { - m_elements.add({ addr, value }); - } - - // ParameterOptionElement element(const Integer index) - // { - // return m_elements[index]; - // } - - // Un StringView "vide" est éqal à un StringView "nul". - // Comme on travaille avec des String et que la distinction - // vide/nul est importante, on passe par un std::optional. - std::optional value(const ParameterOptionAddr& addr) - { - for (const auto& elem : m_elements) { - if (elem == addr) - return elem.value(); - } - return {}; - } - - /*! - * \brief Méthode permettant de savoir si une adresse est présente dans la liste d'éléments. - * Les ANY_TAG/ANY_INDEX sont pris en compte. - * \param addr L'adresse à rechercher. - * \return true si l'adresse est trouvé. - */ - bool isExistAddr(const ParameterOptionAddr& addr) - { - for (const auto& elem : m_elements) { - if (elem == addr) - return true; - } - return false; - } - - /*! - * \brief Méthode permettant de savoir combien de fois une adresse est présente dans la liste d'élements. - * Méthode particulièrement utile avec les ANY_TAG/ANY_INDEX. - * - * \param addr L'adresse à rechercher. - * \return Le nombre de correspondances trouvé. - */ - Integer countAddr(const ParameterOptionAddr& addr) - { - Integer count = 0; - for (const auto& elem : m_elements) { - if (elem == addr) - count++; - } - return count; - } - - /*! - * \brief Méthode permettant de récupérer un ou plusieurs indices dans la liste d'adresses. - * - * Le fonctionnement de cette méthode est simple. - * Nous avons les adresses suivantes : "aaa[1]/bbb[2]/ccc[1]/\@name[1]". - * "aaa[1]/bbb[2]/ccc[2]/\@name[1]". - * "ddd[1]/eee[2]". - * "fff[1]/ggg[2]/hhh[4]". - * L'adresse en paramètre est la suivante : "aaa[1]/bbb[2]/ccc[GET_INDEX]/\@name[1]". - * Les indices ajoutés dans le tableau en paramètre seront 1 et 2. - * - * Attention : Avoir une adresse en entrée avec plusieurs "GET_INDEX" est autorisé mais - * ça peut être dangereux si le nombre d'indices trouvé par adresse est différent pour - * chaque adresse (s'il y a deux "GET_INDEX" mais que dans une des adresses, il n'y a - * pas deux correspondances, ces éventuelles correspondances ne seront pas prises en - * compte). - * - * \param addr_with_get_index L'adresse contenant des indices "GET_INDEX". - * \param indexes [OUT] Le tableau dans lequel sera ajouté le ou les indices (le tableau - * n'est pas effacé avant utilisation). - */ - void getIndexInAddr(const ParameterOptionAddr& addr_with_get_index, UniqueArray& indexes) - { - UniqueArray new_indexes(addr_with_get_index.nbIndexToGetInAddr()); - for (const auto& elem : m_elements) { - if (elem.addr().getIndexInAddr(addr_with_get_index, new_indexes)) { - indexes.addRange(new_indexes); - } - } - } - - private: - - UniqueArray m_elements; -}; - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - ParameterCaseOption:: -ParameterCaseOption(ICaseMng* case_mng) -: m_case_mng(case_mng) -, m_lines(new ParameterOptionElementsCollection) -{ - m_lang = m_case_mng->caseDocumentFragment()->language(); - - m_case_mng->application()->applicationInfo().commandLineArguments().parameters().fillParameters(m_param_names, m_values); - - for (Integer i = 0; i < m_param_names.count(); ++i) { - const String& param = m_param_names[i]; - if (param.startsWith("//")) { - m_lines->addElement(param.view().subView(2), m_values[i].view()); - } - } -} - -/*---------------------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -ParameterCaseOption:: -~ParameterCaseOption() -{ - delete m_lines; -} +ParameterCaseOption(ParameterOptionElementsCollection* parameter_options, const String& lang) +: m_is_fr(lang == "fr") +, m_lines(parameter_options) // On ne récupère pas la propriété. +{} /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -638,7 +97,7 @@ getParameterOrNull(const String& full_xpath) const /*---------------------------------------------------------------------------*/ bool ParameterCaseOption:: -exist(const String& full_xpath) +exist(const String& full_xpath) const { const ParameterOptionAddr addr{ _removeUselessPartInXpath(full_xpath.view()) }; return m_lines->isExistAddr(addr); @@ -651,7 +110,7 @@ bool ParameterCaseOption:: existAnyIndex(const String& xpath_before_index, const String& xpath_after_index) const { ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; - addr.lastAddrPart()->setIndex(ANY_INDEX); + addr.lastAddrPart()->setIndex(ParameterOptionAddrPart::ANY_INDEX); addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); @@ -665,7 +124,7 @@ bool ParameterCaseOption:: existAnyIndex(const String& full_xpath) const { const ParameterOptionAddr addr{ _removeUselessPartInXpath(full_xpath.view()) }; - addr.lastAddrPart()->setIndex(ANY_INDEX); + addr.lastAddrPart()->setIndex(ParameterOptionAddrPart::ANY_INDEX); return m_lines->isExistAddr(addr); } @@ -677,7 +136,7 @@ void ParameterCaseOption:: indexesInParam(const String& xpath_before_index, const String& xpath_after_index, UniqueArray& indexes) const { ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; - addr.lastAddrPart()->setIndex(GET_INDEX); + addr.lastAddrPart()->setIndex(ParameterOptionAddrPart::GET_INDEX); addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); m_lines->getIndexInAddr(addr, indexes); @@ -690,7 +149,7 @@ void ParameterCaseOption:: indexesInParam(const String& xpath_before_index, UniqueArray& indexes, bool allow_elems_after_index) const { ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; - addr.lastAddrPart()->setIndex(GET_INDEX); + addr.lastAddrPart()->setIndex(ParameterOptionAddrPart::GET_INDEX); if (allow_elems_after_index) { addr.addAddrPart(new ParameterOptionAddrPart()); } @@ -705,7 +164,7 @@ Integer ParameterCaseOption:: count(const String& xpath_before_index, const String& xpath_after_index) const { ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; - addr.lastAddrPart()->setIndex(ANY_INDEX); + addr.lastAddrPart()->setIndex(ParameterOptionAddrPart::ANY_INDEX); addr.addAddrPart(new ParameterOptionAddrPart(xpath_after_index.view())); return m_lines->countAddr(addr); @@ -718,7 +177,7 @@ Integer ParameterCaseOption:: count(const String& xpath_before_index) const { const ParameterOptionAddr addr{ _removeUselessPartInXpath(xpath_before_index.view()) }; - addr.lastAddrPart()->setIndex(ANY_INDEX); + addr.lastAddrPart()->setIndex(ParameterOptionAddrPart::ANY_INDEX); return m_lines->countAddr(addr); } @@ -732,7 +191,7 @@ count(const String& xpath_before_index) const inline StringView ParameterCaseOption:: _removeUselessPartInXpath(StringView xpath) const { - if (m_lang == "fr") + if (m_is_fr) return xpath.subView(6); return xpath.subView(7); } diff --git a/arcane/src/arcane/utils/ParameterCaseOption.h b/arcane/src/arcane/utils/ParameterCaseOption.h index 3c0e371d8e..efe733cab0 100644 --- a/arcane/src/arcane/utils/ParameterCaseOption.h +++ b/arcane/src/arcane/utils/ParameterCaseOption.h @@ -7,8 +7,8 @@ /*---------------------------------------------------------------------------*/ /* ParameterCaseOption.h (C) 2000-2025 */ /* */ -/* Classe représentant l'ensemble des paramètres pouvant modifier les */ -/* options du jeu de données . */ +/* Classe permettant d'interroger les paramètres pour savoir si des options */ +/* du jeu de données doivent être modifiées par ceux-ci. */ /*---------------------------------------------------------------------------*/ #ifndef ARCANE_UTILS_PARAMETERCASEOPTION_H @@ -18,10 +18,6 @@ /*---------------------------------------------------------------------------*/ #include "arcane/utils/UtilsTypes.h" -#include "arcane/utils/String.h" -#include "arcane/utils/List.h" - -#include "arcane/core/ICaseMng.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -47,8 +43,7 @@ ParameterCaseOption public: - ParameterCaseOption(ICaseMng* case_mng); - ~ParameterCaseOption(); + ParameterCaseOption(ParameterOptionElementsCollection* parameter_options, const String& lang); public: @@ -138,7 +133,7 @@ ParameterCaseOption * \param full_xpath L'adresse à rechercher. * \return true si l'adresse est trouvée dans la liste. */ - bool exist(const String& full_xpath); + bool exist(const String& full_xpath) const; /*! * \brief Méthode permettant de savoir si une option est présente. @@ -300,10 +295,7 @@ ParameterCaseOption private: - StringList m_param_names; - StringList m_values; - String m_lang; - ICaseMng* m_case_mng; + bool m_is_fr; ParameterOptionElementsCollection* m_lines; }; diff --git a/arcane/src/arcane/utils/ParameterList.cc b/arcane/src/arcane/utils/ParameterList.cc index 03adedbce3..4febbe7c19 100644 --- a/arcane/src/arcane/utils/ParameterList.cc +++ b/arcane/src/arcane/utils/ParameterList.cc @@ -15,6 +15,10 @@ #include "arcane/utils/StringDictionary.h" #include "arcane/utils/String.h" #include "arcane/utils/Array.h" +#include "arcane/utils/FatalErrorException.h" +#include "arcane/utils/Ref.h" + +#include "arcane/utils/internal/ParameterOption.h" #include @@ -40,10 +44,19 @@ class ParameterList::Impl } }; public: - Impl() {} + + Impl() + : m_parameter_option(makeRef(new ParameterOptionElementsCollection())) + {} + public: String getParameter(const String& key) { + if (key.startsWith("//")) { + if (const auto value = m_parameter_option->value(ParameterOptionAddr(key.view().subView(2)))) + return value.value(); + return {}; + } String x = m_parameters_dictionary.find(key); return x; } @@ -53,14 +66,27 @@ class ParameterList::Impl //std::cout << "__ADD_PARAMETER name='" << name << "' v='" << value << "'\n"; if (name.empty()) return; - m_parameters_dictionary.add(name,value); - m_parameters_list.add({name,value}); + + if (name.startsWith("//")) { + m_parameters_option_list.add({ name, value }); + m_parameter_option->addParameter(m_parameters_option_list[m_parameters_option_list.size() - 1].name, m_parameters_option_list[m_parameters_option_list.size() - 1].value); + return; + } + + m_parameters_dictionary.add(name, value); + m_parameters_list.add({ name, value }); + m_parameter_option->addParameter(m_parameters_list[m_parameters_list.size() - 1].name, m_parameters_list[m_parameters_list.size() - 1].value); } void setParameter(const String& name,const String& value) { //std::cout << "__SET_PARAMETER name='" << name << "' v='" << value << "'\n"; if (name.empty()) return; + + if (name.startsWith("//")) { + ARCANE_FATAL("Set parameter not supported for ParameterOptions."); + } + m_parameters_dictionary.add(name,value); // Supprime de la liste toutes les occurences ayant // pour paramètre \a name @@ -73,6 +99,9 @@ class ParameterList::Impl //std::cout << "__REMOVE_PARAMETER name='" << name << "' v='" << value << "'\n"; if (name.empty()) return; + if (name.startsWith("//")) { + ARCANE_FATAL("Remove parameter not supported for ParameterOptions."); + } // Si le paramètre \a name avec la valeur \a value est trouvé, le supprime. // Dans ce cas, il faudra regarder s'il y a toujours // dans \a m_parameters_list un paramètre \a name et si c'est le @@ -93,8 +122,17 @@ class ParameterList::Impl } void fillParameters(StringList& param_names,StringList& values) const { - m_parameters_dictionary.fill(param_names,values); + m_parameters_dictionary.fill(param_names, values); + for (const auto& [name, value] : m_parameters_option_list) { + param_names.add(name); + values.add(value); + } + } + ParameterOptionElementsCollection* getParameterOption() const + { + return m_parameter_option.get(); } + private: void _fillDictionaryWithValueInList(const String& name) { @@ -105,6 +143,8 @@ class ParameterList::Impl private: StringDictionary m_parameters_dictionary; UniqueArray m_parameters_list; + UniqueArray m_parameters_option_list; + Ref m_parameter_option; }; /*---------------------------------------------------------------------------*/ @@ -186,6 +226,15 @@ fillParameters(StringList& param_names,StringList& values) const /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +ParameterCaseOption ParameterList:: +getParameterCaseOption(const String& language) const +{ + return { m_p->getParameterOption(), language }; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + } // End namespace Arcane /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/ParameterList.h b/arcane/src/arcane/utils/ParameterList.h index a7c675358f..6a13d9e033 100644 --- a/arcane/src/arcane/utils/ParameterList.h +++ b/arcane/src/arcane/utils/ParameterList.h @@ -15,6 +15,7 @@ /*---------------------------------------------------------------------------*/ #include "arcane/utils/UtilsTypes.h" +#include "arcane/utils/ParameterCaseOption.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -87,6 +88,16 @@ class ARCANE_UTILS_EXPORT ParameterList */ void fillParameters(StringList& param_names,StringList& values) const; + /*! + * \brief Méthode permettant de récupérer un objet de type ParameterCaseOption. + * + * Cet objet peut être détruit après utilisation. + * + * \param language Le langage dans lequel est écrit le jeu de données. + * \return Un objet de type ParameterCaseOption. + */ + ParameterCaseOption getParameterCaseOption(const String& language) const; + private: Impl* m_p; //!< Implémentation diff --git a/arcane/src/arcane/utils/internal/ParameterOption.cc b/arcane/src/arcane/utils/internal/ParameterOption.cc new file mode 100644 index 0000000000..6d45cf4de4 --- /dev/null +++ b/arcane/src/arcane/utils/internal/ParameterOption.cc @@ -0,0 +1,470 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* ParameterOption.cc (C) 2000-2025 */ +/* */ +/* Classe représentant l'ensemble des paramètres pouvant modifier les */ +/* options du jeu de données. */ +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#include "arcane/utils/internal/ParameterOption.h" + +#include "arcane/utils/ApplicationInfo.h" +#include "arcane/utils/ValueConvert.h" +#include "arcane/utils/Array.h" +#include "arcane/utils/FatalErrorException.h" +#include "arcane/utils/ITraceMng.h" +#include "arcane/utils/Ref.h" + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +namespace Arcane +{ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionAddrPart:: +ParameterOptionAddrPart() +: m_tag(ANY_TAG) +, m_index(ANY_INDEX) +{} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionAddrPart:: +ParameterOptionAddrPart(const StringView tag) +: m_tag(tag) +, m_index(1) +{ + ARCANE_ASSERT(tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbidden")); + ARCANE_ASSERT(!tag.empty(), ("tag is empty")); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionAddrPart:: +ParameterOptionAddrPart(const StringView tag, const Integer index) +: m_tag(tag) +, m_index(index) +{ + ARCANE_ASSERT(index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbidden")); + ARCANE_ASSERT(!tag.empty(), ("tag is empty")); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +StringView ParameterOptionAddrPart:: +tag() const +{ + return m_tag; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Integer ParameterOptionAddrPart:: +index() const +{ + return m_index; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterOptionAddrPart:: +setTag(const StringView tag) +{ + ARCANE_ASSERT(m_index == ANY_INDEX || tag != ANY_TAG, ("ANY_TAG without ANY_INDEX is forbidden")); + ARCANE_ASSERT(!tag.empty(), ("tag is empty")); + + m_tag = tag; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterOptionAddrPart:: +setIndex(const Integer index) +{ + m_index = index; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterOptionAddrPart:: +isAny() const +{ + return (m_tag == ANY_TAG && m_index == ANY_INDEX); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterOptionAddrPart:: +operator==(const ParameterOptionAddrPart& other) const +{ + return (m_tag == other.m_tag || m_tag == ANY_TAG || other.m_tag == ANY_TAG) && + (m_index == other.m_index || m_index == ANY_INDEX || other.m_index == ANY_INDEX || m_index == GET_INDEX || other.m_index == GET_INDEX); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +// TODO AH : À supprimer lors du passage en C++20. +bool ParameterOptionAddrPart:: +operator!=(const ParameterOptionAddrPart& other) const +{ + return !operator==(other); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +std::ostream& operator<<(std::ostream& o, const ParameterOptionAddrPart& h) +{ + o << (h.tag() == ParameterOptionAddrPart::ANY_TAG ? "ANY" : h.tag()) + << "[" << (h.index() == ParameterOptionAddrPart::ANY_INDEX ? "ANY" : (h.index() == ParameterOptionAddrPart::GET_INDEX ? "GET" : std::to_string(h.index()))) + << "]"; + return o; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionAddr:: +ParameterOptionAddr(const StringView addr_str_view) +{ + Span span_line(addr_str_view.bytes()); + Integer begin = 0; + Integer size = 0; + Integer index_begin = -1; + // On interdit les options qui s'appliquent à toutes les caseoptions. + bool have_a_no_any = false; + + // aaa[0] + for (Integer i = 0; i < span_line.size(); ++i) { + if (span_line[i] == '[') { + index_begin = i + 1; + size = i - begin; + ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); + ARCANE_ASSERT(index_begin < span_line.size(), ("Invalid option (']' not found)")); + } + else if (span_line[i] == ']') { + ARCANE_ASSERT(index_begin != -1, ("Invalid option (']' found without '[')")); + + // Motif spécial "[]" (= ANY_INDEX) + if (index_begin == i) { + m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size), ParameterOptionAddrPart::ANY_INDEX))); + have_a_no_any = true; + } + else { + StringView index_str = addr_str_view.subView(index_begin, i - index_begin); + Integer index; + bool is_bad = builtInGetValue(index, index_str); + if (is_bad) { + ARCANE_FATAL("Invalid index"); + } + m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size), index))); + have_a_no_any = true; + } + } + + else if (span_line[i] == '/') { + ARCANE_ASSERT(i + 1 != span_line.size(), ("Invalid option ('/' found at the end of the param option)")); + + if (index_begin == -1) { + size = i - begin; + // Cas ou on a un any_tag any_index ("truc1//truc2"). + if (size == 0) { + m_parts.add(makeRef(new ParameterOptionAddrPart())); + } + else { + m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size)))); + have_a_no_any = true; + } + } + + begin = i + 1; + size = 0; + index_begin = -1; + } + } + if (index_begin == -1) { + size = static_cast(span_line.size()) - begin; + ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); + + m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size)))); + have_a_no_any = true; + } + if (!have_a_no_any) { + ARCANE_FATAL("Invalid option"); + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +// On ne doit pas bloquer les multiples ParameterOptionAddrPart(ANY) : +// Construction par iteration : aaaa/bb/ANY/ANY/cc +void ParameterOptionAddr:: +addAddrPart(ParameterOptionAddrPart* part) +{ + m_parts.add(makeRef(part)); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionAddrPart* ParameterOptionAddr:: +addrPart(const Integer index_of_part) const +{ + if (index_of_part >= m_parts.size()) { + if (m_parts[m_parts.size() - 1]->isAny()) { + return lastAddrPart(); + } + ARCANE_FATAL("Invalid index"); + } + return m_parts[index_of_part].get(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionAddrPart* ParameterOptionAddr:: +lastAddrPart() const +{ + return m_parts[m_parts.size() - 1].get(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Integer ParameterOptionAddr:: +nbAddrPart() const +{ + return m_parts.size(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterOptionAddr:: +getIndexInAddr(const ParameterOptionAddr& addr_with_get_index, ArrayView indexes) const +{ + if (!operator==(addr_with_get_index)) + return false; + + ARCANE_ASSERT(indexes.size() == addr_with_get_index.nbIndexToGetInAddr(), ("ArrayView too small")); + + Integer index = 0; + for (Integer i = 0; i < addr_with_get_index.nbAddrPart(); ++i) { + if (addr_with_get_index.addrPart(i)->index() == ParameterOptionAddrPart::GET_INDEX) { + Integer index_tag = addrPart(i)->index(); + if (index_tag == ParameterOptionAddrPart::ANY_INDEX) + return false; + indexes[index++] = index_tag; + } + } + return true; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Integer ParameterOptionAddr:: +nbIndexToGetInAddr() const +{ + Integer count = 0; + for (const auto& elem : m_parts) { + if (elem->index() == ParameterOptionAddrPart::GET_INDEX) { + count++; + } + } + return count; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterOptionAddr:: +operator==(const ParameterOptionAddr& other) const +{ + Integer nb_iter = 0; + if (lastAddrPart()->isAny()) { + nb_iter = nbAddrPart() - 1; + } + else if (other.lastAddrPart()->isAny()) { + nb_iter = other.nbAddrPart() - 1; + } + else if (nbAddrPart() != other.nbAddrPart()) { + return false; + } + else { + nb_iter = nbAddrPart(); + } + + for (Integer i = 0; i < nb_iter; ++i) { + if (*addrPart(i) != *other.addrPart(i)) { + return false; + } + } + return true; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +std::ostream& operator<<(std::ostream& o, const ParameterOptionAddr& h) +{ + Integer nb_part = h.nbAddrPart(); + if (nb_part != 0) + o << *(h.addrPart(0)); + for (Integer i = 1; i < nb_part; ++i) { + o << "/" << *(h.addrPart(i)); + } + return o; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionElement:: +ParameterOptionElement(const StringView addr, const StringView value) +: m_addr(addr) +, m_value(value) +{} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionAddr ParameterOptionElement:: +addr() const +{ + return m_addr; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +StringView ParameterOptionElement:: +value() const +{ + return m_value; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterOptionElement:: +operator==(const ParameterOptionAddr& addr) const +{ + return m_addr == addr; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterOptionElementsCollection:: +addParameter(const String& parameter, const String& value) +{ + if (parameter.startsWith("//")) { + addElement(parameter.view().subView(2), value.view()); + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterOptionElementsCollection:: +addElement(StringView addr, StringView value) +{ + m_elements.add({ addr, value }); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +// Un StringView "vide" est éqal à un StringView "nul". +// Comme on travaille avec des String et que la distinction +// vide/nul est importante, on passe par un std::optional. +std::optional ParameterOptionElementsCollection:: +value(const ParameterOptionAddr& addr) +{ + for (const auto& elem : m_elements) { + if (elem == addr) + return elem.value(); + } + return {}; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +bool ParameterOptionElementsCollection:: +isExistAddr(const ParameterOptionAddr& addr) +{ + for (const auto& elem : m_elements) { + if (elem == addr) + return true; + } + return false; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +Integer ParameterOptionElementsCollection:: +countAddr(const ParameterOptionAddr& addr) +{ + Integer count = 0; + for (const auto& elem : m_elements) { + if (elem == addr) + count++; + } + return count; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterOptionElementsCollection:: +getIndexInAddr(const ParameterOptionAddr& addr_with_get_index, UniqueArray& indexes) +{ + UniqueArray new_indexes(addr_with_get_index.nbIndexToGetInAddr()); + for (const auto& elem : m_elements) { + if (elem.addr().getIndexInAddr(addr_with_get_index, new_indexes)) { + indexes.addRange(new_indexes); + } + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} // End namespace Arcane + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/internal/ParameterOption.h b/arcane/src/arcane/utils/internal/ParameterOption.h new file mode 100644 index 0000000000..730e3abb80 --- /dev/null +++ b/arcane/src/arcane/utils/internal/ParameterOption.h @@ -0,0 +1,323 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* ParameterOption.h (C) 2000-2025 */ +/* */ +/* Classe représentant l'ensemble des paramètres pouvant modifier les */ +/* options du jeu de données. */ +/*---------------------------------------------------------------------------*/ + +#ifndef ARCANE_UTILS_INTERNAL_PARAMETEROPTION_H +#define ARCANE_UTILS_INTERNAL_PARAMETEROPTION_H + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#include "arcane/utils/UtilsTypes.h" +#include "arcane/utils/String.h" +#include "arcane/utils/List.h" + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +namespace Arcane +{ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*! + * \brief Classe représentant une partie d'une adresse d'option du jeu de données. + * À noter qu'en XML, l'index commence à 1 et non à 0. + * + * Un tag spécial nommé ANY_TAG représente n'importe quel tag. + * Deux index spéciaux sont aussi disponibles : + * - ANY_INDEX : Représente n'importe quel index, + * - GET_INDEX : Représente un index à récupérer (voir la classe ParameterOptionAddr). + * Ces élements sont utiles pour l'opérateur ==. + * À noter que ANY_TAG ne peut pas être définit sans ANY_INDEX. + * Aussi, le tag ne peut pas être vide. + */ +class ARCANE_UTILS_EXPORT +ParameterOptionAddrPart +{ + public: + static constexpr const char* ANY_TAG = "/"; + static constexpr Integer ANY_INDEX = -1; + static constexpr Integer GET_INDEX = -2; + + public: + + /*! + * \brief Constructeur. Définit le tag en ANY_TAG et l'index en ANY_INDEX. + */ + ParameterOptionAddrPart(); + + /*! + * \brief Constructeur. Définit l'index à 1. + * \param tag Le tag de cette partie d'adresse. Ce tag ne peut pas être ANY_TAG. + */ + explicit ParameterOptionAddrPart(const StringView tag); + + /*! + * \brief Constructeur. + * \param tag Le tag de cette partie d'adresse. Ce tag ne peut pas être ANY_TAG + * si l'index n'est pas ANY_INDEX. + * \param index L'index de cette partie d'adresse. + */ + ParameterOptionAddrPart(const StringView tag, const Integer index); + + public: + + StringView tag() const; + Integer index() const; + + //! Si l'index est ANY_INDEX, le tag ne peut pas être ANY_TAG. + void setTag(const StringView tag); + void setIndex(const Integer index); + + //! isAny si ANY_TAG et ANY_INDEX. + bool isAny() const; + + /*! + * \brief Opérateur d'égalité. + * Le tag ANY_TAG est égal à tous les tags. + * L'index ANY_INDEX est égal à tous les index. + * L'index GET_INDEX est égal à tous les index. + */ + bool operator==(const ParameterOptionAddrPart& other) const; + // TODO AH : À supprimer lors du passage en C++20. + bool operator!=(const ParameterOptionAddrPart& other) const; + + private: + + StringView m_tag; + Integer m_index; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*! + * \brief Classe représentant une adresse d'option du jeu de données. + * Cette adresse doit être de la forme : "tag/tag[index]/tag" + * Les parties de l'adresse sans index auront l'index par défaut (=1). + * + * Cette adresse doit obéir à certaines règles : + * - elle ne doit pas être vide, + * - elle ne doit pas représenter l'ensemble des options ("/"), + * - ses tags peuvent être vides ssi l'index est vide (voir après), + * - l'index spécial ANY_INDEX ne peut être présent que si le tag est non vide, + * - l'adresse peut terminer par un attribut ("\@name"), + * - l'adresse donnée au constructeur ne peut pas terminer par un ANY_TAG (mais + * ANY_TAG peut être ajouté après avec la méthode addAddrPart()), + * + * Dans une chaine de caractères : + * - le motif ANY_TAG[ANY_INDEX] peut être défini avec "//" : + * -> "tag/tag//tag" sera convertie ainsi : "tag[1]/tag[1]/ANY_TAG[ANY_INDEX]/tag[1]". + * - l'index ANY_INDEX peut être défini avec un index vide "[]" : + * -> "tag/tag[]/\@attr" sera convertie ainsi : "tag[1]/tag[ANY_INDEX]/\@attr[1]", + * -> le motif "tag/[]/tag" est interdit. + */ +class ARCANE_UTILS_EXPORT +ParameterOptionAddr +{ + public: + + /*! + * \brief Constructeur. + * \param addr_str_view L'adresse à convertir. + */ + explicit ParameterOptionAddr(StringView addr_str_view); + + public: + + // On ne doit pas bloquer les multiples ParameterOptionAddrPart(ANY) : + // Construction par iteration : aaaa/bb/ANY/ANY/cc + /*! + * \brief Méthode permettant d'ajouter une partie à la fin de l'adresse actuelle. + * \param part Un pointeur vers la nouvelle partie. Attention, on récupère la + * propriété de l'objet (on gère le delete). + */ + void addAddrPart(ParameterOptionAddrPart* part); + + /*! + * \brief Méthode permettant de récupérer une partie de l'adresse. + * Si l'adresse termine par un ANY_TAG[ANY_INDEX], tous index donnés en paramètre + * supérieur au nombre de partie de l'adresse retournera le dernier élément de + * l'adresse ("ANY_TAG[ANY_INDEX]"). + * + * \param index_of_part L'index de la partie à récupérer. + * \return La partie de l'adresse. + */ + ParameterOptionAddrPart* addrPart(const Integer index_of_part) const; + + ParameterOptionAddrPart* lastAddrPart() const; + + /*! + * \brief Méthode permettant de récupérer le nombre de partie de l'adresse. + * Les parties égales à "ANY_TAG[ANY_INDEX]" sont comptées. + * + * \return Le nombre de partie de l'adresse. + */ + Integer nbAddrPart() const; + + /*! + * \brief Méthode permettant de récupérer un ou plusieurs indices dans l'adresse. + * + * Le fonctionnement de cette méthode est simple. + * Nous avons l'adresse suivante : "aaa[1]/bbb[2]/ccc[4]/\@name[1]". + * L'adresse en paramètre est la suivante : "aaa[1]/bbb[GET_INDEX]/ccc[4]/\@name[1]". + * L'indice ajouté dans la vue en paramètre sera 2. + * + * Si l'adresse en paramètre est : "aaa[1]/bbb[GET_INDEX]/ccc[GET_INDEX]/\@name[1]". + * Les indices ajoutés dans la vue seront 2 et 4. + * + * En revanche, un "GET_INDEX" ne peut pas être utilisé sur un "ANY_INDEX" (return false). + * Exemple : si l'on a : "aaa[1]/bbb[ANY_INDEX]/ccc[4]/\@name[1]". + * Et si l'adresse en paramètre est : "aaa[1]/bbb[GET_INDEX]/ccc[GET_INDEX]/\@name[1]". + * Le booléen retourné sera false. + * + * Pour avoir la bonne taille de la vue, un appel à la méthode "nbIndexToGetInAddr()" + * peut être effectué. + * + * \param addr_with_get_index L'adresse contenant des indices "GET_INDEX". + * \param indexes [OUT] La vue dans laquelle sera ajouté le ou les indices (la taille devra être correct). + * \return true si la vue a pu être remplie correctement. + */ + bool getIndexInAddr(const ParameterOptionAddr& addr_with_get_index, ArrayView indexes) const; + + /*! + * \brief Méthode permettant de savoir combien il y a de "GET_INDEX" dans l'adresse. + * \return Le nombre de "GET_INDEX". + */ + Integer nbIndexToGetInAddr() const; + + public: + + /*! + * \brief Opérateur d'égalité. + * Cet opérateur tient compte des ANY_TAG / ANY_INDEX. + * L'adresse "aaa[1]/bbb[2]/ANY_TAG[ANY_INDEX]" + * sera éqale à l'adresse "aaa[1]/bbb[2]/ccc[5]/ddd[7]" + * ou à l'adresse "aaa[1]/bbb[ANY_INDEX]/ccc[5]/ddd[7]" + * ou à l'adresse "aaa[1]/bbb[2]" + * mais pas à l'adresse "aaa[1]" + */ + bool operator==(const ParameterOptionAddr& other) const; + + private: + + UniqueArray> m_parts; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*! + * \brief Classe représentant un élément XML (une option Arcane). + * Cet élement a une adresse et une valeur. + */ +class ARCANE_UTILS_EXPORT +ParameterOptionElement +{ + public: + + ParameterOptionElement(const StringView addr, const StringView value); + + ParameterOptionAddr addr() const; + + StringView value() const; + + bool operator==(const ParameterOptionAddr& addr) const; + + private: + + ParameterOptionAddr m_addr; + StringView m_value; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/*! + * \brief Classe représentant un ensemble d'éléments XML (un ensemble d'options Arcane). + */ +class ARCANE_UTILS_EXPORT +ParameterOptionElementsCollection +{ + public: + + void addParameter(const String& parameter, const String& value); + + void addElement(StringView addr, StringView value); + + // ParameterOptionElement element(const Integer index) + // { + // return m_elements[index]; + // } + + // Un StringView "vide" est éqal à un StringView "nul". + // Comme on travaille avec des String et que la distinction + // vide/nul est importante, on passe par un std::optional. + std::optional value(const ParameterOptionAddr& addr); + + /*! + * \brief Méthode permettant de savoir si une adresse est présente dans la liste d'éléments. + * Les ANY_TAG/ANY_INDEX sont pris en compte. + * \param addr L'adresse à rechercher. + * \return true si l'adresse est trouvé. + */ + bool isExistAddr(const ParameterOptionAddr& addr); + + /*! + * \brief Méthode permettant de savoir combien de fois une adresse est présente dans la liste d'élements. + * Méthode particulièrement utile avec les ANY_TAG/ANY_INDEX. + * + * \param addr L'adresse à rechercher. + * \return Le nombre de correspondances trouvé. + */ + Integer countAddr(const ParameterOptionAddr& addr); + + /*! + * \brief Méthode permettant de récupérer un ou plusieurs indices dans la liste d'adresses. + * + * Le fonctionnement de cette méthode est simple. + * Nous avons les adresses suivantes : "aaa[1]/bbb[2]/ccc[1]/\@name[1]". + * "aaa[1]/bbb[2]/ccc[2]/\@name[1]". + * "ddd[1]/eee[2]". + * "fff[1]/ggg[2]/hhh[4]". + * L'adresse en paramètre est la suivante : "aaa[1]/bbb[2]/ccc[GET_INDEX]/\@name[1]". + * Les indices ajoutés dans le tableau en paramètre seront 1 et 2. + * + * Attention : Avoir une adresse en entrée avec plusieurs "GET_INDEX" est autorisé mais + * ça peut être dangereux si le nombre d'indices trouvé par adresse est différent pour + * chaque adresse (s'il y a deux "GET_INDEX" mais que dans une des adresses, il n'y a + * pas deux correspondances, ces éventuelles correspondances ne seront pas prises en + * compte). + * + * \param addr_with_get_index L'adresse contenant des indices "GET_INDEX". + * \param indexes [OUT] Le tableau dans lequel sera ajouté le ou les indices (le tableau + * n'est pas effacé avant utilisation). + */ + void getIndexInAddr(const ParameterOptionAddr& addr_with_get_index, UniqueArray& indexes); + + private: + + UniqueArray m_elements; +}; + + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} // End namespace Arcane + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#endif diff --git a/arcane/src/arcane/utils/srcs.cmake b/arcane/src/arcane/utils/srcs.cmake index dd317f0f34..145dc50d82 100644 --- a/arcane/src/arcane/utils/srcs.cmake +++ b/arcane/src/arcane/utils/srcs.cmake @@ -345,6 +345,8 @@ set(ARCANE_SOURCES internal/MemoryUtilsInternal.h internal/IMemoryRessourceMngInternal.h internal/IMemoryCopier.h + internal/ParameterOption.h + internal/ParameterOption.cc internal/ProfilingInternal.h internal/ValueConvertInternal.h internal/SpecificMemoryCopyList.h From 32fd5876ea4fdc37f0acc5f6fa6b178395fd1337 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Sat, 15 Feb 2025 16:40:13 +0100 Subject: [PATCH 15/24] [arcane:core] Add CaseOptionException in the CaseOptions 'Multi' parts --- arcane/src/arcane/core/CaseOptionExtended.cc | 45 +++++++++++++++++--- arcane/src/arcane/core/CaseOptionService.cc | 40 +++++++++++++++-- arcane/src/arcane/core/CaseOptionSimple.cc | 38 ++++++++++++++--- 3 files changed, 109 insertions(+), 14 deletions(-) diff --git a/arcane/src/arcane/core/CaseOptionExtended.cc b/arcane/src/arcane/core/CaseOptionExtended.cc index 51545f2eaf..b25554b37d 100644 --- a/arcane/src/arcane/core/CaseOptionExtended.cc +++ b/arcane/src/arcane/core/CaseOptionExtended.cc @@ -19,6 +19,7 @@ #include "arcane/utils/CommandLineArguments.h" #include "arcane/utils/ParameterList.h" #include "arcane/utils/ParameterCaseOption.h" +#include "arcane/utils/StringBuilder.h" #include "arcane/core/IApplication.h" #include "arcane/core/ICaseMng.h" @@ -28,6 +29,7 @@ #include "arcane/core/ICaseOptionList.h" #include "arcane/core/MeshHandle.h" #include "arcane/core/ICaseDocument.h" +#include "arcane/core/CaseOptionException.h" #include "arcane/core/internal/StringVariableReplace.h" /*---------------------------------------------------------------------------*/ @@ -52,11 +54,12 @@ _search(bool is_phase1) ITraceMng* tm = traceMng(); const ParameterList& params = caseMng()->application()->applicationInfo().commandLineArguments().parameters(); const ParameterCaseOption pco{ params.getParameterCaseOption(caseDocumentFragment()->language()) }; + String full_xpath = String::format("{0}/{1}", rootElement().xpathFullName(), name()); // !!! En XML, on commence par 1 et non 0. UniqueArray option_in_param; - pco.indexesInParam(String::format("{0}/{1}", rootElement().xpathFullName(), name()), option_in_param, false); + pco.indexesInParam(full_xpath, option_in_param, false); XmlNodeList elem_list = rootElement().children(name()); Integer size = elem_list.size(); @@ -71,6 +74,7 @@ _search(bool is_phase1) Integer max_in_param = 0; + // On regarde si l'utilisateur n'a pas mis un indice trop élevé pour l'option dans la ligne de commande. if (!option_in_param.empty()) { max_in_param = option_in_param[0]; for (Integer index : option_in_param) { @@ -79,31 +83,57 @@ _search(bool is_phase1) } if (max_occurs >= 0) { if (max_in_param > max_occurs) { - ARCANE_FATAL("Max in param > max_occurs"); + StringBuilder msg = "Bad number of occurences in command line (greater than max)"; + msg += " index_max_in_param="; + msg += max_in_param; + msg += " max_occur="; + msg += max_occurs; + msg += " option="; + msg += full_xpath; + throw CaseOptionException(A_FUNCINFO, msg.toString(), true); } } } if (max_occurs >= 0) { if (size > max_occurs) { - ARCANE_FATAL("Nb in XmlNodeList > max_occurs"); + StringBuilder msg = "Bad number of occurences (greater than max)"; + msg += " nb_occur="; + msg += size; + msg += " max_occur="; + msg += max_occurs; + msg += " option="; + msg += full_xpath; + throw CaseOptionException(A_FUNCINFO, msg.toString(), true); } } + // Il y aura toujours au moins min_occurs options. + // S'il n'y a pas assez l'options dans le jeu de données et dans les paramètres de la + // ligne de commande, on ajoute des services par défaut (si pas de défaut, il y aura un plantage). Integer final_size = std::max(size, std::max(min_occurs, max_in_param)); if (is_phase1) { _allocate(final_size); m_values.resize(final_size); } - else{ - //cerr << "** MULTI SEARCH " << size << endl; + else { + // D'abord, on aura les options du jeu de données : comme on ne peut pas définir un indice + // pour les options dans le jeu de données, elles seront forcément au début et seront contigües. + // Puis, s'il manque des options pour atteindre le min_occurs, on ajoute des options par défaut. + // S'il n'y a pas d'option par défaut, il y aura une exception. + // Enfin, l'utilisateur peut avoir ajouté des options à partir de la ligne de commande. On les ajoute alors. + // Si l'utilisateur souhaite modifier des valeurs du jeu de données à partir de la ligne de commande, on + // remplace les options au fur et à mesure de la lecture. for (Integer i = 0; i < final_size; ++i) { String str_val; + // Partie paramètres de la ligne de commande. if (option_in_param.contains(i + 1)) { - str_val = pco.getParameterOrNull(String::format("{0}/{1}", rootElement().xpathFullName(), name()), i + 1, false); + str_val = pco.getParameterOrNull(full_xpath, i + 1, false); } + + // Partie jeu de données. else if (i < size) { XmlNode velem = elem_list[i]; if (!velem.null()) { @@ -111,6 +141,7 @@ _search(bool is_phase1) } } + // Valeur par défaut. if (str_val.null()) { str_val = _defaultValue(); } @@ -119,6 +150,8 @@ _search(bool is_phase1) str_val = StringVariableReplace::replaceWithCmdLineArgs(params, str_val, true); } + // Maintenant, ce plantage concerne aussi le cas où il n'y a pas de valeurs par défaut et qu'il n'y a + // pas assez d'options pour atteindre le min_occurs. if (str_val.null()) { CaseOptionError::addOptionNotFoundError(caseDocumentFragment(),A_FUNCINFO, name(),rootElement()); diff --git a/arcane/src/arcane/core/CaseOptionService.cc b/arcane/src/arcane/core/CaseOptionService.cc index 3b04962f4b..0d0b03057b 100644 --- a/arcane/src/arcane/core/CaseOptionService.cc +++ b/arcane/src/arcane/core/CaseOptionService.cc @@ -19,6 +19,7 @@ #include "arcane/utils/FatalErrorException.h" #include "arcane/utils/ApplicationInfo.h" #include "arcane/utils/CommandLineArguments.h" +#include "arcane/utils/StringBuilder.h" #include "arcane/core/IApplication.h" #include "arcane/core/IServiceFactory.h" @@ -392,7 +393,6 @@ multiAllocate(const XmlNodeList& elem_list) String full_xpath = String::format("{0}/{1}", parent_element.xpathFullName(), name()); // !!! En XML, on commence par 1 et non 0. UniqueArray option_in_param; - pco.indexesInParam(full_xpath, option_in_param, true); Integer size = elem_list.size(); @@ -408,6 +408,7 @@ multiAllocate(const XmlNodeList& elem_list) Integer max_in_param = 0; + // On regarde si l'utilisateur n'a pas mis un indice trop élevé pour l'option dans la ligne de commande. if (!option_in_param.empty()) { max_in_param = option_in_param[0]; for (Integer index : option_in_param) { @@ -416,17 +417,34 @@ multiAllocate(const XmlNodeList& elem_list) } if (max_occurs >= 0) { if (max_in_param > max_occurs) { - ARCANE_FATAL("Max in param > max_occurs"); + StringBuilder msg = "Bad number of occurences in command line (greater than max)"; + msg += " index_max_in_param="; + msg += max_in_param; + msg += " max_occur="; + msg += max_occurs; + msg += " option="; + msg += full_xpath; + throw CaseOptionException(A_FUNCINFO, msg.toString(), true); } } } if (max_occurs >= 0) { if (size > max_occurs) { - ARCANE_FATAL("Nb in XmlNodeList > max_occurs"); + StringBuilder msg = "Bad number of occurences (greater than max)"; + msg += " nb_occur="; + msg += size; + msg += " max_occur="; + msg += max_occurs; + msg += " option="; + msg += full_xpath; + throw CaseOptionException(A_FUNCINFO, msg.toString(), true); } } + // Il y aura toujours au moins min_occurs options. + // S'il n'y a pas assez l'options dans le jeu de données et dans les paramètres de la + // ligne de commande, on ajoute des services par défaut (si pas de défaut, il y aura un plantage). Integer final_size = std::max(size, std::max(min_occurs, max_in_param)); ITraceMng* tm = traceMng(); @@ -439,16 +457,25 @@ multiAllocate(const XmlNodeList& elem_list) m_allocated_options.resize(final_size); m_services_name.resize(final_size); + // D'abord, on aura les options du jeu de données : comme on ne peut pas définir un indice + // pour les options dans le jeu de données, elles seront forcément au début et seront contigües. + // Puis, s'il manque des options pour atteindre le min_occurs, on ajoute des options par défaut. + // S'il n'y a pas d'option par défaut, il y aura une exception. + // Enfin, l'utilisateur peut avoir ajouté des options à partir de la ligne de commande. On les ajoute alors. + // Si l'utilisateur souhaite modifier des valeurs du jeu de données à partir de la ligne de commande, on + // remplace les options au fur et à mesure de la lecture. for (Integer index = 0; index < final_size; ++index) { XmlNode element; String mesh_name; String str_val; + // Partie paramètres de la ligne de commande. if (option_in_param.contains(index + 1)) { mesh_name = pco.getParameterOrNull(full_xpath, "@mesh-name", index + 1); str_val = pco.getParameterOrNull(full_xpath, "@name", index + 1); } + // Partie jeu de données. if (index < size && (mesh_name.null() || str_val.null())) { element = elem_list[index]; if (!element.null()) { @@ -459,6 +486,7 @@ multiAllocate(const XmlNodeList& elem_list) } } + // Valeur par défaut. if (mesh_name.null()) { mesh_name = meshName(); } @@ -467,6 +495,7 @@ multiAllocate(const XmlNodeList& elem_list) mesh_name = StringVariableReplace::replaceWithCmdLineArgs(params, mesh_name, true); } + // Valeur par défaut. if (str_val.null()) { str_val = _defaultValue(); } @@ -474,6 +503,8 @@ multiAllocate(const XmlNodeList& elem_list) // Dans un else : Le remplacement de symboles ne s'applique pas pour les valeurs par défault du .axl. str_val = StringVariableReplace::replaceWithCmdLineArgs(params, str_val, true); } + + // Si l'on n'utilise pas les options du jeu de données, on doit créer de nouvelles options. if (element.null()) { element = parent_element.createElement(name()); @@ -486,6 +517,9 @@ multiAllocate(const XmlNodeList& elem_list) << " v=" << str_val << " default_value='" << _defaultValue() << "'" << " mesh=" << meshHandle().meshName(); + + // Maintenant, ce plantage concerne aussi le cas où il n'y a pas de valeurs par défaut et qu'il n'y a + // pas assez d'options pour atteindre le min_occurs. if (str_val.null()) throw CaseOptionException("get_value", "@name"); diff --git a/arcane/src/arcane/core/CaseOptionSimple.cc b/arcane/src/arcane/core/CaseOptionSimple.cc index c753d83c50..a8b54ad9ef 100644 --- a/arcane/src/arcane/core/CaseOptionSimple.cc +++ b/arcane/src/arcane/core/CaseOptionSimple.cc @@ -19,6 +19,7 @@ #include "arcane/utils/ApplicationInfo.h" #include "arcane/utils/CommandLineArguments.h" #include "arcane/utils/ParameterCaseOption.h" +#include "arcane/utils/StringBuilder.h" #include "arcane/core/IApplication.h" #include "arcane/core/CaseOptionException.h" @@ -667,7 +668,6 @@ _search(bool is_phase1) String full_xpath = String::format("{0}/{1}", rootElement().xpathFullName(), name()); // !!! En XML, on commence par 1 et non 0. UniqueArray option_in_param; - pco.indexesInParam(full_xpath, option_in_param, false); XmlNodeList elem_list = rootElement().children(name()); @@ -692,17 +692,33 @@ _search(bool is_phase1) } if (max_occurs >= 0) { if (max_in_param > max_occurs) { - ARCANE_FATAL("Max in param > max_occurs"); + StringBuilder msg = "Bad number of occurences in command line (greater than max)"; + msg += " index_max_in_param="; + msg += max_in_param; + msg += " max_occur="; + msg += max_occurs; + msg += " option="; + msg += full_xpath; + throw CaseOptionException(A_FUNCINFO, msg.toString(), true); } } } if (max_occurs >= 0) { if (asize > max_occurs) { - ARCANE_FATAL("Nb in XmlNodeList > max_occurs"); + StringBuilder msg = "Bad number of occurences (greater than max)"; + msg += " nb_occur="; + msg += asize; + msg += " max_occur="; + msg += max_occurs; + msg += " option="; + msg += full_xpath; + throw CaseOptionException(A_FUNCINFO, msg.toString(), true); } } - + // Il y aura toujours au moins min_occurs options. + // S'il n'y a pas assez l'options dans le jeu de données et dans les paramètres de la + // ligne de commande, on ajoute des services par défaut (si pas de défaut, il y aura un plantage). Integer final_size = std::max(asize, std::max(min_occurs, max_in_param)); const Type* old_value = m_view.data(); @@ -712,13 +728,22 @@ _search(bool is_phase1) m_view = ArrayViewType(final_size, ptr_value); this->_setArray(ptr_value, final_size); - //cerr << "** MULTI SEARCH " << size << endl; + // D'abord, on aura les options du jeu de données : comme on ne peut pas définir un indice + // pour les options dans le jeu de données, elles seront forcément au début et seront contigües. + // Puis, s'il manque des options pour atteindre le min_occurs, on ajoute des options par défaut. + // S'il n'y a pas d'option par défaut, il y aura une exception. + // Enfin, l'utilisateur peut avoir ajouté des options à partir de la ligne de commande. On les ajoute alors. + // Si l'utilisateur souhaite modifier des valeurs du jeu de données à partir de la ligne de commande, on + // remplace les options au fur et à mesure de la lecture. for (Integer i = 0; i < final_size; ++i) { String str_val; + // Partie paramètres de la ligne de commande. if (option_in_param.contains(i + 1)) { str_val = pco.getParameterOrNull(full_xpath, i + 1, false); } + + // Partie jeu de données. else if (i < asize) { XmlNode velem = elem_list[i]; if (!velem.null()) { @@ -726,6 +751,7 @@ _search(bool is_phase1) } } + // Valeur par défaut. if (str_val.null()) { str_val = _defaultValue(); } @@ -734,6 +760,8 @@ _search(bool is_phase1) str_val = StringVariableReplace::replaceWithCmdLineArgs(params, str_val, true); } + // Maintenant, ce plantage concerne aussi le cas où il n'y a pas de valeurs par défaut et qu'il n'y a + // pas assez d'options pour atteindre le min_occurs. if (str_val.null()) CaseOptionError::addOptionNotFoundError(caseDocumentFragment(), A_FUNCINFO, name(), rootElement()); From b65e878c2c2769dcda7bfbb0dfff14874d05e06f Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Sat, 15 Feb 2025 17:50:03 +0100 Subject: [PATCH 16/24] [arcane:core,utils,launcher] Update header --- arcane/src/arcane/core/CaseOptionBase.cc | 4 ++-- arcane/src/arcane/core/CaseOptionBase.h | 4 ++-- arcane/src/arcane/core/CaseOptionExtended.cc | 4 ++-- arcane/src/arcane/core/CaseOptionList.cc | 4 ++-- arcane/src/arcane/core/CaseOptionService.cc | 4 ++-- arcane/src/arcane/core/CaseOptionSimple.cc | 6 ++--- arcane/src/arcane/core/CaseOptionSimple.h | 4 ++-- arcane/src/arcane/core/CaseOptions.h | 4 ++-- arcane/src/arcane/core/ICaseOptionList.h | 4 ++-- arcane/src/arcane/launcher/ArcaneLauncher.cc | 4 ++-- arcane/src/arcane/launcher/ArcaneLauncher.h | 4 ++-- arcane/src/arcane/launcher/GeneralHelp.cc | 25 ++++++++++++++++---- arcane/src/arcane/launcher/GeneralHelp.h | 15 ++++++++++-- arcane/src/arcane/utils/ParameterList.cc | 4 ++-- arcane/src/arcane/utils/ParameterList.h | 4 ++-- 15 files changed, 60 insertions(+), 34 deletions(-) diff --git a/arcane/src/arcane/core/CaseOptionBase.cc b/arcane/src/arcane/core/CaseOptionBase.cc index 62620a8783..157ee1edd5 100644 --- a/arcane/src/arcane/core/CaseOptionBase.cc +++ b/arcane/src/arcane/core/CaseOptionBase.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* CaseOptionBase.cc (C) 2000-2023 */ +/* CaseOptionBase.cc (C) 2000-2025 */ /* */ /* Gestion des options du jeu de données. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/core/CaseOptionBase.h b/arcane/src/arcane/core/CaseOptionBase.h index 850a788279..9ebb2ae8fa 100644 --- a/arcane/src/arcane/core/CaseOptionBase.h +++ b/arcane/src/arcane/core/CaseOptionBase.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* CaseOptionBase.h (C) 2000-2023 */ +/* CaseOptionBase.h (C) 2000-2025 */ /* */ /* Classe d'une base d'une option du jeu de donnés. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/core/CaseOptionExtended.cc b/arcane/src/arcane/core/CaseOptionExtended.cc index b25554b37d..d47af61a96 100644 --- a/arcane/src/arcane/core/CaseOptionExtended.cc +++ b/arcane/src/arcane/core/CaseOptionExtended.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* CaseOptionExtended.cc (C) 2000-2023 */ +/* CaseOptionExtended.cc (C) 2000-2025 */ /* */ /* Option du jeu de données de type 'Extended'. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/core/CaseOptionList.cc b/arcane/src/arcane/core/CaseOptionList.cc index edd63cbe50..34092e052d 100644 --- a/arcane/src/arcane/core/CaseOptionList.cc +++ b/arcane/src/arcane/core/CaseOptionList.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* CaseOptionList.cc (C) 2000-2023 */ +/* CaseOptionList.cc (C) 2000-2025 */ /* */ /* Liste d'options de configuration d'un service ou module. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/core/CaseOptionService.cc b/arcane/src/arcane/core/CaseOptionService.cc index 0d0b03057b..5ecf700758 100644 --- a/arcane/src/arcane/core/CaseOptionService.cc +++ b/arcane/src/arcane/core/CaseOptionService.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* CaseOptions.cc (C) 2000-2023 */ +/* CaseOptionsService.cc (C) 2000-2025 */ /* */ /* Gestion des options du jeu de données. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/core/CaseOptionSimple.cc b/arcane/src/arcane/core/CaseOptionSimple.cc index a8b54ad9ef..032d5d25a8 100644 --- a/arcane/src/arcane/core/CaseOptionSimple.cc +++ b/arcane/src/arcane/core/CaseOptionSimple.cc @@ -1,13 +1,13 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2022 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* CaseOptionEnum.cc (C) 2000-2023 */ +/* CaseOptionSimple.cc (C) 2000-2025 */ /* */ -/* Option du jeu de données de type énuméré. */ +/* Option du jeu de données de type simple . */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/core/CaseOptionSimple.h b/arcane/src/arcane/core/CaseOptionSimple.h index 2eda02f0be..8b1cdf6efa 100644 --- a/arcane/src/arcane/core/CaseOptionSimple.h +++ b/arcane/src/arcane/core/CaseOptionSimple.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* CaseOptionSimple.h (C) 2000-2023 */ +/* CaseOptionSimple.h (C) 2000-2025 */ /* */ /* Option simple du jeu de données. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/core/CaseOptions.h b/arcane/src/arcane/core/CaseOptions.h index b916ab2181..99ea500210 100644 --- a/arcane/src/arcane/core/CaseOptions.h +++ b/arcane/src/arcane/core/CaseOptions.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* CaseOptions.h (C) 2000-2023 */ +/* CaseOptions.h (C) 2000-2025 */ /* */ /* Options du jeu de données. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/core/ICaseOptionList.h b/arcane/src/arcane/core/ICaseOptionList.h index 067b70f096..d514f46d64 100644 --- a/arcane/src/arcane/core/ICaseOptionList.h +++ b/arcane/src/arcane/core/ICaseOptionList.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ICaseOptionList.h (C) 2000-2023 */ +/* ICaseOptionList.h (C) 2000-2025 */ /* */ /* Options du jeu de données. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/launcher/ArcaneLauncher.cc b/arcane/src/arcane/launcher/ArcaneLauncher.cc index 2ef3ec0cb1..7b69116bea 100644 --- a/arcane/src/arcane/launcher/ArcaneLauncher.cc +++ b/arcane/src/arcane/launcher/ArcaneLauncher.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ArcaneLauncher.cc (C) 2000-2024 */ +/* ArcaneLauncher.cc (C) 2000-2025 */ /* */ /* Classe gérant le lancement de l'exécution. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/launcher/ArcaneLauncher.h b/arcane/src/arcane/launcher/ArcaneLauncher.h index 38d65ad407..fd99a4869c 100644 --- a/arcane/src/arcane/launcher/ArcaneLauncher.h +++ b/arcane/src/arcane/launcher/ArcaneLauncher.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ArcaneLauncher.h (C) 2000-2024 */ +/* ArcaneLauncher.h (C) 2000-2025 */ /* */ /* Classe gérant l'exécution. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/launcher/GeneralHelp.cc b/arcane/src/arcane/launcher/GeneralHelp.cc index f46af3e077..191708118b 100644 --- a/arcane/src/arcane/launcher/GeneralHelp.cc +++ b/arcane/src/arcane/launcher/GeneralHelp.cc @@ -1,4 +1,4 @@ -// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- // Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. @@ -11,14 +11,23 @@ /*---------------------------------------------------------------------------*/ #include "arcane/launcher/GeneralHelp.h" -#include "arcane/utils/ApplicationInfo.h" + #include "arcane/core/ApplicationBuildInfo.h" -#include -#include +#include "arcane/impl/ArcaneMain.h" + +#include "arcane/utils/ApplicationInfo.h" +#include "arcane/utils/CommandLineArguments.h" + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ namespace Arcane { + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + void GeneralHelp:: printHelp() { @@ -46,4 +55,10 @@ printHelp() std::cout << " -A,MaxIteration= Nombre maximum d'itérations à effectuer pour l'exécution. Si le nombre d'itérations spécifié par cette variable est atteint, le calcul s'arrête." << std::endl; } -} +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} // namespace Arcane + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/launcher/GeneralHelp.h b/arcane/src/arcane/launcher/GeneralHelp.h index ddd058cc5f..1c3763d62a 100644 --- a/arcane/src/arcane/launcher/GeneralHelp.h +++ b/arcane/src/arcane/launcher/GeneralHelp.h @@ -1,4 +1,4 @@ -// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- // Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. @@ -16,14 +16,25 @@ #include "arcane/launcher/LauncherGlobal.h" +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + namespace Arcane { + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + class ARCANE_LAUNCHER_EXPORT GeneralHelp { public: static void printHelp(); }; -} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} // namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/ParameterList.cc b/arcane/src/arcane/utils/ParameterList.cc index 4febbe7c19..d60d8ed11e 100644 --- a/arcane/src/arcane/utils/ParameterList.cc +++ b/arcane/src/arcane/utils/ParameterList.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2022 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ParameterList.cc (C) 2000-2020 */ +/* ParameterList.cc (C) 2000-2025 */ /* */ /* Liste de paramêtres. */ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/ParameterList.h b/arcane/src/arcane/utils/ParameterList.h index 6a13d9e033..801586dcaa 100644 --- a/arcane/src/arcane/utils/ParameterList.h +++ b/arcane/src/arcane/utils/ParameterList.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2022 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ParameterList.h (C) 2000-2020 */ +/* ParameterList.h (C) 2000-2025 */ /* */ /* Liste de paramètres. */ /*---------------------------------------------------------------------------*/ From 32965be2ca1dc0d76d723c221decb1e64bdeb81f Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Mon, 17 Feb 2025 10:13:28 +0100 Subject: [PATCH 17/24] [arcane:utils] Replace ASSERTS with FATALS for user dependent errors --- .../arcane/utils/internal/ParameterOption.cc | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/arcane/src/arcane/utils/internal/ParameterOption.cc b/arcane/src/arcane/utils/internal/ParameterOption.cc index 6d45cf4de4..5fec478901 100644 --- a/arcane/src/arcane/utils/internal/ParameterOption.cc +++ b/arcane/src/arcane/utils/internal/ParameterOption.cc @@ -163,11 +163,20 @@ ParameterOptionAddr(const StringView addr_str_view) if (span_line[i] == '[') { index_begin = i + 1; size = i - begin; - ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); - ARCANE_ASSERT(index_begin < span_line.size(), ("Invalid option (']' not found)")); + if (size == 0) { + const StringView current = addr_str_view.subView(0, i + 1); + ARCANE_FATAL("Invalid parameter option (empty tag) -- Current read : {0}", current); + } + if (index_begin >= span_line.size()) { + const StringView current = addr_str_view.subView(0, i + 1); + ARCANE_FATAL("Invalid parameter option (']' not found) -- Current read : {0}", current); + } } else if (span_line[i] == ']') { - ARCANE_ASSERT(index_begin != -1, ("Invalid option (']' found without '[')")); + if (index_begin == -1) { + const StringView current = addr_str_view.subView(0, i + 1); + ARCANE_FATAL("Invalid parameter option (']' found without '[' before) -- Current read : {0}", current); + } // Motif spécial "[]" (= ANY_INDEX) if (index_begin == i) { @@ -179,7 +188,8 @@ ParameterOptionAddr(const StringView addr_str_view) Integer index; bool is_bad = builtInGetValue(index, index_str); if (is_bad) { - ARCANE_FATAL("Invalid index"); + const StringView current = addr_str_view.subView(0, i + 1); + ARCANE_FATAL("Invalid index in parameter option -- Current read : {0}", current); } m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size), index))); have_a_no_any = true; @@ -187,7 +197,10 @@ ParameterOptionAddr(const StringView addr_str_view) } else if (span_line[i] == '/') { - ARCANE_ASSERT(i + 1 != span_line.size(), ("Invalid option ('/' found at the end of the param option)")); + if (i + 1 == span_line.size()) { + const StringView current = addr_str_view.subView(0, i + 1); + ARCANE_FATAL("Invalid parameter option ('/' found at the end of the param option) -- Current read : {0}", current); + } if (index_begin == -1) { size = i - begin; @@ -208,7 +221,10 @@ ParameterOptionAddr(const StringView addr_str_view) } if (index_begin == -1) { size = static_cast(span_line.size()) - begin; - ARCANE_ASSERT(size != 0, ("Invalid option (empty name)")); + if (size == 0) { + const StringView current = addr_str_view.subView(0, size); + ARCANE_FATAL("Invalid parameter option (empty tag) -- Current read : {0}", current); + } m_parts.add(makeRef(new ParameterOptionAddrPart(addr_str_view.subView(begin, size)))); have_a_no_any = true; From 45b22b482f21d5fc47556ee619f052210c8cb82f Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Mon, 17 Feb 2025 12:05:08 +0100 Subject: [PATCH 18/24] [arcane:tests] Add unit tests for ParameterOption classes --- arcane/src/arcane/tests/CMakeLists.txt | 6 + .../src/arcane/tests/ParameterOptionTest.axl | 9 + .../src/arcane/tests/ParameterOptionTest.cc | 293 ++++++++++++++++++ arcane/src/arcane/tests/srcs.cmake | 2 + arcane/tests/testParameterOption.arc | 37 +++ 5 files changed, 347 insertions(+) create mode 100644 arcane/src/arcane/tests/ParameterOptionTest.axl create mode 100644 arcane/src/arcane/tests/ParameterOptionTest.cc create mode 100644 arcane/tests/testParameterOption.arc diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index ec6c1c03bf..fcd7ade925 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -1163,6 +1163,12 @@ arcane_add_test_sequential(string_variable_replace testStringVariableReplace.arc ################################################################# ################################################################# +# Test pour la partie ParameterOption. +arcane_add_test_sequential(parameter_option testParameterOption.arc) + +################################################################# +################################################################# + # Test pour les implementations de TimeHistoryAdder. arcane_add_test(time_history_adder_1 testTimeHistoryAdder-1.arc -c 2 -m 5 -We,ARCANE_ENABLE_NON_IO_MASTER_CURVES,1) diff --git a/arcane/src/arcane/tests/ParameterOptionTest.axl b/arcane/src/arcane/tests/ParameterOptionTest.axl new file mode 100644 index 0000000000..58bd3f47af --- /dev/null +++ b/arcane/src/arcane/tests/ParameterOptionTest.axl @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/arcane/src/arcane/tests/ParameterOptionTest.cc b/arcane/src/arcane/tests/ParameterOptionTest.cc new file mode 100644 index 0000000000..3c6c0c862f --- /dev/null +++ b/arcane/src/arcane/tests/ParameterOptionTest.cc @@ -0,0 +1,293 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* ParameterOptionTest.cc (C) 2000-2025 */ +/* */ +/* Service de test de ParameterOption. */ +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#include "arcane/utils/ParameterList.h" + +#include "arcane/core/BasicUnitTest.h" +#include "arcane/utils/internal/ParameterOption.h" + +#include "arcane/tests/ParameterOptionTest_axl.h" + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +namespace ArcaneTest +{ + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +using namespace Arcane; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +class ParameterOptionTest +: public ArcaneParameterOptionTestObject +{ + public: + + explicit ParameterOptionTest(const ServiceBuildInfo& sbi); + ~ParameterOptionTest(); + + public: + + void initializeTest() override; + void executeTest() override; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ARCANE_REGISTER_SERVICE_PARAMETEROPTIONTEST(ParameterOptionTest, ParameterOptionTest); + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionTest:: +ParameterOptionTest(const ServiceBuildInfo& sbi) +: ArcaneParameterOptionTestObject(sbi) +{ +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +ParameterOptionTest:: +~ParameterOptionTest() += default; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterOptionTest:: +initializeTest() +{ + +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterOptionTest:: +executeTest() +{ + ParameterOptionElementsCollection poec; + + struct POption + { + String param; + String value; + }; + + POption option0{"module/option0", "0 0"}; + + const UniqueArray p_options{ + {"//module/option1", "5"}, + {"//module/option2", "aa"}, + {"//module/option2[2]", "bb"} + }; + + poec.addElement(option0.param, option0.value); + for (const auto& [param, value] : p_options) { + poec.addParameter(param, value); + } + + { + const String addr = "module/option1"; + const String value = poec.value(ParameterOptionAddr(addr.view())).value(); + if (value != "5") { + ARCANE_FATAL("Test 1"); + } + } + + { + const String addr = "noexist/option"; + if (poec.value(ParameterOptionAddr(addr.view())).has_value()) { + ARCANE_FATAL("Test 2"); + } + } + + { + const String addr = "module/option0"; + if (!poec.isExistAddr(ParameterOptionAddr(addr.view()))) { + ARCANE_FATAL("Test 3"); + } + } + + { + const String addr = "module/option2"; + ParameterOptionAddr addr_option(addr.view()); + + // En correspondance parfaite, il n'y en a qu'un seul. + if (poec.countAddr(addr_option) != 1) { + ARCANE_FATAL("Test 4.1"); + } + + addr_option.lastAddrPart()->setIndex(2); + + // Avec l'index 2, il n'y en a aussi qu'un seul. + if (poec.countAddr(addr_option) != 1) { + ARCANE_FATAL("Test 4.2"); + } + + addr_option.lastAddrPart()->setIndex(ParameterOptionAddrPart::ANY_INDEX); + + // Avec un ANY_INDEX à la fin, il y en a les deux. + if (poec.countAddr(addr_option) != 2) { + ARCANE_FATAL("Test 4.3"); + } + } + + { + const String addr = "module/option2"; + + ParameterOptionAddr addr_option(addr.view()); + addr_option.lastAddrPart()->setIndex(ParameterOptionAddrPart::GET_INDEX); + + UniqueArray index; + poec.getIndexInAddr(addr_option, index); + + if (index != UniqueArray{1, 2}) { + ARCANE_FATAL("Test 5"); + } + } + + { + const String addr1 = "test/option2"; + const String addr2 = "test/option2"; + + ParameterOptionAddr addr1_option(addr1.view()); + ParameterOptionAddr addr2_option(addr2.view()); + addr1_option.addAddrPart(new ParameterOptionAddrPart()); + if (addr1_option != addr2_option) { + ARCANE_FATAL("Test 6.1"); + } + if (addr2_option != addr1_option) { + ARCANE_FATAL("Test 6.2"); + } + } + + { + const String addr1 = "test/option2"; + const String addr2 = "test"; + + ParameterOptionAddr addr1_option(addr1.view()); + ParameterOptionAddr addr2_option(addr2.view()); + + if (addr1_option == addr2_option) { + ARCANE_FATAL("Test 7"); + } + } + + { + const String addr1 = "test/option2"; + const String addr2 = "test/option2[2]"; + + ParameterOptionAddr addr1_option(addr1.view()); + ParameterOptionAddr addr2_option(addr2.view()); + + if (addr1_option == addr2_option) { + ARCANE_FATAL("Test 8"); + } + } + + { + const String addr1 = "test/option2[3]/option[10]"; + const String addr2 = "test/option2/option"; + + ParameterOptionAddr addr1_option(addr1.view()); + ParameterOptionAddr addr2_option(addr2.view()); + + addr2_option.addrPart(0)->setIndex(ParameterOptionAddrPart::GET_INDEX); + addr2_option.addrPart(1)->setIndex(ParameterOptionAddrPart::GET_INDEX); + addr2_option.addrPart(2)->setIndex(ParameterOptionAddrPart::GET_INDEX); + + // On a trois GET_INDEX. + if (addr2_option.nbIndexToGetInAddr() != 3) { + ARCANE_FATAL("Test 9.1"); + } + + UniqueArray index(3); + UniqueArray result{1, 3, 10}; + bool ret = addr1_option.getIndexInAddr(addr2_option, index.view()); + + if (!ret) { + ARCANE_FATAL("Test 9.2"); + } + + if (index != result) { + ARCANE_FATAL("Test 9.3"); + } + } + + { + const String addr1 = "test/option2"; + const String addr2 = "test/option2"; + + ParameterOptionAddr addr1_option(addr1.view()); + ParameterOptionAddr addr2_option(addr2.view()); + + addr1_option.lastAddrPart()->setIndex(ParameterOptionAddrPart::ANY_INDEX); + addr2_option.lastAddrPart()->setIndex(ParameterOptionAddrPart::GET_INDEX); + + UniqueArray index(1); + bool ret = addr1_option.getIndexInAddr(addr2_option, index.view()); + + // Impossible de faire un GET_INDEX sur un ANY_INDEX. + if (ret) { + ARCANE_FATAL("Test 10"); + } + } + + // Il y a déjà un ARCANE_ASSERT qui vérifie ça. +#ifndef ARCANE_DEBUG_ASSERT + { + const String addr1 = "test/option2"; + const String addr2 = "test/option2"; + + ParameterOptionAddr addr1_option(addr1.view()); + ParameterOptionAddr addr2_option(addr2.view()); + + addr2_option.lastAddrPart()->setIndex(ParameterOptionAddrPart::GET_INDEX); + + UniqueArray index(3); + bool ret = addr1_option.getIndexInAddr(addr2_option, index.view()); + + // Le tableau index n'est pas à la bonne taille (un seul GET_INDEX). + if (ret) { + ARCANE_FATAL("Test 11"); + } + } +#endif + + { + const String addr1 = "test/option2"; + ParameterOptionAddr addr1_option(addr1.view()); + + const String option3 = "option3"; + addr1_option.lastAddrPart()->setTag(option3.view()); + + if (addr1_option.lastAddrPart()->tag() != option3.view()) { + ARCANE_FATAL("Test 12"); + } + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/tests/srcs.cmake b/arcane/src/arcane/tests/srcs.cmake index 50c01cdb82..3afa4e49a0 100644 --- a/arcane/src/arcane/tests/srcs.cmake +++ b/arcane/src/arcane/tests/srcs.cmake @@ -80,6 +80,7 @@ set(ARCANE_SOURCES StringVariableReplaceTest.cc TimeHistoryAdderTestModule.cc MeshCriteriaLoadBalanceMngTestModule.cc + ParameterOptionTest.cc ) set(AXL_FILES @@ -132,5 +133,6 @@ set(AXL_FILES StringVariableReplaceTest TimeHistoryAdderTest MeshCriteriaLoadBalanceMngTest + ParameterOptionTest ) diff --git a/arcane/tests/testParameterOption.arc b/arcane/tests/testParameterOption.arc new file mode 100644 index 0000000000..26d1708797 --- /dev/null +++ b/arcane/tests/testParameterOption.arc @@ -0,0 +1,37 @@ + + + + Test StringVariableReplace + UnitTest + + + + + + 1 + + 1 + 1 + + 0.0 0.0 + + + 1.0 + 1 + + + + 1.0 + 1 + + + + + + + + + + + + \ No newline at end of file From 17fa32c3bae37d3db143450539e61de3bea6a56f Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Mon, 17 Feb 2025 13:58:06 +0100 Subject: [PATCH 19/24] [arcane:utils,tests] Add three tests for the Command Line Replace part --- arcane/src/arcane/tests/CMakeLists.txt | 31 ++++++++++++++++++- .../arcane/utils/internal/ParameterOption.cc | 10 +++++- .../arcane/utils/internal/ParameterOption.h | 14 +++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index fcd7ade925..d8a2bd06d4 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -337,7 +337,7 @@ arcane_add_test_sequential(caseoptions_commandlinereplace testCaseOptions-comman "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" "-A,TestId=1" "-A,SimpleRealUnit2=0.0" - "-A,//case-options-tester/simple-real=3.0" + "-A,//case-options-tester/simple-real[]=3.0" "-A,//case-options-tester/simple-real-unit=4.2" "-A,SimpleRealUnit2=0.0" "-A,//case-options-tester/simple-realarray-unit=\"2.2 2.3 0.1 3.5\"" @@ -371,6 +371,35 @@ arcane_add_test_sequential(caseoptions_commandlinereplace testCaseOptions-comman "-A,//case-options-tester/complex1/simple-real-2-multi[2]=2.3" ) +arcane_add_test_sequential(caseoptions_commandlinereplace_fail1 testCaseOptions-specific-entry-point.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,//case-options-tester/[1]=3.0" +) +set_property(TEST caseoptions_commandlinereplace_fail1 PROPERTY WILL_FAIL true) + +arcane_add_test_sequential(caseoptions_commandlinereplace_fail2 testCaseOptions-specific-entry-point.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,//case-options-tester/simple-real[aa]=3.0" +) +set_property(TEST caseoptions_commandlinereplace_fail2 PROPERTY WILL_FAIL true) + +arcane_add_test_sequential(caseoptions_commandlinereplace_fail3 testCaseOptions-specific-entry-point.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,//case-options-tester/simple-real[1]/=3.0" +) +set_property(TEST caseoptions_commandlinereplace_fail3 PROPERTY WILL_FAIL true) + +#arcane_add_test_sequential(caseoptions_commandlinereplace_fail4 testCaseOptions-specific-entry-point.arc +# "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" +# "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" +# "-A,//case-options-tester/simple-real[=3.0" +#) +#set_property(TEST caseoptions_commandlinereplace_fail4 PROPERTY WILL_FAIL true) + + if(UDUNITS_FOUND) ARCANE_ADD_TEST_SEQUENTIAL(caseoptions_unit testCaseOptions-2.arc) endif() diff --git a/arcane/src/arcane/utils/internal/ParameterOption.cc b/arcane/src/arcane/utils/internal/ParameterOption.cc index 5fec478901..9a64eeaab4 100644 --- a/arcane/src/arcane/utils/internal/ParameterOption.cc +++ b/arcane/src/arcane/utils/internal/ParameterOption.cc @@ -121,7 +121,6 @@ operator==(const ParameterOptionAddrPart& other) const /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -// TODO AH : À supprimer lors du passage en C++20. bool ParameterOptionAddrPart:: operator!=(const ParameterOptionAddrPart& other) const { @@ -347,6 +346,15 @@ operator==(const ParameterOptionAddr& other) const /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +bool ParameterOptionAddr:: +operator!=(const ParameterOptionAddr& other) const +{ + return !operator==(other); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/utils/internal/ParameterOption.h b/arcane/src/arcane/utils/internal/ParameterOption.h index 730e3abb80..24d538c7f5 100644 --- a/arcane/src/arcane/utils/internal/ParameterOption.h +++ b/arcane/src/arcane/utils/internal/ParameterOption.h @@ -77,6 +77,7 @@ ParameterOptionAddrPart Integer index() const; //! Si l'index est ANY_INDEX, le tag ne peut pas être ANY_TAG. + //! Attention à la durée de vie de tag. void setTag(const StringView tag); void setIndex(const Integer index); @@ -210,6 +211,9 @@ ParameterOptionAddr */ bool operator==(const ParameterOptionAddr& other) const; + // TODO AH : À supprimer lors du passage en C++20. + bool operator!=(const ParameterOptionAddr& other) const; + private: UniqueArray> m_parts; @@ -252,6 +256,16 @@ ParameterOptionElementsCollection { public: + /*! + * \brief Méthode permettant d'ajouter un paramètre d'option dans la liste + * des paramètres d'options. + * + * \warning Les deux paramètres ne sont pas copiés ! On ne récupère qu'une vue. L'utilisateur + * de cette classe doit gérer la durée de vie de ces objets. + * + * \param parameter Le paramètre d'option brut (avec les "//" au début). + * \param value La valeur de l'option. + */ void addParameter(const String& parameter, const String& value); void addElement(StringView addr, StringView value); From df9208e27943161e17f5792d6df22d56acd1ef13 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Mon, 17 Feb 2025 15:07:32 +0100 Subject: [PATCH 20/24] [arcane:tests] Add unit tests for ParameterCaseOption --- .../src/arcane/tests/ParameterOptionTest.cc | 238 ++++++++++++++++-- 1 file changed, 215 insertions(+), 23 deletions(-) diff --git a/arcane/src/arcane/tests/ParameterOptionTest.cc b/arcane/src/arcane/tests/ParameterOptionTest.cc index 3c6c0c862f..d731eccfeb 100644 --- a/arcane/src/arcane/tests/ParameterOptionTest.cc +++ b/arcane/src/arcane/tests/ParameterOptionTest.cc @@ -21,6 +21,15 @@ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +namespace +{ +struct POption +{ + Arcane::String param; + Arcane::String value; +}; +} // namespace + namespace ArcaneTest { @@ -44,6 +53,8 @@ class ParameterOptionTest void initializeTest() override; void executeTest() override; + void _internalStructs(); + void _userStruct(); }; /*---------------------------------------------------------------------------*/ @@ -82,13 +93,17 @@ initializeTest() void ParameterOptionTest:: executeTest() { - ParameterOptionElementsCollection poec; + _internalStructs(); + _userStruct(); +} - struct POption - { - String param; - String value; - }; +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void ParameterOptionTest:: +_internalStructs() +{ + ParameterOptionElementsCollection poec; POption option0{"module/option0", "0 0"}; @@ -107,21 +122,21 @@ executeTest() const String addr = "module/option1"; const String value = poec.value(ParameterOptionAddr(addr.view())).value(); if (value != "5") { - ARCANE_FATAL("Test 1"); + ARCANE_FATAL("_internalStructs -- Test 1"); } } { const String addr = "noexist/option"; if (poec.value(ParameterOptionAddr(addr.view())).has_value()) { - ARCANE_FATAL("Test 2"); + ARCANE_FATAL("_internalStructs -- Test 2"); } } { const String addr = "module/option0"; if (!poec.isExistAddr(ParameterOptionAddr(addr.view()))) { - ARCANE_FATAL("Test 3"); + ARCANE_FATAL("_internalStructs -- Test 3"); } } @@ -131,21 +146,21 @@ executeTest() // En correspondance parfaite, il n'y en a qu'un seul. if (poec.countAddr(addr_option) != 1) { - ARCANE_FATAL("Test 4.1"); + ARCANE_FATAL("_internalStructs -- Test 4.1"); } addr_option.lastAddrPart()->setIndex(2); // Avec l'index 2, il n'y en a aussi qu'un seul. if (poec.countAddr(addr_option) != 1) { - ARCANE_FATAL("Test 4.2"); + ARCANE_FATAL("_internalStructs -- Test 4.2"); } addr_option.lastAddrPart()->setIndex(ParameterOptionAddrPart::ANY_INDEX); // Avec un ANY_INDEX à la fin, il y en a les deux. if (poec.countAddr(addr_option) != 2) { - ARCANE_FATAL("Test 4.3"); + ARCANE_FATAL("_internalStructs -- Test 4.3"); } } @@ -159,7 +174,7 @@ executeTest() poec.getIndexInAddr(addr_option, index); if (index != UniqueArray{1, 2}) { - ARCANE_FATAL("Test 5"); + ARCANE_FATAL("_internalStructs -- Test 5"); } } @@ -171,10 +186,10 @@ executeTest() ParameterOptionAddr addr2_option(addr2.view()); addr1_option.addAddrPart(new ParameterOptionAddrPart()); if (addr1_option != addr2_option) { - ARCANE_FATAL("Test 6.1"); + ARCANE_FATAL("_internalStructs -- Test 6.1"); } if (addr2_option != addr1_option) { - ARCANE_FATAL("Test 6.2"); + ARCANE_FATAL("_internalStructs -- Test 6.2"); } } @@ -186,7 +201,7 @@ executeTest() ParameterOptionAddr addr2_option(addr2.view()); if (addr1_option == addr2_option) { - ARCANE_FATAL("Test 7"); + ARCANE_FATAL("_internalStructs -- Test 7"); } } @@ -198,7 +213,7 @@ executeTest() ParameterOptionAddr addr2_option(addr2.view()); if (addr1_option == addr2_option) { - ARCANE_FATAL("Test 8"); + ARCANE_FATAL("_internalStructs -- Test 8"); } } @@ -215,7 +230,7 @@ executeTest() // On a trois GET_INDEX. if (addr2_option.nbIndexToGetInAddr() != 3) { - ARCANE_FATAL("Test 9.1"); + ARCANE_FATAL("_internalStructs -- Test 9.1"); } UniqueArray index(3); @@ -223,11 +238,11 @@ executeTest() bool ret = addr1_option.getIndexInAddr(addr2_option, index.view()); if (!ret) { - ARCANE_FATAL("Test 9.2"); + ARCANE_FATAL("_internalStructs -- Test 9.2"); } if (index != result) { - ARCANE_FATAL("Test 9.3"); + ARCANE_FATAL("_internalStructs -- Test 9.3"); } } @@ -246,7 +261,7 @@ executeTest() // Impossible de faire un GET_INDEX sur un ANY_INDEX. if (ret) { - ARCANE_FATAL("Test 10"); + ARCANE_FATAL("_internalStructs -- Test 10"); } } @@ -266,7 +281,7 @@ executeTest() // Le tableau index n'est pas à la bonne taille (un seul GET_INDEX). if (ret) { - ARCANE_FATAL("Test 11"); + ARCANE_FATAL("_internalStructs -- Test 11"); } } #endif @@ -279,7 +294,7 @@ executeTest() addr1_option.lastAddrPart()->setTag(option3.view()); if (addr1_option.lastAddrPart()->tag() != option3.view()) { - ARCANE_FATAL("Test 12"); + ARCANE_FATAL("_internalStructs -- Test 12"); } } } @@ -287,6 +302,183 @@ executeTest() /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +void ParameterOptionTest:: +_userStruct() +{ + auto poec = new ParameterOptionElementsCollection(); + + const UniqueArray p_options{ + { "//module/option1", "5" }, + { "//module/option2", "aa" }, + { "//module/option2[2]", "bb" }, + { "//module/option3[]/@min", "3" }, + { "//module/option3", "4" }, + { "//module/option3[2]", "10" }, + { "//module//@mesh-name", "Mesh1" }, + { "//module/service1/@name", "SayHello" }, + { "//module/service1/option1", "2.0 3.0" }, + { "//module/service1/option2[1]", "123456789 987654321" }, + { "//module/service1/option2[2]", "-3 2" }, + { "//module/service1[2]/@name", "SayGoodbye" }, + { "//module/service1[2]/option1", "2.0 3.0" }, + { "//module/service1[2]/option2[1]", "123456789 987654321" }, + { "//module/service1[2]/option2[2]", "-3 2" } + }; + + for (const auto& [param, value] : p_options) { + poec->addParameter(param, value); + } + { + ParameterCaseOption pco(poec, "en"); + + { + const String xpath = "//case/module/option1"; + if (pco.count(xpath) != 1) { + ARCANE_FATAL("_userStruct -- Test 1"); + } + } + + { + const String xpath_before = "//case/module/service1"; + const String xpath_after = "@name"; + if (pco.count(xpath_before, xpath_after) != 2) { + ARCANE_FATAL("_userStruct -- Test 2"); + } + } + + { + const String xpath = "//case/module/service1"; + UniqueArray index; + + pco.indexesInParam(xpath, index, false); + + if (!index.empty()) { + ARCANE_FATAL("_userStruct -- Test 3.1"); + } + + index.clear(); + pco.indexesInParam(xpath, index, true); + + if (index != UniqueArray{ 1, 1, 1, 1, 2, 2, 2, 2 }) { + ARCANE_FATAL("_userStruct -- Test 3.2"); + } + } + + { + const String xpath_before = "//case/module/service1"; + const String xpath_after = "@name"; + UniqueArray index; + pco.indexesInParam(xpath_before, xpath_after, index); + + if (index != UniqueArray{ 1, 2 }) { + ARCANE_FATAL("_userStruct -- Test 4"); + } + } + + { + const String xpath = "//case/module/service1/option2"; + if (!pco.existAnyIndex(xpath)) { + ARCANE_FATAL("_userStruct -- Test 5"); + } + } + + { + const String xpath = "//case/module/service1/option3"; + if (pco.existAnyIndex(xpath)) { + ARCANE_FATAL("_userStruct -- Test 6"); + } + } + + { + const String xpath_before = "//case/module/service1"; + const String xpath_after = "option2"; + if (!pco.existAnyIndex(xpath_before, xpath_after)) { + ARCANE_FATAL("_userStruct -- Test 7"); + } + } + + { + const String xpath_before = "//case/module/service2"; + const String xpath_after = "option2"; + if (pco.existAnyIndex(xpath_before, xpath_after)) { + ARCANE_FATAL("_userStruct -- Test 8"); + } + } + + { + const String xpath = "//case/module/service1/option3"; + if (pco.existAnyIndex(xpath)) { + ARCANE_FATAL("_userStruct -- Test 9"); + } + } + + { + const String xpath = "//case/module/service1/option2[2]"; + if (!pco.exist(xpath)) { + ARCANE_FATAL("_userStruct -- Test 10"); + } + } + + { + const String xpath = "//case/module/service1/option2[3]"; + if (pco.exist(xpath)) { + ARCANE_FATAL("_userStruct -- Test 11"); + } + } + + { + const String xpath = "//case/module[1]/service1[1]/option2[1]"; + if (pco.getParameterOrNull(xpath) != "123456789 987654321") { + ARCANE_FATAL("_userStruct -- Test 12"); + } + } + + { + const String xpath = "//case/module[1]/service1[3]/option2[1]"; + if (pco.getParameterOrNull(xpath) != String()) { + ARCANE_FATAL("_userStruct -- Test 13"); + } + } + + { + const String xpath = "//case/module/option3"; + if (pco.getParameterOrNull(xpath, 1, false) != "4") { + ARCANE_FATAL("_userStruct -- Test 14"); + } + } + + { + const String xpath = "//case/module/option4"; + if (pco.getParameterOrNull(xpath, 1, false) != String()) { + ARCANE_FATAL("_userStruct -- Test 15"); + } + } + + { + const String xpath_before = "//case/module/option3"; + const String xpath_after = "@min"; + if (pco.getParameterOrNull(xpath_before, xpath_after, 1) != "3") { + ARCANE_FATAL("_userStruct -- Test 16.1"); + } + if (pco.getParameterOrNull(xpath_before, xpath_after, 2) != "3") { + ARCANE_FATAL("_userStruct -- Test 16.2"); + } + } + + { + const String xpath = "//case/module/service1[2]/@mesh-name"; + if (pco.getParameterOrNull(xpath) != "Mesh1") { + ARCANE_FATAL("_userStruct -- Test 17"); + } + } + } + + delete poec; +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + } /*---------------------------------------------------------------------------*/ From 5a3223f0b1b8ed5d67b47e4a03968f37278cd87e Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Mon, 17 Feb 2025 15:23:45 +0100 Subject: [PATCH 21/24] [arcane:tests] Add some fail tests for CaseOptions --- arcane/src/arcane/tests/CMakeLists.txt | 39 ++++++++++++++++++- arcane/src/arcane/tests/CaseOptionsTester.axl | 2 +- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index d8a2bd06d4..e82eda9e1c 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -392,12 +392,47 @@ arcane_add_test_sequential(caseoptions_commandlinereplace_fail3 testCaseOptions- ) set_property(TEST caseoptions_commandlinereplace_fail3 PROPERTY WILL_FAIL true) -#arcane_add_test_sequential(caseoptions_commandlinereplace_fail4 testCaseOptions-specific-entry-point.arc +arcane_add_test_sequential(caseoptions_commandlinereplace_fail4 testCaseOptions-specific-entry-point.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,//case-options-tester/simple-real-array-multi[6]=\"3.0 4.0\"" +) +set_property(TEST caseoptions_commandlinereplace_fail4 PROPERTY WILL_FAIL true) + +arcane_add_test_sequential(caseoptions_commandlinereplace_fail5 testCaseOptions-specific-entry-point.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,//case-options-tester/simple-integer=aaa" +) +set_property(TEST caseoptions_commandlinereplace_fail5 PROPERTY WILL_FAIL true) + +arcane_add_test_sequential(caseoptions_commandlinereplace_fail6 testCaseOptions-specific-entry-point.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,//case-options-tester/post-processor1-fr[20]/@name=UCDPostProcessor" +) +set_property(TEST caseoptions_commandlinereplace_fail6 PROPERTY WILL_FAIL true) + +arcane_add_test_sequential(caseoptions_commandlinereplace_fail7 testCaseOptions-specific-entry-point.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,//case-options-tester/post-processor1-fr/binary-file-=false" +) +set_property(TEST caseoptions_commandlinereplace_fail7 PROPERTY WILL_FAIL true) + +arcane_add_test_sequential(caseoptions_commandlinereplace_fail8 testCaseOptions-specific-entry-point.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,//case-options-tester/post-processor1-fr/binary-file:=false" +) +set_property(TEST caseoptions_commandlinereplace_fail8 PROPERTY WILL_FAIL true) + +#arcane_add_test_sequential(caseoptions_commandlinereplace_fail99 testCaseOptions-specific-entry-point.arc # "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" # "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" # "-A,//case-options-tester/simple-real[=3.0" #) -#set_property(TEST caseoptions_commandlinereplace_fail4 PROPERTY WILL_FAIL true) +#set_property(TEST caseoptions_commandlinereplace_fail99 PROPERTY WILL_FAIL true) if(UDUNITS_FOUND) diff --git a/arcane/src/arcane/tests/CaseOptionsTester.axl b/arcane/src/arcane/tests/CaseOptionsTester.axl index a964d33599..76a1d29487 100644 --- a/arcane/src/arcane/tests/CaseOptionsTester.axl +++ b/arcane/src/arcane/tests/CaseOptionsTester.axl @@ -392,7 +392,7 @@ name = "post-processor1" type = "Arcane::IPostProcessorWriter" minOccurs = "0" - maxOccurs = "unbounded" + maxOccurs="10" > post-processor1-fr Liste des services de protection From d4889f6e52d93f6de68a1037408b51ca73a536e2 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Mon, 17 Feb 2025 15:44:21 +0100 Subject: [PATCH 22/24] [arcane:tests] Remove a unit test in internal part --- .../src/arcane/tests/ParameterOptionTest.cc | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/arcane/src/arcane/tests/ParameterOptionTest.cc b/arcane/src/arcane/tests/ParameterOptionTest.cc index d731eccfeb..659f104f1b 100644 --- a/arcane/src/arcane/tests/ParameterOptionTest.cc +++ b/arcane/src/arcane/tests/ParameterOptionTest.cc @@ -265,27 +265,6 @@ _internalStructs() } } - // Il y a déjà un ARCANE_ASSERT qui vérifie ça. -#ifndef ARCANE_DEBUG_ASSERT - { - const String addr1 = "test/option2"; - const String addr2 = "test/option2"; - - ParameterOptionAddr addr1_option(addr1.view()); - ParameterOptionAddr addr2_option(addr2.view()); - - addr2_option.lastAddrPart()->setIndex(ParameterOptionAddrPart::GET_INDEX); - - UniqueArray index(3); - bool ret = addr1_option.getIndexInAddr(addr2_option, index.view()); - - // Le tableau index n'est pas à la bonne taille (un seul GET_INDEX). - if (ret) { - ARCANE_FATAL("_internalStructs -- Test 11"); - } - } -#endif - { const String addr1 = "test/option2"; ParameterOptionAddr addr1_option(addr1.view()); @@ -294,7 +273,7 @@ _internalStructs() addr1_option.lastAddrPart()->setTag(option3.view()); if (addr1_option.lastAddrPart()->tag() != option3.view()) { - ARCANE_FATAL("_internalStructs -- Test 12"); + ARCANE_FATAL("_internalStructs -- Test 11"); } } } From 0bcf9b635d408dfbab1141ae6194113a9ffa978a Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Mon, 17 Feb 2025 18:35:58 +0100 Subject: [PATCH 23/24] [arcane:tests] Add a test for the StringVariableReplace::replaceWithCmdLineArgs() without a ParameterList --- arcane/src/arcane/tests/CMakeLists.txt | 5 ++- .../arcane/tests/StringVariableReplaceTest.cc | 37 +++++++++++-------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index e82eda9e1c..ccc203de1e 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -1222,7 +1222,10 @@ endif() ################################################################# # Test pour la partie StringVariableReplace. -arcane_add_test_sequential(string_variable_replace testStringVariableReplace.arc) +arcane_add_test_sequential(string_variable_replace testStringVariableReplace.arc + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,aa=bb" +) ################################################################# ################################################################# diff --git a/arcane/src/arcane/tests/StringVariableReplaceTest.cc b/arcane/src/arcane/tests/StringVariableReplaceTest.cc index 4d61ee374a..af5c9b9ada 100644 --- a/arcane/src/arcane/tests/StringVariableReplaceTest.cc +++ b/arcane/src/arcane/tests/StringVariableReplaceTest.cc @@ -12,6 +12,9 @@ /*---------------------------------------------------------------------------*/ #include "arcane/utils/ParameterList.h" +#include "arcane/utils/CommandLineArguments.h" +#include "arcane/utils/List.h" +#include "arcane/utils/PlatformUtils.h" #include "arcane/core/BasicUnitTest.h" #include "arcane/core/internal/StringVariableReplace.h" @@ -82,40 +85,42 @@ initializeTest() void StringVariableReplaceTest:: executeTest() { - ParameterList params; + StringList args; + platform::fillCommandLineArguments(args); + const CommandLineArguments cla{ args }; + + ParameterList params(cla.parameters()); String test("aaaa"); bool fatal = true; - String result = StringVariableReplace::replaceWithCmdLineArgs(params, test); + String result = StringVariableReplace::replaceWithCmdLineArgs(test); - if(result != test) { + if (result != test) { ARCANE_FATAL("Test 1 -- Expected: {0} -- Actual: {1}", test, result); } info() << "Test 1 OK"; /*---------------------------------------------------------------------------*/ - params.addParameterLine("ARCANE_REPLACE_SYMBOLS_IN_DATASET=1"); - - result = StringVariableReplace::replaceWithCmdLineArgs(params, ""); + result = StringVariableReplace::replaceWithCmdLineArgs(""); - if(result != "") { + if (result != "") { ARCANE_FATAL("Test 2 -- Expected: {0} -- Actual: {1}", "", result); } info() << "Test 2 OK"; /*---------------------------------------------------------------------------*/ - result = StringVariableReplace::replaceWithCmdLineArgs(params, test); + result = StringVariableReplace::replaceWithCmdLineArgs(test); - if(result != test) { + if (result != test) { ARCANE_FATAL("Test 3 -- Expected: {0} -- Actual: {1}", test, result); } info() << "Test 3 OK"; /*---------------------------------------------------------------------------*/ - params.addParameterLine("aa=bb"); + //params.addParameterLine("aa=bb"); // Dans le CMakeLists. /*---------------------------------------------------------------------------*/ @@ -123,7 +128,7 @@ executeTest() fatal = false; try { - StringVariableReplace::replaceWithCmdLineArgs(params, test); + StringVariableReplace::replaceWithCmdLineArgs(test); fatal = true; } catch (const FatalErrorException& e) { @@ -132,7 +137,7 @@ executeTest() ARCANE_FATAL("Test 4 no fatal test"); } - result = StringVariableReplace::replaceWithCmdLineArgs(params, test, false, false); + result = StringVariableReplace::replaceWithCmdLineArgs(test, false, false); String expected = "aaaa"; if (result != expected) { @@ -144,7 +149,7 @@ executeTest() test = "@aa@aa@aa@"; - result = StringVariableReplace::replaceWithCmdLineArgs(params, test); + result = StringVariableReplace::replaceWithCmdLineArgs(test); expected = "bbaabb"; if (result != expected) { @@ -156,7 +161,7 @@ executeTest() test = "@aa@@aa@"; - result = StringVariableReplace::replaceWithCmdLineArgs(params, test); + result = StringVariableReplace::replaceWithCmdLineArgs(test); expected = "bbbb"; if (result != expected) { @@ -170,7 +175,7 @@ executeTest() fatal = false; try { - StringVariableReplace::replaceWithCmdLineArgs(params, test); + StringVariableReplace::replaceWithCmdLineArgs(test); fatal = true; } catch (const FatalErrorException& e) { @@ -179,7 +184,7 @@ executeTest() ARCANE_FATAL("Test 7 no fatal test"); } - result = StringVariableReplace::replaceWithCmdLineArgs(params, test, false, false); + result = StringVariableReplace::replaceWithCmdLineArgs(test, false, false); expected = ""; if (result != expected) { From 7f8037063fba155d483434bef67ccf60c4b37487 Mon Sep 17 00:00:00 2001 From: Alexandre l'Heritier Date: Mon, 17 Feb 2025 19:32:40 +0100 Subject: [PATCH 24/24] [arcane:tests] Add a test for CaseOptionExtended --- arcane/src/arcane/tests/CMakeLists.txt | 7 +++++++ arcane/src/arcane/tests/CaseOptionsTester.axl | 2 +- arcane/tests/testCaseOptions-commandLineReplace.arc | 1 - 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index ccc203de1e..4c88db426c 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -427,6 +427,13 @@ arcane_add_test_sequential(caseoptions_commandlinereplace_fail8 testCaseOptions- ) set_property(TEST caseoptions_commandlinereplace_fail8 PROPERTY WILL_FAIL true) +arcane_add_test_sequential(caseoptions_commandlinereplace_fail9 testCaseOptions-specific-entry-point.arc + "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" + "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" + "-A,//case-options-tester/complex2[2]/complex3/extended-real-int-c3[9]=enum1" +) +set_property(TEST caseoptions_commandlinereplace_fail9 PROPERTY WILL_FAIL true) + #arcane_add_test_sequential(caseoptions_commandlinereplace_fail99 testCaseOptions-specific-entry-point.arc # "-We,ARCANE_CALL_SPECIFIC_ENTRY_POINT,CaseOptionLoop2" # "-We,ARCANE_REPLACE_SYMBOLS_IN_DATASET,1" diff --git a/arcane/src/arcane/tests/CaseOptionsTester.axl b/arcane/src/arcane/tests/CaseOptionsTester.axl index 76a1d29487..81a3a27359 100644 --- a/arcane/src/arcane/tests/CaseOptionsTester.axl +++ b/arcane/src/arcane/tests/CaseOptionsTester.axl @@ -622,7 +622,7 @@ name = "extended-real-int-c3" type = "ArcaneTest::TestRealInt" minOccurs = "0" - maxOccurs = "unbounded" + maxOccurs = "5" > ExtendedRealInt2 diff --git a/arcane/tests/testCaseOptions-commandLineReplace.arc b/arcane/tests/testCaseOptions-commandLineReplace.arc index 52df3abd98..468c9de234 100644 --- a/arcane/tests/testCaseOptions-commandLineReplace.arc +++ b/arcane/tests/testCaseOptions-commandLineReplace.arc @@ -67,7 +67,6 @@ 3.0 2.0 4.0 4 enum2 - enum1 2.0 3.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0