summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Cmarada <mcmarada@cisco.com>2019-02-08 12:28:09 +0100
committerMichal Cmarada <mcmarada@cisco.com>2019-03-01 14:06:25 +0100
commit2fc03523c64803826e74ce0af42880f65f60a107 (patch)
tree3376ef620ac9b52c26d04ca93ac4e7e5f5ae7365
parentcbdc927c3c401e81ca3e8a3cb875820efac27513 (diff)
introduce EnumSets for Flag types
- this enables to set multiple enum options for flag types in VPP Change-Id: If7a59f8c3a47f712f6f591e1ce2547b15e0b2afb Signed-off-by: Michal Cmarada <mcmarada@cisco.com>
-rwxr-xr-xjava/jvpp/gen/jvpp_gen.py2
-rwxr-xr-xjava/jvpp/gen/jvppgen/enumsets_gen.py149
-rwxr-xr-xjava/jvpp/gen/jvppgen/jni_common_gen.py12
-rwxr-xr-xjava/jvpp/gen/jvppgen/jni_type_handlers_gen.py56
-rwxr-xr-xjava/jvpp/gen/jvppgen/jvpp_model.py45
5 files changed, 260 insertions, 4 deletions
diff --git a/java/jvpp/gen/jvpp_gen.py b/java/jvpp/gen/jvpp_gen.py
index 067a92f..d7f386c 100755
--- a/java/jvpp/gen/jvpp_gen.py
+++ b/java/jvpp/gen/jvpp_gen.py
@@ -20,6 +20,7 @@ import sys
from jvppgen.types_gen import generate_types
from jvppgen.enums_gen import generate_enums
+from jvppgen.enumsets_gen import generate_enumsets
from jvppgen.unions_gen import generate_unions
from jvppgen.dto_gen import generate_dtos
from jvppgen.jvpp_ifc_gen import generate_java_ifc
@@ -36,6 +37,7 @@ def generate_jvpp(root_dir, model, logger):
base_dir = "%s/target/%s" % (root_dir, model.plugin_package.replace(".", "/"))
generate_types(_work_dir(base_dir, "types"), model, logger)
generate_enums(_work_dir(base_dir, "types"), model, logger)
+ generate_enumsets(_work_dir(base_dir, "types"), model, logger)
generate_unions(_work_dir(base_dir, "types"), model, logger)
generate_dtos(_work_dir(base_dir, "dto"), model, logger)
generate_java_ifc(_work_dir(base_dir), model, logger)
diff --git a/java/jvpp/gen/jvppgen/enumsets_gen.py b/java/jvpp/gen/jvppgen/enumsets_gen.py
new file mode 100755
index 0000000..029c4ec
--- /dev/null
+++ b/java/jvpp/gen/jvppgen/enumsets_gen.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python2
+#
+# Copyright (c) 2019 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from string import Template
+
+from jvpp_model import EnumSet
+
+
+def generate_enumsets(work_dir, model, logger):
+ logger.debug("Generating enumset for %s " % model.json_api_files)
+
+ for t in model.types:
+ if not isinstance(t, EnumSet):
+ continue
+ logger.debug("Generating DTO for enumset %s", t)
+ type_class_name = t.java_name
+ type_class = _ENUM_TEMPLATE.substitute(
+ plugin_package=model.plugin_package,
+ c_type_name=t.name,
+ json_filename=model.json_api_files,
+ json_definition=t.doc,
+ java_name=type_class_name,
+ java_enum_name=type_class_name + "Options",
+ constants=_generate_constants(t.constants),
+ value_type=t.value.type.java_name
+ )
+ with open("%s/%s.java" % (work_dir, type_class_name), "w") as f:
+ f.write(type_class)
+
+
+_ENUM_TEMPLATE = Template("""
+package $plugin_package.types;
+
+import java.util.EnumSet;
+
+/**
+ * <p>This class represents $c_type_name enumset definition.
+ * <br>It was generated by enumsets_gen.py based on $json_filename:
+ * <pre>
+$json_definition
+ * </pre>
+ */
+public final class $java_name {
+
+ private final EnumSet<$java_enum_name> options = EnumSet.noneOf($java_enum_name.class);
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (!( obj instanceof $java_name)) {
+ return false;
+ }
+ return options.equals((($java_name)obj).getOptions());
+ }
+
+ public EnumSet<$java_enum_name> getOptions() {
+ return options;
+ }
+
+ public $value_type getOptionsValue() {
+ $value_type optionsValue = 0;
+ for ($java_enum_name opts : options) {
+ optionsValue = optionsValue | opts.value;
+ }
+ return optionsValue;
+ }
+
+ public void setOptionsValue(int value) {
+ options.clear();
+
+ if (value == 0) {
+ // if value is "0" set default value and exit
+ options.add($java_enum_name.forValue(0));
+ return;
+ }
+
+ for ($java_enum_name option : $java_enum_name.values()) {
+ if ((option.value > 0) & ((option.value & value) == option.value)) {
+ options.add(option);
+ }
+ }
+ }
+
+ public boolean add($java_enum_name option) {
+ return options.add(option);
+ }
+
+ public boolean remove($java_enum_name option) {
+ return options.remove(option);
+ }
+
+ public boolean removeAll(EnumSet<$java_enum_name> options) {
+ return options.removeAll(options);
+ }
+
+ public void clear() {
+ options.clear();
+ }
+
+ public boolean contains($java_enum_name option) {
+ return options.contains(option);
+ }
+
+ public boolean containsAll(EnumSet<$java_enum_name> options) {
+ return options.containsAll(options);
+ }
+
+ @Override
+ public java.lang.String toString() {
+ return "$java_name{" + "options=" + options + '}';
+ }
+
+ public enum $java_enum_name {
+$constants;
+
+ public final $value_type value;
+
+ $java_enum_name(final $value_type value) {
+ this.value = value;
+ }
+
+ public static $java_enum_name forValue(final $value_type value) {
+ for ($java_enum_name enumeration : $java_enum_name.values()) {
+ if (value == enumeration.value) {
+ return enumeration;
+ }
+ }
+ return null;
+ }
+ }
+}
+""")
+
+
+def _generate_constants(constants):
+ return ",\n".join(_CONSTANT_TEMPLATE.substitute(name=c['name'], value=c['value']) for c in constants)
+
+
+_CONSTANT_TEMPLATE = Template(""" $name($value)""")
diff --git a/java/jvpp/gen/jvppgen/jni_common_gen.py b/java/jvpp/gen/jvppgen/jni_common_gen.py
index b52e5ff..120241a 100755
--- a/java/jvpp/gen/jvppgen/jni_common_gen.py
+++ b/java/jvpp/gen/jvppgen/jni_common_gen.py
@@ -15,7 +15,7 @@
#
from string import Template
-from jvpp_model import is_array, is_retval, Class, Enum, Union
+from jvpp_model import is_array, is_retval, Class, Enum, EnumSet, Union
def generate_j2c_identifiers(element, class_ref_name, object_ref_name):
@@ -432,7 +432,10 @@ def _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, str
if field_type.name == "string":
template = _C2J_STRING_TYPE_SWAP_TEMPLATE
else:
- template = _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE
+ if isinstance(field_type, EnumSet):
+ template = _C2J_ENUMSET_TYPE_SWAP_TEMPLATE
+ else:
+ template = _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE
else:
template = _C2J_ALIAS_PRIMITIVE_TYPE_SWAP_TEMPLATE
return template.substitute(
@@ -463,6 +466,11 @@ _C2J_ALIAS_PRIMITIVE_TYPE_SWAP_TEMPLATE = Template("""
(*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(*${struct_ref_name}));
""")
+_C2J_ENUMSET_TYPE_SWAP_TEMPLATE = Template("""
+ jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
+ (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(env, ${struct_ref_name}->${c_name}));
+""")
+
def _generate_c2j_primitive_type_no_swap(msg_java_name, field, object_ref_name, struct_ref_name):
field_type = field.type
diff --git a/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py b/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py
index d733dd5..657972d 100755
--- a/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py
+++ b/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py
@@ -16,7 +16,7 @@
from string import Template
from jni_common_gen import generate_j2c_swap, generate_j2c_field_swap, generate_j2c_identifiers, generate_c2j_swap
-from jvpp_model import Class, Enum, Union
+from jvpp_model import Class, Enum, EnumSet, Union
def generate_type_handlers(model, logger):
@@ -32,6 +32,8 @@ def generate_type_handlers(model, logger):
_generate_class(model, t, type_handlers)
elif isinstance(t, Enum):
_generate_enum(model, t, type_handlers)
+ elif isinstance(t, EnumSet):
+ _generate_enumset(model, t, type_handlers)
elif isinstance(t, Union):
_generate_union(model, t, type_handlers)
else:
@@ -138,6 +140,58 @@ static inline ${jni_type} _net_to_host_${c_name}(vl_api_${c_name}_t _net)
}""")
+def _generate_enumset(model, t, type_handlers):
+ value_type = t.value.type
+ type_handlers.append(_ENUMSET_NET_TO_HOST_TEMPLATE.substitute(
+ c_name=t.name,
+ json_filename=model.json_api_files,
+ json_definition=t.doc,
+ class_FQN=t.jni_name,
+ jni_signature=value_type.jni_signature,
+ jni_type=value_type.jni_type,
+ jni_accessor=value_type.jni_accessor,
+ swap=_generate_scalar_host_to_net_swap(t.value)
+ ))
+
+ type_handlers.append(_ENUMSET_HOST_TO_NET_TEMPLATE.substitute(
+ c_name=t.name,
+ json_filename=model.json_api_files,
+ json_definition=t.doc,
+ class_FQN=t.jni_name,
+ jni_type=value_type.jni_type,
+ type_swap=_generate_scalar_net_to_host_swap(t.value)
+ ))
+
+
+_ENUMSET_NET_TO_HOST_TEMPLATE = Template("""
+/**
+ * Host to network byte order conversion for ${c_name} enum.
+ * Generated based on $json_filename:
+$json_definition
+ */
+static inline void _host_to_net_${c_name}(JNIEnv * env, jobject _host, vl_api_${c_name}_t * _net)
+{
+ jclass enumClass = (*env)->FindClass(env, "${class_FQN}");
+ jmethodID getValueMethod = (*env)->GetMethodID(env, enumClass, "getOptionsValue", "()I");
+ ${jni_type} value = (*env)->CallIntMethod(env, _host, getValueMethod);
+ ${swap};
+}""")
+
+_ENUMSET_HOST_TO_NET_TEMPLATE = Template("""
+/**
+ * Network to host byte order conversion for ${c_name} type.
+ * Generated based on $json_filename:
+$json_definition
+ */
+static inline jobject _net_to_host_${c_name}(JNIEnv * env, vl_api_${c_name}_t _net)
+{
+ jclass enumClass = (*env)->FindClass(env, "${class_FQN}");
+ jmethodID enumInit = (*env)->GetMethodID(env, enumClass, "setOptionsValue", "(I)V");
+ ${jni_type} value = (${jni_type}) $type_swap
+ return (*env)->NewObject(env, enumClass, enumInit, value);
+}""")
+
+
def _generate_scalar_host_to_net_swap(field):
field_type = field.type
if field_type.is_swap_needed:
diff --git a/java/jvpp/gen/jvppgen/jvpp_model.py b/java/jvpp/gen/jvppgen/jvpp_model.py
index 9a3204e..c5a7e74 100755
--- a/java/jvpp/gen/jvppgen/jvpp_model.py
+++ b/java/jvpp/gen/jvppgen/jvpp_model.py
@@ -142,6 +142,34 @@ class Enum(Type):
return "_host_to_net_%s(env, %s, &(%s))" % (self.name, host_ref_name, net_ref_name)
+class EnumSet(Type):
+ def __init__(self, name, value, constants, definition, plugin_name):
+ _java_name = _underscore_to_camelcase_upper(name)
+
+ super(EnumSet, self).__init__(
+ name=name,
+ java_name=_java_name,
+ java_name_fqn="io.fd.vpp.jvpp.%s.types.%s" % (plugin_name, _java_name),
+ jni_signature="Lio/fd/vpp/jvpp/%s/types/%s;" % (plugin_name, _java_name),
+ jni_type="jobject",
+ jni_accessor="Object",
+ host_to_net_function="_host_to_net_%s" % name,
+ net_to_host_function="_net_to_host_%s" % name
+ )
+
+ self.value = value
+ self.constants = constants
+ self.doc = _message_to_javadoc(definition)
+ self.java_name_lower = _underscore_to_camelcase_lower(name)
+ self.vpp_name = "%s%s%s" % (_VPP_TYPE_PREFIX, name, _VPP_TYPE_SUFFIX)
+ # Fully qualified class name used by FindClass function, see:
+ # https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#FindClass
+ self.jni_name = "io/fd/vpp/jvpp/%s/types/%s" % (plugin_name, _java_name)
+
+ def get_host_to_net_function(self, host_ref_name, net_ref_name):
+ return "_host_to_net_%s(env, %s, &(%s))" % (self.name, host_ref_name, net_ref_name)
+
+
class Class(Type):
def __init__(self, name, crc, fields, definition, plugin_name):
_java_name = _underscore_to_camelcase_upper(name)
@@ -391,8 +419,10 @@ class JVppModel(object):
type = value['type']
data = value['data'][1:]
try:
- if type == 'enum':
+ if type == 'enum' and "flags" not in name:
type = self._parse_enum(name, data)
+ elif type == 'enum' and "flags" in name:
+ type = self._parse_enumset(name, data)
elif type == 'union':
type = self._parse_union(name, data)
elif type == 'type':
@@ -468,6 +498,19 @@ class JVppModel(object):
raise ParseException("'enumtype' was not defined for %s" % definition)
return Enum(name, Field('value', self._types_by_name[type_name]), constants, definition, self.plugin_name)
+ def _parse_enumset(self, name, definition):
+ self.logger.debug("Parsing enumset %s: %s", name, definition)
+ constants = []
+ type_name = None
+ for item in definition:
+ if type(item) is dict and 'enumtype' in item:
+ type_name = item['enumtype']
+ continue
+ constants.append({'name': item[0], 'value': item[1]})
+ if not type_name:
+ raise ParseException("'enumtype' was not defined for %s" % definition)
+ return EnumSet(name, Field('value', self._types_by_name[type_name]), constants, definition, self.plugin_name)
+
def _parse_union(self, name, definition):
self.logger.debug("Parsing union %s: %s", name, definition)
crc, fields = self._parse_fields(definition)