Replace filed instance transformations with functiors for better readability.
diff --git a/src/field_instance.h b/src/field_instance.h
index 5545ffa..eb72e78 100644
--- a/src/field_instance.h
+++ b/src/field_instance.h
@@ -190,6 +190,9 @@
size_t index() const { return index_; }
private:
+ template <class Fn, class T>
+ friend struct FieldFunction;
+
const protobuf::Message* message_;
const protobuf::FieldDescriptor* descriptor_;
size_t index_;
@@ -301,37 +304,6 @@
if (value) mutable_message->CopyFrom(*value);
}
- template <class Transformation>
- void Apply(const Transformation& transformation) const {
- assert(descriptor());
- using protobuf::FieldDescriptor;
- switch (cpp_type()) {
- case FieldDescriptor::CPPTYPE_INT32:
- return transformation.template Apply<int32_t>(*this);
- case FieldDescriptor::CPPTYPE_INT64:
- return transformation.template Apply<int64_t>(*this);
- case FieldDescriptor::CPPTYPE_UINT32:
- return transformation.template Apply<uint32_t>(*this);
- case FieldDescriptor::CPPTYPE_UINT64:
- return transformation.template Apply<uint64_t>(*this);
- case FieldDescriptor::CPPTYPE_DOUBLE:
- return transformation.template Apply<double>(*this);
- case FieldDescriptor::CPPTYPE_FLOAT:
- return transformation.template Apply<float>(*this);
- case FieldDescriptor::CPPTYPE_BOOL:
- return transformation.template Apply<bool>(*this);
- case FieldDescriptor::CPPTYPE_ENUM:
- return transformation.template Apply<FieldInstance::Enum>(*this);
- case FieldDescriptor::CPPTYPE_STRING:
- return transformation.template Apply<std::string>(*this);
- case FieldDescriptor::CPPTYPE_MESSAGE:
- return transformation
- .template Apply<std::unique_ptr<protobuf::Message>>(*this);
- default:
- assert(!"Unknown type");
- }
- }
-
private:
template <class T>
void InsertRepeated(const T& value) const {
@@ -404,6 +376,50 @@
protobuf::Message* message_;
};
+template <class Fn, class R = void>
+struct FieldFunction {
+ template <class Field, class... Args>
+ R operator()(const Field& field, const Args&... args) const {
+ assert(field.descriptor());
+ using protobuf::FieldDescriptor;
+ switch (field.cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return static_cast<const Fn*>(this)->template ForType<int32_t>(field,
+ args...);
+ case FieldDescriptor::CPPTYPE_INT64:
+ return static_cast<const Fn*>(this)->template ForType<int64_t>(field,
+ args...);
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return static_cast<const Fn*>(this)->template ForType<uint32_t>(
+ field, args...);
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return static_cast<const Fn*>(this)->template ForType<uint64_t>(
+ field, args...);
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return static_cast<const Fn*>(this)->template ForType<double>(field,
+ args...);
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return static_cast<const Fn*>(this)->template ForType<float>(field,
+ args...);
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return static_cast<const Fn*>(this)->template ForType<bool>(field,
+ args...);
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return static_cast<const Fn*>(this)
+ ->template ForType<ConstFieldInstance::Enum>(field, args...);
+ case FieldDescriptor::CPPTYPE_STRING:
+ return static_cast<const Fn*>(this)->template ForType<std::string>(
+ field, args...);
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ return static_cast<const Fn*>(this)
+ ->template ForType<std::unique_ptr<protobuf::Message>>(field,
+ args...);
+ default:
+ assert(!"Unknown type");
+ }
+ }
+};
+
} // namespace protobuf_mutator
#endif // SRC_FIELD_INSTANCE_H_
diff --git a/src/protobuf_mutator.cc b/src/protobuf_mutator.cc
index e63cee6..29eb699 100644
--- a/src/protobuf_mutator.cc
+++ b/src/protobuf_mutator.cc
@@ -78,48 +78,40 @@
return GetRandomIndex(random, n) == 0;
}
-struct CreateDefaultFieldTransformation {
+struct CreateDefaultField : public FieldFunction<CreateDefaultField> {
template <class T>
- void Apply(const FieldInstance& field) const {
+ void ForType(const FieldInstance& field) const {
T value;
field.GetDefault(&value);
field.Create(value);
}
};
-struct DeleteFieldTransformation {
+struct DeleteField : public FieldFunction<DeleteField> {
template <class T>
- void Apply(const FieldInstance& field) const {
+ void ForType(const FieldInstance& field) const {
field.Delete();
}
};
-struct CopyFieldTransformation {
- explicit CopyFieldTransformation(const ConstFieldInstance& field)
- : source(field) {}
-
+struct CopyField : public FieldFunction<CopyField> {
template <class T>
- void Apply(const FieldInstance& field) const {
+ void ForType(const ConstFieldInstance& source,
+ const FieldInstance& field) const {
T value;
source.Load(&value);
field.Store(value);
}
-
- ConstFieldInstance source;
};
-struct AppendFieldTransformation {
- explicit AppendFieldTransformation(const ConstFieldInstance& field)
- : source(field) {}
-
+struct AppendField : public FieldFunction<AppendField> {
template <class T>
- void Apply(const FieldInstance& field) const {
+ void ForType(const ConstFieldInstance& source,
+ const FieldInstance& field) const {
T value;
source.Load(&value);
field.Create(value);
}
-
- ConstFieldInstance source;
};
// Selects random field and mutation from the given proto message.
@@ -380,38 +372,27 @@
namespace {
-class MutateTransformation {
- public:
- MutateTransformation(size_t size_increase_hint, ProtobufMutator* mutator)
- : mutator_(size_increase_hint, mutator) {}
-
+struct MutateField : public FieldFunction<MutateField> {
template <class T>
- void Apply(const FieldInstance& field) const {
+ void ForType(const FieldInstance& field, size_t size_increase_hint,
+ ProtobufMutator* mutator) const {
T value;
field.Load(&value);
- mutator_.Mutate(&value);
+ FieldMutator(size_increase_hint, mutator).Mutate(&value);
field.Store(value);
}
-
- private:
- FieldMutator mutator_;
};
-class CreateFieldTransformation {
+struct CreateField : public FieldFunction<CreateField> {
public:
- CreateFieldTransformation(size_t size_increase_hint, ProtobufMutator* mutator)
- : mutator_(size_increase_hint, mutator) {}
-
template <class T>
- void Apply(const FieldInstance& field) const {
+ void ForType(const FieldInstance& field, size_t size_increase_hint,
+ ProtobufMutator* mutator) const {
T value;
field.GetDefault(&value);
- mutator_.Mutate(&value);
+ FieldMutator(size_increase_hint, mutator).Mutate(&value);
field.Create(value);
}
-
- private:
- FieldMutator mutator_;
};
} // namespace
@@ -426,27 +407,25 @@
break;
case Mutation::Add:
if (GetRandomBool(&random_)) {
- mutation.field().Apply(
- CreateFieldTransformation(size_increase_hint / 2, this));
+ CreateField()(mutation.field(), size_increase_hint / 2, this);
} else {
- mutation.field().Apply(CreateDefaultFieldTransformation());
+ CreateDefaultField()(mutation.field());
}
break;
case Mutation::Mutate:
- mutation.field().Apply(
- MutateTransformation(size_increase_hint / 2, this));
+ MutateField()(mutation.field(), size_increase_hint / 2, this);
break;
case Mutation::Delete:
- mutation.field().Apply(DeleteFieldTransformation());
+ DeleteField()(mutation.field());
break;
case Mutation::Copy: {
DataSourceSampler source(mutation.field(), &random_, message);
if (source.IsEmpty()) {
// Fallback to message deletion.
- mutation.field().Apply(DeleteFieldTransformation());
+ DeleteField()(mutation.field());
break;
}
- mutation.field().Apply(CopyFieldTransformation(source.field()));
+ CopyField()(source.field(), mutation.field());
break;
}
default:
@@ -485,7 +464,7 @@
for (int j = 0; j < field_size1; ++j) {
ConstFieldInstance source(&message1, field, j);
FieldInstance destination(message2, field, field_size2++);
- destination.Apply(AppendFieldTransformation(source));
+ AppendField()(source, destination);
}
assert(field_size2 == reflection->FieldSize(*message2, field));
@@ -519,11 +498,11 @@
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
if (!reflection->HasField(message1, field)) {
if (GetRandomBool(&random_))
- FieldInstance(message2, field).Apply(DeleteFieldTransformation());
+ DeleteField()(FieldInstance(message2, field));
} else if (!reflection->HasField(*message2, field)) {
if (GetRandomBool(&random_)) {
ConstFieldInstance source(&message1, field);
- FieldInstance(message2, field).Apply(CopyFieldTransformation(source));
+ CopyField()(source, FieldInstance(message2, field));
}
} else {
CrossOverImpl(reflection->GetMessage(message1, field),
@@ -533,9 +512,9 @@
if (GetRandomBool(&random_)) {
if (reflection->HasField(message1, field)) {
ConstFieldInstance source(&message1, field);
- FieldInstance(message2, field).Apply(CopyFieldTransformation(source));
+ CopyField()(source, FieldInstance(message2, field));
} else {
- FieldInstance(message2, field).Apply(DeleteFieldTransformation());
+ DeleteField()(FieldInstance(message2, field));
}
}
}
@@ -552,7 +531,7 @@
for (int i = 0; i < descriptor->field_count(); ++i) {
const FieldDescriptor* field = descriptor->field(i);
if (field->is_required() && !reflection->HasField(*message, field))
- FieldInstance(message, field).Apply(CreateDefaultFieldTransformation());
+ CreateDefaultField()(FieldInstance(message, field));
if (max_depth > 0 &&
field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {