mirror of https://github.com/KLayout/klayout.git
Adding enhanced property types to OASIS. The writer options have a new flag that turns non-standard types of properties such as objects or nested lists into annotated strings.
This commit is contained in:
parent
96cf0b640d
commit
d24697a5e3
|
|
@ -101,7 +101,7 @@ public:
|
||||||
* @brief The constructor
|
* @brief The constructor
|
||||||
*/
|
*/
|
||||||
OASISWriterOptions ()
|
OASISWriterOptions ()
|
||||||
: compression_level (2), write_cblocks (true), strict_mode (true), recompress (false), permissive (false),
|
: compression_level (2), enhanced_property_types (true), write_cblocks (true), strict_mode (true), recompress (false), permissive (false),
|
||||||
write_std_properties (1), subst_char ("*"), tables_at_end (false)
|
write_std_properties (1), subst_char ("*"), tables_at_end (false)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
|
|
@ -116,7 +116,20 @@ public:
|
||||||
* 1 - nearest neighbor shape array formation
|
* 1 - nearest neighbor shape array formation
|
||||||
* 2++ - enhanced shape array search algorithm using 2nd and further neighbor distances as well
|
* 2++ - enhanced shape array search algorithm using 2nd and further neighbor distances as well
|
||||||
*/
|
*/
|
||||||
int compression_level;
|
int compression_level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enhanced property types
|
||||||
|
*
|
||||||
|
* If this option is set to true (the default), complex property types
|
||||||
|
* such as lists or even objects can be embedded into OASIS files.
|
||||||
|
* For this, KLayout uses strings with a special annotation
|
||||||
|
* (i.e. "KLAYOUT_VALUE:...").
|
||||||
|
*
|
||||||
|
* This option also implies that only properties with string values
|
||||||
|
* (and numerical keys) are written as S_GDS_PROPERTY properties.
|
||||||
|
*/
|
||||||
|
bool enhanced_property_types;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief CBLOCK compression
|
* @brief CBLOCK compression
|
||||||
|
|
|
||||||
|
|
@ -78,20 +78,6 @@ struct vector_cmp_y
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Determines whether a property shall be produced as S_GDS_PROPERTY
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
make_gds_property (const tl::Variant &name)
|
|
||||||
{
|
|
||||||
// We write S_GDS_PROPERTY properties, because that is the only way to write properties
|
|
||||||
// with numerical keys
|
|
||||||
return (name.is_longlong () && name.to_longlong () < 0x8000 && name.to_longlong () >= 0) ||
|
|
||||||
(name.is_ulonglong () && name.to_ulonglong () < 0x8000) ||
|
|
||||||
(name.is_long () && name.to_long () < 0x8000 && name.to_long () >= 0) ||
|
|
||||||
(name.is_ulong () && name.to_ulong () < 0x8000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -970,15 +956,46 @@ OASISWriter::write_ucoord (db::Coord c)
|
||||||
const std::string klayout_prop_string_prefix = "KLAYOUT_VALUE:";
|
const std::string klayout_prop_string_prefix = "KLAYOUT_VALUE:";
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
OASISWriter::make_prop_string (const tl::Variant &v)
|
OASISWriter::make_prop_string (const tl::Variant &v) const
|
||||||
{
|
{
|
||||||
if (v.is_a_string ()) {
|
if (! m_options.enhanced_property_types) {
|
||||||
|
|
||||||
return v.to_stdstring ();
|
return v.to_stdstring ();
|
||||||
|
|
||||||
|
} else if (v.is_a_string ()) {
|
||||||
|
|
||||||
|
std::string s = v.to_stdstring ();
|
||||||
|
|
||||||
|
// if the string starts with the prefix, encode it using the prefixed notation
|
||||||
|
if (strncmp (s.c_str (), klayout_prop_string_prefix.c_str (), klayout_prop_string_prefix.size ()) == 0) {
|
||||||
|
return klayout_prop_string_prefix + v.to_parsable_string ();
|
||||||
|
} else {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return klayout_prop_string_prefix + v.to_parsable_string ();
|
return klayout_prop_string_prefix + v.to_parsable_string ();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
OASISWriter::make_gds_property (const tl::Variant &name, const tl::Variant &value) const
|
||||||
|
{
|
||||||
|
// Only strings will become GDS properties in enhanced properties mode
|
||||||
|
if (m_options.enhanced_property_types && !value.is_a_string ()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We write S_GDS_PROPERTY properties, because that is the only way to write properties
|
||||||
|
// with numerical keys
|
||||||
|
return (name.is_longlong () && name.to_longlong () < 0x8000 && name.to_longlong () >= 0) ||
|
||||||
|
(name.is_ulonglong () && name.to_ulonglong () < 0x8000) ||
|
||||||
|
(name.is_long () && name.to_long () < 0x8000 && name.to_long () >= 0) ||
|
||||||
|
(name.is_ulong () && name.to_ulong () < 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OASISWriter::emit_propname_def (db::properties_id_type prop_id)
|
OASISWriter::emit_propname_def (db::properties_id_type prop_id)
|
||||||
{
|
{
|
||||||
|
|
@ -989,7 +1006,7 @@ OASISWriter::emit_propname_def (db::properties_id_type prop_id)
|
||||||
const tl::Variant &value = db::property_value (p->second);
|
const tl::Variant &value = db::property_value (p->second);
|
||||||
|
|
||||||
std::string name_str (s_gds_property_name);
|
std::string name_str (s_gds_property_name);
|
||||||
if (! value.is_a_string () || ! make_gds_property (name)) {
|
if (! make_gds_property (name, value)) {
|
||||||
name_str = make_prop_string (name);
|
name_str = make_prop_string (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1016,7 +1033,7 @@ OASISWriter::emit_propstring_def (db::properties_id_type prop_id)
|
||||||
const tl::Variant &name = db::property_name (p->first);
|
const tl::Variant &name = db::property_name (p->first);
|
||||||
const tl::Variant &value = db::property_value (p->second);
|
const tl::Variant &value = db::property_value (p->second);
|
||||||
|
|
||||||
if (! value.is_a_string () || ! make_gds_property (name)) {
|
if (! make_gds_property (name, value)) {
|
||||||
|
|
||||||
if (value.is_list ()) {
|
if (value.is_list ()) {
|
||||||
pvl = &value.get_list ();
|
pvl = &value.get_list ();
|
||||||
|
|
@ -2158,7 +2175,7 @@ OASISWriter::write_props (db::properties_id_type prop_id)
|
||||||
pv_list.clear ();
|
pv_list.clear ();
|
||||||
const std::vector<tl::Variant> *pvl = &pv_list;
|
const std::vector<tl::Variant> *pvl = &pv_list;
|
||||||
|
|
||||||
if (! value.is_a_string () || ! make_gds_property (name)) {
|
if (! make_gds_property (name, value)) {
|
||||||
|
|
||||||
name_str = make_prop_string (name);
|
name_str = make_prop_string (name);
|
||||||
sflag = false;
|
sflag = false;
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,9 @@ private:
|
||||||
|
|
||||||
void reset_modal_variables ();
|
void reset_modal_variables ();
|
||||||
|
|
||||||
static std::string make_prop_string (const tl::Variant &v);
|
std::string make_prop_string (const tl::Variant &v) const;
|
||||||
|
bool make_gds_property (const tl::Variant &name, const tl::Variant &value) const;
|
||||||
|
|
||||||
void emit_propname_def (db::properties_id_type prop_id);
|
void emit_propname_def (db::properties_id_type prop_id);
|
||||||
void emit_propstring_def (db::properties_id_type prop_id);
|
void emit_propstring_def (db::properties_id_type prop_id);
|
||||||
void write_insts (const std::set <db::cell_index_type> &cell_set);
|
void write_insts (const std::set <db::cell_index_type> &cell_set);
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,16 @@ static int get_oasis_write_std_properties_ext (const db::SaveLayoutOptions *opti
|
||||||
return options->get_options<db::OASISWriterOptions> ().write_std_properties;
|
return options->get_options<db::OASISWriterOptions> ().write_std_properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool get_oasis_enhanced_properties (const db::SaveLayoutOptions *options)
|
||||||
|
{
|
||||||
|
return options->get_options<db::OASISWriterOptions> ().enhanced_property_types;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_oasis_enhanced_properties (db::SaveLayoutOptions *options, bool f)
|
||||||
|
{
|
||||||
|
options->get_options<db::OASISWriterOptions> ().enhanced_property_types = f;
|
||||||
|
}
|
||||||
|
|
||||||
static void set_oasis_write_cell_bounding_boxes (db::SaveLayoutOptions *options, bool f)
|
static void set_oasis_write_cell_bounding_boxes (db::SaveLayoutOptions *options, bool f)
|
||||||
{
|
{
|
||||||
db::OASISWriterOptions &oasis_options = options->get_options<db::OASISWriterOptions> ();
|
db::OASISWriterOptions &oasis_options = options->get_options<db::OASISWriterOptions> ();
|
||||||
|
|
@ -278,6 +288,21 @@ gsi::ClassExt<db::SaveLayoutOptions> oasis_writer_options (
|
||||||
// this method is mainly provided as access point for the generic interface
|
// this method is mainly provided as access point for the generic interface
|
||||||
"@hide"
|
"@hide"
|
||||||
) +
|
) +
|
||||||
|
gsi::method_ext ("oasis_enhanced_properties=", &set_oasis_enhanced_properties, gsi::arg ("flag"),
|
||||||
|
"@brief Sets a value indicating whether to write enhanced property values\n"
|
||||||
|
"With this option set to true (the default), non-standard types like lists or objects are supported "
|
||||||
|
"for property names and values. These types are encoded in specially annotated strings.\n"
|
||||||
|
"KLayout's OASIS reader will convert them back to the original types.\n"
|
||||||
|
"With this option set to false, such values are translated into strings.\n"
|
||||||
|
"\n"
|
||||||
|
"This attribute has been introduced in version 0.30.7."
|
||||||
|
) +
|
||||||
|
gsi::method_ext ("oasis_enhanced_properties?", &get_oasis_enhanced_properties,
|
||||||
|
"@brief Gets a value indicating whether to write enhanced property values\n"
|
||||||
|
"See \\oasis_enhanced_properties= for details.\n"
|
||||||
|
"\n"
|
||||||
|
"This attribute has been introduced in version 0.30.7."
|
||||||
|
) +
|
||||||
gsi::method_ext ("oasis_compression_level=", &set_oasis_compression, gsi::arg ("level"),
|
gsi::method_ext ("oasis_compression_level=", &set_oasis_compression, gsi::arg ("level"),
|
||||||
"@brief Set the OASIS compression level\n"
|
"@brief Set the OASIS compression level\n"
|
||||||
"The OASIS compression level is an integer number between 0 and 10. 0 basically is no compression, "
|
"The OASIS compression level is an integer number between 0 and 10. 0 basically is no compression, "
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,37 @@
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static std::string p2s (db::properties_id_type pid)
|
||||||
|
{
|
||||||
|
return db::properties (pid).to_dict_var ().to_parsable_string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Installs a temporary repository instance for testing
|
||||||
|
*
|
||||||
|
* By using a temp instance, we do not disturb other tests.
|
||||||
|
*/
|
||||||
|
class TempPropertiesRepository
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TempPropertiesRepository ()
|
||||||
|
{
|
||||||
|
db::PropertiesRepository::replace_instance_temporarily (&m_temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
~TempPropertiesRepository ()
|
||||||
|
{
|
||||||
|
db::PropertiesRepository::replace_instance_temporarily (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
db::PropertiesRepository m_temp;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int compr, bool recompress, bool tables_at_end)
|
void run_test (tl::TestBase *_this, const char *file, bool scaling_test, int compr, bool recompress, bool tables_at_end)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|
@ -2100,3 +2131,68 @@ TEST(140)
|
||||||
db::compare_layouts (_this, gg, tl::testdata () + "/oasis/dbOASISWriter40_au.gds", db::NoNormalization);
|
db::compare_layouts (_this, gg, tl::testdata () + "/oasis/dbOASISWriter40_au.gds", db::NoNormalization);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Writing enhanced properties to OASIS
|
||||||
|
TEST(150)
|
||||||
|
{
|
||||||
|
TempPropertiesRepository temp_pr;
|
||||||
|
|
||||||
|
db::Layout layout_org;
|
||||||
|
|
||||||
|
db::PropertiesSet ps;
|
||||||
|
tl::Variant list = tl::Variant::empty_list ();
|
||||||
|
list.push (tl::Variant (-1));
|
||||||
|
list.push (tl::Variant (2.5));
|
||||||
|
list.push (tl::Variant ("KLAYOUT_VALUE:h*ll*")); // a string that clashes with the annotation scheme
|
||||||
|
ps.insert (tl::Variant (17), list);
|
||||||
|
ps.insert (tl::Variant ("x"), tl::Variant (db::DBox (0, 0, 1.5, 2.5)));
|
||||||
|
|
||||||
|
db::properties_id_type ps_id = db::properties_id (ps);
|
||||||
|
EXPECT_EQ (p2s (ps_id), "{#17=>(#-1,##2.5,'KLAYOUT_VALUE:h*ll*'),'x'=>[dbox:(0,0;1.5,2.5)]}");
|
||||||
|
|
||||||
|
layout_org.prop_id (ps_id);
|
||||||
|
|
||||||
|
std::string tmp_file = tl::TestBase::tmp_file (tl::sprintf ("tmp_dbOASISWriter150a.oas"));
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::OutputStream out (tmp_file);
|
||||||
|
db::SaveLayoutOptions options;
|
||||||
|
options.set_format ("OASIS");
|
||||||
|
EXPECT_EQ (options.get_option_by_name ("oasis_enhanced_properties").to_bool (), true);
|
||||||
|
db::Writer writer (options);
|
||||||
|
writer.write (layout_org, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::InputStream in (tmp_file);
|
||||||
|
db::Reader reader (in);
|
||||||
|
db::Layout gg;
|
||||||
|
reader.set_warnings_as_errors (true);
|
||||||
|
reader.read (gg);
|
||||||
|
|
||||||
|
EXPECT_EQ (p2s (gg.prop_id ()), "{#17=>(#-1,##2.5,'KLAYOUT_VALUE:h*ll*'),'x'=>[dbox:(0,0;1.5,2.5)]}");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_file = tl::TestBase::tmp_file (tl::sprintf ("tmp_dbOASISWriter150b.oas"));
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::OutputStream out (tmp_file);
|
||||||
|
db::SaveLayoutOptions options;
|
||||||
|
options.set_format ("OASIS");
|
||||||
|
options.set_option_by_name ("oasis_enhanced_properties", false);
|
||||||
|
EXPECT_EQ (options.get_option_by_name ("oasis_enhanced_properties").to_bool (), false);
|
||||||
|
db::Writer writer (options);
|
||||||
|
writer.write (layout_org, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::InputStream in (tmp_file);
|
||||||
|
db::Reader reader (in);
|
||||||
|
db::Layout gg;
|
||||||
|
reader.read (gg);
|
||||||
|
|
||||||
|
EXPECT_EQ (p2s (gg.prop_id ()), "{#17=>'(-1,2.5,KLAYOUT_VALUE:h*ll*)','x'=>'(0,0;1.5,2.5)'}");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue