bindings: replace pybindgen bindings support with cppyy bindings

This commit is contained in:
Gabriel Ferreira
2022-06-06 06:44:42 -07:00
parent c5d0c8efb4
commit 36df81be90
39 changed files with 750 additions and 3630 deletions

View File

@@ -60,7 +60,6 @@ option(NS3_LINK_WHAT_YOU_USE
)
option(NS3_SANITIZE "Build with address, leak and undefined sanitizers" OFF)
option(NS3_SANITIZE_MEMORY "Build with memory sanitizer" OFF)
option(NS3_SCAN_PYTHON_BINDINGS "Scan python bindings" OFF)
# 3rd-party libraries/programs
option(NS3_NETANIM "Build netanim" OFF)
@@ -80,7 +79,7 @@ set(NS3_OUTPUT_DIRECTORY "" CACHE STRING "Directory to store built artifacts")
option(NS3_PRECOMPILE_HEADERS
"Precompile module headers to speed up compilation" ON
)
option(NS3_PYTHON_BINDINGS "Build ns-3 python bindings" OFF)
option(NS3_PYTHON_BINDINGS "Build ns-3 python bindings" ON)
option(NS3_REALTIME "Build with realtime support" ON)
option(NS3_SQLITE "Build with SQLite support" ON)
option(NS3_STATIC "Build a static ns-3 library and link it against executables"
@@ -141,7 +140,6 @@ add_subdirectory(utils)
write_lock()
write_configtable()
write_header_to_modules_map()
# Export package targets when installing
ns3_cmake_package()

View File

@@ -1,9 +0,0 @@
# Store version information for required pybindgen version, used by
# ns-3-allinone/download.py.
# If specifying a released pybindgen version, specify the required pybindgen
# version as, e.g. '0.21.0'
# If specifying a commit on the development tree, specify it like this based
# on 'git describe --tags' command. Example, if the latest release was 0.21.0,
# and 'git describe --tags' reports "0.21.0-6-g8e7c0a9", then write the
# version string below as '0.21.0.post6+ng8e7c0a9'
__required_pybindgen_version__ = '0.22.1'

View File

@@ -1,13 +0,0 @@
from pybindgen import Module, FileCodeSink, write_preamble, param, retval
def register_types(module):
module.add_class('MyClass')
def register_methods(root_module):
MyClass = root_module['MyClass']
MyClass.add_constructor([], visibility='public')
MyClass.add_constructor([param('double', 's'), param('double', 'l'), param('double', 'mean')], visibility='public')
def register_functions(module):
module.add_function('SomeFunction', 'int', [param('int', 'xpto')])

View File

@@ -1,7 +0,0 @@
from _ns3 import *
import atexit
atexit.register(Simulator.Destroy)
del atexit

View File

@@ -1,336 +0,0 @@
#include "ns3module.h"
#include "ns3/ref-count-base.h"
namespace ns3 {
void PythonCompleteConstruct (Ptr<Object> object, TypeId typeId, const AttributeList &attributes)
{
object->SetTypeId (typeId);
object->Object::Construct (attributes);
}
}
class PythonEventImpl : public ns3::EventImpl
{
private:
PyObject *m_callback;
PyObject *m_args;
public:
PythonEventImpl (PyObject *callback, PyObject *args)
{
m_callback = callback;
Py_INCREF (m_callback);
m_args = args;
Py_INCREF (m_args);
}
virtual ~PythonEventImpl ()
{
PyGILState_STATE __py_gil_state;
__py_gil_state = (PyEval_ThreadsInitialized () ? PyGILState_Ensure () : (PyGILState_STATE) 0);
Py_DECREF (m_callback);
Py_DECREF (m_args);
if (PyEval_ThreadsInitialized ())
PyGILState_Release (__py_gil_state);
}
virtual void Notify ()
{
PyGILState_STATE __py_gil_state;
__py_gil_state = (PyEval_ThreadsInitialized () ? PyGILState_Ensure () : (PyGILState_STATE) 0);
PyObject *retval = PyObject_CallObject (m_callback, m_args);
if (retval) {
if (retval != Py_None) {
PyErr_SetString (PyExc_TypeError, "event callback should return None");
PyErr_Print ();
}
Py_DECREF (retval);
} else {
PyErr_Print ();
}
if (PyEval_ThreadsInitialized ())
PyGILState_Release (__py_gil_state);
}
};
PyObject *
_wrap_Simulator_Schedule (PyNs3Simulator *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs,
PyObject **return_exception)
{
PyObject *exc_type, *traceback;
PyObject *py_time;
PyObject *py_callback;
PyObject *user_args;
ns3::Ptr<PythonEventImpl> py_event_impl;
PyNs3EventId *py_EventId;
if (kwargs && PyObject_Length (kwargs) > 0) {
PyErr_SetString (PyExc_TypeError, "keyword arguments not supported");
goto error;
}
if (PyTuple_GET_SIZE (args) < 2) {
PyErr_SetString (PyExc_TypeError, "ns3.Simulator.Schedule needs at least 2 arguments");
goto error;
}
py_time = PyTuple_GET_ITEM (args, 0);
py_callback = PyTuple_GET_ITEM (args, 1);
if (!PyObject_IsInstance (py_time, (PyObject*) &PyNs3Time_Type)) {
PyErr_SetString (PyExc_TypeError, "Parameter 1 should be a ns3.Time instance");
goto error;
}
if (!PyCallable_Check (py_callback)) {
PyErr_SetString (PyExc_TypeError, "Parameter 2 should be callable");
goto error;
}
user_args = PyTuple_GetSlice (args, 2, PyTuple_GET_SIZE (args));
py_event_impl = ns3::Create<PythonEventImpl>(py_callback, user_args);
Py_DECREF (user_args);
py_EventId = PyObject_New (PyNs3EventId, &PyNs3EventId_Type);
py_EventId->obj = new ns3::EventId (
ns3::Simulator::Schedule (*((PyNs3Time *) py_time)->obj, py_event_impl));
return (PyObject *) py_EventId;
error:
PyErr_Fetch (&exc_type, return_exception, &traceback);
Py_XDECREF (exc_type);
Py_XDECREF (traceback);
return NULL;
}
PyObject *
_wrap_Simulator_ScheduleNow (PyNs3Simulator *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs,
PyObject **return_exception)
{
PyObject *exc_type, *traceback;
PyObject *py_callback;
PyObject *user_args;
ns3::Ptr<PythonEventImpl> py_event_impl;
PyNs3EventId *py_EventId;
if (kwargs && PyObject_Length (kwargs) > 0) {
PyErr_SetString (PyExc_TypeError, "keyword arguments not supported");
goto error;
}
if (PyTuple_GET_SIZE (args) < 1) {
PyErr_SetString (PyExc_TypeError, "ns3.Simulator.Schedule needs at least 1 argument");
goto error;
}
py_callback = PyTuple_GET_ITEM (args, 0);
if (!PyCallable_Check (py_callback)) {
PyErr_SetString (PyExc_TypeError, "Parameter 2 should be callable");
goto error;
}
user_args = PyTuple_GetSlice (args, 1, PyTuple_GET_SIZE (args));
py_event_impl = ns3::Create<PythonEventImpl>(py_callback, user_args);
Py_DECREF (user_args);
py_EventId = PyObject_New (PyNs3EventId, &PyNs3EventId_Type);
py_EventId->obj = new ns3::EventId (ns3::Simulator::ScheduleNow (py_event_impl));
return (PyObject *) py_EventId;
error:
PyErr_Fetch (&exc_type, return_exception, &traceback);
Py_XDECREF (exc_type);
Py_XDECREF (traceback);
return NULL;
}
PyObject *
_wrap_Simulator_ScheduleDestroy (PyNs3Simulator *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs,
PyObject **return_exception)
{
PyObject *exc_type, *traceback;
PyObject *py_callback;
PyObject *user_args;
ns3::Ptr<PythonEventImpl> py_event_impl;
PyNs3EventId *py_EventId;
if (kwargs && PyObject_Length (kwargs) > 0) {
PyErr_SetString (PyExc_TypeError, "keyword arguments not supported");
goto error;
}
if (PyTuple_GET_SIZE (args) < 1) {
PyErr_SetString (PyExc_TypeError, "ns3.Simulator.Schedule needs at least 1 argument");
goto error;
}
py_callback = PyTuple_GET_ITEM (args, 0);
if (!PyCallable_Check (py_callback)) {
PyErr_SetString (PyExc_TypeError, "Parameter 2 should be callable");
goto error;
}
user_args = PyTuple_GetSlice (args, 1, PyTuple_GET_SIZE (args));
py_event_impl = ns3::Create<PythonEventImpl>(py_callback, user_args);
Py_DECREF (user_args);
py_EventId = PyObject_New (PyNs3EventId, &PyNs3EventId_Type);
py_EventId->obj = new ns3::EventId (ns3::Simulator::ScheduleDestroy (py_event_impl));
return (PyObject *) py_EventId;
error:
PyErr_Fetch (&exc_type, return_exception, &traceback);
Py_XDECREF (exc_type);
Py_XDECREF (traceback);
return NULL;
}
PyObject *
_wrap_TypeId_LookupByNameFailSafe (PyNs3TypeId *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs,
PyObject **return_exception)
{
bool ok;
const char *name;
Py_ssize_t name_len;
ns3::TypeId tid;
PyNs3TypeId *py_tid;
const char *keywords[] = {"name", NULL};
if (!PyArg_ParseTupleAndKeywords (args, kwargs, (char *) "s#", (char **) keywords, &name, &name_len)) {
PyObject *exc_type, *traceback;
PyErr_Fetch (&exc_type, return_exception, &traceback);
Py_XDECREF (exc_type);
Py_XDECREF (traceback);
return NULL;
}
ok = ns3::TypeId::LookupByNameFailSafe (std::string (name, name_len), &tid);
if (!ok)
{
PyErr_Format (PyExc_KeyError, "The ns3 type with name `%s' is not registered", name);
return NULL;
}
py_tid = PyObject_New (PyNs3TypeId, &PyNs3TypeId_Type);
py_tid->obj = new ns3::TypeId (tid);
PyNs3TypeId_wrapper_registry[(void *) py_tid->obj] = (PyObject *) py_tid;
return (PyObject *) py_tid;
}
class CommandLinePythonValueSetter : public ns3::RefCountBase
{
PyObject *m_namespace;
std::string m_variable;
public:
CommandLinePythonValueSetter (PyObject *ns, std::string const &variable) {
Py_INCREF (ns);
m_namespace = ns;
m_variable = variable;
}
bool Parse (std::string value) {
PyObject *pyvalue = PyString_FromStringAndSize (value.data (), value.size ());
PyObject_SetAttrString (m_namespace, (char *) m_variable.c_str (), pyvalue);
if (PyErr_Occurred ()) {
PyErr_Print ();
return false;
}
return true;
}
virtual ~CommandLinePythonValueSetter () {
Py_DECREF (m_namespace);
m_namespace = NULL;
}
};
PyObject *
_wrap_CommandLine_AddValue (PyNs3CommandLine *self, PyObject *args, PyObject *kwargs,
PyObject **return_exception)
{
const char *name, *help, *variable = NULL;
PyObject *py_namespace = NULL;
const char *keywords[] = {"name", "help", "variable", "namespace", NULL};
if (!PyArg_ParseTupleAndKeywords (args, kwargs, (char *) "ss|sO", (char **) keywords, &name, &help, &variable, &py_namespace)) {
PyObject *exc_type, *traceback;
PyErr_Fetch (&exc_type, return_exception, &traceback);
Py_XDECREF (exc_type);
Py_XDECREF (traceback);
return NULL;
}
if (variable == NULL) {
variable = name;
}
if (py_namespace == NULL) {
py_namespace = (PyObject *) self;
}
ns3::Ptr<CommandLinePythonValueSetter> setter = ns3::Create<CommandLinePythonValueSetter> (py_namespace, variable);
self->obj->AddValue (name, help, ns3::MakeCallback (&CommandLinePythonValueSetter::Parse, setter));
Py_INCREF (Py_None);
return Py_None;
}
PyObject *
_wrap_Simulator_Run (PyNs3Simulator *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs,
PyObject **return_exception)
{
const char *keywords[] = {"signal_check_frequency", NULL};
int signal_check_frequency;
ns3::Ptr<ns3::DefaultSimulatorImpl> defaultSim =
ns3::DynamicCast<ns3::DefaultSimulatorImpl> (ns3::Simulator::GetImplementation ());
if (defaultSim) {
signal_check_frequency = 100;
} else {
signal_check_frequency = -1;
}
if (!PyArg_ParseTupleAndKeywords (args, kwargs, (char *) "|i", (char **) keywords, &signal_check_frequency)) {
PyObject *exc_type, *traceback;
PyErr_Fetch (&exc_type, return_exception, &traceback);
Py_XDECREF (exc_type);
Py_XDECREF (traceback);
return NULL;
}
PyThreadState *py_thread_state = NULL;
if (signal_check_frequency == -1)
{
if (PyEval_ThreadsInitialized ())
py_thread_state = PyEval_SaveThread ();
ns3::Simulator::Run ();
if (py_thread_state)
PyEval_RestoreThread (py_thread_state);
} else {
while (!ns3::Simulator::IsFinished ())
{
if (PyEval_ThreadsInitialized ())
py_thread_state = PyEval_SaveThread ();
for (int n = signal_check_frequency; n > 0 && !ns3::Simulator::IsFinished (); --n)
{
ns3::Simulator::RunOneEvent ();
}
if (py_thread_state)
PyEval_RestoreThread (py_thread_state);
PyErr_CheckSignals ();
if (PyErr_Occurred ())
return NULL;
}
}
Py_INCREF (Py_None);
return Py_None;
}

View File

@@ -1,131 +0,0 @@
from __future__ import print_function
import warnings
import sys
import os
import pybindgen.settings
from pybindgen import Module, FileCodeSink, param, retval, cppclass, typehandlers
from pybindgen.module import MultiSectionFactory
import ns3modulegen_core_customizations
import logging
pybindgen.settings.wrapper_registry = pybindgen.settings.StdMapWrapperRegistry
import traceback
class ErrorHandler(pybindgen.settings.ErrorHandler):
def __init__(self, apidefs_file):
self.apidefs_file = apidefs_file
def handle_error(self, wrapper, exception, traceback_):
stack = getattr(wrapper, 'stack_where_defined', [])
stack.reverse()
for l in stack:
if l[0] == self.apidefs_file:
warnings.warn_explicit("exception %r in wrapper %s" % (exception, wrapper),
Warning, l[0], l[1])
break
else:
warnings.warn("exception %r in wrapper %s" % (exception, wrapper))
return True
#print >> sys.stderr, ">>>>>>>>>>>>>>>>>>>>>>>>>>>> ", bool(eval(os.environ["GCC_RTTI_ABI_COMPLETE"]))
pybindgen.settings.gcc_rtti_abi_complete = bool(eval(os.environ["GCC_RTTI_ABI_COMPLETE"]))
class MyMultiSectionFactory(MultiSectionFactory):
def __init__(self, main_file_name):
super(MyMultiSectionFactory, self).__init__()
self.main_file_name = main_file_name
self.main_sink = FileCodeSink(open(main_file_name, "wt"))
self.header_name = "ns3module.h"
header_file_name = os.path.join(os.path.dirname(self.main_file_name), self.header_name)
#print >> sys.stderr, ">>>>>>>>>>>>>>>>>", header_file_name, main_file_name
self.header_sink = FileCodeSink(open(header_file_name, "wt"))
def get_section_code_sink(self, section_name):
return self.main_sink
def get_main_code_sink(self):
return self.main_sink
def get_common_header_code_sink(self):
return self.header_sink
def get_common_header_include(self):
return '"%s"' % self.header_name
def close(self):
self.header_sink.file.close()
self.main_sink.file.close()
def main(argv):
logging.basicConfig()
logging.getLogger("pybindgen.typehandlers").setLevel(logging.DEBUG)
module_abs_src_path, target, extension_name, output_cc_file_name = argv[1:]
module_name = os.path.basename(module_abs_src_path)
out = MyMultiSectionFactory(output_cc_file_name)
sys.path.insert(0, os.path.join(module_abs_src_path, "bindings"))
try:
module_apidefs = __import__("modulegen__%s" % target)
del sys.modules["modulegen__%s" % target]
try:
module_customization = __import__("modulegen_customizations")
del sys.modules["modulegen_customizations"]
except ImportError:
module_customization = object()
try:
from callbacks_list import callback_classes
except ImportError as ex:
print("***************", repr(ex), file=sys.stderr)
callback_classes = []
else:
print(">>>>>>>>>>>>>>>>", repr(callback_classes), file=sys.stderr)
finally:
sys.path.pop(0)
apidefs_file, dummy = os.path.splitext(module_apidefs.__file__)
apidefs_file += '.py'
pybindgen.settings.error_handler = ErrorHandler(apidefs_file)
root_module = module_apidefs.module_init()
root_module.set_name(extension_name)
root_module.add_include('"ns3/%s-module.h"' % module_name)
ns3modulegen_core_customizations.add_std_ios_openmode(root_module)
# -----------
module_apidefs.register_types(root_module)
if hasattr(module_customization, 'post_register_types'):
module_customization.post_register_types(root_module)
# register Callback<...> type handlers
ns3modulegen_core_customizations.register_callback_classes(root_module.after_forward_declarations,
callback_classes)
# -----------
module_apidefs.register_methods(root_module)
if hasattr(module_customization, 'post_register_methods'):
module_customization.post_register_methods(root_module)
ns3modulegen_core_customizations.Object_customizations(root_module)
ns3modulegen_core_customizations.Attribute_customizations(root_module)
ns3modulegen_core_customizations.generate_callback_classes(root_module,
callback_classes)
# -----------
module_apidefs.register_functions(root_module)
if hasattr(module_customization, 'post_register_functions'):
module_customization.post_register_functions(root_module)
# -----------
root_module.generate(out)
if __name__ == '__main__':
import sys
main(sys.argv)

View File

@@ -1,446 +0,0 @@
from __future__ import print_function
import sys
import re
from pybindgen.typehandlers import base as typehandlers
from pybindgen import ReturnValue, Parameter
from pybindgen.cppmethod import CustomCppMethodWrapper, CustomCppConstructorWrapper
from pybindgen.typehandlers.codesink import MemoryCodeSink
from pybindgen.typehandlers import ctypeparser
from pybindgen.typehandlers.base import ForwardWrapperBase
from pybindgen import cppclass
import warnings
from pybindgen.typehandlers.base import CodeGenerationError
import sys
class SmartPointerTransformation(typehandlers.TypeTransformation):
"""
This class provides a "type transformation" that tends to support
NS-3 smart pointers. Parameters such as "Ptr<Foo> foo" are
transformed into something like Parameter.new("Foo*", "foo",
transfer_ownership=False). Return values such as Ptr<Foo> are
transformed into ReturnValue.new("Foo*",
caller_owns_return=False). Since the underlying objects have
reference counting, PyBindGen does the right thing.
"""
def __init__(self):
super(SmartPointerTransformation, self).__init__()
self.rx = re.compile(r'(ns3::|::ns3::|)Ptr<([^>]+)>\s*$')
print("{0!r}".format(self), file=sys.stderr)
def _get_untransformed_type_traits(self, name):
m = self.rx.match(name)
is_const = False
if m is None:
print("{0!r} did not match".format(name), file=sys.stderr)
return None, False
else:
name1 = m.group(2).strip()
if name1.startswith('const '):
name1 = name1[len('const '):]
is_const = True
if name1.endswith(' const'):
name1 = name1[:-len(' const')]
is_const = True
new_name = name1+' *'
if new_name.startswith('::'):
new_name = new_name[2:]
return new_name, is_const
def get_untransformed_name(self, name):
new_name, dummy_is_const = self._get_untransformed_type_traits(name)
return new_name
def create_type_handler(self, type_handler, *args, **kwargs):
if issubclass(type_handler, Parameter):
kwargs['transfer_ownership'] = False
elif issubclass(type_handler, ReturnValue):
kwargs['caller_owns_return'] = False
else:
raise AssertionError
## fix the ctype, add ns3:: namespace
orig_ctype, is_const = self._get_untransformed_type_traits(args[0])
if is_const:
correct_ctype = 'ns3::Ptr< {0} const >'.format(orig_ctype[:-2])
else:
correct_ctype = 'ns3::Ptr< {0} >'.format(orig_ctype[:-2])
args = tuple([correct_ctype] + list(args[1:]))
handler = type_handler(*args, **kwargs)
handler.set_transformation(self, orig_ctype)
return handler
def untransform(self, type_handler, declarations, code_block, expression):
return 'const_cast<%s> (ns3::PeekPointer (%s))' % (type_handler.untransformed_ctype, expression)
def transform(self, type_handler, declarations, code_block, expression):
assert type_handler.untransformed_ctype[-1] == '*'
return 'ns3::Ptr< %s > (%s)' % (type_handler.untransformed_ctype[:-1], expression)
## register the type transformation
transf = SmartPointerTransformation()
typehandlers.return_type_matcher.register_transformation(transf)
typehandlers.param_type_matcher.register_transformation(transf)
del transf
class CallbackImplProxyMethod(typehandlers.ReverseWrapperBase):
"""
Class that generates a proxy virtual method that calls a similarly named python method.
"""
def __init__(self, return_value, parameters):
super(CallbackImplProxyMethod, self).__init__(return_value, parameters)
def generate_python_call(self):
"""code to call the python method"""
build_params = self.build_params.get_parameters(force_tuple_creation=True)
if build_params[0][0] == '"':
build_params[0] = '(char *) ' + build_params[0]
args = self.before_call.declare_variable('PyObject*', 'args')
self.before_call.write_code('%s = Py_BuildValue(%s);'
% (args, ', '.join(build_params)))
self.before_call.add_cleanup_code('Py_DECREF(%s);' % args)
self.before_call.write_code('py_retval = PyObject_CallObject(m_callback, %s);' % args)
self.before_call.write_error_check('py_retval == NULL')
self.before_call.add_cleanup_code('Py_DECREF(py_retval);')
def register_callback_classes(out, callbacks):
for callback_impl_num, template_parameters in enumerate(callbacks):
cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters)
#print >> sys.stderr, "***** trying to register callback: %r" % cls_name
class_name = "PythonCallbackImpl%i" % callback_impl_num
class PythonCallbackParameter(Parameter):
"Class handlers"
CTYPES = [cls_name]
print("***** registering callback handler: %r (%r)" % (ctypeparser.normalize_type_string(cls_name), cls_name), file=sys.stderr)
DIRECTIONS = [Parameter.DIRECTION_IN]
PYTHON_CALLBACK_IMPL_NAME = class_name
TEMPLATE_ARGS = template_parameters
DISABLED = False
def convert_python_to_c(self, wrapper):
"parses python args to get C++ value"
assert isinstance(wrapper, typehandlers.ForwardWrapperBase)
if self.DISABLED:
raise CodeGenerationError("wrapper could not be generated")
if self.default_value is None:
py_callback = wrapper.declarations.declare_variable('PyObject*', self.name)
wrapper.parse_params.add_parameter('O', ['&'+py_callback], self.name)
wrapper.before_call.write_error_check(
'!PyCallable_Check(%s)' % py_callback,
'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name)
callback_impl = wrapper.declarations.declare_variable(
'ns3::Ptr<%s>' % self.PYTHON_CALLBACK_IMPL_NAME,
'%s_cb_impl' % self.name)
wrapper.before_call.write_code("%s = ns3::Create<%s> (%s);"
% (callback_impl, self.PYTHON_CALLBACK_IMPL_NAME, py_callback))
wrapper.call_params.append(
'ns3::Callback<%s> (%s)' % (', '.join(self.TEMPLATE_ARGS), callback_impl))
else:
py_callback = wrapper.declarations.declare_variable('PyObject*', self.name, 'NULL')
wrapper.parse_params.add_parameter('O', ['&'+py_callback], self.name, optional=True)
value = wrapper.declarations.declare_variable(
'ns3::Callback<%s>' % ', '.join(self.TEMPLATE_ARGS),
self.name+'_value',
self.default_value)
wrapper.before_call.write_code("if (%s) {" % (py_callback,))
wrapper.before_call.indent()
wrapper.before_call.write_error_check(
'!PyCallable_Check(%s)' % py_callback,
'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name)
wrapper.before_call.write_code("%s = ns3::Callback<%s> (ns3::Create<%s> (%s));"
% (value, ', '.join(self.TEMPLATE_ARGS),
self.PYTHON_CALLBACK_IMPL_NAME, py_callback))
wrapper.before_call.unindent()
wrapper.before_call.write_code("}") # closes: if (py_callback) {
wrapper.call_params.append(value)
def convert_c_to_python(self, wrapper):
raise typehandlers.NotSupportedError("Reverse wrappers for ns3::Callback<...> types "
"(python using callbacks defined in C++) not implemented.")
def generate_callback_classes(module, callbacks):
out = module.after_forward_declarations
for callback_impl_num, template_parameters in enumerate(callbacks):
sink = MemoryCodeSink()
cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters)
#print >> sys.stderr, "***** trying to register callback: %r" % cls_name
class_name = "PythonCallbackImpl%i" % callback_impl_num
sink.writeln('''
class %s : public ns3::CallbackImpl<%s>
{
public:
PyObject *m_callback;
%s(PyObject *callback)
{
Py_INCREF(callback);
m_callback = callback;
}
virtual ~%s()
{
PyGILState_STATE __py_gil_state;
__py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() : (PyGILState_STATE) 0);
Py_DECREF(m_callback);
m_callback = NULL;
PyGILState_Release(__py_gil_state);
}
virtual bool IsEqual(ns3::Ptr<const ns3::CallbackImplBase> other_base) const
{
const %s *other = dynamic_cast<const %s*> (ns3::PeekPointer (other_base));
if (other != NULL)
return (other->m_callback == m_callback);
else
return false;
}
''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name))
sink.indent()
callback_return = template_parameters[0]
return_ctype = ctypeparser.parse_type(callback_return)
if ('const' in return_ctype.remove_modifiers()):
kwargs = {'is_const': True}
else:
kwargs = {}
try:
return_type = ReturnValue.new(str(return_ctype), **kwargs)
except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex:
warnings.warn("***** Unable to register callback; Return value '%s' error (used in %s): %r"
% (callback_return, cls_name, ex),
Warning)
continue
arguments = []
ok = True
callback_parameters = [arg for arg in template_parameters[1:] if arg != 'ns3::empty']
for arg_num, arg_type in enumerate(callback_parameters):
arg_name = 'arg%i' % (arg_num+1)
param_ctype = ctypeparser.parse_type(arg_type)
if ('const' in param_ctype.remove_modifiers()):
kwargs = {'is_const': True}
else:
kwargs = {}
try:
param = Parameter.new(str(param_ctype), arg_name, **kwargs)
cpp_class = getattr(param, "cpp_class", None)
if isinstance(cpp_class, cppclass.CppClass):
# check if the "helper class" can be constructed
if cpp_class.helper_class is not None:
cpp_class.helper_class.generate_forward_declarations(
MemoryCodeSink())
if cpp_class.helper_class.cannot_be_constructed:
cpp_class.helper_class = None
cpp_class.helper_class_disabled = True
arguments.append(param)
except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex:
warnings.warn("***** Unable to register callback; parameter '%s %s' error (used in %s): %r"
% (arg_type, arg_name, cls_name, ex),
Warning)
ok = False
if not ok:
try:
typehandlers.return_type_matcher.lookup(cls_name)[0].DISABLED = True
except typehandlers.TypeLookupError:
pass
try:
typehandlers.param_type_matcher.lookup(cls_name)[0].DISABLED = True
except typehandlers.TypeLookupError:
pass
continue
wrapper = CallbackImplProxyMethod(return_type, arguments)
wrapper.generate(sink, 'operator()', decl_modifiers=[])
sink.unindent()
sink.writeln('};\n')
print("Flushing to ", out, file=sys.stderr)
sink.flush_to(out)
# def write_preamble(out):
# pybindgen.write_preamble(out)
# out.writeln("#include \"ns3/everything.h\"")
def Simulator_customizations(module):
Simulator = module['ns3::Simulator']
## Simulator::Schedule(delay, callback, ...user..args...)
Simulator.add_custom_method_wrapper("Schedule", "_wrap_Simulator_Schedule",
flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"])
## Simulator::ScheduleNow(callback, ...user..args...)
Simulator.add_custom_method_wrapper("ScheduleNow", "_wrap_Simulator_ScheduleNow",
flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"])
## Simulator::ScheduleDestroy(callback, ...user..args...)
Simulator.add_custom_method_wrapper("ScheduleDestroy", "_wrap_Simulator_ScheduleDestroy",
flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"])
Simulator.add_custom_method_wrapper("Run", "_wrap_Simulator_Run",
flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"])
def CommandLine_customizations(module):
CommandLine = module['ns3::CommandLine']
CommandLine.add_method('Parse', None, [ArgvParam(None, 'argv')],
is_static=False)
CommandLine.add_custom_method_wrapper("AddValue", "_wrap_CommandLine_AddValue",
flags=["METH_VARARGS", "METH_KEYWORDS"])
def Object_customizations(module):
## ---------------------------------------------------------------------
## Here we generate custom constructor code for all classes that
## derive from ns3::Object. The custom constructors are needed in
## order to support kwargs only and to translate kwargs into ns3
## attributes, etc.
## ---------------------------------------------------------------------
try:
Object = module['ns3::Object']
except KeyError:
return
## add a GetTypeId method to all generatd helper classes
def helper_class_hook(helper_class):
decl = """
static ns3::TypeId GetTypeId (void)
{
static ns3::TypeId tid = ns3::TypeId ("%s")
.SetParent< %s > ()
;
return tid;
}""" % (helper_class.name, helper_class.class_.full_name)
helper_class.add_custom_method(decl)
helper_class.add_post_generation_code(
"NS_OBJECT_ENSURE_REGISTERED (%s);" % helper_class.name)
Object.add_helper_class_hook(helper_class_hook)
def ns3_object_instance_creation_function(cpp_class, code_block, lvalue,
parameters, construct_type_name):
assert lvalue
assert not lvalue.startswith('None')
if cpp_class.cannot_be_constructed:
raise CodeGenerationError("%s cannot be constructed (%s)"
% cpp_class.full_name)
if cpp_class.incomplete_type:
raise CodeGenerationError("%s cannot be constructed (incomplete type)"
% cpp_class.full_name)
code_block.write_code("%s = new %s(%s);" % (lvalue, construct_type_name, parameters))
code_block.write_code("%s->Ref ();" % (lvalue))
def ns3_object_post_instance_creation_function(cpp_class, code_block, lvalue,
parameters, construct_type_name):
code_block.write_code("ns3::CompleteConstruct(%s);" % (lvalue, ))
Object.set_instance_creation_function(ns3_object_instance_creation_function)
Object.set_post_instance_creation_function(ns3_object_post_instance_creation_function)
def Attribute_customizations(module):
# Fix up for the "const AttributeValue &v = EmptyAttribute()"
# case, as used extensively by helper classes.
# Here's why we need to do this: pybindgen.gccxmlscanner, when
# scanning parameter default values, is only provided with the
# value as a simple C expression string. (py)gccxml does not
# report the type of the default value.
# As a workaround, here we iterate over all parameters of all
# methods of all classes and tell pybindgen what is the type of
# the default value for attributes.
for cls in module.classes:
for meth in cls.get_all_methods():
for param in meth.parameters:
if isinstance(param, cppclass.CppClassRefParameter):
if param.cpp_class.name == 'AttributeValue' \
and param.default_value is not None \
and param.default_value_type is None:
param.default_value_type = 'ns3::EmptyAttributeValue'
def TypeId_customizations(module):
TypeId = module['ns3::TypeId']
TypeId.add_custom_method_wrapper("LookupByNameFailSafe", "_wrap_TypeId_LookupByNameFailSafe",
flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"])
def add_std_ofstream(module):
module.add_include('<fstream>')
ostream = module.add_class('ostream', foreign_cpp_namespace='::std')
ostream.set_cannot_be_constructed("abstract base class")
ofstream = module.add_class('ofstream', foreign_cpp_namespace='::std', parent=ostream)
ofstream.add_enum('openmode', [
('app', 'std::ios_base::app'),
('ate', 'std::ios_base::ate'),
('binary', 'std::ios_base::binary'),
('in', 'std::ios_base::in'),
('out', 'std::ios_base::out'),
('trunc', 'std::ios_base::trunc'),
])
ofstream.add_constructor([Parameter.new("const char *", 'filename'),
Parameter.new("::std::ofstream::openmode", 'mode', default_value="std::ios_base::out")])
ofstream.add_method('close', None, [])
add_std_ios_openmode(module)
class IosOpenmodeParam(Parameter):
DIRECTIONS = [Parameter.DIRECTION_IN]
CTYPES = ['std::ios_base::openmode', 'std::_Ios_Openmode']
def convert_c_to_python(self, wrapper):
assert isinstance(wrapper, ReverseWrapperBase)
wrapper.build_params.add_parameter('i', [self.value])
def convert_python_to_c(self, wrapper):
assert isinstance(wrapper, ForwardWrapperBase)
name = wrapper.declarations.declare_variable("std::ios_base::openmode", self.name, self.default_value)
wrapper.parse_params.add_parameter('i', ['&'+name], self.name, optional=bool(self.default_value))
wrapper.call_params.append(name)
def add_std_ios_openmode(module):
for flag in 'in', 'out', 'ate', 'app', 'trunc', 'binary':
module.after_init.write_code('PyModule_AddIntConstant(m, (char *) "STD_IOS_%s", std::ios::%s);'
% (flag.upper(), flag))
def add_ipv4_address_tp_hash(module):
module.body.writeln('''
long
_ns3_Ipv4Address_tp_hash (PyObject *obj)
{
PyNs3Ipv4Address *addr = reinterpret_cast<PyNs3Ipv4Address *> (obj);
return static_cast<long> (ns3::Ipv4AddressHash () (*addr->obj));
}
''')
module.header.writeln('long _ns3_Ipv4Address_tp_hash (PyObject *obj);')
module['Ipv4Address'].pytype.slots['tp_hash'] = "_ns3_Ipv4Address_tp_hash"

View File

@@ -1,292 +0,0 @@
#! /usr/bin/env python3
import sys
import os.path
import pybindgen.settings
from pybindgen.castxmlparser import ModuleParser, PygenClassifier, PygenSection, WrapperWarning, find_declaration_from_name
from pybindgen.typehandlers.codesink import FileCodeSink
from pygccxml.declarations import templates
from pygccxml.declarations.enumeration import enumeration_t
from pygccxml.declarations.class_declaration import class_t
from pygccxml.declarations.free_calldef import free_function_t
from pygccxml.declarations.calldef_members import constructor_t, member_function_t
from pygccxml.declarations.calldef import calldef_t
## we need the smart pointer type transformation to be active even
## during castxml scanning.
import ns3modulegen_core_customizations
## silence castxmlparser errors; we only want error handling in the
## generated python script, not while scanning.
class ErrorHandler(pybindgen.settings.ErrorHandler):
def handle_error(self, dummy_wrapper, dummy_exception, dummy_traceback_):
return True
pybindgen.settings.error_handler = ErrorHandler()
import warnings
warnings.filterwarnings(category=WrapperWarning, action='ignore')
import ns3modulescan
type_annotations = ns3modulescan.type_annotations
def get_ns3_relative_path(path):
l = []
head = path
if not path:
return
while head:
new_head, tail = os.path.split(head)
if new_head == head:
raise ValueError
head = new_head
if tail == 'ns3':
return os.path.join(*l)
l.insert(0, tail)
raise AssertionError("is the path %r inside ns3?!" % path)
class PreScanHook:
def __init__(self, headers_map, module):
self.headers_map = headers_map
self.module = module
def __call__(self, module_parser,
pygccxml_definition,
global_annotations,
parameter_annotations):
try:
ns3_header = get_ns3_relative_path(pygccxml_definition.location.file_name)
except ValueError: # the header is not from ns3
return # ignore the definition, it's not ns-3 def.
if not ns3_header:
return
definition_module = self.headers_map[ns3_header]
## Note: we don't include line numbers in the comments because
## those numbers are very likely to change frequently, which would
## cause needless changes, since the generated python files are
## kept under version control.
#global_annotations['pygen_comment'] = "%s:%i: %s" % \
# (ns3_header, pygccxml_definition.location.line, pygccxml_definition)
global_annotations['pygen_comment'] = "%s (module %r): %s" % \
(ns3_header, definition_module, pygccxml_definition)
## handle ns3::Object::GetObject (left to its own devices,
## pybindgen will generate a mangled name containing the template
## argument type name).
if isinstance(pygccxml_definition, member_function_t) \
and pygccxml_definition.parent.name == 'Object' \
and pygccxml_definition.name == 'GetObject':
template_args = templates.args(str(pygccxml_definition))
if template_args == ['ns3::Object']:
global_annotations['template_instance_names'] = 'ns3::Object=>GetObject'
## Don't wrap Simulator::Schedule* (manually wrapped)
if isinstance(pygccxml_definition, member_function_t) \
and pygccxml_definition.parent.name == 'Simulator' \
and pygccxml_definition.name.startswith('Schedule'):
global_annotations['ignore'] = None
# manually wrapped
if isinstance(pygccxml_definition, member_function_t) \
and pygccxml_definition.parent.name == 'Simulator' \
and pygccxml_definition.name == 'Run':
global_annotations['ignore'] = True
## http://www.gccxml.org/Bug/view.php?id=9915
if isinstance(pygccxml_definition, calldef_t):
for arg in pygccxml_definition.arguments:
if arg.default_value is None:
continue
elif arg.default_value == "ns3::MilliSeconds( )":
arg.default_value = "ns3::MilliSeconds(0)"
elif arg.default_value == "ns3::Seconds( )":
arg.default_value = "ns3::Seconds(0)"
## classes
if isinstance(pygccxml_definition, class_t):
print(pygccxml_definition, file=sys.stderr)
# no need for helper classes to allow subclassing in Python, I think...
#if pygccxml_definition.name.endswith('Helper'):
# global_annotations['allow_subclassing'] = 'false'
#
# If a class is template instantiation, even if the
# template was defined in some other module, if a template
# argument belongs to this module then the template
# instantiation will belong to this module.
#
if templates.is_instantiation(pygccxml_definition.decl_string):
cls_name, template_parameters = templates.split(pygccxml_definition.name)
template_parameters_decls = [find_declaration_from_name(module_parser.global_ns, templ_param)
for templ_param in template_parameters]
#print >> sys.stderr, "********************", cls_name, repr(template_parameters_decls)
template_parameters_modules = []
for templ in template_parameters_decls:
if not hasattr(templ, 'location'):
continue
try:
h = get_ns3_relative_path(templ.location.file_name)
except ValueError:
continue
template_parameters_modules.append(self.headers_map[h])
for templ_mod in template_parameters_modules:
if templ_mod == self.module:
definition_module = templ_mod
break
#print >> sys.stderr, "********************", cls_name, repr(template_parameters_modules)
if definition_module != self.module:
global_annotations['import_from_module'] = 'ns.%s' % (definition_module.replace('-', '_'),)
if pygccxml_definition.decl_string.startswith('::ns3::SimpleRefCount<'):
global_annotations['incref_method'] = 'Ref'
global_annotations['decref_method'] = 'Unref'
global_annotations['peekref_method'] = 'GetReferenceCount'
global_annotations['automatic_type_narrowing'] = 'true'
return
if pygccxml_definition.decl_string.startswith('::ns3::Callback<'):
# manually handled in ns3modulegen_core_customizations.py
global_annotations['ignore'] = None
return
if pygccxml_definition.decl_string.startswith('::ns3::TracedCallback<'):
global_annotations['ignore'] = None
return
if pygccxml_definition.decl_string.startswith('::ns3::Ptr<'):
# handled by pybindgen "type transformation"
global_annotations['ignore'] = None
return
# table driven class customization
try:
annotations = type_annotations[pygccxml_definition.decl_string]
except KeyError:
pass
else:
global_annotations.update(annotations)
## enums
if isinstance(pygccxml_definition, enumeration_t):
if definition_module != self.module:
global_annotations['import_from_module'] = 'ns.%s' % definition_module
## free functions
if isinstance(pygccxml_definition, free_function_t):
if definition_module != self.module:
global_annotations['ignore'] = None
return
if pygccxml_definition.name == 'PeekPointer':
global_annotations['ignore'] = None
return
## table driven methods/constructors/functions customization
if isinstance(pygccxml_definition, (free_function_t, member_function_t, constructor_t)):
try:
annotations = type_annotations[str(pygccxml_definition)]
except KeyError:
pass
else:
for key,value in list(annotations.items()):
if key == 'params':
parameter_annotations.update (value)
del annotations['params']
global_annotations.update(annotations)
# def post_scan_hook(dummy_module_parser, dummy_pygccxml_definition, pybindgen_wrapper):
# ## classes
# if isinstance(pybindgen_wrapper, CppClass):
# if pybindgen_wrapper.name.endswith('Checker'):
# print >> sys.stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", pybindgen_wrapper
# #pybindgen_wrapper.set_instance_creation_function(AttributeChecker_instance_creation_function)
def scan_callback_classes(module_parser, callback_classes_file):
callback_classes_file.write("callback_classes = [\n")
for cls in module_parser.module_namespace.classes(function=module_parser.location_filter,
recursive=False):
if not cls.name.startswith("Callback<"):
continue
assert templates.is_instantiation(cls.decl_string), "%s is not a template instantiation" % cls
dummy_cls_name, template_parameters = templates.split(cls.decl_string)
callback_classes_file.write(" %r,\n" % template_parameters)
callback_classes_file.write("]\n")
def ns3_module_scan(top_builddir, module_name, headers_map, output_file_name, cflags):
module_parser = ModuleParser('ns.%s' % module_name.replace('-', '_'), 'ns3')
module_parser.add_pre_scan_hook(PreScanHook(headers_map, module_name))
#module_parser.add_post_scan_hook(post_scan_hook)
castxml_options = dict(
include_paths=[top_builddir, os.path.join(top_builddir, "include")],
define_symbols={
#'NS3_ASSERT_ENABLE': None,
#'NS3_LOG_ENABLE': None,
},
cflags=('-std=c++17 %s' % cflags)
)
try:
os.unlink(output_file_name)
except OSError:
pass
try:
os.makedirs(os.path.dirname(output_file_name))
except OSError:
pass
output_file = open(output_file_name, "wt")
output_sink = FileCodeSink(output_file)
# if there exists a scan-header.h file in src/<module>/bindings or contrib/<module>/bindings,
# scan it, otherwise scan ns3/xxxx-module.h.
scan_header = os.path.join(os.path.dirname(output_file_name), "scan-header.h")
if not os.path.exists(scan_header):
scan_header = os.path.join(top_builddir, "ns3", "%s-module.h" % module_name)
if not os.path.exists(scan_header):
scan_header = os.path.join(top_builddir, "include", "ns3", "%s-module.h" % module_name)
module_parser.parse_init([scan_header],
None, whitelist_paths=[top_builddir],
pygen_sink=output_sink,
castxml_options=castxml_options)
module_parser.scan_types()
callback_classes_file = open(os.path.join(os.path.dirname(output_file_name), "callbacks_list.py"), "wt")
scan_callback_classes(module_parser, callback_classes_file)
callback_classes_file.close()
module_parser.scan_methods()
module_parser.scan_functions()
module_parser.parse_finalize()
output_file.close()
os.chmod(output_file_name, 0o400)
if __name__ == '__main__':
if len(sys.argv) != 6:
print("ns3modulescan-modular.py top_builddir module_path module_headers output_file_name cflags")
sys.exit(1)
if os.path.exists(sys.argv[3]):
import json
with open(sys.argv[3], "r") as f:
module_headers = json.load(f)
else:
module_headers = eval(sys.argv[3])
ns3_module_scan(sys.argv[1], sys.argv[2], module_headers, sys.argv[4], sys.argv[5])
sys.exit(0)

View File

@@ -1,335 +0,0 @@
#! /usr/bin/env python3
import sys
import os.path
import pybindgen.settings
from pybindgen.castxmlparser import ModuleParser, PygenClassifier, PygenSection, WrapperWarning
from pybindgen.typehandlers.codesink import FileCodeSink
from pygccxml.declarations import templates
from pygccxml.declarations.class_declaration import class_t
from pygccxml.declarations.free_calldef import free_function_t
from pygccxml.declarations.calldef_members import constructor_t, member_function_t
from pygccxml.declarations.calldef import calldef_t
## we need the smart pointer type transformation to be active even
## during gccxml scanning.
import ns3modulegen_core_customizations
## silence castxmlparser errors; we only want error handling in the
## generated python script, not while scanning.
class ErrorHandler(pybindgen.settings.ErrorHandler):
def handle_error(self, dummy_wrapper, dummy_exception, dummy_traceback_):
return True
pybindgen.settings.error_handler = ErrorHandler()
import warnings
warnings.filterwarnings(category=WrapperWarning, action='ignore')
type_annotations = {
'::ns3::AttributeChecker': {
'automatic_type_narrowing': 'true',
'allow_subclassing': 'false',
},
'::ns3::AttributeValue': {
'automatic_type_narrowing': 'true',
'allow_subclassing': 'false',
},
'::ns3::CommandLine': {
'allow_subclassing': 'true', # needed so that AddValue is able to set attributes on the object
},
'::ns3::NscTcpL4Protocol': {
'ignore': 'true', # this class is implementation detail
},
'ns3::RandomVariable::RandomVariable(ns3::RandomVariableBase const & variable) [constructor]': {
'ignore': None,
},
'ns3::RandomVariableBase * ns3::RandomVariable::Peek() const [member function]': {
'ignore': None,
},
'void ns3::RandomVariable::GetSeed(uint32_t * seed) const [member function]': {
'params': {'seed':{'direction':'out',
'array_length':'6'}}
},
'bool ns3::TypeId::LookupAttributeByName(std::string name, ns3::TypeId::AttributeInformation * info) const [member function]': {
'params': {'info':{'transfer_ownership': 'false'}}
},
'static bool ns3::TypeId::LookupByNameFailSafe(std::string name, ns3::TypeId * tid) [member function]': {
'ignore': None, # manually wrapped in
},
'bool ns3::TraceSourceAccessor::ConnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': {
'params': {'obj': {'transfer_ownership':'false'}}
},
'bool ns3::TraceSourceAccessor::Connect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': {
'params': {'obj': {'transfer_ownership':'false'}}
},
'bool ns3::TraceSourceAccessor::DisconnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': {
'params': {'obj': {'transfer_ownership':'false'}}
},
'bool ns3::TraceSourceAccessor::Disconnect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': {
'params': {'obj': {'transfer_ownership':'false'}}
},
'bool ns3::AttributeAccessor::Set(ns3::ObjectBase * object, ns3::AttributeValue const & value) const [member function]': {
'params': {'object': {'transfer_ownership':'false'}}
},
'ns3::EmpiricalVariable::EmpiricalVariable(ns3::RandomVariableBase const & variable) [constructor]': {
'ignore': None
},
'static ns3::AttributeList * ns3::AttributeList::GetGlobal() [member function]': {
'caller_owns_return': 'false'
},
'void ns3::CommandLine::Parse(int argc, char * * argv) const [member function]': {
'ignore': None # manually wrapped
},
'extern void ns3::PythonCompleteConstruct(ns3::Ptr<ns3::Object> object, ns3::TypeId typeId, ns3::AttributeList const & attributes) [free function]': {
'ignore': None # used transparently by, should not be wrapped
},
'ns3::Ptr<ns3::Ipv4RoutingProtocol> ns3::Ipv4ListRouting::GetRoutingProtocol(uint32_t index, int16_t & priority) const [member function]': {
'params': {'priority':{'direction':'out'}}
},
'ns3::Ipv4RoutingTableEntry * ns3::GlobalRouter::GetInjectedRoute(uint32_t i) [member function]': {
'params': {'return': { 'caller_owns_return': 'false',}},
},
'ns3::Ipv4RoutingTableEntry * ns3::Ipv4GlobalRouting::GetRoute(uint32_t i) const [member function]': {
'params': {'return': { 'caller_owns_return': 'false',}},
},
'::ns3::TestCase': {
'ignore': 'true', # we don't need to write test cases in Python
},
'::ns3::TestRunner': {
'ignore': 'true', # we don't need to write test cases in Python
},
'::ns3::TestSuite': {
'ignore': 'true', # we don't need to write test cases in Python
},
}
def get_ns3_relative_path(path):
l = []
head = path
while head:
head, tail = os.path.split(head)
if tail == 'ns3':
return os.path.join(*l)
l.insert(0, tail)
raise AssertionError("is the path %r inside ns3?!" % path)
def pre_scan_hook(dummy_module_parser,
pygccxml_definition,
global_annotations,
parameter_annotations):
ns3_header = get_ns3_relative_path(pygccxml_definition.location.file_name)
## Note: we don't include line numbers in the comments because
## those numbers are very likely to change frequently, which would
## cause needless changes, since the generated python files are
## kept under version control.
#global_annotations['pygen_comment'] = "%s:%i: %s" % \
# (ns3_header, pygccxml_definition.location.line, pygccxml_definition)
global_annotations['pygen_comment'] = "%s: %s" % \
(ns3_header, pygccxml_definition)
## handle ns3::Object::GetObject (left to its own devices,
## pybindgen will generate a mangled name containing the template
## argument type name).
if isinstance(pygccxml_definition, member_function_t) \
and pygccxml_definition.parent.name == 'Object' \
and pygccxml_definition.name == 'GetObject':
template_args = templates.args(pygccxml_definition.demangled_name)
if template_args == ['ns3::Object']:
global_annotations['template_instance_names'] = 'ns3::Object=>GetObject'
## Don't wrap Simulator::Schedule* (manually wrapped)
if isinstance(pygccxml_definition, member_function_t) \
and pygccxml_definition.parent.name == 'Simulator' \
and pygccxml_definition.name.startswith('Schedule'):
global_annotations['ignore'] = None
# manually wrapped
if isinstance(pygccxml_definition, member_function_t) \
and pygccxml_definition.parent.name == 'Simulator' \
and pygccxml_definition.name == 'Run':
global_annotations['ignore'] = True
## http://www.gccxml.org/Bug/view.php?id=9915
if isinstance(pygccxml_definition, calldef_t):
for arg in pygccxml_definition.arguments:
if arg.default_value is None:
continue
if "ns3::MilliSeconds( )" == arg.default_value:
arg.default_value = "ns3::MilliSeconds(0)"
if "ns3::Seconds( )" == arg.default_value:
arg.default_value = "ns3::Seconds(0)"
## classes
if isinstance(pygccxml_definition, class_t):
# no need for helper classes to allow subclassing in Python, I think...
#if pygccxml_definition.name.endswith('Helper'):
# global_annotations['allow_subclassing'] = 'false'
if pygccxml_definition.decl_string.startswith('::ns3::SimpleRefCount<'):
global_annotations['incref_method'] = 'Ref'
global_annotations['decref_method'] = 'Unref'
global_annotations['peekref_method'] = 'GetReferenceCount'
global_annotations['automatic_type_narrowing'] = 'true'
return
if pygccxml_definition.decl_string.startswith('::ns3::Callback<'):
# manually handled in ns3modulegen_core_customizations.py
global_annotations['ignore'] = None
return
if pygccxml_definition.decl_string.startswith('::ns3::TracedCallback<'):
global_annotations['ignore'] = None
return
if pygccxml_definition.decl_string.startswith('::ns3::Ptr<'):
# handled by pybindgen "type transformation"
global_annotations['ignore'] = None
return
# table driven class customization
try:
annotations = type_annotations[pygccxml_definition.decl_string]
except KeyError:
pass
else:
global_annotations.update(annotations)
## free functions
if isinstance(pygccxml_definition, free_function_t):
if pygccxml_definition.name == 'PeekPointer':
global_annotations['ignore'] = None
return
## table driven methods/constructors/functions customization
if isinstance(pygccxml_definition, (free_function_t, member_function_t, constructor_t)):
try:
annotations = type_annotations[str(pygccxml_definition)]
except KeyError:
pass
else:
for key,value in annotations.items():
if key == 'params':
parameter_annotations.update (value)
del annotations['params']
global_annotations.update(annotations)
# def post_scan_hook(dummy_module_parser, dummy_pygccxml_definition, pybindgen_wrapper):
# ## classes
# if isinstance(pybindgen_wrapper, CppClass):
# if pybindgen_wrapper.name.endswith('Checker'):
# print >> sys.stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", pybindgen_wrapper
# #pybindgen_wrapper.set_instance_creation_function(AttributeChecker_instance_creation_function)
def scan_callback_classes(module_parser, callback_classes_file):
callback_classes_file.write("callback_classes = [\n")
for cls in module_parser.module_namespace.classes(function=module_parser.location_filter,
recursive=False):
if not cls.name.startswith("Callback<"):
continue
assert templates.is_instantiation(cls.decl_string), "%s is not a template instantiation" % cls
dummy_cls_name, template_parameters = templates.split(cls.decl_string)
callback_classes_file.write(" %r,\n" % template_parameters)
callback_classes_file.write("]\n")
class MyPygenClassifier(PygenClassifier):
def __init__(self, headers_map, section_precendences):
self.headers_map = headers_map
self.section_precendences = section_precendences
def classify(self, pygccxml_definition):
name = os.path.basename(pygccxml_definition.location.file_name)
try:
return self.headers_map[name]
except KeyError:
return '__main__'
def get_section_precedence(self, section_name):
if section_name == '__main__':
return -1
return self.section_precendences[section_name]
def ns3_module_scan(top_builddir, pygen_file_name, everything_h, cflags):
ns3_modules = eval(sys.stdin.readline())
## do a topological sort on the modules graph
from topsort import topsort
graph = []
module_names = ns3_modules.keys()
module_names.sort()
for ns3_module_name in module_names:
ns3_module_deps = list(ns3_modules[ns3_module_name][0])
ns3_module_deps.sort()
for dep in ns3_module_deps:
graph.append((dep, ns3_module_name))
sorted_ns3_modules = topsort(graph)
#print >> sys.stderr, "******* topological sort: ", sorted_ns3_modules
sections = [PygenSection('__main__', FileCodeSink(open(pygen_file_name, "wt")))]
headers_map = {} # header_name -> section_name
section_precendences = {} # section_name -> precedence
for prec, ns3_module in enumerate(sorted_ns3_modules):
section_name = "ns3_module_%s" % ns3_module.replace('-', '_')
file_name = os.path.join(os.path.dirname(pygen_file_name), "%s.py" % section_name)
sections.append(PygenSection(section_name, FileCodeSink(open(file_name, "wt")),
section_name + "__local"))
for header in ns3_modules[ns3_module][1]:
headers_map[header] = section_name
section_precendences[section_name] = prec
module_parser = ModuleParser('ns3', 'ns3')
module_parser.add_pre_scan_hook(pre_scan_hook)
#module_parser.add_post_scan_hook(post_scan_hook)
gccxml_options = dict(
include_paths=[top_builddir],
define_symbols={
#'NS3_ASSERT_ENABLE': None,
#'NS3_LOG_ENABLE': None,
},
cflags=('--gccxml-cxxflags "%s -DPYTHON_SCAN"' % cflags)
)
module_parser.parse_init([everything_h],
None, whitelist_paths=[top_builddir, os.path.dirname(everything_h)],
#includes=['"ns3/everything.h"'],
pygen_sink=sections,
pygen_classifier=MyPygenClassifier(headers_map, section_precendences),
gccxml_options=gccxml_options)
module_parser.scan_types()
callback_classes_file = open(os.path.join(os.path.dirname(pygen_file_name), "callbacks_list.py"), "wt")
scan_callback_classes(module_parser, callback_classes_file)
callback_classes_file.close()
module_parser.scan_methods()
module_parser.scan_functions()
module_parser.parse_finalize()
for section in sections:
section.code_sink.file.close()
if __name__ == '__main__':
ns3_module_scan(sys.argv[1], sys.argv[3], sys.argv[2], sys.argv[4])

View File

@@ -1 +1,218 @@
import builtins
import os.path
import sys
import re
def find_ns3_directory():
# Get the absolute path to this file
path_to_this_init_file = os.path.dirname(os.path.abspath(__file__))
path_to_lock = path_to_this_init_file
lock_file = (".lock-ns3_%s_build" % sys.platform)
# Go back and scan each folder until the c4che folder is found
found = False
while not found:
for f in os.listdir(path_to_lock):
# Skip files
if not os.path.isfile(f):
continue
# Search for lock
if lock_file in f:
path_to_lock += os.sep + f
found = True
break
if found:
break
# Move to the directory above if we haven't found it yet
old_path = path_to_lock
path_to_lock = os.path.dirname(path_to_lock)
# We give up if we can't move to the directory above
if path_to_lock == old_path:
raise Exception("ns-3 lock file firectory was not found.\n"
"Are you sure %s is inside your ns-3 directory?" % path_to_this_init_file)
return path_to_lock
def load_modules(ns3_directory):
# Load NS3_ENABLED_MODULES from _cache.py file inside the build directory
values = {}
exec(open(find_ns3_directory()).read(), {}, values)
suffix = "-" + values["BUILD_PROFILE"] if values["BUILD_PROFILE"] != "release" else ""
required_modules = [module.replace("ns3-", "") for module in values["NS3_ENABLED_MODULES"]]
ns3_output_directory = values["out_dir"]
libraries = {x.split(".")[0]: x for x in os.listdir(os.path.join(ns3_output_directory, "lib"))}
import cppyy
# Enable full logs for debugging
# cppyy.set_debug(True)
# Register Ptr<> as a smart pointer
import libcppyy
libcppyy.AddSmartPtrType('Ptr')
# Import ns-3 libraries
cppyy.add_library_path("%s/lib" % ns3_output_directory)
cppyy.add_include_path("%s/include" % ns3_output_directory)
for module in required_modules:
cppyy.include("ns3/%s-module.h" % module)
for module in required_modules:
library_name = "libns{version}-{module}{suffix}".format(
version=values["VERSION"],
module=module,
suffix=suffix
)
if library_name not in libraries:
raise Exception("Missing library %s\n" % library_name,
"Build all modules with './ns3 build'"
)
cppyy.load_library(libraries[library_name])
# We expose cppyy to consumers of this module as ns.cppyy
setattr(cppyy.gbl.ns3, "cppyy", cppyy)
# To maintain compatibility with pybindgen scripts,
# we set an attribute per module that just redirects to the upper object
for module in required_modules:
setattr(cppyy.gbl.ns3, module.replace("-", "_"), cppyy.gbl.ns3)
# Setup a few tricks
cppyy.cppdef("""
using namespace ns3;
bool Time_ge(Time& a, Time& b){ return a >= b;}
bool Time_eq(Time& a, Time& b){ return a == b;}
bool Time_ne(Time& a, Time& b){ return a != b;}
bool Time_le(Time& a, Time& b){ return a <= b;}
bool Time_gt(Time& a, Time& b){ return a > b;}
bool Time_lt(Time& a, Time& b){ return a < b;}
""")
cppyy.gbl.ns3.Time.__ge__ = cppyy.gbl.Time_ge
cppyy.gbl.ns3.Time.__eq__ = cppyy.gbl.Time_eq
cppyy.gbl.ns3.Time.__ne__ = cppyy.gbl.Time_ne
cppyy.gbl.ns3.Time.__le__ = cppyy.gbl.Time_le
cppyy.gbl.ns3.Time.__gt__ = cppyy.gbl.Time_gt
cppyy.gbl.ns3.Time.__lt__ = cppyy.gbl.Time_lt
# Node::~Node isn't supposed to destroy the object,
# since it gets destroyed at the end of the simulation
# we need to hold the reference until it gets destroyed by C++
#
# Search for NodeList::Add (this)
cppyy.gbl.ns3.__nodes_pending_deletion = []
def Nodedel(self: cppyy.gbl.ns3.Node) -> None:
cppyy.gbl.ns3.__nodes_pending_deletion.append(self)
return None
cppyy.gbl.ns3.Node.__del__ = Nodedel
# Define ns.cppyy.gbl.addressFromIpv4Address and others
cppyy.cppdef("""using namespace ns3;
Address addressFromIpv4Address(Ipv4Address ip){ return Address(ip); };
Address addressFromInetSocketAddress(InetSocketAddress addr){ return Address(addr); };
Address addressFromPacketSocketAddress(PacketSocketAddress addr){ return Address(addr); };
""")
# Expose addressFromIpv4Address as a member of the ns3 namespace (equivalent to ns)
setattr(cppyy.gbl.ns3, "addressFromIpv4Address", cppyy.gbl.addressFromIpv4Address)
setattr(cppyy.gbl.ns3, "addressFromInetSocketAddress", cppyy.gbl.addressFromInetSocketAddress)
setattr(cppyy.gbl.ns3, "addressFromPacketSocketAddress", cppyy.gbl.addressFromPacketSocketAddress)
cppyy.cppdef(
"""using namespace ns3; CommandLine& getCommandLine(std::string filename){ static CommandLine g_cmd = CommandLine(filename); return g_cmd; };""")
setattr(cppyy.gbl.ns3, "getCommandLine", cppyy.gbl.getCommandLine)
cppyy.cppdef(
"""using namespace ns3; template Callback<bool, std::string> ns3::MakeNullCallback<bool, std::string>(void);""")
cppyy.cppdef(
"""using namespace ns3; Callback<bool, std::string> null_callback(){ return MakeNullCallback<bool, std::string>(); };""")
setattr(cppyy.gbl.ns3, "null_callback", cppyy.gbl.null_callback)
#cppyy.cppdef(
# """using namespace ns3; template <typename T> Ptr<T> getAggregatedObject(Ptr<Object> parentPtr, T param))
# {
# return parentPtr->GetObject<T>();
# }
# """
#)
cppyy.cppdef("""
using namespace ns3;
std::tuple<bool, TypeId> LookupByNameFailSafe(std::string name)
{
TypeId id;
bool ok = TypeId::LookupByNameFailSafe(name, &id);
return std::make_tuple(ok, id);
}
""")
setattr(cppyy.gbl.ns3, "LookupByNameFailSafe", cppyy.gbl.LookupByNameFailSafe)
def CreateObject(className):
try:
try:
func = "CreateObject%s" % re.sub('[<|>]', '_', className)
return getattr(cppyy.gbl, func)()
except AttributeError:
pass
try:
func = "Create%s" % re.sub('[<|>]', '_', className)
return getattr(cppyy.gbl, func)()
except AttributeError:
pass
raise AttributeError
except AttributeError:
try:
func = "CreateObject%s" % re.sub('[<|>]', '_', className)
cppyy.cppdef("""
using namespace ns3;
Ptr<%s> %s(){
Ptr<%s> object = CreateObject<%s>();
return object;
}
""" % (className, func, className, className)
)
except Exception as e:
try:
func = "Create%s" % re.sub('[<|>]', '_', className)
cppyy.cppdef("""
using namespace ns3;
%s %s(){
%s object = %s();
return object;
}
""" % (className, func, className, className)
)
except Exception as e:
exit(-1)
return getattr(cppyy.gbl, func)()
setattr(cppyy.gbl.ns3, "CreateObject", CreateObject)
def GetObject(parentObject, aggregatedObject):
# Objects have __cpp_name__ attributes, so parentObject
# should not have it while aggregatedObject can
if hasattr(parentObject, "__cpp_name__"):
raise Exception("Class was passed instead of an instance in parentObject")
aggregatedIsClass = hasattr(aggregatedObject, "__cpp_name__")
aggregatedIsString = type(aggregatedObject) == str
aggregatedIsInstance = not aggregatedIsClass and not aggregatedIsString
if aggregatedIsClass:
aggregatedType = aggregatedObject.__cpp_name__
if aggregatedIsInstance:
aggregatedType = aggregatedObject.__class__.__cpp_name__
if aggregatedIsString:
aggregatedType = aggregatedObject
cppyy.cppdef(
"""using namespace ns3; template <> Ptr<%s> getAggregatedObject<%s>(Ptr<Object> parentPtr, %s param)
{
return parentPtr->GetObject<%s>();
}
""" % (aggregatedType, aggregatedType, aggregatedType, aggregatedType)
)
return cppyy.gbl.getAggregatedObject(parentObject, aggregatedObject if aggregatedIsClass else aggregatedObject.__class__)
setattr(cppyy.gbl.ns3, "GetObject", GetObject)
return cppyy.gbl.ns3
# Load all modules and make them available via a built-in
ns = load_modules(find_ns3_directory()) # can be imported via 'from ns import ns'
builtins.__dict__['ns'] = ns # or be made widely available with 'from ns import *'

View File

@@ -1,909 +0,0 @@
# Copyright (c) 2007 RADLogic
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Provide various handy Python functions.
Running this script directly will execute the doctests.
Functions:
int2bin(i, n) -- Convert integer to binary string.
bin2int(bin_string) -- Convert binary string to integer.
reverse(input_string) -- Reverse a string.
transpose(matrix) -- Transpose a list of lists.
polygon_area(points_list) -- Calculate the area of an arbitrary polygon.
timestamp() -- Return string containing current time stamp.
pt2str(point) -- Return prettier string version of point tuple.
gcf(a, b) -- Return the greatest common factor of two numbers.
lcm(a, b) -- Return the least common multiple of two numbers.
permutations(input_list) -- Generate all permutations of a list of items.
reduce_fraction(fraction) -- Reduce fraction (num, denom) to simplest form.
quantile(l, p) -- Return p quantile of list l. E.g. p=0.25 for q1.
trim(l) -- Discard values in list more than 1.5*IQR outside IQR.
nice_units(value) -- Return value converted to human readable units.
uniquify(seq) -- Return sequence with duplicate items in sequence seq removed.
reverse_dict(d) -- Return the dictionary with the items as keys and vice-versa.
lsb(x, n) -- Return the n least significant bits of x.
gray_encode(i) -- Gray encode the given integer.
random_vec(bits, max_value=None) -- Return a random binary vector.
binary_range(bits) -- Return list of all possible binary numbers width=bits.
float_range([start], stop, [step]) -- Return range of floats.
find_common_fixes(s1, s2) -- Find common (prefix, suffix) of two strings.
is_rotated(seq1, seq2) -- Return true if the list is a rotation of other list.
getmodule(obj) -- Return the module that contains the object definition of obj.
(use inspect.getmodule instead, though)
get_args(argv) -- Store command-line args in a dictionary.
This module requires Python >= 2.2
"""
__author__ = 'Tim Wegener <twegener@radlogic.com.au>'
__date__ = '$Date: 2007/03/27 03:15:06 $'
__version__ = '$Revision: 0.45 $'
__credits__ = """
David Chandler, for polygon area algorithm.
(https://web.archive.org/web/20091104151838/http://www.davidchandler.com/AreaOfAGeneralPolygon.pdf)
"""
import re
import sys
import time
import random
try:
True, False
except NameError:
True, False = (1==1, 0==1)
def int2bin(i, n):
"""Convert decimal integer i to n-bit binary number (string).
>>> int2bin(0, 8)
'00000000'
>>> int2bin(123, 8)
'01111011'
>>> int2bin(123L, 8)
'01111011'
>>> int2bin(15, 2)
Traceback (most recent call last):
ValueError: Value too large for given number of bits.
"""
hex2bin = {'0': '0000', '1': '0001', '2': '0010', '3': '0011',
'4': '0100', '5': '0101', '6': '0110', '7': '0111',
'8': '1000', '9': '1001', 'a': '1010', 'b': '1011',
'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'}
# Convert to hex then map each hex digit to binary equivalent.
result = ''.join([hex2bin[x] for x in hex(i).lower().replace('l','')[2:]])
# Shrink result to appropriate length.
# Raise an error if the value is changed by the truncation.
if '1' in result[:-n]:
raise ValueError("Value too large for given number of bits.")
result = result[-n:]
# Zero-pad if length longer than mapped result.
result = '0'*(n-len(result)) + result
return result
def bin2int(bin_string):
"""Convert binary number string to decimal integer.
Note: Python > v2 has int(bin_string, 2)
>>> bin2int('1111')
15
>>> bin2int('0101')
5
"""
## result = 0
## bin_list = list(bin_string)
## if len(filter(lambda x: x in ('1','0'), bin_list)) < len(bin_list):
## raise Exception ("bin2int: Error - not a binary number: %s"
## % bin_string)
## bit_list = map(int, bin_list)
## bit_list.reverse() # Make most significant bit have highest index.
## for bit_place in range(len(bit_list)):
## result = result + ((2**bit_place) * bit_list[bit_place])
## return result
return int(bin_string, 2)
def reverse(input_string):
"""Reverse a string. Useful for strings of binary numbers.
>>> reverse('abc')
'cba'
"""
str_list = list(input_string)
str_list.reverse()
return ''.join(str_list)
def transpose(matrix):
"""Transpose a list of lists.
>>> transpose([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']])
[['a', 'd', 'g'], ['b', 'e', 'h'], ['c', 'f', 'i']]
>>> transpose([['a', 'b', 'c'], ['d', 'e', 'f']])
[['a', 'd'], ['b', 'e'], ['c', 'f']]
>>> transpose([['a', 'b'], ['d', 'e'], ['g', 'h']])
[['a', 'd', 'g'], ['b', 'e', 'h']]
"""
result = zip(*matrix)
# Convert list of tuples to list of lists.
# map is faster than a list comprehension since it is being used with
# a built-in function as an argument.
result = map(list, result)
return result
def polygon_area(points_list, precision=100):
"""Calculate area of an arbitrary polygon using an algorithm from the web.
Return the area of the polygon as a positive float.
Arguments:
points_list -- list of point tuples [(x0, y0), (x1, y1), (x2, y2), ...]
(Unclosed polygons will be closed automatically.
precision -- Internal arithmetic precision (integer arithmetic).
>>> polygon_area([(0, 0), (0, 1), (1, 1), (1, 2), (2, 2), (2, 0), (0, 0)])
3.0
Credits:
Area of a General Polygon by David Chandler
https://web.archive.org/web/20091104151838/http://www.davidchandler.com/AreaOfAGeneralPolygon.pdf
"""
# Scale up co-ordinates and convert them to integers.
for i in range(len(points_list)):
points_list[i] = (int(points_list[i][0] * precision),
int(points_list[i][1] * precision))
# Close polygon if not closed.
if points_list[-1] != points_list[0]:
points_list.append(points_list[0])
# Calculate area.
area = 0
for i in range(len(points_list)-1):
(x_i, y_i) = points_list[i]
(x_i_plus_1, y_i_plus_1) = points_list[i+1]
area = area + (x_i_plus_1 * y_i) - (y_i_plus_1 * x_i)
area = abs(area / 2)
# Unscale area.
area = float(area)/(precision**2)
return area
def timestamp():
"""Return string containing current time stamp.
Note: In Python 2 onwards can use time.asctime() with no arguments.
"""
return time.asctime()
def pt2str(point):
"""Return prettier string version of point tuple.
>>> pt2str((1.8, 1.9))
'(1.8, 1.9)'
"""
return "(%s, %s)" % (str(point[0]), str(point[1]))
def gcf(a, b, epsilon=1e-16):
"""Return the greatest common factor of a and b, using Euclidean algorithm.
Arguments:
a, b -- two numbers
If both numbers are integers return an integer result,
otherwise return a float result.
epsilon -- floats less than this magnitude are considered to be zero
(default: 1e-16)
Examples:
>>> gcf(12, 34)
2
>>> gcf(13.5, 4)
0.5
>>> gcf(-2, 4)
2
>>> gcf(5, 0)
5
By (a convenient) definition:
>>> gcf(0, 0)
0
"""
result = max(a, b)
remainder = min(a, b)
while remainder and abs(remainder) > epsilon:
new_remainder = result % remainder
result = remainder
remainder = new_remainder
return abs(result)
def lcm(a, b, precision=None):
"""Return the least common multiple of a and b, using the gcf function.
Arguments:
a, b -- two numbers. If both are integers return an integer result,
otherwise a return a float result.
precision -- scaling factor if a and/or b are floats.
>>> lcm(21, 6)
42
>>> lcm(2.5, 3.5)
17.5
>>> str(lcm(1.5e-8, 2.5e-8, precision=1e9))
'7.5e-08'
By (an arbitrary) definition:
>>> lcm(0, 0)
0
"""
# Note: Dummy precision argument is for backwards compatibility.
# Do the division first.
# (See https://en.wikipedia.org/wiki/Least_common_multiple )
denom = gcf(a, b)
if denom == 0:
result = 0
else:
result = a * (b / denom)
return result
def permutations(input_list):
"""Return a list containing all permutations of the input list.
Note: This is a recursive function.
>>> perms = permutations(['a', 'b', 'c'])
>>> perms.sort()
>>> for perm in perms:
... print perm
['a', 'b', 'c']
['a', 'c', 'b']
['b', 'a', 'c']
['b', 'c', 'a']
['c', 'a', 'b']
['c', 'b', 'a']
"""
out_lists = []
if len(input_list) > 1:
# Extract first item in list.
item = input_list[0]
# Find all permutations of remainder of list. (Recursive call.)
sub_lists = permutations(input_list[1:])
# For every permutation of the sub list...
for sub_list in sub_lists:
# Insert the extracted first item at every position of the list.
for i in range(len(input_list)):
new_list = sub_list[:]
new_list.insert(i, item)
out_lists.append(new_list)
else:
# Termination condition: only one item in input list.
out_lists = [input_list]
return out_lists
def reduce_fraction(fraction):
"""Reduce fraction tuple to simplest form. fraction=(num, denom)
>>> reduce_fraction((14, 7))
(2, 1)
>>> reduce_fraction((-2, 4))
(-1, 2)
>>> reduce_fraction((0, 4))
(0, 1)
>>> reduce_fraction((4, 0))
(1, 0)
"""
(numerator, denominator) = fraction
common_factor = abs(gcf(numerator, denominator))
result = (numerator/common_factor, denominator/common_factor)
return result
def quantile(l, p):
"""Return p quantile of list l. E.g. p=0.25 for q1.
See:
https://www.rdocumentation.org/packages/stats/versions/3.6.2/topics/quantile
"""
l_sort = l[:]
l_sort.sort()
n = len(l)
r = 1 + ((n - 1) * p)
i = int(r)
f = r - i
if i < n:
result = (1-f)*l_sort[i-1] + f*l_sort[i]
else:
result = l_sort[i-1]
return result
def trim(l):
"""Discard values in list more than 1.5*IQR outside IQR.
(IQR is inter-quartile-range)
This function uses rad_util.quantile
1.5*IQR -- mild outlier
3*IQR -- extreme outlier
See:
http://wind.cc.whecn.edu/~pwildman/statnew/section_7_-_exploratory_data_analysis.htm
"""
l_sort = l[:]
l_sort.sort()
# Calculate medianscore (based on stats.py lmedianscore by Gary Strangman)
if len(l_sort) % 2 == 0:
# If even number of scores, average middle 2.
index = int(len(l_sort) / 2) # Integer division correct
median = float(l_sort[index] + l_sort[index-1]) / 2
else:
# int division gives mid value when count from 0
index = int(len(l_sort) / 2)
median = l_sort[index]
# Calculate IQR.
q1 = quantile(l_sort, 0.25)
q3 = quantile(l_sort, 0.75)
iqr = q3 - q1
iqr_extra = iqr * 1.5
def in_interval(x, i=iqr_extra, q1=q1, q3=q3):
return (x >= q1-i and x <= q3+i)
l_trimmed = [x for x in l_sort if in_interval(x)]
return l_trimmed
def nice_units(value, dp=0, sigfigs=None, suffix='', space=' ',
use_extra_prefixes=False, use_full_name=False, mode='si'):
"""Return value converted to human readable units eg milli, micro, etc.
Arguments:
value -- number in base units
dp -- number of decimal places to display (rounded)
sigfigs -- number of significant figures to display (rounded)
This overrides dp if set.
suffix -- optional unit suffix to append to unit multiplier
space -- separator between value and unit multiplier (default: ' ')
use_extra_prefixes -- use hecto, deka, deci and centi as well if set.
(default: False)
use_full_name -- use full name for multiplier symbol,
e.g. milli instead of m
(default: False)
mode -- 'si' for SI prefixes, 'bin' for binary multipliers (1024, etc.)
(Default: 'si')
SI prefixes from:
http://physics.nist.gov/cuu/Units/prefixes.html
(Greek mu changed to u.)
Binary prefixes based on:
http://physics.nist.gov/cuu/Units/binary.html
>>> nice_units(2e-11)
'20 p'
>>> nice_units(2e-11, space='')
'20p'
"""
si_prefixes = {1e24: ('Y', 'yotta'),
1e21: ('Z', 'zetta'),
1e18: ('E', 'exa'),
1e15: ('P', 'peta'),
1e12: ('T', 'tera'),
1e9: ('G', 'giga'),
1e6: ('M', 'mega'),
1e3: ('k', 'kilo'),
1e-3: ('m', 'milli'),
1e-6: ('u', 'micro'),
1e-9: ('n', 'nano'),
1e-12: ('p', 'pico'),
1e-15: ('f', 'femto'),
1e-18: ('a', 'atto'),
1e-21: ('z', 'zepto'),
1e-24: ('y', 'yocto')
}
if use_extra_prefixes:
si_prefixes.update({1e2: ('h', 'hecto'),
1e1: ('da', 'deka'),
1e-1: ('d', 'deci'),
1e-2: ('c', 'centi')
})
bin_prefixes = {2**10: ('K', 'kilo'),
2**20: ('M', 'mega'),
2**30: ('G', 'mega'),
2**40: ('T', 'tera'),
2**50: ('P', 'peta'),
2**60: ('E', 'exa')
}
if mode == 'bin':
prefixes = bin_prefixes
else:
prefixes = si_prefixes
prefixes[1] = ('', '') # Unity.
# Determine appropriate multiplier.
multipliers = prefixes.keys()
multipliers.sort()
mult = None
for i in range(len(multipliers) - 1):
lower_mult = multipliers[i]
upper_mult = multipliers[i+1]
if lower_mult <= value < upper_mult:
mult_i = i
break
if mult is None:
if value < multipliers[0]:
mult_i = 0
elif value >= multipliers[-1]:
mult_i = len(multipliers) - 1
mult = multipliers[mult_i]
# Convert value for this multiplier.
new_value = value / mult
# Deal with special case due to rounding.
if sigfigs is None:
if mult_i < (len(multipliers) - 1) and \
round(new_value, dp) == \
round((multipliers[mult_i+1] / mult), dp):
mult = multipliers[mult_i + 1]
new_value = value / mult
# Concatenate multiplier symbol.
if use_full_name:
label_type = 1
else:
label_type = 0
# Round and truncate to appropriate precision.
if sigfigs is None:
str_value = eval('"%.'+str(dp)+'f" % new_value', locals(), {})
else:
str_value = eval('"%.'+str(sigfigs)+'g" % new_value', locals(), {})
return str_value + space + prefixes[mult][label_type] + suffix
def uniquify(seq, preserve_order=False):
"""Return sequence with duplicate items in sequence seq removed.
The code is based on usenet post by Tim Peters.
This code is O(N) if the sequence items are hashable, O(N**2) if not.
Peter Bengtsson has a blog post with an empirical comparison of other
approaches:
http://www.peterbe.com/plog/uniqifiers-benchmark
If order is not important and the sequence items are hashable then
list(set(seq)) is readable and efficient.
If order is important and the sequence items are hashable generator
expressions can be used (in py >= 2.4) (useful for large sequences):
seen = set()
do_something(x for x in seq if x not in seen or seen.add(x))
Arguments:
seq -- sequence
preserve_order -- if not set the order will be arbitrary
Using this option will incur a speed penalty.
(default: False)
Example showing order preservation:
>>> uniquify(['a', 'aa', 'b', 'b', 'ccc', 'ccc', 'd'], preserve_order=True)
['a', 'aa', 'b', 'ccc', 'd']
Example using a sequence of un-hashable items:
>>> uniquify([['z'], ['x'], ['y'], ['z']], preserve_order=True)
[['z'], ['x'], ['y']]
The sorted output or the non-order-preserving approach should equal
that of the sorted order-preserving approach output:
>>> unordered = uniquify([3, 3, 1, 2], preserve_order=False)
>>> unordered.sort()
>>> ordered = uniquify([3, 3, 1, 2], preserve_order=True)
>>> ordered.sort()
>>> ordered
[1, 2, 3]
>>> int(ordered == unordered)
1
"""
try:
# Attempt fast algorithm.
d = {}
if preserve_order:
# This is based on Dave Kirby's method (f8) noted in the post:
# http://www.peterbe.com/plog/uniqifiers-benchmark
return [x for x in seq if (x not in d) and not d.__setitem__(x, 0)]
else:
for x in seq:
d[x] = 0
return d.keys()
except TypeError:
# Have an unhashable object, so use slow algorithm.
result = []
app = result.append
for x in seq:
if x not in result:
app(x)
return result
# Alias to noun form for backward compatibility.
unique = uniquify
def reverse_dict(d):
"""Reverse a dictionary so the items become the keys and vice-versa.
Note: The results will be arbitrary if the items are not unique.
>>> d = reverse_dict({'a': 1, 'b': 2})
>>> d_items = d.items()
>>> d_items.sort()
>>> d_items
[(1, 'a'), (2, 'b')]
"""
result = {}
for key, value in d.items():
result[value] = key
return result
def lsb(x, n):
"""Return the n least significant bits of x.
>>> lsb(13, 3)
5
"""
return x & ((2 ** n) - 1)
def gray_encode(i):
"""Gray encode the given integer."""
return i ^ (i >> 1)
def random_vec(bits, max_value=None):
"""Generate a random binary vector of length bits and given max value."""
vector = ""
for _ in range(int(bits / 10) + 1):
i = int((2**10) * random.random())
vector += int2bin(i, 10)
if max_value and (max_value < 2 ** bits - 1):
vector = int2bin((int(vector, 2) / (2 ** bits - 1)) * max_value, bits)
return vector[0:bits]
def binary_range(bits):
"""Return a list of all possible binary numbers in order with width=bits.
It would be nice to extend it to match the
functionality of python's range() built-in function.
"""
l = []
v = ['0'] * bits
toggle = [1] + [0] * bits
while toggle[bits] != 1:
v_copy = v[:]
v_copy.reverse()
l.append(''.join(v_copy))
toggle = [1] + [0]*bits
i = 0
while i < bits and toggle[i] == 1:
if toggle[i]:
if v[i] == '0':
v[i] = '1'
toggle[i+1] = 0
else:
v[i] = '0'
toggle[i+1] = 1
i += 1
return l
def float_range(start, stop=None, step=None):
"""Return a list containing an arithmetic progression of floats.
Return a list of floats between 0.0 (or start) and stop with an
increment of step.
This is in functionality to python's range() built-in function
but can accept float increments.
As with range(), stop is omitted from the list.
"""
if stop is None:
stop = float(start)
start = 0.0
if step is None:
step = 1.0
cur = float(start)
l = []
while cur < stop:
l.append(cur)
cur += step
return l
def find_common_fixes(s1, s2):
"""Find common (prefix, suffix) of two strings.
>>> find_common_fixes('abc', 'def')
('', '')
>>> find_common_fixes('abcelephantdef', 'abccowdef')
('abc', 'def')
>>> find_common_fixes('abcelephantdef', 'abccow')
('abc', '')
>>> find_common_fixes('elephantdef', 'abccowdef')
('', 'def')
"""
prefix = []
suffix = []
i = 0
common_len = min(len(s1), len(s2))
while i < common_len:
if s1[i] != s2[i]:
break
prefix.append(s1[i])
i += 1
i = 1
while i < (common_len + 1):
if s1[-i] != s2[-i]:
break
suffix.append(s1[-i])
i += 1
suffix.reverse()
prefix = ''.join(prefix)
suffix = ''.join(suffix)
return (prefix, suffix)
def is_rotated(seq1, seq2):
"""Return true if the first sequence is a rotation of the second sequence.
>>> seq1 = ['A', 'B', 'C', 'D']
>>> seq2 = ['C', 'D', 'A', 'B']
>>> int(is_rotated(seq1, seq2))
1
>>> seq2 = ['C', 'D', 'B', 'A']
>>> int(is_rotated(seq1, seq2))
0
>>> seq1 = ['A', 'B', 'C', 'A']
>>> seq2 = ['A', 'A', 'B', 'C']
>>> int(is_rotated(seq1, seq2))
1
>>> seq2 = ['A', 'B', 'C', 'A']
>>> int(is_rotated(seq1, seq2))
1
>>> seq2 = ['A', 'A', 'C', 'B']
>>> int(is_rotated(seq1, seq2))
0
"""
# Do a sanity check.
if len(seq1) != len(seq2):
return False
# Look for occurrences of second sequence head item in first sequence.
start_indexes = []
head_item = seq2[0]
for index1 in range(len(seq1)):
if seq1[index1] == head_item:
start_indexes.append(index1)
# Check that wrapped sequence matches.
double_seq1 = seq1 + seq1
for index1 in start_indexes:
if double_seq1[index1:index1+len(seq1)] == seq2:
return True
return False
def getmodule(obj):
"""Return the module that contains the object definition of obj.
Note: Use inspect.getmodule instead.
Arguments:
obj -- python obj, generally a class or a function
Examples:
A function:
>>> module = getmodule(random.choice)
>>> module.__name__
'random'
>>> module is random
1
A class:
>>> module = getmodule(random.Random)
>>> module.__name__
'random'
>>> module is random
1
A class inheriting from a class in another module:
(note: The inheriting class must define at least one function.)
>>> class MyRandom(random.Random):
... def play(self):
... pass
>>> module = getmodule(MyRandom)
>>> if __name__ == '__main__':
... name = 'rad_util'
... else:
... name = module.__name__
>>> name
'rad_util'
>>> module is sys.modules[__name__]
1
Discussion:
This approach is slightly hackish, and won't work in various situations.
However, this was the approach recommended by GvR, so it's as good as
you'll get.
See GvR's post in this thread:
http://groups.google.com.au/group/comp.lang.python/browse_thread/thread/966a7bdee07e3b34/c3cab3f41ea84236?lnk=st&q=python+determine+class+module&rnum=4&hl=en#c3cab3f41ea84236
"""
if hasattr(obj, 'func_globals'):
func = obj
else:
# Handle classes.
func = None
for item in obj.__dict__.values():
if hasattr(item, 'func_globals'):
func = item
break
if func is None:
raise ValueError("No functions attached to object: %r" % obj)
module_name = func.func_globals['__name__']
# Get module.
module = sys.modules[module_name]
return module
def round_grid(value, grid, mode=0):
"""Round off the given value to the given grid size.
Arguments:
value -- value to be roudne
grid -- result must be a multiple of this
mode -- 0 nearest, 1 up, -1 down
Examples:
>>> round_grid(7.5, 5)
10
>>> round_grid(7.5, 5, mode=-1)
5
>>> round_grid(7.3, 5, mode=1)
10
>>> round_grid(7.3, 5.0, mode=1)
10.0
"""
off_grid = value % grid
if mode == 0:
add_one = int(off_grid >= (grid / 2.0))
elif mode == 1 and off_grid:
add_one = 1
elif mode == -1 and off_grid:
add_one = 0
result = ((int(value / grid) + add_one) * grid)
return result
def get_args(argv):
"""Store command-line args in a dictionary.
-, -- prefixes are removed
Items not prefixed with - or -- are stored as a list, indexed by 'args'
For options that take a value use --option=value
Consider using optparse or getopt (in Python standard library) instead.
"""
d = {}
args = []
for arg in argv:
if arg.startswith('-'):
parts = re.sub(r'^-+', '', arg).split('=')
if len(parts) == 2:
d[parts[0]] = parts[1]
else:
d[parts[0]] = None
else:
args.append(arg)
d['args'] = args
return d
if __name__ == '__main__':
import doctest
doctest.testmod(sys.modules['__main__'])

View File

@@ -1,392 +0,0 @@
# topsort - dependency (topological) sorting and cycle finding functions
# Copyright (C) 2007 RADLogic
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation;
# version 2.1 of the License.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# See https://www.fsf.org/licensing/licenses/lgpl.txt for full license text.
"""Provide toplogical sorting (i.e. dependency sorting) functions.
The topsort function is based on code posted on Usenet by Tim Peters.
Modifications:
- added doctests
- changed some bits to use current Python idioms
(listcomp instead of filter, +=/-=, inherit from Exception)
- added a topsort_levels version that ports items in each dependency level
into a sub-list
- added find_cycles to aid in cycle debugging
Run this module directly to run the doctests (unittests).
Make sure they all pass before checking in any modifications.
Requires Python >= 2.2
(For Python 2.2 also requires separate sets.py module)
This requires the rad_util.py module.
"""
# Provide support for Python 2.2*
from __future__ import generators
__version__ = '$Revision: 0.9 $'
__date__ = '$Date: 2007/03/27 04:15:26 $'
__credits__ = '''Tim Peters -- original topsort code
Tim Wegener -- doctesting, updating to current idioms, topsort_levels,
find_cycles
'''
# Make Python 2.3 sets look like Python 2.4 sets.
try:
set
except NameError:
from sets import Set as set
from rad_util import is_rotated
class CycleError(Exception):
"""Cycle Error"""
pass
def topsort(pairlist):
"""Topologically sort a list of (parent, child) pairs.
Return a list of the elements in dependency order (parent to child order).
>>> print topsort( [(1,2), (3,4), (5,6), (1,3), (1,5), (1,6), (2,5)] )
[1, 2, 3, 5, 4, 6]
>>> print topsort( [(1,2), (1,3), (2,4), (3,4), (5,6), (4,5)] )
[1, 2, 3, 4, 5, 6]
>>> print topsort( [(1,2), (2,3), (3,2)] )
Traceback (most recent call last):
CycleError: ([1], {2: 1, 3: 1}, {2: [3], 3: [2]})
"""
num_parents = {} # element -> # of predecessors
children = {} # element -> list of successors
for parent, child in pairlist:
# Make sure every element is a key in num_parents.
if not num_parents.has_key( parent ):
num_parents[parent] = 0
if not num_parents.has_key( child ):
num_parents[child] = 0
# Since child has a parent, increment child's num_parents count.
num_parents[child] += 1
# ... and parent gains a child.
children.setdefault(parent, []).append(child)
# Suck up everything without a parent.
answer = [x for x in num_parents.keys() if num_parents[x] == 0]
# For everything in answer, knock down the parent count on its children.
# Note that answer grows *in* the loop.
for parent in answer:
del num_parents[parent]
if children.has_key( parent ):
for child in children[parent]:
num_parents[child] -= 1
if num_parents[child] == 0:
answer.append( child )
# Following "del" isn't needed; just makes
# CycleError details easier to grasp.
del children[parent]
if num_parents:
# Everything in num_parents has at least one child ->
# there's a cycle.
raise CycleError(answer, num_parents, children)
return answer
def topsort_levels(pairlist):
"""Topologically sort a list of (parent, child) pairs into depth levels.
This returns a generator.
Turn this into a an iterator using the iter built-in function.
(if you iterate over the iterator, each element gets generated when
it is asked for, rather than generating the whole list up-front.)
Each generated element is a list of items at that dependency level.
>>> dependency_pairs = [(1,2), (3,4), (5,6), (1,3), (1,5), (1,6), (2,5)]
>>> for level in iter(topsort_levels( dependency_pairs )):
... print level
[1]
[2, 3]
[4, 5]
[6]
>>> dependency_pairs = [(1,2), (1,3), (2,4), (3,4), (5,6), (4,5)]
>>> for level in iter(topsort_levels( dependency_pairs )):
... print level
[1]
[2, 3]
[4]
[5]
[6]
>>> dependency_pairs = [(1,2), (2,3), (3,4), (4, 3)]
>>> try:
... for level in iter(topsort_levels( dependency_pairs )):
... print level
... except CycleError, exc:
... print 'CycleError:', exc
[1]
[2]
CycleError: ({3: 1, 4: 1}, {3: [4], 4: [3]})
The cycle error should look like.
CycleError: ({3: 1, 4: 1}, {3: [4], 4: [3]})
# todo: Make the doctest more robust (i.e. handle arbitrary dict order).
"""
num_parents = {} # element -> # of predecessors
children = {} # element -> list of successors
for parent, child in pairlist:
# Make sure every element is a key in num_parents.
if not num_parents.has_key( parent ):
num_parents[parent] = 0
if not num_parents.has_key( child ):
num_parents[child] = 0
# Since child has a parent, increment child's num_parents count.
num_parents[child] += 1
# ... and parent gains a child.
children.setdefault(parent, []).append(child)
return topsort_levels_core(num_parents, children)
def topsort_levels_core(num_parents, children):
"""Topologically sort a bunch of interdependent items based on dependency.
This returns a generator.
Turn this into a an iterator using the iter built-in function.
(if you iterate over the iterator, each element gets generated when
it is asked for, rather than generating the whole list up-front.)
Each generated element is a list of items at that dependency level.
>>> list(topsort_levels_core(
... {1: 0, 2: 1, 3: 1, 4: 1, 5: 2, 6: 2},
... {1: [2, 3, 5, 6], 2: [5], 3: [4], 4: [], 5: [6]}))
[[1], [2, 3], [4, 5], [6]]
>>> list(topsort_levels_core(
... {1: 0, 2: 2, 3: 1},
... {1: [2], 2: [3], 3: [2]}))
Traceback (most recent call last):
CycleError: ({2: 1, 3: 1}, {2: [3], 3: [2]})
This function has a more complicated interface than topsort_levels,
but is useful if the data is easier to generate in this form.
Arguments:
num_parents -- key: item, value: number of parents (predecessors)
children -- key: item, value: list of children (successors)
"""
while 1:
# Suck up everything without a predecessor.
level_parents = [x for x in num_parents.keys() if num_parents[x] == 0]
if not level_parents:
break
# Offer the next generated item,
# which is a list of the items at this dependency level.
yield level_parents
# For everything item in this level,
# decrement the parent count,
# since we have accounted for its parent.
for level_parent in level_parents:
del num_parents[level_parent]
if children.has_key(level_parent):
for level_parent_child in children[level_parent]:
num_parents[level_parent_child] -= 1
del children[level_parent]
if num_parents:
# Everything in num_parents has at least one child ->
# there's a cycle.
raise CycleError(num_parents, children)
else:
# This is the end of the generator.
raise StopIteration
def find_cycles(parent_children):
"""Yield cycles. Each result is a list of items comprising a cycle.
Use a 'stack' based approach to find all the cycles.
This is a generator, so yields each cycle as it finds it.
It is implicit that the last item in each cycle list is a parent of the
first item (thereby forming a cycle).
Arguments:
parent_children -- parent -> collection of children
Simplest cycle:
>>> cycles = list(find_cycles({'A': ['B'], 'B': ['A']}))
>>> len(cycles)
1
>>> cycle = cycles[0]
>>> cycle.sort()
>>> print cycle
['A', 'B']
Simplest cycle with extra baggage at the start and the end:
>>> cycles = list(find_cycles(parent_children={'A': ['B'],
... 'B': ['C'],
... 'C': ['B', 'D'],
... 'D': [],
... }))
>>> len(cycles)
1
>>> cycle = cycles[0]
>>> cycle.sort()
>>> print cycle
['B', 'C']
Double cycle:
>>> cycles = list(find_cycles(parent_children={'A': ['B'],
... 'B': ['C1', 'C2'],
... 'C1': ['D1'],
... 'D1': ['E1'],
... 'E1': ['D1'],
... 'C2': ['D2'],
... 'D2': ['E2'],
... 'E2': ['D2'],
... }))
>>> len(cycles)
2
>>> for cycle in cycles:
... cycle.sort()
>>> cycles.sort()
>>> cycle1 = cycles[0]
>>> cycle1.sort()
>>> print cycle1
['D1', 'E1']
>>> cycle2 = cycles[1]
>>> cycle2.sort()
>>> print cycle2
['D2', 'E2']
Simple cycle with children not specified for one item:
# todo: Should this barf instead?
>>> cycles = list(find_cycles(parent_children={'A': ['B'],
... 'B': ['A'],
... 'C': ['D']}))
>>> len(cycles)
1
>>> cycle = cycles[0]
>>> cycle.sort()
>>> print cycle
['A', 'B']
Diamond cycle
>>> cycles = list(find_cycles(parent_children={'A': ['B1', 'B2'],
... 'B1': ['C'],
... 'B2': ['C'],
... 'C': ['A', 'B1']}))
>>> len(cycles)
3
>>> sorted_cycles = []
>>> for cycle in cycles:
... cycle = list(cycle)
... cycle.sort()
... sorted_cycles.append(cycle)
>>> sorted_cycles.sort()
>>> for cycle in sorted_cycles:
... print cycle
['A', 'B1', 'C']
['A', 'B2', 'C']
['B1', 'C']
Hairy case (order can matter if something is wrong):
(Note order of B and C in the list.)
>>> cycles = list(find_cycles(parent_children={
... 'TD': ['DD'],
... 'TC': ['DC'],
... 'DC': ['DQ'],
... 'C': ['DQ'],
... 'DQ': ['IA', 'TO'],
... 'IA': ['A'],
... 'A': ['B', 'C'],
... }))
>>> len(cycles)
1
>>> cycle = cycles[0]
>>> cycle.sort()
>>> print cycle
['A', 'C', 'DQ', 'IA']
"""
cycles = []
visited_nodes = set()
for parent in parent_children:
if parent in visited_nodes:
# This node is part of a path that has already been traversed.
continue
paths = [[parent]]
while paths:
path = paths.pop()
parent = path[-1]
try:
children = parent_children[parent]
except KeyError:
continue
for child in children:
# Keeping a set of the path nodes, for O(1) lookups at the
# expense of more memory and complexity, actually makes speed
# worse. (Due to construction of sets.)
# This is O(N).
if child in path:
# This is a cycle.
cycle = path[path.index(child):]
# Check that this is not a dup cycle.
is_dup = False
for other_cycle in cycles:
if is_rotated(other_cycle, cycle):
is_dup = True
break
if not is_dup:
cycles.append(cycle)
yield cycle
else:
# Push this new path onto the 'stack'.
# This is probably the most expensive part of the algorithm
# (a list copy).
paths.append(path + [child])
# Mark the node as visited.
visited_nodes.add(child)
if __name__ == '__main__':
# Run the doctest tests.
import sys
import doctest
doctest.testmod(sys.modules['__main__'])

View File

@@ -160,11 +160,6 @@ macro(write_configtable)
string(APPEND out "PyViz visualizer : ")
check_on_or_off("${NS3_VISUALIZER}" "${ENABLE_VISUALIZER}")
string(APPEND out "Python API Scanning Support : ")
check_on_or_off(
"${NS3_SCAN_PYTHON_BINDINGS}" "${ENABLE_SCAN_PYTHON_BINDINGS}"
)
string(APPEND out "Python Bindings : ")
check_on_or_off("${NS3_PYTHON_BINDINGS}" "${ENABLE_PYTHON_BINDINGS}")

View File

@@ -69,9 +69,6 @@ function(write_lock)
cache_cmake_flag(NS3_BRITE "ENABLE_BRITE" lock_contents)
cache_cmake_flag(NS3_ENABLE_SUDO "ENABLE_SUDO" lock_contents)
cache_cmake_flag(NS3_PYTHON_BINDINGS "ENABLE_PYTHON_BINDINGS" lock_contents)
cache_cmake_flag(
NS3_SCAN_PYTHON_BINDINGS "ENABLE_SCAN_PYTHON_BINDINGS" lock_contents
)
string(APPEND lock_contents "EXAMPLE_DIRECTORIES = [")
foreach(example_folder ${ns3-example-folders})

View File

@@ -276,198 +276,6 @@ function(build_lib)
endif()
endforeach()
# Get architecture pair for python bindings
if((${CMAKE_SIZEOF_VOID_P} EQUAL 8) AND (NOT APPLE))
set(arch gcc_LP64)
set(arch_flags -m64)
else()
set(arch gcc_ILP32)
set(arch_flags)
endif()
# Add target to scan python bindings
if(${ENABLE_SCAN_PYTHON_BINDINGS}
AND (EXISTS ${CMAKE_HEADER_OUTPUT_DIRECTORY}/${BLIB_LIBNAME}-module.h)
AND (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/bindings")
)
set(bindings_output_folder ${PROJECT_SOURCE_DIR}/${FOLDER}/bindings)
file(MAKE_DIRECTORY ${bindings_output_folder})
set(module_api_ILP32 ${bindings_output_folder}/modulegen__gcc_ILP32.py)
set(module_api_LP64 ${bindings_output_folder}/modulegen__gcc_LP64.py)
set(modulescan_modular_command
${Python3_EXECUTABLE}
${PROJECT_SOURCE_DIR}/bindings/python/ns3modulescan-modular.py
)
set(header_map "")
# We need a python map that takes header.h to module e.g. "ptr.h": "core"
foreach(header ${BLIB_HEADER_FILES})
# header is a relative path to the current working directory
get_filename_component(
header_name ${CMAKE_CURRENT_SOURCE_DIR}/${header} NAME
)
string(APPEND header_map "\"${header_name}\":\"${BLIB_LIBNAME}\",")
endforeach()
set(ns3-headers-to-module-map "${ns3-headers-to-module-map}${header_map}"
CACHE INTERNAL "Map connecting headers to their modules"
)
# API scan needs the include directories to find a few headers (e.g. mpi.h)
get_target_includes(${lib${BLIB_LIBNAME}} modulegen_include_dirs)
set(module_to_generate_api ${module_api_ILP32})
set(LP64toILP32)
if("${arch}" STREQUAL "gcc_LP64")
set(module_to_generate_api ${module_api_LP64})
set(LP64toILP32
${Python3_EXECUTABLE}
${PROJECT_SOURCE_DIR}/build-support/pybindings-LP64-to-ILP32.py
${module_api_LP64} ${module_api_ILP32}
)
endif()
add_custom_target(
${lib${BLIB_LIBNAME}}-apiscan
COMMAND
${modulescan_modular_command} ${CMAKE_OUTPUT_DIRECTORY} ${BLIB_LIBNAME}
${PROJECT_BINARY_DIR}/header_map.json ${module_to_generate_api}
\"${arch_flags} ${modulegen_include_dirs}\" 2>
${bindings_output_folder}/apiscan.log
COMMAND ${LP64toILP32}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${lib${BLIB_LIBNAME}}
)
add_dependencies(apiscan-all ${lib${BLIB_LIBNAME}}-apiscan)
endif()
# Build pybindings if requested and if bindings subfolder exists in
# NS3/src/BLIB_LIBNAME
if(${ENABLE_PYTHON_BINDINGS} AND (EXISTS
"${CMAKE_CURRENT_SOURCE_DIR}/bindings")
)
set(bindings_output_folder ${CMAKE_OUTPUT_DIRECTORY}/${FOLDER}/bindings)
file(MAKE_DIRECTORY ${bindings_output_folder})
set(module_src ${bindings_output_folder}/ns3module.cc)
set(module_hdr ${bindings_output_folder}/ns3module.h)
string(REPLACE "-" "_" BLIB_LIBNAME_sub ${BLIB_LIBNAME}) # '-' causes
# problems (e.g.
# csma-layout), replace with '_' (e.g. csma_layout)
# Set prefix of binding to _ if a ${BLIB_LIBNAME}.py exists, and copy the
# ${BLIB_LIBNAME}.py to the output folder
set(prefix)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/bindings/${BLIB_LIBNAME}.py)
set(prefix _)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/bindings/${BLIB_LIBNAME}.py
DESTINATION ${CMAKE_OUTPUT_DIRECTORY}/bindings/python/ns
)
endif()
# Run modulegen-modular to generate the bindings sources
if((NOT EXISTS ${module_hdr}) OR (NOT EXISTS ${module_src})) # OR TRUE) # to
# force
# reprocessing
string(REPLACE ";" "," ENABLED_FEATURES
"${ns3-libs};${BLIB_MODULE_ENABLED_FEATURES}"
)
set(modulegen_modular_command
GCC_RTTI_ABI_COMPLETE=True NS3_ENABLED_FEATURES="${ENABLED_FEATURES}"
${Python3_EXECUTABLE}
${PROJECT_SOURCE_DIR}/bindings/python/ns3modulegen-modular.py
)
execute_process(
COMMAND
${CMAKE_COMMAND} -E env
PYTHONPATH=${CMAKE_OUTPUT_DIRECTORY}:$ENV{PYTHONPATH}
${modulegen_modular_command} ${CMAKE_CURRENT_SOURCE_DIR} ${arch}
${prefix}${BLIB_LIBNAME_sub} ${module_src}
TIMEOUT 60
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_FILE ${module_hdr}
ERROR_FILE ${bindings_output_folder}/ns3modulegen.log
RESULT_VARIABLE error_code
)
if(${error_code} OR NOT (EXISTS ${module_hdr}))
# Delete broken bindings to make sure we will his this error again if
# nothing changed
if(EXISTS ${module_src})
file(REMOVE ${module_src})
endif()
if(EXISTS ${module_hdr})
file(REMOVE ${module_hdr})
endif()
message(
FATAL_ERROR
"Something went wrong during processing of the python bindings of module ${BLIB_LIBNAME}."
" Make sure you have the latest version of Pybindgen."
)
endif()
endif()
# Add core module helper sources
set(python_module_files ${module_hdr} ${module_src})
file(GLOB custom_python_module_files
${CMAKE_CURRENT_SOURCE_DIR}/bindings/*.cc
${CMAKE_CURRENT_SOURCE_DIR}/bindings/*.h
)
list(APPEND python_module_files ${custom_python_module_files})
set(bindings-name lib${BLIB_LIBNAME}-bindings)
add_library(${bindings-name} SHARED "${python_module_files}")
target_include_directories(
${bindings-name} PUBLIC ${Python3_INCLUDE_DIRS} ${bindings_output_folder}
)
# If there is any, remove the "lib" prefix of libraries (search for
# "set(lib${BLIB_LIBNAME}")
list(LENGTH ns_libraries_to_link num_libraries)
if(num_libraries GREATER "0")
string(REPLACE ";" "-bindings;" bindings_to_link
"${ns_libraries_to_link};"
) # add -bindings suffix to all lib${name}
endif()
target_link_libraries(
${bindings-name}
PUBLIC ${LIB_AS_NEEDED_PRE} ${lib${BLIB_LIBNAME}} "${bindings_to_link}"
"${BLIB_LIBRARIES_TO_LINK}" ${LIB_AS_NEEDED_POST}
PRIVATE ${Python3_LIBRARIES}
)
target_include_directories(
${bindings-name} PRIVATE ${PROJECT_SOURCE_DIR}/src/core/bindings
)
set(suffix)
if(APPLE)
# Python doesn't like Apple's .dylib and will refuse to load bindings
# unless its an .so
set(suffix SUFFIX .so)
endif()
# Set binding library name and output folder
set_target_properties(
${bindings-name}
PROPERTIES OUTPUT_NAME ${prefix}${BLIB_LIBNAME_sub}
PREFIX ""
${suffix} LIBRARY_OUTPUT_DIRECTORY
${CMAKE_OUTPUT_DIRECTORY}/bindings/python/ns
)
set(ns3-python-bindings-modules
"${bindings-name};${ns3-python-bindings-modules}"
CACHE INTERNAL "list of modules python bindings"
)
# Make sure all bindings are built before building the visualizer module
# that makes use of them
if(${ENABLE_VISUALIZER} AND (visualizer IN_LIST libs_to_build))
if(NOT (${BLIB_LIBNAME} STREQUAL visualizer))
add_dependencies(${libvisualizer} ${bindings-name})
endif()
endif()
endif()
# Handle package export
install(
TARGETS ${lib${BLIB_LIBNAME}}

View File

@@ -766,14 +766,14 @@ macro(process_options)
if(${NS3_PYTHON_BINDINGS})
if(NOT ${Python3_FOUND})
message(
FATAL_ERROR
${HIGHLIGHTED_STATUS}
"Bindings: python bindings require Python, but it could not be found"
)
else()
check_python_packages("pybindgen" missing_packages)
check_python_packages("cppyy" missing_packages)
if(missing_packages)
message(
FATAL_ERROR
${HIGHLIGHTED_STATUS}
"Bindings: python bindings disabled due to the following missing dependencies: ${missing_packages}"
)
else()
@@ -794,44 +794,6 @@ macro(process_options)
add_compile_options(-Wno-potentially-evaluated-expression)
endif()
set(ENABLE_SCAN_PYTHON_BINDINGS OFF)
if(${NS3_SCAN_PYTHON_BINDINGS})
if(NOT ${Python3_FOUND})
message(
FATAL_ERROR
"Bindings: scanning python bindings require Python, but it could not be found"
)
else()
# Check if pybindgen, pygccxml, cxxfilt and castxml are installed
check_python_packages(
"pybindgen;pygccxml;cxxfilt;castxml" missing_packages
)
# If castxml has not been found via python import, fallback to searching
# the binary
if(castxml IN_LIST missing_packages)
mark_as_advanced(CASTXML)
find_program(CASTXML castxml)
if(NOT ("${CASTXML}" STREQUAL "CASTXML-NOTFOUND"))
list(REMOVE_ITEM missing_packages castxml)
endif()
endif()
# If packages were not found, print message
if(missing_packages)
message(
FATAL_ERROR
"Bindings: scanning of python bindings disabled due to the following missing dependencies: ${missing_packages}"
)
else()
set(ENABLE_SCAN_PYTHON_BINDINGS ON)
# empty scan target that will depend on other module scan targets to
# scan all of them
add_custom_target(apiscan-all)
endif()
endif()
endif()
set(ENABLE_VISUALIZER FALSE)
if(${NS3_VISUALIZER})
if((NOT ${ENABLE_PYTHON_BINDINGS}) OR (NOT ${Python3_FOUND}))
@@ -2079,20 +2041,6 @@ function(find_external_library)
endif()
endfunction()
function(write_header_to_modules_map)
if(${ENABLE_SCAN_PYTHON_BINDINGS})
set(header_map ${ns3-headers-to-module-map})
# Trim last comma
string(LENGTH "${header_map}" header_map_len)
math(EXPR header_map_len "${header_map_len}-1")
string(SUBSTRING "${header_map}" 0 ${header_map_len} header_map)
# Then write to header_map.json for consumption of pybindgen
file(WRITE ${PROJECT_BINARY_DIR}/header_map.json "{${header_map}}")
endif()
endfunction()
function(get_target_includes target output)
set(include_directories)
get_target_property(include_dirs ${target} INCLUDE_DIRECTORIES)

View File

@@ -13,6 +13,7 @@ if(${ENABLE_EXAMPLES})
CACHE INTERNAL "list of example folders"
)
endforeach()
scan_python_examples(${CMAKE_CURRENT_SOURCE_DIR})
endif()
scan_python_examples(${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -23,11 +23,7 @@
# - DropTail queues
# - Tracing of queues and packet receptions to file "udp-echo.tr"
import ns.applications
import ns.core
import ns.csma
import ns.internet
import ns.network
from ns import ns
def main(argv):
#
@@ -89,7 +85,7 @@ def main(argv):
packetSize = 1024
maxPacketCount = 500
interPacketInterval = ns.core.Seconds(0.01)
client = ns.applications.UdpEchoClientHelper(i.GetAddress (1), port)
client = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(i.GetAddress (1)), port)
client.SetAttribute("MaxPackets", ns.core.UintegerValue(maxPacketCount))
client.SetAttribute("Interval", ns.core.TimeValue(interPacketInterval))
client.SetAttribute("PacketSize", ns.core.UintegerValue(packetSize))
@@ -105,6 +101,7 @@ def main(argv):
# Now, do the actual simulation.
#
print ("Run Simulation.")
ns.core.Simulator.Stop(ns.Seconds(10))
ns.core.Simulator.Run()
ns.core.Simulator.Destroy()
print ("Done.")

View File

@@ -27,86 +27,77 @@
# router
#
import ns.internet_apps
import ns.core
import ns.csma
import ns.internet
import ns.network
from ns import ns
def main(argv):
cmd = ns.CommandLine()
cmd = ns.core.CommandLine();
cmd.Parse(argv);
cmd.Parse(argv)
# Create nodes
print ("Create nodes")
n0 = ns.network.Node();
r = ns.network.Node();
n1 = ns.network.Node();
print("Create nodes")
net1 = ns.network.NodeContainer();
net1.Add(n0);
net1.Add(r);
net2 = ns.network.NodeContainer();
net2.Add(r);
net2.Add(n1);
all = ns.network.NodeContainer();
all.Add(n0);
all.Add(r);
all.Add(n1);
all = ns.NodeContainer(3)
net1 = ns.NodeContainer()
net1.Add(all.Get(0))
net1.Add(all.Get(1))
net2 = ns.NodeContainer()
net2.Add(all.Get(1))
net2.Add(all.Get(2))
# Create IPv6 Internet Stack
internetv6 = ns.internet.InternetStackHelper();
internetv6.Install(all);
internetv6 = ns.InternetStackHelper()
internetv6.Install(all)
# Create channels
csma = ns.csma.CsmaHelper();
csma.SetChannelAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate(5000000)));
csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.MilliSeconds(2)));
d1 = csma.Install(net1);
d2 = csma.Install(net2);
csma = ns.csma.CsmaHelper()
csma.SetChannelAttribute("DataRate", ns.DataRateValue(ns.DataRate(5000000)))
csma.SetChannelAttribute("Delay", ns.TimeValue(ns.MilliSeconds(2)))
d1 = csma.Install(net1)
d2 = csma.Install(net2)
# Create networks and assign IPv6 Addresses
print ("Addressing")
ipv6 = ns.internet.Ipv6AddressHelper();
ipv6.SetBase(ns.network.Ipv6Address("2001:1::"), ns.network.Ipv6Prefix(64));
i1 = ipv6.Assign(d1);
i1.SetForwarding(1, True);
i1.SetDefaultRouteInAllNodes(1);
ipv6.SetBase(ns.network.Ipv6Address("2001:2::"), ns.network.Ipv6Prefix(64));
i2 = ipv6.Assign(d2);
i2.SetForwarding(0, True);
i2.SetDefaultRouteInAllNodes(0);
print("Addressing")
ipv6 = ns.Ipv6AddressHelper()
ipv6.SetBase(ns.Ipv6Address("2001:1::"), ns.Ipv6Prefix(64))
i1 = ipv6.Assign(d1)
i1.SetForwarding(1, True)
i1.SetDefaultRouteInAllNodes(1)
ipv6.SetBase(ns.Ipv6Address("2001:2::"), ns.Ipv6Prefix(64))
i2 = ipv6.Assign(d2)
i2.SetForwarding(0, True)
i2.SetDefaultRouteInAllNodes(0)
# Create a Ping6 application to send ICMPv6 echo request from n0 to n1 via r
print ("Application")
packetSize = 1024;
maxPacketCount = 5;
interPacketInterval = ns.core.Seconds(1.);
ping6 = ns.internet_apps.Ping6Helper();
print("Application")
packetSize = 1024
maxPacketCount = 5
interPacketInterval = ns.Seconds(1.)
ping6 = ns.Ping6Helper()
ping6.SetLocal(i1.GetAddress(0, 1));
ping6.SetRemote(i2.GetAddress(1, 1));
ping6.SetLocal(i1.GetAddress(0, 1))
ping6.SetRemote(i2.GetAddress(1, 1))
ping6.SetAttribute("MaxPackets", ns.core.UintegerValue(maxPacketCount));
ping6.SetAttribute("Interval", ns.core.TimeValue(interPacketInterval));
ping6.SetAttribute("PacketSize", ns.core.UintegerValue(packetSize));
ping6.SetAttribute("MaxPackets", ns.UintegerValue(maxPacketCount))
ping6.SetAttribute("Interval", ns.TimeValue(interPacketInterval))
ping6.SetAttribute("PacketSize", ns.UintegerValue(packetSize))
apps = ping6.Install(ns.network.NodeContainer(net1.Get(0)));
apps.Start(ns.core.Seconds(2.0));
apps.Stop(ns.core.Seconds(20.0));
apps = ping6.Install(ns.NodeContainer(net1.Get(0)))
apps.Start(ns.Seconds(2.0))
apps.Stop(ns.Seconds(20.0))
print ("Tracing")
ascii = ns.network.AsciiTraceHelper()
print("Tracing")
ascii = ns.AsciiTraceHelper()
csma.EnableAsciiAll(ascii.CreateFileStream("simple-routing-ping6.tr"))
csma.EnablePcapAll("simple-routing-ping6", True)
# Run Simulation
ns.core.Simulator.Run()
ns.core.Simulator.Destroy()
ns.Simulator.Run()
ns.Simulator.Destroy()
if __name__ == '__main__':
import sys
main(sys.argv)
main(sys.argv)

View File

@@ -13,11 +13,7 @@
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# */
import ns.applications
import ns.core
import ns.internet
import ns.network
import ns.point_to_point
from ns import ns
# // Default Network Topology
# //
@@ -53,7 +49,8 @@ serverApps = echoServer.Install(nodes.Get(1))
serverApps.Start(ns.core.Seconds(1.0))
serverApps.Stop(ns.core.Seconds(10.0))
echoClient = ns.applications.UdpEchoClientHelper(interfaces.GetAddress(1), 9)
address = ns.addressFromIpv4Address(interfaces.GetAddress(1))
echoClient = ns.applications.UdpEchoClientHelper(address, 9)
echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0)))
echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))

View File

@@ -16,12 +16,7 @@
# * Ported to Python by Mohit P. Tahiliani
# */
import ns.core
import ns.network
import ns.csma
import ns.internet
import ns.point_to_point
import ns.applications
from ns import ns
import sys
# // Default Network Topology
@@ -31,21 +26,30 @@ import sys
# // point-to-point | | | |
# // ================
# // LAN 10.1.2.0
ns.cppyy.cppdef("""
using namespace ns3;
cmd = ns.core.CommandLine()
cmd.nCsma = 3
cmd.verbose = "True"
cmd.AddValue("nCsma", "Number of \"extra\" CSMA nodes/devices")
cmd.AddValue("verbose", "Tell echo applications to log if true")
CommandLine& GetCommandLine(std::string filename, int& nCsma, bool& verbose)
{
static CommandLine cmd = CommandLine(filename);
cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma);
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose);
return cmd;
}
""")
from ctypes import c_int, c_bool
nCsma = c_int(3)
verbose = c_bool(True)
cmd = ns.cppyy.gbl.GetCommandLine(__file__, nCsma, verbose)
cmd.Parse(sys.argv)
nCsma = int(cmd.nCsma)
verbose = cmd.verbose
nCsma = nCsma.value
verbose = verbose.value
if verbose == "True":
ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
nCsma = 1 if int(nCsma) == 0 else int(nCsma)
nCsma = 1 if nCsma == 0 else nCsma
p2pNodes = ns.network.NodeContainer()
p2pNodes.Create(2)
@@ -83,7 +87,7 @@ serverApps = echoServer.Install(csmaNodes.Get(nCsma))
serverApps.Start(ns.core.Seconds(1.0))
serverApps.Stop(ns.core.Seconds(10.0))
echoClient = ns.applications.UdpEchoClientHelper(csmaInterfaces.GetAddress(nCsma), 9)
echoClient = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(csmaInterfaces.GetAddress(nCsma)), 9)
echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds (1.0)))
echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))

View File

@@ -16,14 +16,7 @@
# * Ported to Python by Mohit P. Tahiliani
# */
import ns.core
import ns.network
import ns.point_to_point
import ns.applications
import ns.wifi
import ns.mobility
import ns.csma
import ns.internet
from ns import ns
import sys
# // Default Network Topology
@@ -37,23 +30,21 @@ import sys
# // ================
# // LAN 10.1.2.0
cmd = ns.core.CommandLine()
cmd.nCsma = 3
cmd.verbose = "True"
cmd.nWifi = 3
cmd.tracing = "False"
cmd = ns.getCommandLine(__file__)
nCsma ="3"
verbose = "True"
nWifi = "3"
tracing = "False"
cmd.AddValue("nCsma", "Number of \"extra\" CSMA nodes/devices")
cmd.AddValue("nWifi", "Number of wifi STA devices")
cmd.AddValue("verbose", "Tell echo applications to log if true")
cmd.AddValue("tracing", "Enable pcap tracing")
cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", ns.null_callback(), nCsma)
cmd.AddValue("nWifi", "Number of wifi STA devices", ns.null_callback(), nWifi)
cmd.AddValue("verbose", "Tell echo applications to log if true", ns.null_callback(), verbose)
cmd.AddValue("tracing", "Enable pcap tracing", ns.null_callback(), tracing)
cmd.Parse(sys.argv)
nCsma = int(cmd.nCsma)
verbose = cmd.verbose
nWifi = int(cmd.nWifi)
tracing = cmd.tracing
nCsma = int(nCsma)
nWifi = int(nWifi)
# The underlying restriction of 18 is due to the grid position
# allocator's configuration; the grid layout will exceed the
@@ -137,7 +128,7 @@ serverApps = echoServer.Install(csmaNodes.Get(nCsma))
serverApps.Start(ns.core.Seconds(1.0))
serverApps.Stop(ns.core.Seconds(10.0))
echoClient = ns.applications.UdpEchoClientHelper(csmaInterfaces.GetAddress(nCsma), 9)
echoClient = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(csmaInterfaces.GetAddress(nCsma)), 9)
echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1))
echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds (1.0)))
echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024))

View File

@@ -51,14 +51,7 @@
# +----------------+ +----------------+
#
import ns.applications
import ns.core
import ns.csma
import ns.internet
import ns.mobility
import ns.network
import ns.olsr
import ns.wifi
from ns import ns
# #
# # This function will be used below as a trace sink
@@ -76,11 +69,11 @@ def main(argv):
# simulation parameters.
#
cmd = ns.core.CommandLine()
cmd.backboneNodes = 10
cmd.infraNodes = 2
cmd.lanNodes = 2
cmd.stopTime = 20
cmd = ns.getCommandLine(__file__)
cmd.backboneNodes = "10"
cmd.infraNodes = "2"
cmd.lanNodes = "2"
cmd.stopTime = "20"
#
# Simulation defaults are typically set next, before command line
@@ -95,10 +88,10 @@ def main(argv):
# "--backboneNodes=20"
#
cmd.AddValue("backboneNodes", "number of backbone nodes")
cmd.AddValue("infraNodes", "number of leaf nodes")
cmd.AddValue("lanNodes", "number of LAN nodes")
cmd.AddValue("stopTime", "simulation stop time(seconds)")
cmd.AddValue("backboneNodes", "number of backbone nodes", ns.null_callback(), cmd.backboneNodes)
cmd.AddValue("infraNodes", "number of leaf nodes", ns.null_callback(), cmd.infraNodes)
cmd.AddValue("lanNodes", "number of LAN nodes", ns.null_callback(), cmd.lanNodes)
cmd.AddValue("stopTime", "simulation stop time(seconds)", ns.null_callback(), cmd.stopTime)
#
# The system global variables and the local values added to the argument
@@ -316,19 +309,26 @@ def main(argv):
appSource = ns.network.NodeList.GetNode(backboneNodes)
lastNodeIndex = backboneNodes + backboneNodes*(lanNodes - 1) + backboneNodes*(infraNodes - 1) - 1
appSink = ns.network.NodeList.GetNode(lastNodeIndex)
# Let's fetch the IP address of the last node, which is on Ipv4Interface 1
remoteAddr = appSink.GetObject(ns.internet.Ipv4.GetTypeId()).GetAddress(1,0).GetLocal()
onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory",
ns.network.Address(ns.network.InetSocketAddress(remoteAddr, port)))
ns.cppyy.cppdef("""
Ipv4Address getIpv4AddressFromNode(Ptr<Node> node){
return node->GetObject<Ipv4>()->GetAddress(1,0).GetLocal();
}
""")
# Let's fetch the IP address of the last node, which is on Ipv4Interface 1
remoteAddr = ns.cppyy.gbl.getIpv4AddressFromNode(appSink)
socketAddr = ns.network.InetSocketAddress(remoteAddr, port)
genericAddress = ns.addressFromInetSocketAddress(socketAddr)
onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory", genericAddress)
apps = onoff.Install(ns.network.NodeContainer(appSource))
apps.Start(ns.core.Seconds(3))
apps.Stop(ns.core.Seconds(stopTime - 1))
# Create a packet sink to receive these packets
sink = ns.applications.PacketSinkHelper("ns3::UdpSocketFactory",
ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port))
apps = sink.Install(ns.network.NodeContainer(appSink))
ns.addressFromInetSocketAddress(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port)))
sinkContainer = ns.network.NodeContainer(appSink)
apps = sink.Install(sinkContainer)
apps.Start(ns.core.Seconds(3))
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # /
@@ -371,7 +371,6 @@ def main(argv):
ns.core.Simulator.Run()
ns.core.Simulator.Destroy()
if __name__ == '__main__':
import sys
main(sys.argv)

View File

@@ -22,13 +22,7 @@
import sys
import ns.applications
import ns.core
import ns.internet
import ns.mobility
import ns.network
import ns.point_to_point
import ns.wifi
from ns import ns
# void
# DevTxTrace (std::string context, Ptr<const Packet> p, Mac48Address address)
@@ -76,23 +70,17 @@ import ns.wifi
# std::cout << " start="<<start<<" duration="<<duration<<std::endl;
# }
def SetPosition(node, position):
mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
mobility.SetPosition(position)
def GetPosition(node):
mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
return mobility.GetPosition()
def AdvancePosition(node):
pos = GetPosition(node);
pos.x += 5.0
if pos.x >= 210.0:
return
SetPosition(node, pos)
ns.core.Simulator.Schedule(ns.core.Seconds(1.0), AdvancePosition, node)
ns.cppyy.cppdef("""
using namespace ns3;
void AdvancePosition(Ptr<Node> node){
Ptr<MobilityModel> mob = node->GetObject<MobilityModel>();
Vector pos = mob->GetPosition();
pos.x += 5.0;
if (pos.x >= 210.0)
return;
mob->SetPosition(pos);
Simulator::Schedule(Seconds(1.0), AdvancePosition, node);
}""")
def main(argv):
ns.core.CommandLine().Parse(argv)
@@ -133,14 +121,15 @@ def main(argv):
mobility.Install(stas)
mobility.Install(ap)
ns.core.Simulator.Schedule(ns.core.Seconds(1.0), AdvancePosition, ap.Get(0))
ns.core.Simulator.Schedule(ns.core.Seconds(1.0), ns.cppyy.gbl.AdvancePosition, ap.Get(0))
socket = ns.network.PacketSocketAddress()
socket.SetSingleDevice(staDevs.Get(0).GetIfIndex())
socket.SetPhysicalAddress(staDevs.Get(1).GetAddress())
socket.SetProtocol(1)
onoff = ns.applications.OnOffHelper("ns3::PacketSocketFactory", ns.network.Address(socket))
genericAddress = ns.addressFromPacketSocketAddress(socket)
onoff = ns.applications.OnOffHelper("ns3::PacketSocketFactory", genericAddress)
onoff.SetConstantRate (ns.network.DataRate ("500kb/s"))
apps = onoff.Install(ns.network.NodeContainer(stas.Get(0)))

View File

@@ -33,12 +33,7 @@
# Bridge example connecting two broadcast domains.
import ns.applications
import ns.bridge
import ns.core
import ns.csma
import ns.internet
import ns.network
from ns import ns
def main(argv):
@@ -100,8 +95,9 @@ def main(argv):
#print "Create Applications."
port = 9 # Discard port(RFC 863)
inet_sock_address = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.2"), port)
onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory",
ns.network.Address(ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.2"), port)))
ns.network.Address(ns.addressFromInetSocketAddress(inet_sock_address)))
onoff.SetConstantRate (ns.network.DataRate ("500kb/s"))
app = onoff.Install(ns.network.NodeContainer(terminals.Get(0)))
@@ -110,16 +106,18 @@ def main(argv):
app.Stop(ns.core.Seconds(10.0))
# Create an optional packet sink to receive these packets
inet_address = ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port)
sink = ns.applications.PacketSinkHelper("ns3::UdpSocketFactory",
ns.network.Address(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port)))
ns.network.Address(ns.addressFromInetSocketAddress(inet_address)))
app = sink.Install(ns.network.NodeContainer(terminals.Get(1)))
app.Start(ns.core.Seconds(0.0))
#
# Create a similar flow from n3 to n0, starting at time 1.1 seconds
#
inet_address = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.1"), port)
onoff.SetAttribute("Remote",
ns.network.AddressValue(ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.1"), port)))
ns.network.AddressValue(ns.addressFromInetSocketAddress(inet_address)))
app = onoff.Install(ns.network.NodeContainer(terminals.Get(3)))
app.Start(ns.core.Seconds(1.1))
app.Stop(ns.core.Seconds(10.0))

View File

@@ -25,14 +25,15 @@
import numpy as np
import matplotlib.pyplot as plt
import ns.core
from ns import ns
# mu, var = 100, 225
## Random number generator.
rng = ns.core.NormalRandomVariable()
rng.SetAttribute("Mean", ns.core.DoubleValue(100.0))
rng.SetAttribute("Variance", ns.core.DoubleValue(225.0))
rng = ns.CreateObject("NormalRandomVariable")
rng.SetAttribute("Mean", ns.DoubleValue(100.0))
rng.SetAttribute("Variance", ns.DoubleValue(225.0))
## Random number samples.
x = [rng.GetValue() for t in range(10000)]
@@ -40,14 +41,14 @@ x = [rng.GetValue() for t in range(10000)]
## Make a probability density histogram
density = 1
## Plot color
## Plot color
facecolor='g'
## Plot alpha value (transparency)
alpha=0.75
# We don't really need the plot results, we're just going to show it later.
# n, bins, patches = plt.hist(x, 50, density=1, facecolor='g', alpha=0.75)
plt.hist(x, 50, density=1, facecolor='g', alpha=0.75)
n, bins, patches = plt.hist(x, 50, density=True, facecolor='g', alpha=0.75)
plt.title('ns-3 histogram')
plt.text(60, .025, r'$\mu=100,\ \sigma=15$')

View File

@@ -26,35 +26,11 @@
# Python example program demonstrating use of various Schedule functions.
import ns.core
class MyModel(object):
"""Simple model object to illustrate event handling."""
## \return None.
def Start(self):
"""Start model execution by scheduling a HandleEvent."""
ns.core.Simulator.Schedule(ns.core.Seconds(10.0), self.HandleEvent, ns.core.Simulator.Now().GetSeconds())
## \param [in] self This instance of MyModel
## \param [in] value Event argument.
## \return None.
def HandleEvent(self, value):
"""Simple event handler."""
print ("Member method received event at", ns.core.Simulator.Now().GetSeconds(), \
"s started at", value, "s")
## Example function - starts MyModel.
## \param [in] model The instance of MyModel
## \return None.
def ExampleFunction(model):
print ("ExampleFunction received event at", ns.core.Simulator.Now().GetSeconds(), "s")
model.Start()
from ns import ns
## Example function - triggered at a random time.
## \param [in] model The instance of MyModel
## \return None.
def RandomFunction(model):
def RandomFunction():
print ("RandomFunction received event at", ns.core.Simulator.Now().GetSeconds(), "s")
## Example function - triggered if an event is canceled (should not be called).
@@ -62,19 +38,88 @@ def RandomFunction(model):
def CancelledEvent():
print ("I should never be called... ")
def main(dummy_argv):
ns.core.CommandLine().Parse(dummy_argv)
ns.cppyy.cppdef("""
#include "CPyCppyy/API.h"
model = MyModel()
v = ns.core.UniformRandomVariable()
using namespace ns3;
/** Simple model object to illustrate event handling. */
class MyModel
{
public:
/** Start model execution by scheduling a HandleEvent. */
void Start (void);
private:
/**
* Simple event handler.
*
* \param [in] eventValue Event argument.
*/
void HandleEvent (double eventValue);
};
void
MyModel::Start (void)
{
Simulator::Schedule (Seconds (10.0),
&MyModel::HandleEvent,
this, Simulator::Now ().GetSeconds ());
}
void
MyModel::HandleEvent (double value)
{
std::cout << "Member method received event at "
<< Simulator::Now ().GetSeconds ()
<< "s started at " << value << "s" << std::endl;
}
void ExampleFunction(MyModel& model){
std::cout << "ExampleFunction received event at " << Simulator::Now().GetSeconds() << "s" << std::endl;
model.Start();
};
EventImpl* ExampleFunctionEvent(MyModel& model)
{
return MakeEvent(&ExampleFunction, model);
}
void RandomFunctionCpp(MyModel& model) {
CPyCppyy::Eval("RandomFunction()");
}
EventImpl* RandomFunctionEvent(MyModel& model)
{
return MakeEvent(&RandomFunctionCpp, model);
}
void CancelledFunctionCpp(void) {
CPyCppyy::Eval("CancelledEvent()");
}
EventImpl* CancelledFunctionEvent()
{
return MakeEvent(&CancelledFunctionCpp);
}
""")
def main(dummy_argv):
cmd = ns.getCommandLine(__file__)
cmd.Parse(dummy_argv)
model = ns.cppyy.gbl.MyModel()
v = ns.CreateObject("UniformRandomVariable")
v.SetAttribute("Min", ns.core.DoubleValue (10))
v.SetAttribute("Max", ns.core.DoubleValue (20))
ns.core.Simulator.Schedule(ns.core.Seconds(10.0), ExampleFunction, model)
ev = ns.cppyy.gbl.ExampleFunctionEvent(model)
ns.core.Simulator.Schedule(ns.core.Seconds(10.0), ev)
ns.core.Simulator.Schedule(ns.core.Seconds(v.GetValue()), RandomFunction, model)
ev2 = ns.cppyy.gbl.RandomFunctionEvent(model)
ns.core.Simulator.Schedule(ns.core.Seconds(v.GetValue()), ev2)
id = ns.core.Simulator.Schedule(ns.core.Seconds(30.0), CancelledEvent)
ev3 = ns.cppyy.gbl.CancelledFunctionEvent()
id = ns.core.Simulator.Schedule(ns.core.Seconds(30.0), ev3)
ns.core.Simulator.Cancel(id)
ns.core.Simulator.Run()

View File

@@ -19,40 +19,39 @@
from __future__ import print_function
import sys
import ns.applications
import ns.core
import ns.flow_monitor
import ns.internet
import ns.mobility
import ns.network
import ns.olsr
import ns.wifi
try:
import ns.visualizer
except ImportError:
pass
from ns import ns
DISTANCE = 20 # (m)
NUM_NODES_SIDE = 3
ns.cppyy.cppdef("""
using namespace ns3;
CommandLine& GetCommandLine(std::string filename, int& NumNodesSide, bool& Plot, std::string Results)
{
static CommandLine cmd = CommandLine(filename);
cmd.AddValue("NumNodesSide", "Grid side number of nodes (total number of nodes will be this number squared)", NumNodesSide);
cmd.AddValue("Results", "Write XML results to file", Results);
cmd.AddValue("Plot", "Plot the results using the matplotlib python module", Plot);
return cmd;
}
""")
def main(argv):
cmd = ns.core.CommandLine()
cmd.NumNodesSide = None
cmd.AddValue("NumNodesSide", "Grid side number of nodes (total number of nodes will be this number squared)")
cmd.Results = None
cmd.AddValue("Results", "Write XML results to file")
cmd.Plot = None
cmd.AddValue("Plot", "Plot the results using the matplotlib python module")
from ctypes import c_int, c_bool
NumNodesSide = c_int(2)
Plot = c_bool(True)
Results = "output.xml"
cmd = ns.cppyy.gbl.GetCommandLine(__file__, NumNodesSide, Plot, Results)
cmd.Parse(argv)
wifi = ns.wifi.WifiHelper()
wifiMac = ns.wifi.WifiMacHelper()
wifiPhy = ns.wifi.YansWifiPhyHelper()
Plot = Plot.value
NumNodesSide = NumNodesSide.value
wifi = ns.CreateObject("WifiHelper")
wifiMac = ns.CreateObject("WifiMacHelper")
wifiPhy = ns.CreateObject("YansWifiPhyHelper")
wifiChannel = ns.wifi.YansWifiChannelHelper.Default()
wifiPhy.SetChannel(wifiChannel.Create())
ssid = ns.wifi.Ssid("wifi-default")
@@ -71,8 +70,9 @@ def main(argv):
ipv4Addresses.SetBase(ns.network.Ipv4Address("10.0.0.0"), ns.network.Ipv4Mask("255.255.255.0"))
port = 9 # Discard port(RFC 863)
inetAddress = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.0.0.1"), port)
onOffHelper = ns.applications.OnOffHelper("ns3::UdpSocketFactory",
ns.network.Address(ns.network.InetSocketAddress(ns.network.Ipv4Address("10.0.0.1"), port)))
ns.network.Address(ns.addressFromInetSocketAddress(inetAddress)))
onOffHelper.SetAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate("100kbps")))
onOffHelper.SetAttribute("OnTime", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=1]"))
onOffHelper.SetAttribute("OffTime", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=0]"))
@@ -80,34 +80,39 @@ def main(argv):
addresses = []
nodes = []
if cmd.NumNodesSide is None:
if NumNodesSide is None:
num_nodes_side = NUM_NODES_SIDE
else:
num_nodes_side = int(cmd.NumNodesSide)
num_nodes_side = NumNodesSide
nodes = ns.NodeContainer(num_nodes_side*num_nodes_side)
accumulator = 0
for xi in range(num_nodes_side):
for yi in range(num_nodes_side):
node = ns.network.Node()
nodes.append(node)
node = nodes.Get(accumulator)
accumulator += 1
container = ns.network.NodeContainer(node)
internet.Install(container)
internet.Install(ns.network.NodeContainer(node))
mobility = ns.mobility.ConstantPositionMobilityModel()
mobility = ns.CreateObject("ConstantPositionMobilityModel")
mobility.SetPosition(ns.core.Vector(xi*DISTANCE, yi*DISTANCE, 0))
node.AggregateObject(mobility)
devices = wifi.Install(wifiPhy, wifiMac, node)
ipv4_interfaces = ipv4Addresses.Assign(devices)
device = wifi.Install(wifiPhy, wifiMac, node)
ipv4_interfaces = ipv4Addresses.Assign(device)
addresses.append(ipv4_interfaces.GetAddress(0))
for i, node in enumerate(nodes):
for i, node in [(i, nodes.Get(i)) for i in range(nodes.GetN())]:
destaddr = addresses[(len(addresses) - 1 - i) % len(addresses)]
#print (i, destaddr)
onOffHelper.SetAttribute("Remote", ns.network.AddressValue(ns.network.InetSocketAddress(destaddr, port)))
app = onOffHelper.Install(ns.network.NodeContainer(node))
urv = ns.core.UniformRandomVariable()
app.Start(ns.core.Seconds(urv.GetValue(20, 30)))
genericAddress = ns.addressFromInetSocketAddress(ns.network.InetSocketAddress(destaddr, port))
onOffHelper.SetAttribute("Remote", ns.network.AddressValue(genericAddress))
container = ns.network.NodeContainer(node)
app = onOffHelper.Install(container)
urv = ns.CreateObject("UniformRandomVariable")#ns.cppyy.gbl.get_rng()
startDelay = ns.Seconds(urv.GetValue(20, 30))
app.Start(startDelay)
#internet.EnablePcapAll("wifi-olsr")
flowmon_helper = ns.flow_monitor.FlowMonitorHelper()
@@ -154,7 +159,7 @@ def main(argv):
monitor.CheckForLostPackets()
classifier = flowmon_helper.GetClassifier()
if cmd.Results is None:
if Results is None:
for flow_id, flow_stats in monitor.GetFlowStats():
t = classifier.FindFlow(flow_id)
proto = {6: 'TCP', 17: 'UDP'} [t.protocol]
@@ -162,10 +167,10 @@ def main(argv):
(flow_id, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort))
print_stats(sys.stdout, flow_stats)
else:
print (monitor.SerializeToXmlFile(cmd.Results, True, True))
print (monitor.SerializeToXmlFile(Results, True, True))
if cmd.Plot is not None:
if Plot is not None:
import pylab
delays = []
for flow_id, flow_stats in monitor.GetFlowStats():

View File

@@ -18,11 +18,7 @@
import sys
import ns.core
import ns.csma
import ns.internet
import ns.network
import ns.tap_bridge
from ns import ns
def main(argv):
@@ -34,7 +30,7 @@ def main(argv):
# and take the time to calculate checksums.
#
ns.core.GlobalValue.Bind("SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl"))
ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue("true"))
ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue(True))
#
# Create two ghost nodes. The first will represent the virtual machine host
@@ -76,7 +72,7 @@ def main(argv):
# Run the simulation for ten minutes to give the user time to play around
#
ns.core.Simulator.Stop (ns.core.Seconds (600))
ns.core.Simulator.Run(signal_check_frequency = -1)
ns.core.Simulator.Run()#signal_check_frequency = -1
ns.core.Simulator.Destroy()
return 0

View File

@@ -17,12 +17,7 @@
#
import sys
import ns.core
import ns.internet
import ns.mobility
import ns.network
import ns.tap_bridge
import ns.wifi
from ns import ns
def main(argv):
@@ -34,7 +29,7 @@ def main(argv):
# and take the time to calculate checksums.
#
ns.core.GlobalValue.Bind("SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl"))
ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue("true"))
ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue(True))
#
# Create two ghost nodes. The first will represent the virtual machine host
@@ -105,7 +100,7 @@ def main(argv):
# Run the simulation for ten minutes to give the user time to play around
#
ns.core.Simulator.Stop (ns.core.Seconds (600));
ns.core.Simulator.Run(signal_check_frequency = -1)
ns.core.Simulator.Run()#signal_check_frequency = -1
ns.core.Simulator.Destroy()
return 0

View File

@@ -1,3 +1,15 @@
from ns import *
# Some useful tricks for visualizer
# we need to check if the node has a mobility model, but we can't pass Ptr<MobilityModel> to python
ns.cppyy.cppdef("""using namespace ns3; bool hasMobilityModel(Ptr<Node> node){ return !(node->GetObject<MobilityModel>() == 0); };""")
ns.cppyy.cppdef("""using namespace ns3; Vector3D getNodePosition(Ptr<Node> node){ return node->GetObject<MobilityModel>()->GetPosition(); };""")
ns.cppyy.cppdef("""using namespace ns3; Ptr<Ipv4> getNodeIpv4(Ptr<Node> node){ return node->GetObject<Ipv4>(); };""")
ns.cppyy.cppdef("""using namespace ns3; Ptr<Ipv6> getNodeIpv6(Ptr<Node> node){ return node->GetObject<Ipv6>(); };""")
ns.cppyy.cppdef("""using namespace ns3; std::string getMobilityModelName(Ptr<Node> node){ return node->GetObject<MobilityModel>()->GetInstanceTypeId().GetName(); };""")
ns.cppyy.cppdef("""using namespace ns3; bool hasOlsr(Ptr<Node> node){ return !(node->GetObject<olsr::RoutingProtocol>() == 0); };""")
ns.cppyy.cppdef("""using namespace ns3; Ptr<olsr::RoutingProtocol> getNodeOlsr(Ptr<Node> node){ return node->GetObject<olsr::RoutingProtocol>(); };""")
from .core import start, register_plugin, set_bounds, add_initialization_hook

View File

@@ -1,12 +1,4 @@
from __future__ import print_function
import ns.point_to_point
import ns.csma
import ns.wifi
import ns.bridge
import ns.internet
import ns.mesh
import ns.wimax
import ns.lte
from gi.repository import GObject
import os.path
@@ -58,16 +50,16 @@ class NetDeviceTraits(object):
self.is_virtual = is_virtual
netdevice_traits = {
ns.point_to_point.PointToPointNetDevice: NetDeviceTraits(is_wireless=False),
ns.csma.CsmaNetDevice: NetDeviceTraits(is_wireless=False),
ns.wifi.WifiNetDevice: NetDeviceTraits(is_wireless=True),
ns.bridge.BridgeNetDevice: NetDeviceTraits(is_virtual=True),
ns.internet.LoopbackNetDevice: NetDeviceTraits(is_virtual=True, is_wireless=False),
ns.mesh.MeshPointDevice: NetDeviceTraits(is_virtual=True),
ns.wimax.SubscriberStationNetDevice: NetDeviceTraits(is_wireless=True),
ns.wimax.BaseStationNetDevice: NetDeviceTraits(is_wireless=True),
ns.lte.LteUeNetDevice: NetDeviceTraits(is_wireless=True),
ns.lte.LteEnbNetDevice: NetDeviceTraits(is_wireless=True),
ns.PointToPointNetDevice: NetDeviceTraits(is_wireless=False),
ns.CsmaNetDevice: NetDeviceTraits(is_wireless=False),
ns.WifiNetDevice: NetDeviceTraits(is_wireless=True),
ns.BridgeNetDevice: NetDeviceTraits(is_virtual=True),
ns.LoopbackNetDevice: NetDeviceTraits(is_virtual=True, is_wireless=False),
ns.MeshPointDevice: NetDeviceTraits(is_virtual=True),
ns.SubscriberStationNetDevice: NetDeviceTraits(is_wireless=True),
ns.BaseStationNetDevice: NetDeviceTraits(is_wireless=True),
ns.LteUeNetDevice: NetDeviceTraits(is_wireless=True),
ns.LteEnbNetDevice: NetDeviceTraits(is_wireless=True),
}
def lookup_netdevice_traits(class_type):

View File

@@ -1,6 +1,7 @@
# -*- Mode: python; coding: utf-8 -*-
from __future__ import division, print_function
#from __future__ import with_statement
from ctypes import c_double
LAYOUT_ALGORITHM = 'neato' # ['neato'|'dot'|'twopi'|'circo'|'fdp'|'nop']
REPRESENT_CHANNELS_AS_NODES = 1
@@ -20,13 +21,6 @@ if platform.system() == "Windows":
else:
SHELL_FONT = "Luxi Mono 10"
import ns.core
import ns.network
import ns.visualizer
import ns.internet
import ns.mobility
import math
import os
import sys
@@ -50,6 +44,7 @@ try:
from gi.repository import GooCanvas
import threading
from . import hud
#import time
try:
import svgitem
@@ -231,12 +226,12 @@ class Node(PyVizObject):
"""
self.visualizer.simulation.lock.acquire()
try:
ns3_node = ns.network.NodeList.GetNode(self.node_index)
ipv4 = ns3_node.GetObject(ns.internet.Ipv4.GetTypeId())
ipv6 = ns3_node.GetObject(ns.internet.Ipv6.GetTypeId())
ns3_node = ns.NodeList.GetNode(self.node_index)
ipv4 = ns.cppyy.gbl.getNodeIpv4(ns3_node)
ipv6 = ns.cppyy.gbl.getNodeIpv6(ns3_node)
name = '<b><u>Node %i</u></b>' % self.node_index
node_name = ns.core.Names.FindName (ns3_node)
node_name = ns.Names.FindName (ns3_node)
if len(node_name)!=0:
name += ' <b>(' + node_name + ')</b>'
@@ -245,15 +240,16 @@ class Node(PyVizObject):
self.emit("query-extra-tooltip-info", lines)
mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mob is not None:
lines.append(' <b>Mobility Model</b>: %s' % mob.GetInstanceTypeId().GetName())
mob = ns.cppyy.gbl.hasMobilityModel(ns3_node)
if mob:
mobility_model_name = ns.cppyy.gbl.getMobilityModelName(ns3_node)
lines.append(' <b>Mobility Model</b>: %s' % ns.cppyy.gbl.getMobilityModelName(ns3_node))
for devI in range(ns3_node.GetNDevices()):
lines.append('')
lines.append(' <u>NetDevice %i:</u>' % devI)
dev = ns3_node.GetDevice(devI)
name = ns.core.Names.FindName(dev)
name = ns.Names.FindName(dev)
if name:
lines.append(' <b>Name:</b> %s' % name)
devname = dev.GetInstanceTypeId().GetName()
@@ -504,9 +500,8 @@ class Node(PyVizObject):
@return modility option
"""
if self._has_mobility is None:
node = ns.network.NodeList.GetNode(self.node_index)
mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
self._has_mobility = (mobility is not None)
node = ns.NodeList.GetNode(self.node_index)
self._has_mobility = ns.cppyy.gbl.hasMobilityModel(node)
return self._has_mobility
@@ -629,7 +624,7 @@ class SimulationThread(threading.Thread):
self.go.clear()
self.target_time = 0 # in seconds
self.quit = False
self.sim_helper = ns.visualizer.PyViz()
self.sim_helper = ns.PyViz()
self.pause_messages = []
def set_nodes_of_interest(self, nodes):
@@ -664,13 +659,13 @@ class SimulationThread(threading.Thread):
self.lock.acquire()
try:
if 0:
if ns3.core.Simulator.IsFinished():
if ns3.Simulator.IsFinished():
self.viz.play_button.set_sensitive(False)
break
#print "sim: Current time is %f; Run until: %f" % (ns3.Simulator.Now ().GetSeconds (), self.target_time)
#if ns3.Simulator.Now ().GetSeconds () > self.target_time:
# print "skipping, model is ahead of view!"
self.sim_helper.SimulatorRunUntil(ns.core.Seconds(self.target_time))
self.sim_helper.SimulatorRunUntil(ns.Seconds(self.target_time))
#print "sim: Run until ended at current time: ", ns3.Simulator.Now ().GetSeconds ()
self.pause_messages.extend(self.sim_helper.GetPauseMessages())
GLib.idle_add(self.viz.update_model, priority=PRIORITY_UPDATE_MODEL)
@@ -776,7 +771,7 @@ class Visualizer(GObject.GObject):
assert isinstance(mode, ShowTransmissionsMode)
self._show_transmissions_mode = mode
if self._show_transmissions_mode == ShowTransmissionsMode.ALL:
self.simulation.set_nodes_of_interest(list(range(ns.network.NodeList.GetNNodes())))
self.simulation.set_nodes_of_interest(list(range(ns.NodeList.GetNNodes())))
elif self._show_transmissions_mode == ShowTransmissionsMode.NONE:
self.simulation.set_nodes_of_interest([])
elif self._show_transmissions_mode == ShowTransmissionsMode.SELECTED:
@@ -1111,22 +1106,22 @@ class Visualizer(GObject.GObject):
self.window.show()
def scan_topology(self):
print("scanning topology: %i nodes..." % (ns.network.NodeList.GetNNodes(),))
print("scanning topology: %i nodes..." % (ns.NodeList.GetNNodes(),))
graph = pygraphviz.AGraph()
seen_nodes = 0
for nodeI in range(ns.network.NodeList.GetNNodes()):
for nodeI in range(ns.NodeList.GetNNodes()):
seen_nodes += 1
if seen_nodes == 100:
print("scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns.network.NodeList.GetNNodes()))
print("scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns.NodeList.GetNNodes()))
seen_nodes = 0
node = ns.network.NodeList.GetNode(nodeI)
node = ns.NodeList.GetNode(nodeI)
node_name = "Node %i" % nodeI
node_view = self.get_node(nodeI)
mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mobility is not None:
mobility = ns.cppyy.gbl.hasMobilityModel(node)
if mobility:
node_view.set_color("red")
pos = mobility.GetPosition()
pos = ns.cppyy.gbl.getNodePosition(node)
node_view.set_position(*transform_point_simulation_to_canvas(pos.x, pos.y))
#print "node has mobility position -> ", "%f,%f" % (pos.x, pos.y)
else:
@@ -1213,7 +1208,7 @@ class Visualizer(GObject.GObject):
def update_view(self):
#print "update_view"
self.time_label.set_text("Time: %f s" % ns.core.Simulator.Now().GetSeconds())
self.time_label.set_text("Time: %f s" % ns.Simulator.Now().GetSeconds())
self._update_node_positions()
@@ -1229,10 +1224,10 @@ class Visualizer(GObject.GObject):
def _update_node_positions(self):
for node in self.nodes.values():
if node.has_mobility:
ns3_node = ns.network.NodeList.GetNode(node.node_index)
mobility = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mobility is not None:
pos = mobility.GetPosition()
ns3_node = ns.NodeList.GetNode(node.node_index)
mobility = ns.cppyy.gbl.hasMobilityModel(ns3_node)
if mobility:
pos = ns.cppyy.gbl.getNodePosition(ns3_node)
x, y = transform_point_simulation_to_canvas(pos.x, pos.y)
node.set_position(x, y)
if node is self.follow_node:
@@ -1243,14 +1238,14 @@ class Visualizer(GObject.GObject):
vadj.set_value(py - vadj.get_page_size() / 2)
def center_on_node(self, node):
if isinstance(node, ns.network.Node):
if isinstance(node, ns.Node):
node = self.nodes[node.GetId()]
elif isinstance(node, (int, long)):
node = self.nodes[node]
elif isinstance(node, Node):
pass
else:
raise TypeError("expected int, viz.Node or ns.network.Node, not %r" % node)
raise TypeError("expected int, viz.Node or ns.Node, not %r" % node)
x, y = node.get_position()
hadj = self._scrolled_window.get_hadjustment()
@@ -1285,10 +1280,14 @@ class Visualizer(GObject.GObject):
bounds_x1, bounds_y1 = self.canvas.convert_from_pixels(hadj.get_value(), vadj.get_value())
bounds_x2, bounds_y2 = self.canvas.convert_from_pixels(hadj.get_value() + hadj.get_page_size(),
vadj.get_value() + vadj.get_page_size())
pos1_x, pos1_y, pos2_x, pos2_y = ns.visualizer.PyViz.LineClipping(bounds_x1, bounds_y1,
try:
pos1_x, pos1_y, pos2_x, pos2_y = ns.PyViz.LineClipping(bounds_x1, bounds_y1,
bounds_x2, bounds_y2,
pos1_x, pos1_y,
pos2_x, pos2_y)
except:
res = (0,0,0,0)
pos1_x, pos1_y, pos2_x, pos2_y = res
return (pos1_x + pos2_x)/2, (pos1_y + pos2_y)/2
def _update_transmissions_view(self):
@@ -1349,8 +1348,8 @@ class Visualizer(GObject.GObject):
anchor=GooCanvas.CanvasAnchorType.N,
x=0, y=line_width/2)
M = cairo.Matrix()
lx, ly = self._get_label_over_line_position(pos1_x, pos1_y,
pos2_x, pos2_y)
lx, ly = self._get_label_over_line_position(c_double(pos1_x), c_double(pos1_y),
c_double(pos2_x), c_double(pos2_y))
M.translate(lx, ly)
M.rotate(angle)
try:
@@ -1436,7 +1435,7 @@ class Visualizer(GObject.GObject):
self.simulation.pause_messages = []
try:
self.update_view()
self.simulation.target_time = ns.core.Simulator.Now ().GetSeconds () + self.sample_period
self.simulation.target_time = ns.Simulator.Now ().GetSeconds () + self.sample_period
#print "view: target time set to %f" % self.simulation.target_time
finally:
self.simulation.lock.release()
@@ -1590,13 +1589,13 @@ class Visualizer(GObject.GObject):
def begin_node_drag(self, node, event):
self.simulation.lock.acquire()
try:
ns3_node = ns.network.NodeList.GetNode(node.node_index)
mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mob is None:
ns3_node = ns.NodeList.GetNode(node.node_index)
mob = ns.cppyy.gbl.hasMobilityModel(ns3_node)
if not mob:
return
if self.node_drag_state is not None:
return
pos = mob.GetPosition()
pos = ns.cppyy.gbl.getNodePosition(ns3_node)
finally:
self.simulation.lock.release()
devpos = self.canvas.get_window().get_device_position(event.device)
@@ -1607,9 +1606,9 @@ class Visualizer(GObject.GObject):
def node_drag_motion(self, item, targe_item, event, node):
self.simulation.lock.acquire()
try:
ns3_node = ns.network.NodeList.GetNode(node.node_index)
mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId())
if mob is None:
ns3_node = ns.NodeList.GetNode(node.node_index)
mob = ns.cppyy.gbl.hasMobilityModel(ns3_node)
if not mob:
return False
if self.node_drag_state is None:
return False
@@ -1652,14 +1651,14 @@ class Visualizer(GObject.GObject):
else:
self.simulation.lock.acquire()
try:
ns3_node = ns.network.NodeList.GetNode(self.selected_node.node_index)
ns3_node = ns.NodeList.GetNode(self.selected_node.node_index)
finally:
self.simulation.lock.release()
self.ipython.updateNamespace({'selected_node': ns3_node})
def select_node(self, node):
if isinstance(node, ns.network.Node):
if isinstance(node, ns.Node):
node = self.nodes[node.GetId()]
elif isinstance(node, (int, long)):
node = self.nodes[node]
@@ -1668,7 +1667,7 @@ class Visualizer(GObject.GObject):
elif node is None:
pass
else:
raise TypeError("expected None, int, viz.Node or ns.network.Node, not %r" % node)
raise TypeError("expected None, int, viz.Node or ns.Node, not %r" % node)
if node is self.selected_node:
return
@@ -1795,7 +1794,7 @@ class Visualizer(GObject.GObject):
surface.finish()
def set_follow_node(self, node):
if isinstance(node, ns.network.Node):
if isinstance(node, ns.Node):
node = self.nodes[node.GetId()]
self.follow_node = node
@@ -1856,11 +1855,11 @@ def start():
import sys
print("No visualization support (%s)." % (str(_import_error),),
file=sys.stderr)
ns.core.Simulator.Run()
ns.Simulator.Run()
return
load_plugins()
viz = Visualizer()
for hook, args in initialization_hooks:
GLib.idle_add(hook, viz, *args)
ns.network.Packet.EnablePrinting()
ns.Packet.EnablePrinting()
viz.start()

View File

@@ -1,6 +1,4 @@
from gi.repository import Gtk
import ns.core
import ns.network
from visualizer.base import InformationWindow
NODE_STATISTICS_MEMORY = 10
@@ -182,13 +180,13 @@ class ShowInterfaceStatistics(InformationWindow):
@param self this object
@return none
"""
node = ns.network.NodeList.GetNode(self.node_index)
node = ns.NodeList.GetNode(self.node_index)
stats_list = self.statistics_collector.get_interface_statistics(self.node_index)
self.table_model.clear()
for iface, stats in enumerate(stats_list):
tree_iter = self.table_model.append()
netdevice = node.GetDevice(iface)
interface_name = ns.core.Names.FindName(netdevice)
interface_name = ns.Names.FindName(netdevice)
if not interface_name:
interface_name = "(interface %i)" % iface
self.table_model.set(tree_iter,

View File

@@ -1,9 +1,5 @@
from gi.repository import Gtk
import ns.core
import ns.network
import ns.internet
from visualizer.base import InformationWindow
## ShowIpv4RoutingTable class
@@ -97,23 +93,23 @@ class ShowIpv4RoutingTable(InformationWindow):
@param self this object
@return none
"""
node = ns.network.NodeList.GetNode(self.node_index)
ipv4 = node.GetObject(ns.internet.Ipv4.GetTypeId())
node = ns.NodeList.GetNode(self.node_index)
ipv4 = ns.cppyy.gbl.getNodeIpv4(node)
routing = ipv4.GetRoutingProtocol()
if routing is None:
return
routing_protocols = [] # list of (protocol, type_string, priority)
if isinstance(routing, ns.internet.Ipv4StaticRouting):
if isinstance(routing, ns.Ipv4StaticRouting):
ipv4_routing = routing_protocols.append((routing, "static", 0))
elif isinstance(routing, ns.internet.Ipv4ListRouting):
elif isinstance(routing, ns.Ipv4ListRouting):
list_routing = routing
for rI in range(list_routing.GetNRoutingProtocols()):
routing, prio = list_routing.GetRoutingProtocol(rI)
if isinstance(routing, ns.internet.Ipv4StaticRouting):
if isinstance(routing, ns.Ipv4StaticRouting):
routing_protocols.append((routing, "static", prio))
elif isinstance(routing, ns.internet.Ipv4GlobalRouting):
elif isinstance(routing, ns.Ipv4GlobalRouting):
routing_protocols.append((routing, "global", prio))
if not routing_protocols:
return
@@ -127,7 +123,7 @@ class ShowIpv4RoutingTable(InformationWindow):
if netdevice is None:
interface_name = 'lo'
else:
interface_name = ns.core.Names.FindName(netdevice)
interface_name = ns.Names.FindName(netdevice)
if not interface_name:
interface_name = "(interface %i)" % route.GetInterface()
self.table_model.set(tree_iter,

View File

@@ -2,11 +2,6 @@ from __future__ import print_function
from gi.repository import Gtk
from gi.repository import Gdk
import ns.core
import ns.network
import ns.internet
import ns.olsr
from visualizer.base import InformationWindow
## ShowOlsrRoutingTable class
@@ -94,11 +89,12 @@ class ShowOlsrRoutingTable(InformationWindow):
@param self this object
@return none
"""
node = ns.network.NodeList.GetNode(self.node_index)
olsr = node.GetObject(ns.olsr.olsr.RoutingProtocol.GetTypeId())
ipv4 = node.GetObject(ns.internet.Ipv4.GetTypeId())
if olsr is None:
node = ns.NodeList.GetNode(self.node_index)
ipv4 = node.GetObject(ns.Ipv4.GetTypeId())
if not ns.cppyy.gbl.hasOlsr(ns3_node):
return
olsr = ns.cppyy.gbl.getNodeOlsr(node)
self.table_model.clear()
for route in olsr.GetRoutingTableEntries():
tree_iter = self.table_model.append()
@@ -106,7 +102,7 @@ class ShowOlsrRoutingTable(InformationWindow):
if netdevice is None:
interface_name = 'lo'
else:
interface_name = ns.core.Names.FindName(netdevice)
interface_name = ns.Names.FindName(netdevice)
if not interface_name:
interface_name = "(interface %i)" % route.interface
self.table_model.set(tree_iter,
@@ -117,9 +113,8 @@ class ShowOlsrRoutingTable(InformationWindow):
def populate_node_menu(viz, node, menu):
ns3_node = ns.network.NodeList.GetNode(node.node_index)
olsr = ns3_node.GetObject(ns.olsr.olsr.RoutingProtocol.GetTypeId())
if olsr is None:
ns3_node = ns.NodeList.GetNode(node.node_index)
if not ns.cppyy.gbl.hasOlsr(ns3_node):
print("No OLSR")
return

View File

@@ -1,9 +1,7 @@
from gi.repository import GObject
from gi.repository import Gtk
import ns.core
import ns.network
import ns.visualizer
from ns import ns
from visualizer.base import InformationWindow
from kiwi.ui.objectlist import ObjectList, Column

View File

@@ -1,6 +1,5 @@
import math
import ns.wifi
import ns.network
from ns import ns
from gi.repository import GooCanvas
from visualizer.base import Link, transform_distance_canvas_to_simulation

View File

@@ -19,13 +19,8 @@
# Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
import unittest
from ns.core import Simulator, Seconds, Config, int64x64_t
import ns.core
import ns.network
import ns.internet
import ns.mobility
import ns.csma
import ns.applications
from ns import ns
import sys
UINT32_MAX = 0xFFFFFFFF
@@ -46,19 +41,27 @@ class TestSimulator(unittest.TestCase):
@param self this object
@return none
"""
def callback(args):
def callback(args: ns.cppyy.gbl.std.vector) -> None:
"""! Callback function
@param args arguments
return none
"""
self._args_received = args
self._cb_time = Simulator.Now()
Simulator.Destroy()
import copy
self._args_received = list(map(lambda x: x.decode("utf-8"), args))
self._cb_time = ns.Simulator.Now()
ns.Simulator.Destroy()
self._args_received = None
self._cb_time = None
Simulator.ScheduleNow(callback, "args")
Simulator.Run()
self.assertEqual(self._args_received, "args")
ns.cppyy.cppdef("""
EventImpl* pythonMakeEvent(void (*f)(std::vector<std::string>), std::vector<std::string> l)
{
return MakeEvent(f, l);
}
""")
event = ns.cppyy.gbl.pythonMakeEvent(callback, sys.argv)
ns.Simulator.ScheduleNow(event)
ns.Simulator.Run()
self.assertListEqual(self._args_received, sys.argv)
self.assertEqual(self._cb_time.GetSeconds(), 0.0)
def testSchedule(self):
@@ -66,19 +69,26 @@ class TestSimulator(unittest.TestCase):
@param self this object
@return none
"""
def callback(args):
def callback(args: ns.cppyy.gbl.std.vector):
"""! Callback function
@param args arguments
@return none
"""
self._args_received = args
self._cb_time = Simulator.Now()
Simulator.Destroy()
self._args_received = list(map(lambda x: x.decode("utf-8"), args))
self._cb_time = ns.Simulator.Now()
ns.Simulator.Destroy()
self._args_received = None
self._cb_time = None
Simulator.Schedule(Seconds(123), callback, "args")
Simulator.Run()
self.assertEqual(self._args_received, "args")
ns.cppyy.cppdef("""
EventImpl* pythonMakeEvent2(void (*f)(std::vector<std::string>), std::vector<std::string> l)
{
return MakeEvent(f, l);
}
""")
event = ns.cppyy.gbl.pythonMakeEvent2(callback, sys.argv)
ns.Simulator.Schedule(ns.Seconds(123), event)
ns.Simulator.Run()
self.assertListEqual(self._args_received, sys.argv)
self.assertEqual(self._cb_time.GetSeconds(), 123.0)
def testScheduleDestroy(self):
@@ -86,22 +96,29 @@ class TestSimulator(unittest.TestCase):
@param self this object
@return none
"""
def callback(args):
def callback(args: ns.cppyy.gbl.std.vector):
"""! Callback function
@param args
@return none
"""
self._args_received = args
self._cb_time = Simulator.Now()
Simulator.Destroy()
self._args_received = list(map(lambda x: x.decode("utf-8"), args))
self._cb_time = ns.Simulator.Now()
ns.Simulator.Destroy()
self._args_received = None
self._cb_time = None
def null(): pass
Simulator.Schedule(Seconds(123), null)
Simulator.ScheduleDestroy(callback, "args")
Simulator.Run()
Simulator.Destroy()
self.assertEqual(self._args_received, "args")
ns.cppyy.cppdef("void null(){ return; }")
ns.Simulator.Schedule(ns.Seconds(123), ns.cppyy.gbl.null)
ns.cppyy.cppdef("""
EventImpl* pythonMakeEvent3(void (*f)(std::vector<std::string>), std::vector<std::string> l)
{
return MakeEvent(f, l);
}
""")
event = ns.cppyy.gbl.pythonMakeEvent3(callback, sys.argv)
ns.Simulator.ScheduleDestroy(event)
ns.Simulator.Run()
ns.Simulator.Destroy()
self.assertListEqual(self._args_received, sys.argv)
self.assertEqual(self._cb_time.GetSeconds(), 123.0)
def testScheduleWithContext(self):
@@ -109,23 +126,30 @@ class TestSimulator(unittest.TestCase):
@param self this object
@return none
"""
def callback(context, args):
def callback(context, args: ns.cppyy.gbl.std.vector):
"""! Callback
@param context the cntet
@param args the arguments
@return none
"""
self._context_received = context
self._args_received = args
self._cb_time = Simulator.Now()
Simulator.Destroy()
self._args_received = list(map(lambda x: x.decode("utf-8"), args))
self._cb_time = ns.Simulator.Now()
ns.Simulator.Destroy()
self._args_received = None
self._cb_time = None
self._context_received = None
Simulator.ScheduleWithContext(54321, Seconds(123), callback, "args")
Simulator.Run()
ns.cppyy.cppdef("""
EventImpl* pythonMakeEvent4(void (*f)(uint32_t, std::vector<std::string>), uint32_t context, std::vector<std::string> l)
{
return MakeEvent(f, context, l);
}
""")
event = ns.cppyy.gbl.pythonMakeEvent4(callback, 54321, sys.argv)
ns.Simulator.ScheduleWithContext(54321, ns.Seconds(123), event)
ns.Simulator.Run()
self.assertEqual(self._context_received, 54321)
self.assertEqual(self._args_received, "args")
self.assertListEqual(self._args_received, sys.argv)
self.assertEqual(self._cb_time.GetSeconds(), 123.0)
def testTimeComparison(self):
@@ -133,29 +157,29 @@ class TestSimulator(unittest.TestCase):
@param self this object
@return none
"""
self.assertTrue(Seconds(123) == Seconds(123))
self.assertTrue(Seconds(123) >= Seconds(123))
self.assertTrue(Seconds(123) <= Seconds(123))
self.assertTrue(Seconds(124) > Seconds(123))
self.assertTrue(Seconds(123) < Seconds(124))
self.assertTrue(ns.Seconds(123) == ns.Seconds(123))
self.assertTrue(ns.Seconds(123) >= ns.Seconds(123))
self.assertTrue(ns.Seconds(123) <= ns.Seconds(123))
self.assertTrue(ns.Seconds(124) > ns.Seconds(123))
self.assertTrue(ns.Seconds(123) < ns.Seconds(124))
def testTimeNumericOperations(self):
"""! Test numeric operations
@param self this object
@return none
"""
self.assertEqual(Seconds(10) + Seconds(5), Seconds(15))
self.assertEqual(Seconds(10) - Seconds(5), Seconds(5))
self.assertEqual(ns.Seconds(10) + ns.Seconds(5), ns.Seconds(15))
self.assertEqual(ns.Seconds(10) - ns.Seconds(5), ns.Seconds(5))
v1 = int64x64_t(5.0)*int64x64_t(10)
self.assertEqual(v1, int64x64_t(50))
v1 = ns.int64x64_t(5.0)*ns.int64x64_t(10)
self.assertEqual(v1, ns.int64x64_t(50))
def testConfig(self):
"""! Test configuration
@param self this object
@return none
"""
Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.core.UintegerValue(123))
ns.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.core.UintegerValue(123))
# hm.. no Config.Get?
def testSocket(self):
@@ -163,27 +187,30 @@ class TestSimulator(unittest.TestCase):
@param self
@return none
"""
node = ns.network.Node()
internet = ns.internet.InternetStackHelper()
nc = ns.NodeContainer(1)
node = nc.Get(0)
internet = ns.CreateObject("InternetStackHelper")
internet.Install(node)
self._received_packet = None
def rx_callback(socket):
"""! Receive Callback
@param socket the socket to receive
@return none
"""
assert self._received_packet is None
def python_rx_callback(socket) -> None:
self._received_packet = socket.Recv(maxSize=UINT32_MAX, flags=0)
ns.cppyy.cppdef("""
Callback<void,ns3::Ptr<ns3::Socket> > make_rx_callback(void(*func)(Ptr<Socket>))
{
return MakeCallback(func);
}
""")
sink = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
sink.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80))
sink.SetRecvCallback(rx_callback)
sink.Bind(ns.addressFromInetSocketAddress(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80)))
sink.SetRecvCallback(ns.cppyy.gbl.make_rx_callback(python_rx_callback))
source = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
source.SendTo(ns.network.Packet(19), 0, ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80))
source.SendTo(ns.network.Packet(19), 0, ns.addressFromInetSocketAddress(ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80)))
Simulator.Run()
ns.Simulator.Run()
self.assertTrue(self._received_packet is not None)
self.assertEqual(self._received_packet.GetSize(), 19)
@@ -194,7 +221,7 @@ class TestSimulator(unittest.TestCase):
@return none
"""
# Templated class DropTailQueue<Packet> in C++
queue = ns.network.DropTailQueue__Ns3Packet()
queue = ns.CreateObject("DropTailQueue<Packet>")
queueSizeValue = ns.network.QueueSizeValue (ns.network.QueueSize ("500p"))
queue.SetAttribute("MaxSize", queueSizeValue)
@@ -203,66 +230,69 @@ class TestSimulator(unittest.TestCase):
self.assertEqual(limit.Get(), ns.network.QueueSize ("500p"))
## -- object pointer values
mobility = ns.mobility.RandomWaypointMobilityModel()
ptr = ns.core.PointerValue()
mobility = ns.CreateObject("RandomWaypointMobilityModel")
ptr = ns.CreateObject("PointerValue")
mobility.GetAttribute("PositionAllocator", ptr)
self.assertEqual(ptr.GetObject(), None)
self.assertEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr))
pos = ns.mobility.ListPositionAllocator()
mobility.SetAttribute("PositionAllocator", ns.core.PointerValue(pos))
ptr.SetObject(pos)
mobility.SetAttribute("PositionAllocator", ptr)
ptr = ns.core.PointerValue()
mobility.GetAttribute("PositionAllocator", ptr)
self.assertTrue(ptr.GetObject() is not None)
ptr2 = ns.CreateObject("PointerValue")
mobility.GetAttribute("PositionAllocator", ptr2)
self.assertNotEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr))
def testIdentity(self):
"""! Test identify
@param self this object
@return none
"""
csma = ns.csma.CsmaNetDevice()
channel = ns.csma.CsmaChannel()
csma = ns.CreateObject("CsmaNetDevice")
channel = ns.CreateObject("CsmaChannel")
csma.Attach(channel)
c1 = csma.GetChannel()
c2 = csma.GetChannel()
self.assertTrue(c1 is c2)
self.assertEqual(c1, c2)
def testTypeId(self):
"""! Test type ID
@param self this object
@return none
"""
typeId1 = ns.core.TypeId.LookupByNameFailSafe("ns3::UdpSocketFactory")
ok, typeId1 = ns.LookupByNameFailSafe("ns3::UdpSocketFactory")
self.assertTrue(ok)
self.assertEqual(typeId1.GetName (), "ns3::UdpSocketFactory")
self.assertRaises(KeyError, ns.core.TypeId.LookupByNameFailSafe, "__InvalidTypeName__")
ok, typeId1 = ns.LookupByNameFailSafe("ns3::__InvalidTypeName__")
self.assertFalse(ok)
def testCommandLine(self):
"""! Test command line
@param self this object
@return none
"""
cmd = ns.core.CommandLine()
cmd.AddValue("Test1", "this is a test option")
cmd.AddValue("Test2", "this is a test option")
cmd.AddValue("Test3", "this is a test option", variable="test_xxx")
cmd.Test1 = None
cmd.Test2 = None
cmd.test_xxx = None
class Foo:
pass
foo = Foo()
foo.test_foo = None
cmd.AddValue("Test4", "this is a test option", variable="test_foo", namespace=foo)
cmd.Parse(["python", "--Test1=value1", "--Test2=value2", "--Test3=123", "--Test4=xpto"])
self.assertEqual(cmd.Test1, "value1")
self.assertEqual(cmd.Test2, "value2")
self.assertEqual(cmd.test_xxx, "123")
self.assertEqual(foo.test_foo, "xpto")
# def testCommandLine(self):
# """! Test command line
# @param self this object
# @return none
# """
# cmd = ns.core.CommandLine(__file__)
# cmd.AddValue("Test1", "this is a test option")
# cmd.AddValue("Test2", "this is a test option")
# cmd.AddValue("Test3", "this is a test option", variable="test_xxx")
# cmd.Test1 = None
# cmd.Test2 = None
# cmd.test_xxx = None
# class Foo:
# pass
# foo = Foo()
# foo.test_foo = None
# cmd.AddValue("Test4", "this is a test option", variable="test_foo", namespace=foo)
#
# cmd.Parse(["python", "--Test1=value1", "--Test2=value2", "--Test3=123", "--Test4=xpto"])
#
# self.assertEqual(cmd.Test1, "value1")
# self.assertEqual(cmd.Test2, "value2")
# self.assertEqual(cmd.test_xxx, "123")
# self.assertEqual(foo.test_foo, "xpto")
def testSubclass(self):
"""! Test subclass
@@ -271,15 +301,14 @@ class TestSimulator(unittest.TestCase):
"""
## MyNode class
class MyNode(ns.network.Node):
def __init__(self):
"""! Initializer
@param self this object
@return none
"""
super(MyNode, self).__init__()
def GetLocalTime(self) -> ns.Time:
return ns.Seconds(10)
node = MyNode()
forced_local_time = node.GetLocalTime()
self.assertEqual(forced_local_time, ns.Seconds(10))
del node
if __name__ == '__main__':
unittest.main()
unittest.main(verbosity=1, failfast=True)