From e869dc432cf2eee733bd62823b367eee4441b471 Mon Sep 17 00:00:00 2001 From: Kergadon Date: Sat, 30 Aug 2025 18:46:59 -0400 Subject: [PATCH 1/9] sketch of layername header created --- include/gdstk/layername.hpp | 77 +++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 include/gdstk/layername.hpp diff --git a/include/gdstk/layername.hpp b/include/gdstk/layername.hpp new file mode 100644 index 00000000..7f584c06 --- /dev/null +++ b/include/gdstk/layername.hpp @@ -0,0 +1,77 @@ +/* +Copyright 2020 Lucas Heitzmann Gabrielli. +This file is part of gdstk, distributed under the terms of the +Boost Software License - Version 1.0. See the accompanying +LICENSE file or +*/ + +#ifndef GDSTK_HEADER_PROPERTY +#define GDSTK_HEADER_PROPERTY + +#define __STDC_FORMAT_MACROS 1 +#define _USE_MATH_DEFINES + +#include +#include + +#include "utils.hpp" + +namespace gdstk { + +struct OasisStream; +struct OasisState; + +// based roughly on property.hpp, please see that file for someone who knows what they're doing + +enum struct LayerNameType { Layer, Text }; + +enum struct IntervalType { Unbounded, ZeroToBound, BoundToInf, Single, BoundToBound }; + +struct Interval { + IntervalType type; + union { + uint64_t bound; + struct { + uint64_t bound_a; + uint64_t bound_b; + }; + }; +}; + +// Properties are stored as a NULL-terminated linked list. Their name is a +// NULL-terminated string. Property names in the OASIS should be strings of +// characters within the range 0x21 and 0x7E with at least 1 character. +struct LayerName { + LayerNameType type; + char* name; + Interval* LayerInterval; + Interval* TypeInterval; + LayerName* next; +}; + +// The set_layername functions add layer mappings to the library with the +// given name. A new one is created if none exists or create_new == true. +// New values are added to the start of the value list, so in the OASIS file, +// they will appear in reverse of the insertion order (last added will appear +// first). The NULL byte at the end of string is NOT included in the layer +// name. +void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype, + bool create_new); +void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype, + bool create_new); +// Still thinking about how to deal with bounds that aren't type 3 + + +void remove_layername(LayerName*& layer_names, const char* name, bool all_occurences); + +LayerName* get_mapped_layers(LayerName* layer_names, const char* name); + + + +// These functions output the properties in the OASIS format. They +// are not supposed to be called by the user. +ErrorCode layernames_to_oas(const Property* properties, OasisStream& out, OasisState& state); + +} // namespace gdstk + +#endif From 5f947a8275f1158a23aff6fcb9cce270036abce4 Mon Sep 17 00:00:00 2001 From: Kergadon Date: Tue, 2 Sep 2025 10:41:35 -0400 Subject: [PATCH 2/9] Started implmentation of functions for feature --- include/gdstk/layername.hpp | 21 ++-- include/gdstk/library.hpp | 4 + src/CMakeLists.txt | 2 + src/layername.cpp | 192 ++++++++++++++++++++++++++++++++++++ 4 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 src/layername.cpp diff --git a/include/gdstk/layername.hpp b/include/gdstk/layername.hpp index 7f584c06..0250aa9e 100644 --- a/include/gdstk/layername.hpp +++ b/include/gdstk/layername.hpp @@ -5,8 +5,8 @@ Boost Software License - Version 1.0. See the accompanying LICENSE file or */ -#ifndef GDSTK_HEADER_PROPERTY -#define GDSTK_HEADER_PROPERTY +#ifndef GDSTK_HEADER_LAYERNAME +#define GDSTK_HEADER_LAYERNAME #define __STDC_FORMAT_MACROS 1 #define _USE_MATH_DEFINES @@ -23,10 +23,13 @@ struct OasisState; // based roughly on property.hpp, please see that file for someone who knows what they're doing +// the spec lists tag types 11 and 12 which are representing layer and textlayer data respectively enum struct LayerNameType { Layer, Text }; +// there are 5 bound types, unbounded means all values match enum struct IntervalType { Unbounded, ZeroToBound, BoundToInf, Single, BoundToBound }; +// only bound type index 4 (bound to bound) requires two bound values struct Interval { IntervalType type; union { @@ -55,22 +58,24 @@ struct LayerName { // they will appear in reverse of the insertion order (last added will appear // first). The NULL byte at the end of string is NOT included in the layer // name. -void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype, - bool create_new); -void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype, - bool create_new); +void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype); +void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype); +void set_layername(LayerName*& layer_names, const char* name, Interval layertype, Interval datatype); +void set_textlayername(LayerName*& layer_names, const char* name, Interval layertype, Interval datatype); // Still thinking about how to deal with bounds that aren't type 3 - +// removes first instance of layername present in the linked list or all occourances if +// all occourences is set void remove_layername(LayerName*& layer_names, const char* name, bool all_occurences); +void layernames_clear(Layername*& layer_names); LayerName* get_mapped_layers(LayerName* layer_names, const char* name); // These functions output the properties in the OASIS format. They // are not supposed to be called by the user. -ErrorCode layernames_to_oas(const Property* properties, OasisStream& out, OasisState& state); +ErrorCode layernames_to_oas(const LayerName* layer_names, OasisStream& out, OasisState& state); } // namespace gdstk diff --git a/include/gdstk/library.hpp b/include/gdstk/library.hpp index 412e3414..2f85c766 100644 --- a/include/gdstk/library.hpp +++ b/include/gdstk/library.hpp @@ -16,6 +16,7 @@ LICENSE file or #include "array.hpp" #include "cell.hpp" +#include "layername.hpp" namespace gdstk { @@ -38,6 +39,8 @@ struct Library { Array rawcell_array; Property* properties; + + LayerName* layer_names; // Used by the python interface to store the associated PyObject* (if any). // No functions in gdstk namespace should touch this value! @@ -57,6 +60,7 @@ struct Library { cell_array.clear(); rawcell_array.clear(); properties_clear(properties); + layernames_clear(layer_names); } // Clear and free the memory of the whole library (this should be used with diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1da39ce..d2ad951d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,6 +34,7 @@ set(HEADER_LIST "${gdstk_SOURCE_DIR}/include/gdstk/gdstk.hpp" "${gdstk_SOURCE_DIR}/include/gdstk/gdswriter.hpp" "${gdstk_SOURCE_DIR}/include/gdstk/label.hpp" + "${gdstk_SOURCE_DIR}/include/gdstk/layername.hpp" "${gdstk_SOURCE_DIR}/include/gdstk/library.hpp" "${gdstk_SOURCE_DIR}/include/gdstk/map.hpp" "${gdstk_SOURCE_DIR}/include/gdstk/oasis.hpp" @@ -59,6 +60,7 @@ set(SOURCE_LIST flexpath.cpp gdsii.cpp label.cpp + layername.cpp library.cpp oasis.cpp polygon.cpp diff --git a/src/layername.cpp b/src/layername.cpp new file mode 100644 index 00000000..278c80a7 --- /dev/null +++ b/src/layername.cpp @@ -0,0 +1,192 @@ +/* +Copyright 2020 Lucas Heitzmann Gabrielli. +This file is part of gdstk, distributed under the terms of the +Boost Software License - Version 1.0. See the accompanying +LICENSE file or +*/ + +#define __STDC_FORMAT_MACROS 1 +#define _USE_MATH_DEFINES + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace gdstk { + +// not sure what funciton properties print has other than diagnostic +// void properties_print(Property* properties) { +// if (!properties) return; +// puts("Properties:"); +// for (; properties; properties = properties->next) { +// printf("- <%p> %s:", properties, properties->name); +// for (PropertyValue* value = properties->value; value; value = value->next) { +// switch (value->type) { +// case PropertyType::UnsignedInteger: +// printf(" %" PRIu64, value->unsigned_integer); +// break; +// case PropertyType::Integer: +// printf(" %" PRId64, value->integer); +// break; +// case PropertyType::Real: +// printf(" %lg", value->real); +// break; +// case PropertyType::String: { +// putchar(' '); +// uint8_t* c = value->bytes; +// for (uint64_t i = 0; i < value->count; i++, c++) +// if (*c >= 0x20 && *c < 0x7f) +// putchar(*c); +// else +// printf("[%02x]", *c); +// } +// } +// } +// putchar('\n'); +// } +// } + + + + + + + +// bool remove_gds_property(Property*& properties, uint16_t attribute) { +// if (properties == NULL) return false; +// if (is_gds_property(properties) && properties->value->unsigned_integer == attribute) { +// property_values_clear(properties->value); +// free_allocation(properties->name); +// Property* next = properties->next; +// free_allocation(properties); +// properties = next; +// return true; +// } +// Property* property = properties; +// while (property->next && +// (!is_gds_property(property->next) || property->next->value->unsigned_integer != attribute)) +// property = property->next; +// if (property->next) { +// Property* rem = property->next; +// property_values_clear(rem->value); +// free_allocation(rem->name); +// property->next = rem->next; +// free_allocation(rem); +// return true; +// } +// return false; +// } + +// PropertyValue* get_property(Property* properties, const char* name) { +// while (properties && strcmp(properties->name, name) != 0) properties = properties->next; +// if (properties) return properties->value; +// return NULL; +// } + + +// void set_layername(LayerName*& layer_names, const char* name, Interval layertype, Interval datatype){ +// LayerName + +// } + + +void layernames_clear(LayerName*& layer_names){ + while (layer_names){ + free_allocation(layer_names->name); + free_allocation(layer_names->LayerInterval); + free_allocation(layer_names->TypeInterval); + LayerName* next = layer_names->next; + free_allocation(layer_names); + layer_names = next; + } +} + + +ErrorCode layernames_to_oas(const Property* properties, OasisStream& out, OasisState& state) { + // needs full rewrite + while (properties) { + uint8_t info = 0x06; + // if (is_gds_property(properties)) info |= 0x01; + + uint64_t value_count = 0; + for (PropertyValue* value = properties->value; value; value = value->next) value_count++; + if (value_count > 14) { + info |= 0xF0; + } else { + info |= (uint8_t)(value_count & 0x0F) << 4; + } + + oasis_putc((int)OasisRecord::PROPERTY, out); + oasis_putc(info, out); + + uint64_t index; + if (state.property_name_map.has_key(properties->name)) { + index = state.property_name_map.get(properties->name); + } else { + index = state.property_name_map.count; + state.property_name_map.set(properties->name, index); + } + oasis_write_unsigned_integer(out, index); + + if (value_count > 14) { + oasis_write_unsigned_integer(out, value_count); + } + + for (PropertyValue* value = properties->value; value; value = value->next) { + switch (value->type) { + case PropertyType::Real: + oasis_write_real(out, value->real); + break; + case PropertyType::UnsignedInteger: + oasis_putc(8, out); + oasis_write_unsigned_integer(out, value->unsigned_integer); + break; + case PropertyType::Integer: + oasis_putc(9, out); + oasis_write_integer(out, value->integer); + break; + case PropertyType::String: { + bool space = false; + bool binary = false; + uint8_t* byte = value->bytes; + for (uint64_t i = value->count; i > 0; i--, byte++) { + if (*byte < 0x20 || *byte > 0x7E) { + binary = true; + break; + } else if (*byte == 0x20) { + space = true; + } + } + if (binary) { + oasis_putc(14, out); + } else if (space) { + oasis_putc(13, out); + } else { + oasis_putc(15, out); + } + for (index = 0; index < state.property_value_array.count; index++) { + PropertyValue* it = state.property_value_array[index]; + if (it->count == value->count && + memcmp(it->bytes, value->bytes, it->count) == 0) + break; + } + if (index == state.property_value_array.count) + state.property_value_array.append(value); + oasis_write_unsigned_integer(out, index); + } + } + } + + properties = properties->next; + } + return ErrorCode::NoError; +} + +} // namespace gdstk From 8d887e592c0c47155d25aa416f0d7362c0643eaf Mon Sep 17 00:00:00 2001 From: Kergadon Date: Tue, 2 Sep 2025 10:52:17 -0400 Subject: [PATCH 3/9] Fixed typo in layername clear --- include/gdstk/layername.hpp | 2 +- src/layername.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/gdstk/layername.hpp b/include/gdstk/layername.hpp index 0250aa9e..39b11ad3 100644 --- a/include/gdstk/layername.hpp +++ b/include/gdstk/layername.hpp @@ -68,10 +68,10 @@ void set_textlayername(LayerName*& layer_names, const char* name, Interval layer // all occourences is set void remove_layername(LayerName*& layer_names, const char* name, bool all_occurences); -void layernames_clear(Layername*& layer_names); LayerName* get_mapped_layers(LayerName* layer_names, const char* name); +void layernames_clear(LayerName*& layer_names); // These functions output the properties in the OASIS format. They // are not supposed to be called by the user. diff --git a/src/layername.cpp b/src/layername.cpp index 278c80a7..b9e9f8a2 100644 --- a/src/layername.cpp +++ b/src/layername.cpp @@ -18,6 +18,7 @@ LICENSE file or #include #include #include +// #include "layername.hpp" namespace gdstk { @@ -97,7 +98,7 @@ namespace gdstk { // } -void layernames_clear(LayerName*& layer_names){ +void layernames_clear(LayerName*& layer_names) { while (layer_names){ free_allocation(layer_names->name); free_allocation(layer_names->LayerInterval); @@ -190,3 +191,4 @@ ErrorCode layernames_to_oas(const Property* properties, OasisStream& out, OasisS } } // namespace gdstk + From 8d1391f631613837911ea80a83c6894a624e23f6 Mon Sep 17 00:00:00 2001 From: Kergadon Date: Wed, 3 Sep 2025 10:14:29 -0400 Subject: [PATCH 4/9] Noticed layername and interval names in the oasis.cpp and added this to my code --- include/gdstk/layername.hpp | 12 ++--- src/layername.cpp | 97 +++++++++---------------------------- 2 files changed, 30 insertions(+), 79 deletions(-) diff --git a/include/gdstk/layername.hpp b/include/gdstk/layername.hpp index 39b11ad3..1be8fb6b 100644 --- a/include/gdstk/layername.hpp +++ b/include/gdstk/layername.hpp @@ -15,6 +15,7 @@ LICENSE file or #include #include "utils.hpp" +#include "oasis.hpp" namespace gdstk { @@ -24,14 +25,13 @@ struct OasisState; // based roughly on property.hpp, please see that file for someone who knows what they're doing // the spec lists tag types 11 and 12 which are representing layer and textlayer data respectively -enum struct LayerNameType { Layer, Text }; - -// there are 5 bound types, unbounded means all values match -enum struct IntervalType { Unbounded, ZeroToBound, BoundToInf, Single, BoundToBound }; - +enum struct LayerNameType : uint8_t { + DATA = static_cast(OasisRecord::LAYERNAME_DATA), + TEXT = static_cast(OasisRecord::LAYERNAME_TEXT), +}; // only bound type index 4 (bound to bound) requires two bound values struct Interval { - IntervalType type; + OasisInterval type; union { uint64_t bound; struct { diff --git a/src/layername.cpp b/src/layername.cpp index b9e9f8a2..483f9fd0 100644 --- a/src/layername.cpp +++ b/src/layername.cpp @@ -109,83 +109,34 @@ void layernames_clear(LayerName*& layer_names) { } } - -ErrorCode layernames_to_oas(const Property* properties, OasisStream& out, OasisState& state) { +// need to rewrite to work with layer map +ErrorCode layernames_to_oas(const LayerName* layer_names, OasisStream& out, OasisState& state) { // needs full rewrite - while (properties) { - uint8_t info = 0x06; - // if (is_gds_property(properties)) info |= 0x01; - - uint64_t value_count = 0; - for (PropertyValue* value = properties->value; value; value = value->next) value_count++; - if (value_count > 14) { - info |= 0xF0; - } else { - info |= (uint8_t)(value_count & 0x0F) << 4; - } - - oasis_putc((int)OasisRecord::PROPERTY, out); - oasis_putc(info, out); - - uint64_t index; - if (state.property_name_map.has_key(properties->name)) { - index = state.property_name_map.get(properties->name); - } else { - index = state.property_name_map.count; - state.property_name_map.set(properties->name, index); + while (layer_names) { + oasis_write_integer(out,(uint8_t)layer_names->type); + size_t name_length = strlen(layer_names->name); + oasis_write_unsigned_integer(out, (uint64_t)name_length); + oasis_write(layer_names->name, 1, name_length, out); + + // write layertype interval + oasis_putc((uint8_t)layer_names->LayerInterval->type, out); + if (layer_names->LayerInterval->type == OasisInterval::Bounded) { + oasis_write_unsigned_integer(out, layer_names->LayerInterval->bound_a); + oasis_write_unsigned_integer(out, layer_names->LayerInterval->bound_b); + } else if (layer_names->LayerInterval->type != OasisInterval::AllValues) { + oasis_write_unsigned_integer(out, layer_names->LayerInterval->bound); } - oasis_write_unsigned_integer(out, index); - if (value_count > 14) { - oasis_write_unsigned_integer(out, value_count); + oasis_putc((uint8_t)layer_names->TypeInterval->type, out); + if (layer_names->TypeInterval->type == OasisInterval::Bounded) { + oasis_write_unsigned_integer(out, layer_names->TypeInterval->bound_a); + oasis_write_unsigned_integer(out, layer_names->TypeInterval->bound_b); + } else if (layer_names->TypeInterval->type != OasisInterval::AllValues) { + oasis_write_unsigned_integer(out, layer_names->TypeInterval->bound); } - - for (PropertyValue* value = properties->value; value; value = value->next) { - switch (value->type) { - case PropertyType::Real: - oasis_write_real(out, value->real); - break; - case PropertyType::UnsignedInteger: - oasis_putc(8, out); - oasis_write_unsigned_integer(out, value->unsigned_integer); - break; - case PropertyType::Integer: - oasis_putc(9, out); - oasis_write_integer(out, value->integer); - break; - case PropertyType::String: { - bool space = false; - bool binary = false; - uint8_t* byte = value->bytes; - for (uint64_t i = value->count; i > 0; i--, byte++) { - if (*byte < 0x20 || *byte > 0x7E) { - binary = true; - break; - } else if (*byte == 0x20) { - space = true; - } - } - if (binary) { - oasis_putc(14, out); - } else if (space) { - oasis_putc(13, out); - } else { - oasis_putc(15, out); - } - for (index = 0; index < state.property_value_array.count; index++) { - PropertyValue* it = state.property_value_array[index]; - if (it->count == value->count && - memcmp(it->bytes, value->bytes, it->count) == 0) - break; - } - if (index == state.property_value_array.count) - state.property_value_array.append(value); - oasis_write_unsigned_integer(out, index); - } - } - } - - properties = properties->next; + + layer_names = layer_names->next; + } return ErrorCode::NoError; } From c04122f1741ffb4f2b412307b9268fa0ba9fb9ed Mon Sep 17 00:00:00 2001 From: Kergadon Date: Wed, 3 Sep 2025 11:34:46 -0400 Subject: [PATCH 5/9] Added some more definitions to layername.cpp --- include/gdstk/layername.hpp | 7 ++-- src/layername.cpp | 79 +++++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/include/gdstk/layername.hpp b/include/gdstk/layername.hpp index 1be8fb6b..152e3532 100644 --- a/include/gdstk/layername.hpp +++ b/include/gdstk/layername.hpp @@ -15,7 +15,7 @@ LICENSE file or #include #include "utils.hpp" -#include "oasis.hpp" +// #include "oasis.hpp" namespace gdstk { @@ -60,8 +60,8 @@ struct LayerName { // name. void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype); void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype); -void set_layername(LayerName*& layer_names, const char* name, Interval layertype, Interval datatype); -void set_textlayername(LayerName*& layer_names, const char* name, Interval layertype, Interval datatype); +void set_layername(LayerName*& layer_names, const char* name, Interval* layertype, Interval* datatype); +void set_textlayername(LayerName*& layer_names, const char* name, Interval* layertype, Interval* datatype); // Still thinking about how to deal with bounds that aren't type 3 // removes first instance of layername present in the linked list or all occourances if @@ -70,6 +70,7 @@ void remove_layername(LayerName*& layer_names, const char* name, bool all_occure LayerName* get_mapped_layers(LayerName* layer_names, const char* name); +LayerName* get_names_from_layers(LayerName* layer_names, uint64_t layertype, uint64_t datatype); void layernames_clear(LayerName*& layer_names); diff --git a/src/layername.cpp b/src/layername.cpp index 483f9fd0..6970dced 100644 --- a/src/layername.cpp +++ b/src/layername.cpp @@ -95,9 +95,83 @@ namespace gdstk { // void set_layername(LayerName*& layer_names, const char* name, Interval layertype, Interval datatype){ // LayerName -// } +void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype) { + Interval* layertype_interval = (Interval*)allocate_clear(sizeof(Interval)); + layertype_interval->type = OasisInterval::SingleValue; + layertype_interval->bound = layertype; + Interval* datatype_interval = (Interval*)allocate_clear(sizeof(Interval)); + datatype_interval->type = OasisInterval::SingleValue; + datatype_interval->bound = datatype; + set_layername(layer_names, name, layertype_interval, datatype_interval); +} +void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype) { + Interval* layertype_interval; + layertype_interval->type = OasisInterval::SingleValue; + layertype_interval->bound = layertype; + Interval* datatype_interval; + datatype_interval->type = OasisInterval::SingleValue; + datatype_interval->bound = datatype; + set_textlayername(layer_names, name, layertype_interval, datatype_interval); +} + +void set_layername(LayerName*& layer_names, const char* name, Interval* layertype, Interval* datatype) { + LayerName* ln = (LayerName*)allocate_clear(sizeof(LayerName)); + ln->type = LayerNameType::DATA; + ln->name = copy_string(name, NULL); + ln->LayerInterval = layertype; + ln->TypeInterval = datatype; + ln->next = layer_names; + layer_names = ln; +} +void set_textlayername(LayerName*& layer_names, const char* name, Interval* layertype, Interval* datatype) { + LayerName* ln = (LayerName*)allocate_clear(sizeof(LayerName)); + ln->type = LayerNameType::TEXT; + ln->name = copy_string(name, NULL); + ln->LayerInterval = layertype; + ln->TypeInterval = datatype; + ln->next = layer_names; + layer_names = ln; +} + +void remove_layername(LayerName*& layer_names, const char* target_name, bool all_occurences) { + if (layer_names == NULL) return; + LayerName* current = layer_names; + LayerName* previous = NULL; + while (current) { + if (strcmp(current->name, target_name) == 0) { + + if (previous) { + previous->next = current->next; + } else { + layer_names = current->next; // Update head if needed + } + free_allocation(current->name); + free_allocation(current->LayerInterval); + free_allocation(current->TypeInterval); + LayerName* to_delete = current; + current = current->next; // Move to next before deleting + free_allocation(to_delete); + if (!all_occurences) { + return; // Exit if only the first occurrence should be removed + } + } else { + previous = current; + current = current->next; + } + } +} +// this is suspect as it only returns the first match +// I may have to create a new data structure to hold multiple matches +LayerName* get_mapped_layers(LayerName* layer_names, const char* name) { + while (layer_names && strcmp(layer_names->name, name) != 0) layer_names = layer_names->next; + return layer_names; +} + +// LayerName* get_names_from_layers(LayerName* layer_names, uint64_t layertype, uint64_t datatype) + + void layernames_clear(LayerName*& layer_names) { while (layer_names){ free_allocation(layer_names->name); @@ -109,9 +183,8 @@ void layernames_clear(LayerName*& layer_names) { } } -// need to rewrite to work with layer map + ErrorCode layernames_to_oas(const LayerName* layer_names, OasisStream& out, OasisState& state) { - // needs full rewrite while (layer_names) { oasis_write_integer(out,(uint8_t)layer_names->type); size_t name_length = strlen(layer_names->name); From 8e02220dc7f4a0ca58ca32bfc6bdf7122fea3c52 Mon Sep 17 00:00:00 2001 From: Kergadon Date: Wed, 3 Sep 2025 11:36:40 -0400 Subject: [PATCH 6/9] Add allocations to textlayername --- src/layername.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layername.cpp b/src/layername.cpp index 6970dced..ffdc6333 100644 --- a/src/layername.cpp +++ b/src/layername.cpp @@ -107,10 +107,10 @@ void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype set_layername(layer_names, name, layertype_interval, datatype_interval); } void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype) { - Interval* layertype_interval; + Interval* layertype_interval = (Interval*)allocate_clear(sizeof(Interval)); layertype_interval->type = OasisInterval::SingleValue; layertype_interval->bound = layertype; - Interval* datatype_interval; + Interval* datatype_interval = (Interval*)allocate_clear(sizeof(Interval)); datatype_interval->type = OasisInterval::SingleValue; datatype_interval->bound = datatype; set_textlayername(layer_names, name, layertype_interval, datatype_interval); From aef0bc553814df9b4f3a14627f3fecbb47b0a3aa Mon Sep 17 00:00:00 2001 From: Kergadon Date: Thu, 4 Sep 2025 10:59:01 -0400 Subject: [PATCH 7/9] Added support for layernames to read_oas and added contains layer check logic --- src/layername.cpp | 78 ++++++++++++++++++++++++++++++- src/library.cpp | 117 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 184 insertions(+), 11 deletions(-) diff --git a/src/layername.cpp b/src/layername.cpp index ffdc6333..e046c21d 100644 --- a/src/layername.cpp +++ b/src/layername.cpp @@ -169,9 +169,85 @@ LayerName* get_mapped_layers(LayerName* layer_names, const char* name) { return layer_names; } -// LayerName* get_names_from_layers(LayerName* layer_names, uint64_t layertype, uint64_t datatype) +bool layername_contains_layer_and_type(const LayerName* layer_name, uint64_t layertype, uint64_t datatype) { + bool matches = false; + // Check layertype + switch (layer_name->LayerInterval->type) { + case OasisInterval::AllValues: + matches = true; + break; + case OasisInterval::UpperBound: + matches = (layertype <= layer_name->LayerInterval->bound); + break; + case OasisInterval::LowerBound: + matches = (layertype >= layer_name->LayerInterval->bound); + break; + case OasisInterval::SingleValue: + matches = (layer_name->LayerInterval->bound == layertype); + break; + case OasisInterval::Bounded: + matches = (layertype >= layer_name->LayerInterval->bound_a && + layertype <= layer_name->LayerInterval->bound_b); + break; + } + if (matches == false) { + return false; + } + switch (layer_name->TypeInterval->type) { + case OasisInterval::AllValues: + matches = true; + break; + case OasisInterval::UpperBound: + matches = (datatype <= layer_name->TypeInterval->bound); + break; + case OasisInterval::LowerBound: + matches = (datatype >= layer_name->TypeInterval->bound); + break; + case OasisInterval::SingleValue: + matches = (layer_name->TypeInterval->bound == datatype); + break; + case OasisInterval::Bounded: + matches = (layertype >= layer_name->TypeInterval->bound_a && + layertype <= layer_name->TypeInterval->bound_b); + break; + } + return matches; +} + +LayerName* get_names_from_layers(LayerName* layer_names, uint64_t layertype, uint64_t datatype) { + LayerName* result_head = NULL; + LayerName* result_tail = NULL; + + while (layer_names) { + // this might not need a deep copy since it just returning a result + // the dealocaiton might be messy though + if (layername_contains_layer_and_type(layer_names, layertype, datatype)) { + // Create a new LayerName node for the result list + LayerName* new_node = (LayerName*)allocate_clear(sizeof(LayerName)); + new_node->type = layer_names->type; + new_node->name = copy_string(layer_names->name, NULL); + new_node->LayerInterval = (Interval*)allocate_clear(sizeof(Interval)); + *(new_node->LayerInterval) = *(layer_names->LayerInterval); // Deep copy + new_node->TypeInterval = (Interval*)allocate_clear(sizeof(Interval)); + *(new_node->TypeInterval) = *(layer_names->TypeInterval); // Deep copy + new_node->next = NULL; + + // Append to the result list + if (result_tail) { + result_tail->next = new_node; + result_tail = new_node; + } else { + result_head = new_node; + result_tail = new_node; + } + } + } + return result_head; +} + + void layernames_clear(LayerName*& layer_names) { while (layer_names){ free_allocation(layer_names->name); diff --git a/src/library.cpp b/src/library.cpp index 381bd493..a1cb2ed1 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -1171,7 +1171,7 @@ Library read_gds(const char* filename, double unit, double tolerance, const Set< if (reference->repetition.type != RepetitionType::None) { Repetition* repetition = &reference->repetition; if (reference->rotation == 0 && !reference->x_reflection && - data32[3] == 0 && data32[4] == 0) { + data32[3] == 0 && data32[4] == 0) { repetition->spacing.x = (factor * data32[2] - origin.x) / repetition->columns; repetition->spacing.y = @@ -1695,16 +1695,113 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* next_property = &property_value_table[ref_number].properties; } break; case OasisRecord::LAYERNAME_DATA: + uint8_t* name = oasis_read_string(in, true, len); + Interval* layertype_interval = (Interval*)allocate_clear(sizeof(Interval)); + layertype_interval->type = (OasisInterval)oasis_read_unsigned_integer(in); + + switch (layertype_interval->type) { + case OasisInterval::UpperBound: + case OasisInterval::LowerBound: + case OasisInterval::SingleValue: { + layertype_interval->bound = (uint32_t)oasis_read_unsigned_integer(in); + + } break; + case OasisInterval::Bounded: { + layertype_interval->bound_a = (uint32_t)oasis_read_unsigned_integer(in); + layertype_interval->bound_b = (uint32_t)oasis_read_unsigned_integer(in); + } break; + case OasisInterval::AllValues: + break; + default: + if (error_logger) + fprintf( + error_logger, + "[GDSTK] Unsupported layertype interval type %u in LAYERNAME_DATA record.\n", + layertype_interval->type); + if (error_code) *error_code = ErrorCode::UnsupportedRecord; + } + Interval* datatype_interval = (Interval*)allocate_clear(sizeof(Interval)); + datatype_interval->type = (OasisInterval)oasis_read_unsigned_integer(in); + switch (datatype_interval->type) { + case OasisInterval::UpperBound: + case OasisInterval::LowerBound: + case OasisInterval::SingleValue: { + datatype_interval->bound = (uint32_t)oasis_read_unsigned_integer(in); + + } break; + case OasisInterval::Bounded: { + datatype_interval->bound_a = (uint32_t)oasis_read_unsigned_integer(in); + datatype_interval->bound_b = (uint32_t)oasis_read_unsigned_integer(in); + } break; + case OasisInterval::AllValues: + break; + // handle default case with error + default: + if (error_logger) + fprintf( + error_logger, + "[GDSTK] Unsupported datatype interval type %u in LAYERNAME_DATA record.\n", + datatype_interval->type); + if (error_code) *error_code = ErrorCode::UnsupportedRecord; + } + set_layername(library.layer_names, (char*)name, layertype_interval, + datatype_interval); + free_allocation(name); + break; + case OasisRecord::LAYERNAME_TEXT: - // Unused record - free_allocation(oasis_read_string(in, false, len)); - for (uint32_t i = 2; i > 0; i--) { - uint64_t type = oasis_read_unsigned_integer(in); - if (type > 0) { - if (type == 4) oasis_read_unsigned_integer(in); - oasis_read_unsigned_integer(in); - } - } + uint8_t* name = oasis_read_string(in, true, len); + Interval* layertype_interval = (Interval*)allocate_clear(sizeof(Interval)); + layertype_interval->type = (OasisInterval)oasis_read_unsigned_integer(in); + + switch (layertype_interval->type) { + case OasisInterval::UpperBound: + case OasisInterval::LowerBound: + case OasisInterval::SingleValue: { + layertype_interval->bound = (uint32_t)oasis_read_unsigned_integer(in); + + } break; + case OasisInterval::Bounded: { + layertype_interval->bound_a = (uint32_t)oasis_read_unsigned_integer(in); + layertype_interval->bound_b = (uint32_t)oasis_read_unsigned_integer(in); + } break; + case OasisInterval::AllValues: + break; + default: + if (error_logger) + fprintf( + error_logger, + "[GDSTK] Unsupported layertype interval type %u in LAYERNAME_DATA record.\n", + layertype_interval->type); + if (error_code) *error_code = ErrorCode::UnsupportedRecord; + } + Interval* datatype_interval = (Interval*)allocate_clear(sizeof(Interval)); + datatype_interval->type = (OasisInterval)oasis_read_unsigned_integer(in); + switch (datatype_interval->type) { + case OasisInterval::UpperBound: + case OasisInterval::LowerBound: + case OasisInterval::SingleValue: { + datatype_interval->bound = (uint32_t)oasis_read_unsigned_integer(in); + + } break; + case OasisInterval::Bounded: { + datatype_interval->bound_a = (uint32_t)oasis_read_unsigned_integer(in); + datatype_interval->bound_b = (uint32_t)oasis_read_unsigned_integer(in); + } break; + case OasisInterval::AllValues: + break; + // handle default case with error + default: + if (error_logger) + fprintf( + error_logger, + "[GDSTK] Unsupported datatype interval type %u in LAYERNAME_DATA record.\n", + datatype_interval->type); + if (error_code) *error_code = ErrorCode::UnsupportedRecord; + } + set_text_layername(library.layer_names, (char*)name, layertype_interval, + datatype_interval); + free_allocation(name); break; case OasisRecord::CELL_REF_NUM: case OasisRecord::CELL: { From b5a7f7da19ec19b431bb57df2d6e21f3d0ee1a5f Mon Sep 17 00:00:00 2001 From: Kergadon Date: Fri, 5 Sep 2025 11:05:13 -0400 Subject: [PATCH 8/9] added ability to write layers --- .vscode/settings.json | 11 +++ include/gdstk/layername.hpp | 27 +++++--- src/layername.cpp | 133 ++++++++---------------------------- src/library.cpp | 7 +- 4 files changed, 63 insertions(+), 115 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..ff0a23f9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.associations": { + "cmath": "cpp", + "algorithm": "cpp", + "format": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xutility": "cpp", + "system_error": "cpp" + } +} \ No newline at end of file diff --git a/include/gdstk/layername.hpp b/include/gdstk/layername.hpp index 152e3532..c095510a 100644 --- a/include/gdstk/layername.hpp +++ b/include/gdstk/layername.hpp @@ -25,7 +25,7 @@ struct OasisState; // based roughly on property.hpp, please see that file for someone who knows what they're doing // the spec lists tag types 11 and 12 which are representing layer and textlayer data respectively -enum struct LayerNameType : uint8_t { +enum struct LayerNameType : uint8_t { DATA = static_cast(OasisRecord::LAYERNAME_DATA), TEXT = static_cast(OasisRecord::LAYERNAME_TEXT), }; @@ -33,10 +33,10 @@ enum struct LayerNameType : uint8_t { struct Interval { OasisInterval type; union { - uint64_t bound; + uint32_t bound; struct { - uint64_t bound_a; - uint64_t bound_b; + uint32_t bound_a; + uint32_t bound_b; }; }; }; @@ -52,16 +52,20 @@ struct LayerName { LayerName* next; }; -// The set_layername functions add layer mappings to the library with the +// The set_layername functions add layer mappings to the library with the // given name. A new one is created if none exists or create_new == true. // New values are added to the start of the value list, so in the OASIS file, // they will appear in reverse of the insertion order (last added will appear // first). The NULL byte at the end of string is NOT included in the layer // name. -void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype); -void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype); -void set_layername(LayerName*& layer_names, const char* name, Interval* layertype, Interval* datatype); -void set_textlayername(LayerName*& layer_names, const char* name, Interval* layertype, Interval* datatype); +void set_layername(LayerName*& layer_names, const char* name, uint32_t layertype, + uint32_t datatype); +void set_textlayername(LayerName*& layer_names, const char* name, uint32_t layertype, + uint32_t datatype); +void set_layername(LayerName*& layer_names, const char* name, Interval* layertype, + Interval* datatype); +void set_textlayername(LayerName*& layer_names, const char* name, Interval* layertype, + Interval* datatype); // Still thinking about how to deal with bounds that aren't type 3 // removes first instance of layername present in the linked list or all occourances if @@ -70,7 +74,10 @@ void remove_layername(LayerName*& layer_names, const char* name, bool all_occure LayerName* get_mapped_layers(LayerName* layer_names, const char* name); -LayerName* get_names_from_layers(LayerName* layer_names, uint64_t layertype, uint64_t datatype); +bool layername_contains_layer_and_type(const LayerName* layer_name, uint32_t layertype, + uint32_t datatype); + +LayerName* get_names_from_layers(LayerName* layer_names, uint32_t layertype, uint32_t datatype); void layernames_clear(LayerName*& layer_names); diff --git a/src/layername.cpp b/src/layername.cpp index e046c21d..257e68a1 100644 --- a/src/layername.cpp +++ b/src/layername.cpp @@ -14,91 +14,20 @@ LICENSE file or #include #include +#include #include #include -#include #include + // #include "layername.hpp" namespace gdstk { -// not sure what funciton properties print has other than diagnostic -// void properties_print(Property* properties) { -// if (!properties) return; -// puts("Properties:"); -// for (; properties; properties = properties->next) { -// printf("- <%p> %s:", properties, properties->name); -// for (PropertyValue* value = properties->value; value; value = value->next) { -// switch (value->type) { -// case PropertyType::UnsignedInteger: -// printf(" %" PRIu64, value->unsigned_integer); -// break; -// case PropertyType::Integer: -// printf(" %" PRId64, value->integer); -// break; -// case PropertyType::Real: -// printf(" %lg", value->real); -// break; -// case PropertyType::String: { -// putchar(' '); -// uint8_t* c = value->bytes; -// for (uint64_t i = 0; i < value->count; i++, c++) -// if (*c >= 0x20 && *c < 0x7f) -// putchar(*c); -// else -// printf("[%02x]", *c); -// } -// } -// } -// putchar('\n'); -// } -// } - - - - - - - -// bool remove_gds_property(Property*& properties, uint16_t attribute) { -// if (properties == NULL) return false; -// if (is_gds_property(properties) && properties->value->unsigned_integer == attribute) { -// property_values_clear(properties->value); -// free_allocation(properties->name); -// Property* next = properties->next; -// free_allocation(properties); -// properties = next; -// return true; -// } -// Property* property = properties; -// while (property->next && -// (!is_gds_property(property->next) || property->next->value->unsigned_integer != attribute)) -// property = property->next; -// if (property->next) { -// Property* rem = property->next; -// property_values_clear(rem->value); -// free_allocation(rem->name); -// property->next = rem->next; -// free_allocation(rem); -// return true; -// } -// return false; -// } - -// PropertyValue* get_property(Property* properties, const char* name) { -// while (properties && strcmp(properties->name, name) != 0) properties = properties->next; -// if (properties) return properties->value; -// return NULL; -// } -// void set_layername(LayerName*& layer_names, const char* name, Interval layertype, Interval datatype){ -// LayerName - - - -void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype) { - Interval* layertype_interval = (Interval*)allocate_clear(sizeof(Interval)); +void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype, + uint64_t datatype) { + Interval* layertype_interval = (Interval*)allocate_clear(sizeof(Interval)); layertype_interval->type = OasisInterval::SingleValue; layertype_interval->bound = layertype; Interval* datatype_interval = (Interval*)allocate_clear(sizeof(Interval)); @@ -106,8 +35,9 @@ void set_layername(LayerName*& layer_names, const char* name, uint64_t layertype datatype_interval->bound = datatype; set_layername(layer_names, name, layertype_interval, datatype_interval); } -void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layertype, uint64_t datatype) { - Interval* layertype_interval = (Interval*)allocate_clear(sizeof(Interval)); +void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layertype, + uint64_t datatype) { + Interval* layertype_interval = (Interval*)allocate_clear(sizeof(Interval)); layertype_interval->type = OasisInterval::SingleValue; layertype_interval->bound = layertype; Interval* datatype_interval = (Interval*)allocate_clear(sizeof(Interval)); @@ -116,7 +46,8 @@ void set_textlayername(LayerName*& layer_names, const char* name, uint64_t layer set_textlayername(layer_names, name, layertype_interval, datatype_interval); } -void set_layername(LayerName*& layer_names, const char* name, Interval* layertype, Interval* datatype) { +void set_layername(LayerName*& layer_names, const char* name, Interval* layertype, + Interval* datatype) { LayerName* ln = (LayerName*)allocate_clear(sizeof(LayerName)); ln->type = LayerNameType::DATA; ln->name = copy_string(name, NULL); @@ -125,7 +56,8 @@ void set_layername(LayerName*& layer_names, const char* name, Interval* layertyp ln->next = layer_names; layer_names = ln; } -void set_textlayername(LayerName*& layer_names, const char* name, Interval* layertype, Interval* datatype) { +void set_textlayername(LayerName*& layer_names, const char* name, Interval* layertype, + Interval* datatype) { LayerName* ln = (LayerName*)allocate_clear(sizeof(LayerName)); ln->type = LayerNameType::TEXT; ln->name = copy_string(name, NULL); @@ -141,20 +73,19 @@ void remove_layername(LayerName*& layer_names, const char* target_name, bool all LayerName* previous = NULL; while (current) { if (strcmp(current->name, target_name) == 0) { - if (previous) { previous->next = current->next; } else { - layer_names = current->next; // Update head if needed + layer_names = current->next; // Update head if needed } free_allocation(current->name); free_allocation(current->LayerInterval); free_allocation(current->TypeInterval); LayerName* to_delete = current; - current = current->next; // Move to next before deleting + current = current->next; // Move to next before deleting free_allocation(to_delete); if (!all_occurences) { - return; // Exit if only the first occurrence should be removed + return; // Exit if only the first occurrence should be removed } } else { previous = current; @@ -169,9 +100,9 @@ LayerName* get_mapped_layers(LayerName* layer_names, const char* name) { return layer_names; } -bool layername_contains_layer_and_type(const LayerName* layer_name, uint64_t layertype, uint64_t datatype) { +bool layername_contains_layer_and_type(const LayerName* layer_name, uint64_t layertype, + uint64_t datatype) { bool matches = false; - // Check layertype switch (layer_name->LayerInterval->type) { @@ -183,13 +114,13 @@ bool layername_contains_layer_and_type(const LayerName* layer_name, uint64_t lay break; case OasisInterval::LowerBound: matches = (layertype >= layer_name->LayerInterval->bound); - break; + break; case OasisInterval::SingleValue: matches = (layer_name->LayerInterval->bound == layertype); break; case OasisInterval::Bounded: matches = (layertype >= layer_name->LayerInterval->bound_a && - layertype <= layer_name->LayerInterval->bound_b); + layertype <= layer_name->LayerInterval->bound_b); break; } if (matches == false) { @@ -204,13 +135,13 @@ bool layername_contains_layer_and_type(const LayerName* layer_name, uint64_t lay break; case OasisInterval::LowerBound: matches = (datatype >= layer_name->TypeInterval->bound); - break; + break; case OasisInterval::SingleValue: matches = (layer_name->TypeInterval->bound == datatype); break; case OasisInterval::Bounded: matches = (layertype >= layer_name->TypeInterval->bound_a && - layertype <= layer_name->TypeInterval->bound_b); + layertype <= layer_name->TypeInterval->bound_b); break; } return matches; @@ -221,7 +152,7 @@ LayerName* get_names_from_layers(LayerName* layer_names, uint64_t layertype, uin LayerName* result_tail = NULL; while (layer_names) { - // this might not need a deep copy since it just returning a result + // this might not need a deep copy since it just returning a result // the dealocaiton might be messy though if (layername_contains_layer_and_type(layer_names, layertype, datatype)) { // Create a new LayerName node for the result list @@ -229,9 +160,9 @@ LayerName* get_names_from_layers(LayerName* layer_names, uint64_t layertype, uin new_node->type = layer_names->type; new_node->name = copy_string(layer_names->name, NULL); new_node->LayerInterval = (Interval*)allocate_clear(sizeof(Interval)); - *(new_node->LayerInterval) = *(layer_names->LayerInterval); // Deep copy + *(new_node->LayerInterval) = *(layer_names->LayerInterval); // Deep copy new_node->TypeInterval = (Interval*)allocate_clear(sizeof(Interval)); - *(new_node->TypeInterval) = *(layer_names->TypeInterval); // Deep copy + *(new_node->TypeInterval) = *(layer_names->TypeInterval); // Deep copy new_node->next = NULL; // Append to the result list @@ -246,10 +177,9 @@ LayerName* get_names_from_layers(LayerName* layer_names, uint64_t layertype, uin } return result_head; } - void layernames_clear(LayerName*& layer_names) { - while (layer_names){ + while (layer_names) { free_allocation(layer_names->name); free_allocation(layer_names->LayerInterval); free_allocation(layer_names->TypeInterval); @@ -258,15 +188,14 @@ void layernames_clear(LayerName*& layer_names) { layer_names = next; } } - - +// TODO figure out where this needs to be used ErrorCode layernames_to_oas(const LayerName* layer_names, OasisStream& out, OasisState& state) { while (layer_names) { - oasis_write_integer(out,(uint8_t)layer_names->type); - size_t name_length = strlen(layer_names->name); + oasis_write_integer(out, (uint8_t)layer_names->type); + size_t name_length = strlen(layer_names->name); oasis_write_unsigned_integer(out, (uint64_t)name_length); oasis_write(layer_names->name, 1, name_length, out); - + // write layertype interval oasis_putc((uint8_t)layer_names->LayerInterval->type, out); if (layer_names->LayerInterval->type == OasisInterval::Bounded) { @@ -283,12 +212,10 @@ ErrorCode layernames_to_oas(const LayerName* layer_names, OasisStream& out, Oasi } else if (layer_names->TypeInterval->type != OasisInterval::AllValues) { oasis_write_unsigned_integer(out, layer_names->TypeInterval->bound); } - + layer_names = layer_names->next; - } return ErrorCode::NoError; } } // namespace gdstk - diff --git a/src/library.cpp b/src/library.cpp index a1cb2ed1..50db6790 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -442,7 +442,10 @@ ErrorCode Library::write_oas(const char* filename, double circle_tolerance, state.scaling = unit / precision; oasis_write_real(out, 1e-6 / precision); oasis_putc(1, out); // flag indicating that table-offsets will be stored in the END record - + + uint64_t layer_name_offset = layer_names ? ftell(out.file) : 0; + layernames_to_oasis(layer_names,out,state) + if (state.config_flags & OASIS_CONFIG_PROPERTY_TOP_LEVEL) { remove_property(properties, s_top_level_property_name, true); Array top_cells = {}; @@ -881,7 +884,7 @@ ErrorCode Library::write_oas(const char* filename, double circle_tolerance, oasis_putc(1, out); oasis_write_unsigned_integer(out, prop_string_offset); oasis_putc(1, out); - oasis_putc(0, out); // LAYERNAME table + oasis_write_unsigned_integer(out, layer_name_offset); // LAYERNAME table oasis_putc(1, out); oasis_putc(0, out); // XNAME table From ac56051763f746b06c27af05b7cbe19716f5b8ff Mon Sep 17 00:00:00 2001 From: Kergadon Date: Mon, 8 Sep 2025 10:34:26 -0400 Subject: [PATCH 9/9] Adding python bindings for checking the present layer names --- python/docstrings.cpp | 3 ++ python/library_object.cpp | 7 ++++ python/parsing.cpp | 78 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/python/docstrings.cpp b/python/docstrings.cpp index fda7924f..da4dd9ec 100644 --- a/python/docstrings.cpp +++ b/python/docstrings.cpp @@ -2910,6 +2910,9 @@ PyDoc_STRVAR(library_object_layers_and_texttypes_doc, R"!(layers_and_texttypes() Return a set of tuples with the layer and text types in the library.)!"); +PyDoc_STRVAR(library_object_layer_datatype_names_doc, R"!(layer_datatype_names() -> list +Return a list of tuples with name, layer range and datatype ranges library.)!"); + PyDoc_STRVAR(library_object_remap_doc, R"!(remap(layer_type_map) -> self Remap layers and data/text types for all elements in this library. diff --git a/python/library_object.cpp b/python/library_object.cpp index 3a620e06..664564f7 100644 --- a/python/library_object.cpp +++ b/python/library_object.cpp @@ -334,6 +334,11 @@ static PyObject* library_object_layers_and_texttypes(LibraryObject* self, PyObje return result; } +static PyObject* library_object_layer_datatype_names(LibraryObject* self, PyObject*) { + PyObject* result = build_layername_list(tags); + return result; +} + static PyObject* library_object_remap(LibraryObject* self, PyObject* args, PyObject* kwds) { PyObject* py_map = NULL; const char* keywords[] = {"layer_type_map", NULL}; @@ -492,6 +497,8 @@ static PyMethodDef library_object_methods[] = { library_object_layers_and_datatypes_doc}, {"layers_and_texttypes", (PyCFunction)library_object_layers_and_texttypes, METH_NOARGS, library_object_layers_and_texttypes_doc}, + {"layer_datatype_names", (PyCFunction)library_object_layer_datatype_names, METH_NOARGS, + library_object_layer_datatype_names_doc}, {"remap", (PyCFunction)library_object_remap, METH_VARARGS | METH_KEYWORDS, library_object_remap_doc}, {"write_gds", (PyCFunction)library_object_write_gds, METH_VARARGS | METH_KEYWORDS, diff --git a/python/parsing.cpp b/python/parsing.cpp index baa5e9cd..790c979a 100644 --- a/python/parsing.cpp +++ b/python/parsing.cpp @@ -633,3 +633,81 @@ static PyObject* build_tag_set(const Set& tags) { } return result; } + +// not sure if range or slcie is better, using range since you can use the +// in keword with it to determine membership +PyObject* create_range_object(long start, long stop, long step) { + // Import the built-in "range" type + + PyObject* range_func = PyObject_GetAttrString(PyEval_GetBuiltins(), "range"); + if (!range_func || !PyCallable_Check(range_func)) { + PyErr_SetString(PyExc_RuntimeError, "Could not find built-in 'range'"); + Py_XDECREF(range_func); + return NULL; + } + + // Call range(start, stop, step) + PyObject* range_args = Py_BuildValue("(lll)", start, stop, step); + PyObject* range_obj = PyObject_CallObject(range_func, range_args); + + // Cleanup + Py_DECREF(range_func); + Py_DECREF(range_args); + + return range_obj; // May be nullptr if call failed +} + +static PyObject* build_layer_interval(const Interval* interval){ + + if (interval == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Invalid interval."); + return NULL; + } + if (interval->type == OasisInterval::AllValues){ + return create_range_object(0,65536,1); + } else if (interval->type == OasisInterval::UpperBound){ + return create_range_object(0,interval->bound,1); + } else if (interval->type == OasisInterval::LowerBound){ + return create_range_object(interval->bound,65536,1); + } else if (interval->type == OasisInterval::SingleValue){ + return create_range_object(interval->bound,interval->bound+1,1); + } else if (interval->type == OasisInterval::Bounded){ + return create_range_object(interval->bound_a,interval->bound_b+1,1); + } else { + PyErr_SetString(PyExc_RuntimeError, "Unknown interval type."); + return NULL; + } +} + + + +static PyObject* build_layername_list(const LayerName* layer_names) { + PyObject* result = PyList_New(NULL); + if (!result) { + PyErr_SetString(PyExc_RuntimeError, "Unable to create dict object."); + return NULL; + } + while(layer_names){ + PyObject* entry = PyTuple_New(3); + if (!entry) { + PyErr_SetString(PyExc_RuntimeError, "Unable to create (name, layer, type) tuple."); + Py_DECREF(result); + return NULL; + } + // this might need to be a byte string instead of unicode + PyTuple_SET_ITEM(entry, 0, PyUnicode_FromString(layer_names->name)); + PyTuple_SET_ITEM(entry, 1, build_layer_interval(&layer_names->layer)); + PyTuple_SET_ITEM(entry, 2, build_layer_interval(&layer_names->datatype)); + if (PyList_Append(result, entry) < 0) { + PyErr_SetString(PyExc_RuntimeError, "Unable to add item to list."); + Py_DECREF(entry); + Py_DECREF(result); + return NULL; + } + Py_DECREF(entry); + layer_names = layer_names->next; + } + return result; +} + + \ No newline at end of file