feat(cpp): add map type support#1590
Conversation
|
cc @cpetig and @TartanLlama |
|
@TartanLlama addressing your comments, the "why" behind things, I am effectively Junior in C++, please be patience with me here 🙏🏻 I am try to understand the intent and I will give it a second path |
|
If I were to implement this feature I would introduce a wit::map type which has the same layout as the lowered data. This way the data doesn't need to be copied unless the user code requests it (making map a lower cost abstraction). On the other hand I just ran into an adjacent problem with list lowering (and avoiding re-allocation) in #1592 , so avoiding a copy in case of complex types might still be impossible - due to C++ type layout restrictions. A |
|
@cpetig @TartanLlama can you give it a pass again? 🙏🏻 Ideally, please share the intent of what you would like to see, I can figure out eventually the implementation but I am not qualify to the best practices or insights of C++. I can figure that out for sure, it would help to declare the intent so I can go off, study, and figure out what you want 😄 |
|
Hmm I think that providing indexing functions for But I think in general there's a big tradeoff in performance vs ergonomics here. Ideally, I think we'd be able to configure whether we wanted a low-copy, low-usability type like |
|
I am gonna wait until @TartanLlama and @cpetig agree on the direction |
cpetig
left a comment
There was a problem hiding this comment.
Don't feel disheartened by the complexity of designing proper language bindings, it took me more than a year to come up with something I mostly liked - and then @TartanLlama made a significant improvement by pointing out that moved arguments can be received into normal objects.
Sorry, but writing proper bindings is simply complex, and mapping map is more so.
I would not want to have functions which aren't part of the standard (unordered_)map - unless they are needed to construct the object within the bindings (or help construct these types in user code).
I don't know which to prefer. This usually indicates that a generator option is a good solution. But I am quite sure that Also I feel that wit::vector vs std::vector and wit::string vs std::string would be selected by the same option. This feels out of scope for just implementing WebAssembly/component-model#554 |
…ix rustfmt wit::string lacked comparison operators, causing compilation failures when used as a std::map key. Also fixes rustfmt formatting issues.
std::map keys are const, but the ABI lowering needs to call leak() on string keys to transfer ownership to the flat buffer. Use const_cast since the map is consumed during the lowering operation.
const_cast fails when the map key type differs between contexts (e.g. std::string_view in imports vs wit::string in exports). Copying by value works universally and is safe since the map is consumed.
wasm-component-ld bundled with wasi-sdk 30 doesn't support the map type encoding (0x63) in the component model binary format. The C++ map codegen is still validated by the codegen test. The runtime test can be re-added when wasi-sdk ships a compatible wasm-component-ld.
std::map requires per-entry rb-tree allocation during lift; wit::map mirrors the canonical ABI layout (flat pair array) so lift is a single allocation, matching the existing wit::vector / wit::string pattern. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
wit::map::size() and std::span::size() already return size_t, so the C-style cast was a no-op. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Avoids an unused `base` local and the `(void) base;` suppression when the element has no nested heap-owned fields (e.g. list<u32>, map<char, u32>). Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
The cast converts void* (from cabi_realloc) to uint8_t*, which is a well-defined static_cast and doesn't need a C-style cast. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Leaves the moved-from map in a fully consistent state so any later inspection of size()/empty() reflects the empty invariant, not just the destructor's short-circuit on a null data_ pointer. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Index-based subscript on a map is a footgun: integral keys would silently compile while doing positional access. Iteration via range-for and pointer access via data() are sufficient for codegen and don't carry the same expectation mismatch. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
A span of pairs is a vector-shaped view that doesn't fit a map abstraction; codegen sites that need a flat pair span build it explicitly from data() and size() at the call site. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Borrowed map arguments were surfacing as std::span<std::pair<K,V> const>, which carries vector-shaped affordances (positional indexing, span conversions) on what is conceptually a map. wit::map_view is a borrow- only counterpart to wit::map that mimics map semantics rather than vector semantics. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Component-model map<K,V> carries no ordering or hashing guarantee, and the type's API surface deliberately mirrors std::unordered_map (size, empty, begin/end) plus bindings-construction primitives, so the name should reflect the unordered semantics rather than std::map's ordered ones. Companion borrow type renamed to wit::unordered_map_view. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
6387484 to
8e357c2
Compare
Adjacent block bodies (string/list/option dealloc) now reference _base after main's rename, so MapLower / MapLift / GuestDeallocateMap must declare the per-entry pointer under the same name to compile. Adds the matching (void) _base; suppression so loops still compile when the inner body doesn't reference it. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
|
@TartanLlama @cpetig give it another pass please 🙏🏻 |
This PR adds map type support to the C++ backend, following the same pattern established in #1562 (core), #1583 (Go), and #1584 (MoonBit).