-
Notifications
You must be signed in to change notification settings - Fork 476
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
genericize DataIdentity
for container types
#4591
base: develop
Are you sure you want to change the base?
Conversation
this partial rework of the data identity system provides genericized support for container types using concepts, and in general cleans up and modernizes this code this doesn't cover several the std::vector specializations, still figuring out the best way to do this
fix compliance with gcc-12 for `requires` (this is because gcc-10 implemented the concepts proposal while gcc-12 implemented the final standard which is different; msvc is lax and accepts either) also fix mistake in constraints for `isAssocContainer`
had the wrong type variable in the `container_identity` constructor, oops
this hides the underlying C++ type but this isn't necessarily useful anyway and exposing it requires complex nonportable code that is probably more work than it's worth
i'd like to not have to do this, but we're not there yet
library/include/DataIdentity.h
Outdated
template<isIndexedContainer C> | ||
struct DFHACK_EXPORT identity_traits<C> { | ||
static type_identity* get() { | ||
static generic_container_identity<C> identity{}; | ||
return &identity; | ||
} | ||
}; | ||
|
||
template<isAssocContainer C> | ||
struct DFHACK_EXPORT identity_traits<C> { | ||
static type_identity* get() { | ||
static generic_assoc_container_identity<C> identity{}; | ||
return &identity; | ||
} | ||
}; | ||
|
||
template<isSetContainer C> | ||
struct DFHACK_EXPORT identity_traits<C> { | ||
static type_identity* get() { | ||
static generic_set_container_identity<C> identity{}; | ||
return &identity; | ||
} | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure these no longer need to be behind BUILD_DFHACK_LIB
? My understanding is that had something to do with linking issues with plugins attempting to use these specializations, and it was deemed better/easier to not allow that at all, but I'm afraid I don't remember much more than that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm still exploring this - i think it has to do inconsistent typing of the get
static method. there appears to be no reason why all of the get
methods cannot return a type_identity*
as the type is polymorphic anyhow
however, i'm still investigating this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the issue of duplicate implementations still exists, but in this case the static object being created is read-only so if there are two copies there should be no risk of harm. the problem that arises when there are multiple instances of the same specialization is when there is mutable data, but there's no mutable data in a type_identity
also, both gcc and msvc have improved their loading models since 2012 to reduce problems with duplicated implementations
there is a ton of stuff in our code that is there to work around compiler bugs and shortcomings, or even C++ language shortcomings, that were fixed, in some cases, over a decade ago
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the issue of duplicate implementations still exists, but in this case the static object being created is read-only so if there are two copies there should be no risk of harm.
Are we sure the address of that object isn't used as an identifier anywhere? I'm pretty sure at least something in the Lua layer passes around pointers to type_identity
objects and compares them for equality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least some places where the pointer to type_identity
is used:
- Several registry tables:
- The table at
&DFHACK_TYPEID_TABLE_TOKEN
mapstype_identity*
pointers (as raw lightuserdata) to the corresponding DF type object (e.g.identity_traits<df::item>::get()
maps to the luadf.item
). - The table at
&DFHACK_TYPETABLE_TOKEN
is a bidirectional map oftype_identity*
to metatable
- The table at
- In DF object metatables:
- The value at
&DFHACK_IDENTITY_FIELD_TOKEN
is the object's type_identity. This is the value with a "userdata" key visible inprintall(debug.getmetatable(df.item))
, for example.- This is used in
is_type_compatible()
, but that already returns false for allIDTYPE_CONTAINER
identities anyway, so your change has no effect there. - It's also returned by
get_object_identity()
, but that doesn't seem to be used for identification anywhere (although the result is passed on to several calls that I didn't trace...). Mainly, the identity is used by calling methods that should return the same thing for duplicate copies of the identity.
- This is used in
- The value at
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, unless I'm missing something else, I think duplicates might be ok. Especially for templated container types, for which several operations that use the type_identity
aren't implemented to begin with.
@@ -113,10 +114,10 @@ namespace DFHack | |||
|
|||
class DFHACK_EXPORT container_identity : public constructed_identity { | |||
type_identity *item; | |||
enum_identity *ienum; | |||
type_identity *ienum; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious why this changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
specifically because of associative containers, the identity key type of an associative container goes there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. I wonder if there is a way to enforce that this is an enum_identity
for non-associative containers. Probably complicated.
mostly so this code will pass CI - in the long term i'd prefer something different
Seems to work for me. I can pass a vector into Lua and modify it. |
This reverts commit 93d9977.
due credit to james t.
library/include/DataIdentity.h
Outdated
template<typename T> struct type_name<std::deque<T>> { | ||
static const inline std::string name = "deque"; | ||
}; | ||
template<typename T, int sz> struct type_name<std::array<T, sz>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be
template<typename T, int sz> struct type_name<std::array<T, sz>> { | |
template<typename T, size_t sz> struct type_name<std::array<T, sz>> { |
to match properly.
I am debating removing the name = "container"
from the base template to catch this sort of thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what I was testing with: DFHack/df-structures#757
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am debating removing the
name = "container"
from the base template to catch this sort of thing.
i was ambivalent on that issue originally. it's not hard for us to add a new specialization but it's more of a burden for a developer of an external plugin. maybe only include the generic case in the library build? that would cause any unspecialized in core code to error at compile time, while allowing plugin developers freedom to use specialized containers for their own purposes (although i'm not sure what the scenario for that is, tbh) nah i don't think that does what i want.. maybe someone else would have a better idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Support for adding new types in plugins is limited anyway. Their identities won't be registered in the global registry tables in #4591 (comment) (although I'm a little unsure whether any container types are registered there).
Really, my intent of breaking the base template would be to catch specializations like array<T, int>
that are intended to work but don't. It took me a while to figure out why a std::array was printing as "container" instead of "array".
fix parameter type of `std::array` Co-authored-by: Alan <[email protected]>
Regarding Any attempt to |
The Lua interface to C++ associative containers is at best shoehorned and needs to be reconceptualized. This PR may not be the best place to do this. |
Should I open an issue at this time? I don't need it for anything I'm working on. I just remembered it being mentioned on Discord as something to test. If nobody ever ends up needing it, then it'd be kind of pointless. (I guess Bay12 might use the type eventually?) |
Bay12 is already using Our current Lua interfaces only supports reading the "values" list as if it were a regular array, and does not support modifications at all. I personally believe that it would be good to move past these limitations. |
Let me add here that this code is not really ready to go yet. I really want to extend this to encompass I did test to see what happens if you just remove the specialization: the launcher sprouts hundreds of scrollbars, which is both hilarious and entirely unhelpful. |
Was that something I said? I didn't mean that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this deserve a changelog line (probably under API)?
lemme finish writing it first lol |
I'm not sure it does. It's really not a user-facing change. The only aspect that could affect some external devs is the ability to define |
the main "features" this PR offers are the ability to pass a wider range of types into Lua from C++, especially from plug-ins, future proofing the identity system to possibly support a broader range of container types (which we expect to be likely to arise as we continue to extend/revise structures), and general code quality (at least i would like to think so) all of this is basically being driven by bay12's increasing use of C++20 paradigms that our identity system was never designed to work with. the existing system having was basically designed using C++03 + "boost but not really boost" which are at best dated by modern standards, but which worked very well with toady's C++98ish style of coding DF itself, and which doesn't necessarily play that well with C++20 which we are increasingly moving toward both because C++20 has some really nice paradigms (i am especially fond of i'm very much cognizant of the fact that we have, in recent revisions, added several types to structures that are currently being handled as opaque types within the Lua identity system but which really ought to have more meaningful Lua semantics. while this PR does not itself resolve this issue, i'd like to think that it's a step toward a more flexible identity management system that will hopefully enable us to do so. specific goals i have in mind here include making anyway, i don't think any of this merits a changelog since it's 90% inside baseball and really only impacts the core team, at least initially. we didn't changelog #4406 as far as i know, and this is basically the same type of change as that was |
i'm moving this to draft status because i am not convinced that it's worth pursing at this time |
this partial rework of the data identity system provides genericized support for container types using concepts, and in general cleans up and modernizes this code
this doesn't cover several the std::vector specializations, still figuring out the best way to do that so this can be considered WIP but this code works on Windows and so i am putting up a PR mainly to run CI tests and see if gcc likes this or not
the process of going through this code has identified a number of other possible refinements that should probably be done which i'll come back to after i've had some rest