Skip to content

Add option to use primitive arrays for packed scalars#2433

Merged
swankjesse merged 17 commits intosquare:masterfrom
JGulbronson:jgulbronson.add-use-primitive-array-field-option
Apr 24, 2023
Merged

Add option to use primitive arrays for packed scalars#2433
swankjesse merged 17 commits intosquare:masterfrom
JGulbronson:jgulbronson.add-use-primitive-array-field-option

Conversation

@JGulbronson
Copy link
Copy Markdown
Collaborator

This will allow us to generate repeated, packed, scalar fields to use the appropriate Array type. This has huge benefits for the JVM, because it will prevent autoboxing of values. (For example, float -> Float).

This is still a WIP, I've largely hardcoded things as FloatArray while I play around with it, but it's starting to take shape. Unfortunately we can't use generics and avoid the autoboxing, hence the 4 different *ArrayList classes.

@JGulbronson
Copy link
Copy Markdown
Collaborator Author

Okay I think this is ready for review.

Notably because I can't really use generics here, I've chosen to only support use_array with packed fields to simplify things. This seems like a reasonable tradeoff to start, and I can explore removing that restriction in the future.

I do still have to put up a PR to reserve the extension for Wire, similar to https://github.com/protocolbuffers/protobuf/pull/7020/files. Was planning on doing that after this is approved (or at least the API), and then before it's merged.

In terms of testing, I feel pretty good about the test changes I made. Unfortunately trying to test for autoboxing isn't really feasible, but in terms of correctness we should be good.

@JGulbronson JGulbronson marked this pull request as ready for review April 14, 2023 15:42
@JGulbronson JGulbronson changed the title DRAFT - Add option to use primitive arrays for packed scalars Add option to use primitive arrays for packed scalars Apr 14, 2023
@JGulbronson
Copy link
Copy Markdown
Collaborator Author

Note that this doesn't prevent autoboxing, because of the use of generics in the ProtoAdapter abstract class

@JGulbronson
Copy link
Copy Markdown
Collaborator Author

Okay this should prevent autoboxing now

@JGulbronson
Copy link
Copy Markdown
Collaborator Author

The multiplatform test failed because of an HTTP error

Caused by: org.gradle.internal.resource.transport.http.HttpErrorStatusCodeException: Could not HEAD 'https://nodejs.org/dist/v16.13.1/node-v16.13.1-darwin-x64.tar.gz'. Received status code 500 from server: Internal Server Error

@JGulbronson JGulbronson reopened this Apr 19, 2023
@JGulbronson JGulbronson reopened this Apr 20, 2023
copybara-service bot pushed a commit to protocolbuffers/protobuf that referenced this pull request Apr 20, 2023
release notes: no

Supports square/wire#2433

Closes #12491

COPYBARA_INTEGRATE_REVIEW=#12491 from JGulbronson:jgulbronson.claim-1180-for-wire f577336
PiperOrigin-RevId: 525793344
val fieldName = localNameAllocator[fieldOrOneOf]
addStatement("if (%1L != %2N.%1L) return·false", fieldName, otherName)
if (fieldOrOneOf.useArray) {
addStatement("if (!%1L.contentEquals(%2N.%1L)) return·false", fieldName, otherName)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch

Copy link
Copy Markdown
Collaborator

@swankjesse swankjesse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wonderful

fieldName
)
if (field.useArray && reverse) {
val encodeArray = MemberName("com.squareup.wire.internal", "encodeArray")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

Comment thread wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt Outdated
EncodeMode.REPEATED -> List::class.asClassName().parameterizedBy(baseClass)
EncodeMode.PACKED -> {
if (useArray) {
primitiveArrayClassForType.asTypeName()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

override fun encodedSize(value: DoubleArray): Int {
var size = 0
for (i in 0 until value.size) {
size += originalAdapter.encodedSize(value[i])
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know if I prefer this or not:

return originalAdapter.encodedSize(0.0) * value.size

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly not worth the deviation

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be optimizing the slow path right? Since using the reverse writer means you just get the size after encoding?

linker.errors += "packed=true not permitted on $type"
}
if (useArray && !isPacked) {
linker.errors += "wire.use_array=true only permitted on packed fields"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, this is what I was asking for above. Yay!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, resolving the original comment

} catch (expected: SchemaException) {
assertThat(expected).hasMessage(
"""
|wire.use_array=true only permitted on packed fields
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SWEEET test!

- Rename `getTruncatedArray()` to `toArray()`
- Add copyright headers
- Add helper `forDecoding()` method on companion objects
@JGulbronson JGulbronson requested a review from swankjesse April 24, 2023 14:55
override fun toString(): String = data.copyOf(size).contentToString()

companion object {
fun forDecoding(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

.coerceAtMost(Int.MAX_VALUE.toLong())
.toInt()
array_int32 = IntArrayList(initialCapacity)
array_int32 = IntArrayList.forDecoding(reader.nextFieldMinLengthInBytes(), 1)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YES!

@swankjesse swankjesse merged commit de33624 into square:master Apr 24, 2023
@oldergod oldergod added this to the 4.5.6 milestone Apr 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants