[ObjC] Add apis for removing things from `GPBUnknownFields`.
PiperOrigin-RevId: 658538490
diff --git a/objectivec/GPBUnknownFields.h b/objectivec/GPBUnknownFields.h
index 1ee5057..4f05c2b 100644
--- a/objectivec/GPBUnknownFields.h
+++ b/objectivec/GPBUnknownFields.h
@@ -109,6 +109,26 @@
**/
- (nonnull GPBUnknownFields *)addGroupWithFieldNumber:(int32_t)fieldNumber;
+/**
+ * Removes the given field from the set.
+ *
+ * It is a programming error to attempt to remove a field that is not in this collection.
+ *
+ * Reminder: it is not save to mutate the collection while also using fast enumeration on it.
+ *
+ * @param field The field to remove.
+ **/
+- (void)removeField:(nonnull GPBUnknownField *)field;
+
+/**
+ * Removes all of the fields from the collection that have the given field number.
+ *
+ * If there are no fields with the given field number, this is a no-op.
+ *
+ * @param fieldNumber The field number to remove.
+ **/
+- (void)clearFieldNumber:(int32_t)fieldNumber;
+
@end
@interface GPBUnknownFields (AccessHelpers)
diff --git a/objectivec/GPBUnknownFields.m b/objectivec/GPBUnknownFields.m
index 836e249..2672d10 100644
--- a/objectivec/GPBUnknownFields.m
+++ b/objectivec/GPBUnknownFields.m
@@ -318,6 +318,34 @@
return [group autorelease];
}
+- (void)removeField:(nonnull GPBUnknownField *)field {
+ NSUInteger count = fields_.count;
+ [fields_ removeObjectIdenticalTo:field];
+ if (count == fields_.count) {
+ [NSException raise:NSInvalidArgumentException format:@"The field was not present."];
+ }
+}
+
+- (void)clearFieldNumber:(int32_t)fieldNumber {
+ CHECK_FIELD_NUMBER(fieldNumber);
+ NSMutableIndexSet *toRemove = nil;
+ NSUInteger idx = 0;
+ for (GPBUnknownField *field in fields_) {
+ if (field->number_ == fieldNumber) {
+ if (toRemove == nil) {
+ toRemove = [[NSMutableIndexSet alloc] initWithIndex:idx];
+ } else {
+ [toRemove addIndex:idx];
+ }
+ }
+ ++idx;
+ }
+ if (toRemove) {
+ [fields_ removeObjectsAtIndexes:toRemove];
+ [toRemove release];
+ }
+}
+
#pragma mark - NSFastEnumeration protocol
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
diff --git a/objectivec/Tests/GPBUnknownFieldsTest.m b/objectivec/Tests/GPBUnknownFieldsTest.m
index 8c2adcf..6c6481d 100644
--- a/objectivec/Tests/GPBUnknownFieldsTest.m
+++ b/objectivec/Tests/GPBUnknownFieldsTest.m
@@ -510,6 +510,82 @@
XCTAssertNil([ufs fields:99]); // Not present
}
+- (void)testRemoveField {
+ GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease];
+ [ufs addFieldNumber:1 varint:1];
+ [ufs addFieldNumber:1 fixed32:1];
+ [ufs addFieldNumber:1 fixed64:1];
+ XCTAssertEqual(ufs.count, 3);
+
+ NSArray<GPBUnknownField*>* fields = [ufs fields:1];
+ XCTAssertEqual(fields.count, 3);
+ GPBUnknownField* field = fields[0];
+ XCTAssertEqual(field.number, 1);
+ XCTAssertEqual(field.type, GPBUnknownFieldTypeVarint);
+ XCTAssertEqual(field.varint, 1);
+ [ufs removeField:field]; // Remove first (varint)
+ XCTAssertEqual(ufs.count, 2);
+
+ fields = [ufs fields:1];
+ XCTAssertEqual(fields.count, 2);
+ field = fields[0];
+ XCTAssertEqual(field.number, 1);
+ XCTAssertEqual(field.type, GPBUnknownFieldTypeFixed32);
+ field = fields[1];
+ XCTAssertEqual(field.number, 1);
+ XCTAssertEqual(field.type, GPBUnknownFieldTypeFixed64);
+ [ufs removeField:field]; // Remove the second (fixed64)
+ XCTAssertEqual(ufs.count, 1);
+
+ fields = [ufs fields:1];
+ XCTAssertEqual(fields.count, 1);
+ field = fields[0];
+ XCTAssertEqual(field.number, 1);
+ XCTAssertEqual(field.type, GPBUnknownFieldTypeFixed32);
+
+ field = [[field retain] autorelease]; // Hold on to this last one.
+ [ufs removeField:field]; // Remove the last one (fixed32)
+ XCTAssertEqual(ufs.count, 0);
+
+ // Trying to remove something not in the set should fail.
+ XCTAssertThrowsSpecificNamed([ufs removeField:field], NSException, NSInvalidArgumentException);
+}
+
+- (void)testClearFieldNumber {
+ GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease];
+ [ufs addFieldNumber:1 varint:1];
+ [ufs addFieldNumber:2 fixed32:2];
+ [ufs addFieldNumber:1 fixed64:1];
+ [ufs addFieldNumber:3 varint:3];
+ XCTAssertEqual(ufs.count, 4);
+
+ [ufs clearFieldNumber:999]; // Not present, noop.
+ XCTAssertEqual(ufs.count, 4);
+
+ [ufs clearFieldNumber:1]; // Should remove slot zero and slot two.
+ XCTAssertEqual(ufs.count, 2);
+ NSArray<GPBUnknownField*>* fields = [ufs fields:2];
+ XCTAssertEqual(fields.count, 1);
+ GPBUnknownField* field = fields[0];
+ XCTAssertEqual(field.number, 2);
+ XCTAssertEqual(field.type, GPBUnknownFieldTypeFixed32);
+ XCTAssertEqual(field.fixed32, 2);
+ fields = [ufs fields:3];
+ XCTAssertEqual(fields.count, 1);
+ field = fields[0];
+ XCTAssertEqual(field.number, 3);
+ XCTAssertEqual(field.type, GPBUnknownFieldTypeVarint);
+ XCTAssertEqual(field.varint, 3);
+
+ [ufs clearFieldNumber:2]; // Should remove slot one.
+ fields = [ufs fields:3];
+ XCTAssertEqual(fields.count, 1);
+ field = fields[0];
+ XCTAssertEqual(field.number, 3);
+ XCTAssertEqual(field.type, GPBUnknownFieldTypeVarint);
+ XCTAssertEqual(field.varint, 3);
+}
+
- (void)testFastEnumeration {
GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease];
[ufs addFieldNumber:1 varint:1];