mirror of https://github.com/KLayout/klayout.git
WIP: provide a recipe registration facility for LVS rerun
This commit is contained in:
parent
444e10d32f
commit
515b68b76f
|
|
@ -27,6 +27,7 @@
|
|||
#include "tlProgress.h"
|
||||
#include "tlExpression.h"
|
||||
#include "tlGlobPattern.h"
|
||||
#include "tlRecipe.h"
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Logger binding
|
||||
|
|
@ -640,4 +641,83 @@ Class<tl::GlobPattern> decl_GlobPattern ("tl", "GlobPattern",
|
|||
"This class has been introduced in version 0.26."
|
||||
);
|
||||
|
||||
class Recipe_Impl
|
||||
: public tl::Recipe
|
||||
{
|
||||
public:
|
||||
Recipe_Impl (const std::string &name, const std::string &description)
|
||||
: tl::Recipe (name, description)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual tl::Variant execute (const std::map<std::string, tl::Variant> ¶ms) const
|
||||
{
|
||||
if (execute_cb.can_issue ()) {
|
||||
return execute_cb.issue<tl::Recipe, tl::Variant, const std::map<std::string, tl::Variant> &> (&tl::Recipe::execute, params);
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback execute_cb;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
template <> struct type_traits<gsi::Recipe_Impl> : public type_traits<tl::Recipe> { };
|
||||
}
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
static Recipe_Impl *make_recipe (const std::string &name, const std::string &description)
|
||||
{
|
||||
return new Recipe_Impl (name, description);
|
||||
}
|
||||
|
||||
Class<Recipe_Impl> decl_Recipe_Impl ("tl", "Recipe",
|
||||
gsi::constructor ("new", &make_recipe, gsi::arg ("name"), gsi::arg ("description", std::string ()),
|
||||
"@brief Creates a new recipe object with the given name and (optional) description"
|
||||
) +
|
||||
gsi::method ("name", &Recipe_Impl::name,
|
||||
"@brief Gets the name of the recipe."
|
||||
) +
|
||||
gsi::method ("description", &Recipe_Impl::description,
|
||||
"@brief Gets the description of the recipe."
|
||||
) +
|
||||
gsi::method ("make", &Recipe_Impl::make, gsi::arg ("generator"),
|
||||
"@brief Executes the recipe given by the generator string.\n"
|
||||
"The generator string is the one delivered with \\generator."
|
||||
) +
|
||||
gsi::method ("generator", &Recipe_Impl::generator, gsi::arg ("params"),
|
||||
"@brief Delivers the generator string from the given parameters.\n"
|
||||
"The generator string can be used with \\make to re-run the recipe."
|
||||
) +
|
||||
gsi::callback ("execute", &Recipe_Impl::execute, &Recipe_Impl::execute_cb,
|
||||
"@brief Reimplement this method to provide the functionality of the recipe.\n"
|
||||
"This method is supposed to re-run the recipe with the given parameters and deliver the "
|
||||
"the intended output object."
|
||||
),
|
||||
"@brief A facility for providing reproducable recipes\n"
|
||||
"The idea of this facility is to provide a service by which an object\n"
|
||||
"can be reproduced in a parametrized way. The intended use case is a \n"
|
||||
"DRC report for example, where the DRC script is the generator.\n"
|
||||
"\n"
|
||||
"In this use case, the DRC engine will register a recipe. It will \n"
|
||||
"put the serialized version of the recipe into the DRC report. If the \n"
|
||||
"user requests a re-run of the DRC, the recipe will be called and \n"
|
||||
"the implementation is supposed to deliver a new database.\n"
|
||||
"\n"
|
||||
"To register a recipe, reimplement tl::Recipe and create a singleton\n"
|
||||
"instance. To serialize a recipe, use \"generator\", to execute the\n"
|
||||
"recipe, use \"make\". \n"
|
||||
"\n"
|
||||
"Parameters are kept as a generic key/value map.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.26."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ SOURCES = \
|
|||
tlUniqueId.cc \
|
||||
tlList.cc \
|
||||
tlEquivalenceClusters.cc \
|
||||
tlUniqueName.cc
|
||||
tlUniqueName.cc \
|
||||
tlRecipe.cc
|
||||
|
||||
HEADERS = \
|
||||
tlAlgorithm.h \
|
||||
|
|
@ -100,7 +101,8 @@ HEADERS = \
|
|||
tlUniqueId.h \
|
||||
tlList.h \
|
||||
tlEquivalenceClusters.h \
|
||||
tlUniqueName.h
|
||||
tlUniqueName.h \
|
||||
tlRecipe.h
|
||||
|
||||
equals(HAVE_CURL, "1") {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "tlRecipe.h"
|
||||
#include "tlString.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
Recipe::Recipe (const std::string &name, const std::string &description)
|
||||
: tl::RegisteredClass<tl::Recipe> (this, 0, name.c_str (), false)
|
||||
{
|
||||
m_name = name;
|
||||
m_description = description;
|
||||
}
|
||||
|
||||
std::string Recipe::generator (const std::map<std::string, tl::Variant> ¶ms)
|
||||
{
|
||||
std::string g;
|
||||
g += tl::to_word_or_quoted_string (name ());
|
||||
g += ": ";
|
||||
|
||||
for (std::map<std::string, tl::Variant>::const_iterator p = params.begin (); p != params.end (); ++p) {
|
||||
if (p != params.begin ()) {
|
||||
g += ",";
|
||||
}
|
||||
g += tl::to_word_or_quoted_string (p->first);
|
||||
g += "=";
|
||||
g += p->second.to_parsable_string ();
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
tl::Variant Recipe::make (const std::string &generator)
|
||||
{
|
||||
tl::Extractor ex (generator.c_str ());
|
||||
|
||||
std::string recipe;
|
||||
ex.read_word_or_quoted (recipe);
|
||||
ex.test (":");
|
||||
|
||||
std::map<std::string, tl::Variant> params;
|
||||
while (! ex.at_end ()) {
|
||||
std::string key;
|
||||
ex.read_word_or_quoted (key);
|
||||
ex.test ("=");
|
||||
tl::Variant v;
|
||||
ex.read (v);
|
||||
ex.test (",");
|
||||
params.insert (std::make_pair (key, v));
|
||||
}
|
||||
|
||||
tl::Recipe *recipe_obj = 0;
|
||||
for (tl::Registrar<tl::Recipe>::iterator r = tl::Registrar<tl::Recipe>::begin (); r != tl::Registrar<tl::Recipe>::end (); ++r) {
|
||||
if (r->name () == recipe) {
|
||||
recipe_obj = r.operator-> ();
|
||||
}
|
||||
}
|
||||
|
||||
if (! recipe_obj) {
|
||||
return tl::Variant ();
|
||||
} else {
|
||||
return recipe_obj->execute (params);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tl
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_tlRecipe
|
||||
#define HDR_tlRecipe
|
||||
|
||||
#include "tlCommon.h"
|
||||
#include "tlVariant.h"
|
||||
#include "tlTypeTraits.h"
|
||||
#include "tlClassRegistry.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A facility for providing reproducable recipes
|
||||
*
|
||||
* The idea of this facility is to provide a service by which an object
|
||||
* can be reproduced in a parametrized way. The intended use case is a
|
||||
* DRC report for example, where the DRC script is the generator.
|
||||
*
|
||||
* In this use case, the DRC engine will register a recipe. It will
|
||||
* put the serialized version of the recipe into the DRC report. If the
|
||||
* user requests a re-run of the DRC, the recipe will be called and
|
||||
* the implementation is supposed to deliver a new database.
|
||||
*
|
||||
* To register a recipe, reimplement tl::Recipe and create a singleton
|
||||
* instance. To serialize a recipe, use "generator", to execute the
|
||||
* recipe, use "make".
|
||||
*
|
||||
* Parameters are kept as a generic key/value map.
|
||||
*/
|
||||
class TL_PUBLIC Recipe
|
||||
: public tl::RegisteredClass<Recipe>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief @brief Creates a new recipe object
|
||||
*/
|
||||
Recipe (const std::string &name, const std::string &description = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~Recipe () { }
|
||||
|
||||
/**
|
||||
* @brief Gets the recipes name (a unique identifier)
|
||||
*/
|
||||
const std::string &name () const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the description text
|
||||
*/
|
||||
const std::string &description () const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief An utility function to get a parameters
|
||||
*/
|
||||
template <class T>
|
||||
static T get_value (const std::map<std::string, tl::Variant> ¶ms, const std::string &pname, const T &def_value)
|
||||
{
|
||||
std::map<std::string, tl::Variant>::const_iterator p = params.find (pname);
|
||||
if (p != params.end ()) {
|
||||
const tl::Variant &v = p->second;
|
||||
return v.to<T> ();
|
||||
} else {
|
||||
return def_value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serializes the given recipe
|
||||
*/
|
||||
std::string generator (const std::map<std::string, tl::Variant> ¶ms);
|
||||
|
||||
/**
|
||||
* @brief Executes the recipe from the generator
|
||||
*
|
||||
* Returns nil if the recipe can't be executed, e.g. because the recipe isn't known.
|
||||
*/
|
||||
static tl::Variant make (const std::string &generator);
|
||||
|
||||
/**
|
||||
* @brief Recipe interface: executes the recipe with the given parameters
|
||||
*/
|
||||
virtual tl::Variant execute (const std::map<std::string, tl::Variant> ¶ms) const = 0;
|
||||
|
||||
private:
|
||||
Recipe (const Recipe &) : tl::RegisteredClass<tl::Recipe> (this) { }
|
||||
Recipe &operator= (const Recipe &) { return *this; }
|
||||
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
};
|
||||
|
||||
template<> struct type_traits<tl::Recipe> : public type_traits<void>
|
||||
{
|
||||
typedef tl::false_tag has_copy_constructor;
|
||||
typedef tl::false_tag has_default_constructor;
|
||||
};
|
||||
|
||||
} // namespace tl
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "tlRecipe.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
|
||||
class MyRecipe : public tl::Recipe
|
||||
{
|
||||
public:
|
||||
MyRecipe () : tl::Recipe ("test_recipe", "description") { }
|
||||
|
||||
tl::Variant execute (const std::map<std::string, tl::Variant> ¶ms) const
|
||||
{
|
||||
int a = get_value (params, "A", 0);
|
||||
double b = get_value (params, "B", 0.0);
|
||||
return tl::Variant (b * a);
|
||||
}
|
||||
};
|
||||
|
||||
static MyRecipe my_recipe;
|
||||
|
||||
}
|
||||
|
||||
// basic abilities
|
||||
TEST(1)
|
||||
{
|
||||
std::map<std::string, tl::Variant> params;
|
||||
params["A"] = tl::Variant (7);
|
||||
params["B"] = tl::Variant (6.0);
|
||||
std::string g = my_recipe.generator (params);
|
||||
EXPECT_EQ (g, "test_recipe: A=#7,B=##6");
|
||||
|
||||
tl::Variant res = tl::Recipe::make (g);
|
||||
EXPECT_EQ (res.to_double (), 42.0);
|
||||
}
|
||||
|
|
@ -38,7 +38,8 @@ SOURCES = \
|
|||
tlListTests.cc \
|
||||
tlEquivalenceClustersTests.cc \
|
||||
tlUniqueNameTests.cc \
|
||||
tlGlobPatternTests.cc
|
||||
tlGlobPatternTests.cc \
|
||||
tlRecipeTests.cc
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -262,6 +262,42 @@ class Tl_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
class MyRecipe < RBA::Recipe
|
||||
|
||||
def initialize
|
||||
super("test_recipe", "description")
|
||||
end
|
||||
|
||||
def execute(params)
|
||||
a = params["A"] || 0
|
||||
b = params["B"] || 0.0
|
||||
b * a
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Recipe
|
||||
def test_4_Recipe
|
||||
|
||||
# make sure there isn't a second instance
|
||||
GC.start
|
||||
|
||||
my_recipe = MyRecipe::new
|
||||
my_recipe._create # makes debugging easier
|
||||
|
||||
assert_equal(my_recipe.name, "test_recipe")
|
||||
assert_equal(my_recipe.description, "description")
|
||||
|
||||
g = my_recipe.generator("A" => 6, "B" => 7.0)
|
||||
assert_equal(g, "test_recipe: A=#6,B=##7")
|
||||
assert_equal("%g" % RBA::Recipe::make(g).to_s, "42")
|
||||
|
||||
my_recipe._destroy
|
||||
my_recipe = nil
|
||||
GC.start
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue