<commit_before>#include "unittest.hpp"
#include "rice/Class.hpp"
#include "rice/Constructor.hpp"
#include "rice/protect.hpp"
#include "rice/Exception.hpp"
#include "rice/Array.hpp"
#include "rice/String.hpp"
#include "rice/Symbol.hpp"
#include <iostream>

using namespace Rice;

TESTSUITE(Class);

SETUP(Class)
{
  ruby_init();
}

TESTCASE(construct)
{
  Class c(rb_cObject);
  ASSERT_EQUAL(rb_cObject, c.value());
}

TESTCASE(undef_creation_funcs)
{
  Class c(anonymous_class());
  Class & c2(c.undef_creation_funcs());
  ASSERT_EQUAL(&c, &c2);
  ASSERT_EXCEPTION_CHECK(
      Exception,
      c.call("new"),
      ASSERT_EQUAL(
          Object(rb_eTypeError), // TODO: 1.6.x?
          Object(CLASS_OF(ex.value()))
          )
      );
}

TESTCASE(include_module)
{
  Class c(anonymous_class());
  Class & c2(c.include_module(rb_mEnumerable));
  ASSERT_EQUAL(&c, &c2);
  Array ancestors(c.ancestors());
  Array expected_ancestors;
  expected_ancestors.push(c);
  expected_ancestors.push(Module(rb_mEnumerable));
  expected_ancestors.push(Module(rb_cObject));
  expected_ancestors.push(Module(rb_mKernel));
  ASSERT_EQUAL(expected_ancestors, ancestors);
}

TESTCASE(const_set_get_by_id)
{
  Class c(anonymous_class());
  Object v = to_ruby(42);
  Class & c2(c.const_set(rb_intern("FOO"), v));
  ASSERT_EQUAL(&c, &c2);
  ASSERT_EQUAL(v, c.const_get(rb_intern("FOO")));
}

TESTCASE(const_set_get_by_identifier)
{
  Class c(anonymous_class());
  Object v = to_ruby(42);
  Class & c2(c.const_set(Identifier("FOO"), v));
  ASSERT_EQUAL(&c, &c2);
  ASSERT_EQUAL(v, c.const_get(Identifier("FOO")));
}

TESTCASE(const_set_get_by_string)
{
  Class c(anonymous_class());
  Object v = to_ruby(42);
  Class & c2(c.const_set("FOO", v));
  ASSERT_EQUAL(&c, &c2);
  ASSERT_EQUAL(v, c.const_get("FOO"));
}

namespace
{

bool define_method_simple_ok;

void define_method_simple_helper(Object o)
{
  define_method_simple_ok = true;
}

} // namespace

TESTCASE(define_method_simple)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_simple_helper);
  Object o = c.call("new");
  define_method_simple_ok = false;
  o.call("foo");
  ASSERT(define_method_simple_ok);
}

TESTCASE(define_singleton_method_simple)
{
  Class c(anonymous_class());
  c.define_singleton_method("foo", &define_method_simple_helper);
  define_method_simple_ok = false;
  Object o = c.call("foo");
  ASSERT(define_method_simple_ok);
}

TESTCASE(define_module_function_simple)
{
  // module_function only works with Module, not Class
  Class c(anonymous_class());
  ASSERT_EXCEPTION_CHECK(
      Exception,
      c.define_module_function("foo", &define_method_simple_helper),
      ASSERT_EQUAL(
          Object(rb_eNoMethodError), // TODO: 1.6.x?
          Object(CLASS_OF(ex.value()))
          )
      );
}

namespace
{

int define_method_int_result;

void define_method_int_helper(Object o, int i)
{
  define_method_int_result = i;
}

} // namespace

TESTCASE(define_method_int)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_int_helper);
  Object o = c.call("new");
  define_method_int_result = 0;
  o.call("foo", 42);
  ASSERT_EQUAL(42, define_method_int_result);
}

TESTCASE(define_method_int_passed_two_args)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_int_helper);
  Object o = c.call("new");
  ASSERT_EXCEPTION_CHECK(
      Exception,
      o.call("foo", 1, 2),
      ASSERT_EQUAL(
          Object(rb_eArgError),
          Object(CLASS_OF(ex.value()))
          )
      );
}

TESTCASE(define_method_int_passed_no_args)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_int_helper);
  Object o = c.call("new");
  ASSERT_EXCEPTION_CHECK(
      Exception,
      o.call("foo"),
      ASSERT_EQUAL(
          Object(rb_eArgError),
          Object(CLASS_OF(ex.value()))
          )
      );
}

namespace
{

struct Foo
{
  int x;
};

int define_method_int_foo_result_i;
Foo * define_method_int_foo_result_x;

void define_method_int_foo_helper(Object o, int i, Foo * x)
{
  define_method_int_foo_result_i = i;
  define_method_int_foo_result_x = x;
}

} // namespace

template<>
Foo * from_ruby<Foo *>(Object x)
{
  Foo * retval;
  Data_Get_Struct(x.value(), Foo, retval);
  return retval;
}

TESTCASE(define_method_int_foo)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_int_foo_helper);
  Object o = c.call("new");
  define_method_int_result = 0;
  Foo * foo = new Foo;
  foo->x = 1024;
  VALUE f = Data_Wrap_Struct(rb_cObject, 0, Default_Allocation_Strategy<Foo>::free, foo);
  o.call("foo", 42, Object(f));
  ASSERT_EQUAL(42, define_method_int_foo_result_i);
  ASSERT_EQUAL(foo, define_method_int_foo_result_x);
}

namespace
{

class Silly_Exception
  : public std::exception
{
};

void handle_silly_exception(Silly_Exception const & ex)
{
  throw Exception(rb_eRuntimeError, "SILLY");
}

void throw_silly_exception(Object self)
{
  throw Silly_Exception();
}

}

TESTCASE(add_handler)
{
  Class c(rb_cObject);
  c.add_handler<Silly_Exception>(handle_silly_exception);
  c.define_method("foo", throw_silly_exception);
  Object exc = protect(rb_eval_string, "begin; foo; rescue Exception; $!; end");
  ASSERT_EQUAL(rb_eRuntimeError, CLASS_OF(exc));
  Exception ex(exc);
  ASSERT_EQUAL(String("SILLY"), String(ex.message()));
}

namespace
{

class Container
{
public:
  Container(int * array, size_t length)
    : array_(array)
    , length_(length)
  {
  }

  int * begin() { return array_; }
  int * end() { return array_ + length_; }

private:
  int * array_;
  size_t length_;
};

} // namespace

template<>
Container * from_ruby<Container *>(Object x)
{
  Container * retval;
  Data_Get_Struct(x.value(), Container, retval);
  return retval;
}

TESTCASE(define_iterator)
{
  int array[] = { 1, 2, 3 };
  Class c(anonymous_class());
  c.define_iterator(&Container::begin, &Container::end);
  Container * container = new Container(array, 3);
  Object wrapped_container = Data_Wrap_Struct(
      c, 0, Default_Allocation_Strategy<Container>::free, container);
  Array a = wrapped_container.instance_eval("a = []; each() { |x| a << x }; a");
  ASSERT_EQUAL(3u, a.size());
  ASSERT_EQUAL(to_ruby(1), Object(a[0]));
  ASSERT_EQUAL(to_ruby(2), Object(a[1]));
  ASSERT_EQUAL(to_ruby(3), Object(a[2]));
}

TESTCASE(define_class)
{
  Class object(rb_cObject);
  if(object.const_defined("Foo"))
  {
    object.remove_const("Foo");
  }

  Class c = define_class("Foo");

  ASSERT(c.is_a(rb_cClass));
  ASSERT_EQUAL(c, object.const_get("Foo"));
}

TESTCASE(define_class_under)
{
  Class object(rb_cObject);
  if(object.const_defined("Foo"))
  {
    object.remove_const("Foo");
  }

  Module math(rb_mMath);
  if(math.const_defined("Foo"))
  {
    math.remove_const("Foo");
  }

  Class c = define_class_under(math, "Foo");

  ASSERT(c.is_a(rb_cClass));
  ASSERT_EQUAL(c, math.const_get("Foo"));
  ASSERT(!object.const_defined("Foo"));
}

TESTCASE(module_define_class)
{
  Class object(rb_cObject);
  if(object.const_defined("Foo"))
  {
    object.remove_const("Foo");
  }

  Module math(rb_mMath);
  if(math.const_defined("Foo"))
  {
    math.remove_const("Foo");
  }

  Class c = math.define_class("Foo");

  ASSERT(c.is_a(rb_cClass));
  ASSERT_EQUAL(c, math.const_get("Foo"));
  ASSERT(!object.const_defined("Foo"));
}

namespace {
  class BaseClass {
    public:
      BaseClass() { }
  };
}

TESTCASE(subclassing)
{
  Module m = define_module("Testing");
  define_class_under<BaseClass>(m, "BaseClass").
    define_constructor(Constructor<BaseClass>());

  // Not sure how to make this a true failure case. If the subclassing
  // doesn't work, Ruby will throw an error:
  //
  //    in `new': wrong instance allocation
  //
  m.instance_eval("class NewClass < Testing::BaseClass; end;");
  m.instance_eval("n = NewClass.new");
}
<commit_msg>Expect BasicObject to be in the ancestors list on 1.9.<commit_after>#include "unittest.hpp"
#include "rice/Class.hpp"
#include "rice/Constructor.hpp"
#include "rice/protect.hpp"
#include "rice/Exception.hpp"
#include "rice/Array.hpp"
#include "rice/String.hpp"
#include "rice/Symbol.hpp"
#include <iostream>

using namespace Rice;

TESTSUITE(Class);

SETUP(Class)
{
  ruby_init();
}

TESTCASE(construct)
{
  Class c(rb_cObject);
  ASSERT_EQUAL(rb_cObject, c.value());
}

TESTCASE(undef_creation_funcs)
{
  Class c(anonymous_class());
  Class & c2(c.undef_creation_funcs());
  ASSERT_EQUAL(&c, &c2);
  ASSERT_EXCEPTION_CHECK(
      Exception,
      c.call("new"),
      ASSERT_EQUAL(
          Object(rb_eTypeError), // TODO: 1.6.x?
          Object(CLASS_OF(ex.value()))
          )
      );
}

TESTCASE(include_module)
{
  Class c(anonymous_class());
  Class & c2(c.include_module(rb_mEnumerable));
  ASSERT_EQUAL(&c, &c2);
  Array ancestors(c.ancestors());
  Array expected_ancestors;
  expected_ancestors.push(c);
  expected_ancestors.push(Module(rb_mEnumerable));
  expected_ancestors.push(Module(rb_cObject));
  expected_ancestors.push(Module(rb_mKernel));
#ifdef RUBY_VM
  expected_ancestors.push(Module(rb_cBasicObject));
#endif
  ASSERT_EQUAL(expected_ancestors, ancestors);
}

TESTCASE(const_set_get_by_id)
{
  Class c(anonymous_class());
  Object v = to_ruby(42);
  Class & c2(c.const_set(rb_intern("FOO"), v));
  ASSERT_EQUAL(&c, &c2);
  ASSERT_EQUAL(v, c.const_get(rb_intern("FOO")));
}

TESTCASE(const_set_get_by_identifier)
{
  Class c(anonymous_class());
  Object v = to_ruby(42);
  Class & c2(c.const_set(Identifier("FOO"), v));
  ASSERT_EQUAL(&c, &c2);
  ASSERT_EQUAL(v, c.const_get(Identifier("FOO")));
}

TESTCASE(const_set_get_by_string)
{
  Class c(anonymous_class());
  Object v = to_ruby(42);
  Class & c2(c.const_set("FOO", v));
  ASSERT_EQUAL(&c, &c2);
  ASSERT_EQUAL(v, c.const_get("FOO"));
}

namespace
{

bool define_method_simple_ok;

void define_method_simple_helper(Object o)
{
  define_method_simple_ok = true;
}

} // namespace

TESTCASE(define_method_simple)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_simple_helper);
  Object o = c.call("new");
  define_method_simple_ok = false;
  o.call("foo");
  ASSERT(define_method_simple_ok);
}

TESTCASE(define_singleton_method_simple)
{
  Class c(anonymous_class());
  c.define_singleton_method("foo", &define_method_simple_helper);
  define_method_simple_ok = false;
  Object o = c.call("foo");
  ASSERT(define_method_simple_ok);
}

TESTCASE(define_module_function_simple)
{
  // module_function only works with Module, not Class
  Class c(anonymous_class());
  ASSERT_EXCEPTION_CHECK(
      Exception,
      c.define_module_function("foo", &define_method_simple_helper),
      ASSERT_EQUAL(
          Object(rb_eNoMethodError), // TODO: 1.6.x?
          Object(CLASS_OF(ex.value()))
          )
      );
}

namespace
{

int define_method_int_result;

void define_method_int_helper(Object o, int i)
{
  define_method_int_result = i;
}

} // namespace

TESTCASE(define_method_int)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_int_helper);
  Object o = c.call("new");
  define_method_int_result = 0;
  o.call("foo", 42);
  ASSERT_EQUAL(42, define_method_int_result);
}

TESTCASE(define_method_int_passed_two_args)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_int_helper);
  Object o = c.call("new");
  ASSERT_EXCEPTION_CHECK(
      Exception,
      o.call("foo", 1, 2),
      ASSERT_EQUAL(
          Object(rb_eArgError),
          Object(CLASS_OF(ex.value()))
          )
      );
}

TESTCASE(define_method_int_passed_no_args)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_int_helper);
  Object o = c.call("new");
  ASSERT_EXCEPTION_CHECK(
      Exception,
      o.call("foo"),
      ASSERT_EQUAL(
          Object(rb_eArgError),
          Object(CLASS_OF(ex.value()))
          )
      );
}

namespace
{

struct Foo
{
  int x;
};

int define_method_int_foo_result_i;
Foo * define_method_int_foo_result_x;

void define_method_int_foo_helper(Object o, int i, Foo * x)
{
  define_method_int_foo_result_i = i;
  define_method_int_foo_result_x = x;
}

} // namespace

template<>
Foo * from_ruby<Foo *>(Object x)
{
  Foo * retval;
  Data_Get_Struct(x.value(), Foo, retval);
  return retval;
}

TESTCASE(define_method_int_foo)
{
  Class c(anonymous_class());
  c.define_method("foo", &define_method_int_foo_helper);
  Object o = c.call("new");
  define_method_int_result = 0;
  Foo * foo = new Foo;
  foo->x = 1024;
  VALUE f = Data_Wrap_Struct(rb_cObject, 0, Default_Allocation_Strategy<Foo>::free, foo);
  o.call("foo", 42, Object(f));
  ASSERT_EQUAL(42, define_method_int_foo_result_i);
  ASSERT_EQUAL(foo, define_method_int_foo_result_x);
}

namespace
{

class Silly_Exception
  : public std::exception
{
};

void handle_silly_exception(Silly_Exception const & ex)
{
  throw Exception(rb_eRuntimeError, "SILLY");
}

void throw_silly_exception(Object self)
{
  throw Silly_Exception();
}

}

TESTCASE(add_handler)
{
  Class c(rb_cObject);
  c.add_handler<Silly_Exception>(handle_silly_exception);
  c.define_method("foo", throw_silly_exception);
  Object exc = protect(rb_eval_string, "begin; foo; rescue Exception; $!; end");
  ASSERT_EQUAL(rb_eRuntimeError, CLASS_OF(exc));
  Exception ex(exc);
  ASSERT_EQUAL(String("SILLY"), String(ex.message()));
}

namespace
{

class Container
{
public:
  Container(int * array, size_t length)
    : array_(array)
    , length_(length)
  {
  }

  int * begin() { return array_; }
  int * end() { return array_ + length_; }

private:
  int * array_;
  size_t length_;
};

} // namespace

template<>
Container * from_ruby<Container *>(Object x)
{
  Container * retval;
  Data_Get_Struct(x.value(), Container, retval);
  return retval;
}

TESTCASE(define_iterator)
{
  int array[] = { 1, 2, 3 };
  Class c(anonymous_class());
  c.define_iterator(&Container::begin, &Container::end);
  Container * container = new Container(array, 3);
  Object wrapped_container = Data_Wrap_Struct(
      c, 0, Default_Allocation_Strategy<Container>::free, container);
  Array a = wrapped_container.instance_eval("a = []; each() { |x| a << x }; a");
  ASSERT_EQUAL(3u, a.size());
  ASSERT_EQUAL(to_ruby(1), Object(a[0]));
  ASSERT_EQUAL(to_ruby(2), Object(a[1]));
  ASSERT_EQUAL(to_ruby(3), Object(a[2]));
}

TESTCASE(define_class)
{
  Class object(rb_cObject);
  if(object.const_defined("Foo"))
  {
    object.remove_const("Foo");
  }

  Class c = define_class("Foo");

  ASSERT(c.is_a(rb_cClass));
  ASSERT_EQUAL(c, object.const_get("Foo"));
}

TESTCASE(define_class_under)
{
  Class object(rb_cObject);
  if(object.const_defined("Foo"))
  {
    object.remove_const("Foo");
  }

  Module math(rb_mMath);
  if(math.const_defined("Foo"))
  {
    math.remove_const("Foo");
  }

  Class c = define_class_under(math, "Foo");

  ASSERT(c.is_a(rb_cClass));
  ASSERT_EQUAL(c, math.const_get("Foo"));
  ASSERT(!object.const_defined("Foo"));
}

TESTCASE(module_define_class)
{
  Class object(rb_cObject);
  if(object.const_defined("Foo"))
  {
    object.remove_const("Foo");
  }

  Module math(rb_mMath);
  if(math.const_defined("Foo"))
  {
    math.remove_const("Foo");
  }

  Class c = math.define_class("Foo");

  ASSERT(c.is_a(rb_cClass));
  ASSERT_EQUAL(c, math.const_get("Foo"));
  ASSERT(!object.const_defined("Foo"));
}

namespace {
  class BaseClass {
    public:
      BaseClass() { }
  };
}

TESTCASE(subclassing)
{
  Module m = define_module("Testing");
  define_class_under<BaseClass>(m, "BaseClass").
    define_constructor(Constructor<BaseClass>());

  // Not sure how to make this a true failure case. If the subclassing
  // doesn't work, Ruby will throw an error:
  //
  //    in `new': wrong instance allocation
  //
  m.instance_eval("class NewClass < Testing::BaseClass; end;");
  m.instance_eval("n = NewClass.new");
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "FontHostConfiguration_android.h"
#include "SkString.h"
#include "SkTDArray.h"
#include <expat.h>
#include <sys/system_properties.h>

#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"

// These defines are used to determine the kind of tag that we're currently
// populating with data. We only care about the sibling tags nameset and fileset
// for now.
#define NO_TAG 0
#define NAMESET_TAG 1
#define FILESET_TAG 2

/**
 * The FamilyData structure is passed around by the parser so that each handler
 * can read these variables that are relevant to the current parsing.
 */
struct FamilyData {
    FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) :
            parser(parserRef), families(familiesRef), currentTag(NO_TAG) {};

    XML_Parser *parser;                // The expat parser doing the work
    SkTDArray<FontFamily*> &families;  // The array that each family is put into as it is parsed
    FontFamily *currentFamily;         // The current family being created
    int currentTag;                    // A flag to indicate whether we're in nameset/fileset tags
};

/**
 * Handler for arbitrary text. This is used to parse the text inside each name
 * or file tag. The resulting strings are put into the fNames or fFileNames arrays.
 */
void textHandler(void *data, const char *s, int len) {
    FamilyData *familyData = (FamilyData*) data;
    // Make sure we're in the right state to store this name information
    if (familyData->currentFamily &&
            (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) {
        // Malloc new buffer to store the string
        char *buff;
        buff = (char*) malloc((len + 1) * sizeof(char));
        strncpy(buff, s, len);
        buff[len] = '\0';
        switch (familyData->currentTag) {
        case NAMESET_TAG:
            *(familyData->currentFamily->fNames.append()) = buff;
            break;
        case FILESET_TAG:
            *(familyData->currentFamily->fFileNames.append()) = buff;
            break;
        default:
            // Noop - don't care about any text that's not in the Fonts or Names list
            break;
        }
    }
}

/**
 * Handler for the start of a tag. The only tags we expect are family, nameset,
 * fileset, name, and file.
 */
void startElementHandler(void *data, const char *tag, const char **atts) {
    FamilyData *familyData = (FamilyData*) data;
    int len = strlen(tag);
    if (strncmp(tag, "family", len)== 0) {
        familyData->currentFamily = new FontFamily();
        familyData->currentFamily->order = -1;
        // The Family tag has an optional "order" attribute with an integer value >= 0
        // If this attribute does not exist, the default value is -1
        for (int i = 0; atts[i] != NULL; i += 2) {
            const char* attribute = atts[i];
            const char* valueString = atts[i+1];
            int value;
            int len = sscanf(valueString, "%d", &value);
            if (len > 0) {
                familyData->currentFamily->order = value;
            }
        }
    } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
        familyData->currentTag = NAMESET_TAG;
    } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
        familyData->currentTag = FILESET_TAG;
    } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
            (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
        // If it's a Name, parse the text inside
        XML_SetCharacterDataHandler(*familyData->parser, textHandler);
    }
}

/**
 * Handler for the end of tags. We only care about family, nameset, fileset,
 * name, and file.
 */
void endElementHandler(void *data, const char *tag) {
    FamilyData *familyData = (FamilyData*) data;
    int len = strlen(tag);
    if (strncmp(tag, "family", len)== 0) {
        // Done parsing a Family - store the created currentFamily in the families array
        *familyData->families.append() = familyData->currentFamily;
        familyData->currentFamily = NULL;
    } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
        familyData->currentTag = NO_TAG;
    } else if (len == 7 && strncmp(tag, "fileset", len)== 0) {
        familyData->currentTag = NO_TAG;
    } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
            (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
        // Disable the arbitrary text handler installed to load Name data
        XML_SetCharacterDataHandler(*familyData->parser, NULL);
    }
}

/**
 * Read the persistent locale.
 */
void getLocale(AndroidLocale &locale)
{
    char propLang[PROP_VALUE_MAX], propRegn[PROP_VALUE_MAX];
    __system_property_get("persist.sys.language", propLang);
    __system_property_get("persist.sys.country", propRegn);

    if (*propLang == 0 && *propRegn == 0) {
        /* Set to ro properties, default is en_US */
        __system_property_get("ro.product.locale.language", propLang);
        __system_property_get("ro.product.locale.region", propRegn);
        if (*propLang == 0 && *propRegn == 0) {
            strcpy(propLang, "en");
            strcpy(propRegn, "US");
        }
    }
    strncpy(locale.language, propLang, 2);
    locale.language[2] = '\0';
    strncpy(locale.region, propRegn, 2);
    locale.region[2] = '\0';
}

/**
 * Use the current system locale (language and region) to open the best matching
 * customization. For example, when the language is Japanese, the sequence might be:
 *      /system/etc/fallback_fonts-ja-JP.xml
 *      /system/etc/fallback_fonts-ja.xml
 *      /system/etc/fallback_fonts.xml
 */
FILE* openLocalizedFile(const char* origname) {
    FILE* file = 0;
    SkString basename;
    SkString filename;
    AndroidLocale locale;

    basename.set(origname);
    // Remove the .xml suffix. We'll add it back in a moment.
    if (basename.endsWith(".xml")) {
        basename.resize(basename.size()-4);
    }
    getLocale(locale);
    // Try first with language and region
    filename.printf("%s-%s-%s.xml", basename.c_str(), locale.language, locale.region);
    file = fopen(filename.c_str(), "r");
    if (!file) {
        // If not found, try next with just language
        filename.printf("%s-%s.xml", basename.c_str(), locale.language);
        file = fopen(filename.c_str(), "r");

        if (!file) {
            // If still not found, try just the original name
            file = fopen(origname, "r");
        }
    }
    return file;
}

/**
 * This function parses the given filename and stores the results in the given
 * families array.
 */
void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
    XML_Parser parser = XML_ParserCreate(NULL);
    FamilyData *familyData = new FamilyData(&parser, families);
    XML_SetUserData(parser, familyData);
    XML_SetElementHandler(parser, startElementHandler, endElementHandler);
    FILE *file = openLocalizedFile(filename);
    // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
    // are optional - failure here is okay because one of these optional files may not exist.
    if (file == NULL) {
        return;
    }
    char buffer[512];
    bool done = false;
    while (!done) {
        fgets(buffer, sizeof(buffer), file);
        int len = strlen(buffer);
        if (feof(file) != 0) {
            done = true;
        }
        XML_Parse(parser, buffer, len, done);
    }
}

void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
    parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies);
}

void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) {
    SkTDArray<FontFamily*> vendorFonts;
    parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts);
    parseConfigFile(VENDOR_FONTS_FILE, vendorFonts);

    // This loop inserts the vendor fallback fonts in the correct order in the
    // overall fallbacks list.
    int currentOrder = -1;
    for (int i = 0; i < vendorFonts.count(); ++i) {
        FontFamily* family = vendorFonts[i];
        int order = family->order;
        if (order < 0) {
            if (currentOrder < 0) {
                // Default case - just add it to the end of the fallback list
                *fallbackFonts.append() = family;
            } else {
                // no order specified on this font, but we're incrementing the order
                // based on an earlier order insertion request
                *fallbackFonts.insert(currentOrder++) = family;
            }
        } else {
            // Add the font into the fallback list in the specified order. Set
            // currentOrder for correct placement of other fonts in the vendor list.
            *fallbackFonts.insert(order) = family;
            currentOrder = order + 1;
        }
    }
}

/**
 * Loads data on font families from various expected configuration files. The
 * resulting data is returned in the given fontFamilies array.
 */
void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
    SkTDArray<FontFamily*> fallbackFonts;

    getSystemFontFamilies(fontFamilies);
    getFallbackFontFamilies(fallbackFonts);

    // Append all fallback fonts to system fonts
    for (int i = 0; i < fallbackFonts.count(); ++i) {
        *fontFamilies.append() = fallbackFonts[i];
    }
}

void getTestFontFamilies(SkTDArray<FontFamily*> &fontFamilies,
                         const char* testMainConfigFile,
                         const char* testFallbackConfigFile) {
    parseConfigFile(testMainConfigFile, fontFamilies);

    SkTDArray<FontFamily*> fallbackFonts;
    parseConfigFile(testFallbackConfigFile, fallbackFonts);

    // Append all fallback fonts to system fonts
    for (int i = 0; i < fallbackFonts.count(); ++i) {
        *fontFamilies.append() = fallbackFonts[i];
    }
}
<commit_msg>Fix Japanese font issue for devices running JB MR1 and higher.<commit_after>/*
 * Copyright 2011 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "FontHostConfiguration_android.h"
#include "SkString.h"
#include "SkTDArray.h"
#include <expat.h>
#include <sys/system_properties.h>

#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"

// These defines are used to determine the kind of tag that we're currently
// populating with data. We only care about the sibling tags nameset and fileset
// for now.
#define NO_TAG 0
#define NAMESET_TAG 1
#define FILESET_TAG 2

/**
 * The FamilyData structure is passed around by the parser so that each handler
 * can read these variables that are relevant to the current parsing.
 */
struct FamilyData {
    FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef, const AndroidLocale &localeRef) :
            parser(parserRef), families(familiesRef), currentTag(NO_TAG),
            locale(localeRef), currentFamilyLangMatch(false), familyLangMatchCount(0) {}

    XML_Parser *parser;                // The expat parser doing the work
    SkTDArray<FontFamily*> &families;  // The array that each family is put into as it is parsed
    FontFamily *currentFamily;         // The current family being created
    int currentTag;                    // A flag to indicate whether we're in nameset/fileset tags
    const AndroidLocale &locale;       // The locale to which we compare the "lang" attribute of File.
    bool currentFamilyLangMatch;       // If currentFamily's File has a "lang" attribute and matches locale.
    int familyLangMatchCount;          // Number of families containing File which has a "lang" attribute and matches locale.
};

/**
 * Handler for arbitrary text. This is used to parse the text inside each name
 * or file tag. The resulting strings are put into the fNames or fFileNames arrays.
 */
void textHandler(void *data, const char *s, int len) {
    FamilyData *familyData = (FamilyData*) data;
    // Make sure we're in the right state to store this name information
    if (familyData->currentFamily &&
            (familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) {
        // Malloc new buffer to store the string
        char *buff;
        buff = (char*) malloc((len + 1) * sizeof(char));
        strncpy(buff, s, len);
        buff[len] = '\0';
        switch (familyData->currentTag) {
        case NAMESET_TAG:
            *(familyData->currentFamily->fNames.append()) = buff;
            break;
        case FILESET_TAG:
            *(familyData->currentFamily->fFileNames.append()) = buff;
            break;
        default:
            // Noop - don't care about any text that's not in the Fonts or Names list
            break;
        }
    }
}

/**
 * Handler for the start of a tag. The only tags we expect are family, nameset,
 * fileset, name, and file.
 */
void startElementHandler(void *data, const char *tag, const char **atts) {
    FamilyData *familyData = (FamilyData*) data;
    int len = strlen(tag);
    if (strncmp(tag, "family", len)== 0) {
        familyData->currentFamily = new FontFamily();
        familyData->currentFamily->order = -1;
        // The Family tag has an optional "order" attribute with an integer value >= 0
        // If this attribute does not exist, the default value is -1
        for (int i = 0; atts[i] != NULL; i += 2) {
            const char* attribute = atts[i];
            const char* valueString = atts[i+1];
            int value;
            int len = sscanf(valueString, "%d", &value);
            if (len > 0) {
                familyData->currentFamily->order = value;
            }
        }
    } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
        familyData->currentTag = NAMESET_TAG;
    } else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
        familyData->currentTag = FILESET_TAG;
    } else if (strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) {
        XML_SetCharacterDataHandler(*familyData->parser, textHandler);
    } else if (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG) {
        // From JB MR1, the File tag has a "lang" attribute to specify a language specific font file
        // and the family entry has higher priority than the others without "lang" attribute.
        bool includeTheEntry = true;
        for (int i = 0; atts[i] != NULL; i += 2) {
            const char* attribute = atts[i];
            const char* value = atts[i+1];
            if (strncmp(attribute, "lang", 4) == 0) {
                if (strcmp(value, familyData->locale.language) == 0) {
                    // Found matching "lang" attribute. The current Family will have higher priority in the family list.
                    familyData->currentFamilyLangMatch = true;
                } else {
                    // Don't include the entry if "lang" is specified but not matching.
                    includeTheEntry = false;
                }
            }
        }
        if (includeTheEntry) {
            XML_SetCharacterDataHandler(*familyData->parser, textHandler);
        }
    }
}

/**
 * Handler for the end of tags. We only care about family, nameset, fileset,
 * name, and file.
 */
void endElementHandler(void *data, const char *tag) {
    FamilyData *familyData = (FamilyData*) data;
    int len = strlen(tag);
    if (strncmp(tag, "family", len)== 0) {
        // Done parsing a Family - store the created currentFamily in the families array
        if (familyData->currentFamilyLangMatch) {
            *familyData->families.insert(familyData->familyLangMatchCount++) = familyData->currentFamily;
            familyData->currentFamilyLangMatch = false;
        } else {
            *familyData->families.append() = familyData->currentFamily;
        }
        familyData->currentFamily = NULL;
    } else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
        familyData->currentTag = NO_TAG;
    } else if (len == 7 && strncmp(tag, "fileset", len)== 0) {
        familyData->currentTag = NO_TAG;
    } else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
            (strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
        // Disable the arbitrary text handler installed to load Name data
        XML_SetCharacterDataHandler(*familyData->parser, NULL);
    }
}

/**
 * Read the persistent locale.
 */
void getLocale(AndroidLocale &locale)
{
    char propLang[PROP_VALUE_MAX], propRegn[PROP_VALUE_MAX];
    __system_property_get("persist.sys.language", propLang);
    __system_property_get("persist.sys.country", propRegn);

    if (*propLang == 0 && *propRegn == 0) {
        /* Set to ro properties, default is en_US */
        __system_property_get("ro.product.locale.language", propLang);
        __system_property_get("ro.product.locale.region", propRegn);
        if (*propLang == 0 && *propRegn == 0) {
            strcpy(propLang, "en");
            strcpy(propRegn, "US");
        }
    }
    strncpy(locale.language, propLang, 2);
    locale.language[2] = '\0';
    strncpy(locale.region, propRegn, 2);
    locale.region[2] = '\0';
}

/**
 * Use the current system locale (language and region) to open the best matching
 * customization. For example, when the language is Japanese, the sequence might be:
 *      /system/etc/fallback_fonts-ja-JP.xml
 *      /system/etc/fallback_fonts-ja.xml
 *      /system/etc/fallback_fonts.xml
 */
FILE* openLocalizedFile(const char* origname, const AndroidLocale& locale) {
    FILE* file = 0;
    SkString basename;
    SkString filename;

    basename.set(origname);
    // Remove the .xml suffix. We'll add it back in a moment.
    if (basename.endsWith(".xml")) {
        basename.resize(basename.size()-4);
    }
    // Try first with language and region
    filename.printf("%s-%s-%s.xml", basename.c_str(), locale.language, locale.region);
    file = fopen(filename.c_str(), "r");
    if (!file) {
        // If not found, try next with just language
        filename.printf("%s-%s.xml", basename.c_str(), locale.language);
        file = fopen(filename.c_str(), "r");

        if (!file) {
            // If still not found, try just the original name
            file = fopen(origname, "r");
        }
    }
    return file;
}

/**
 * This function parses the given filename and stores the results in the given
 * families array.
 */
void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
    AndroidLocale locale;
    getLocale(locale);
    XML_Parser parser = XML_ParserCreate(NULL);
    FamilyData familyData(&parser, families, locale);
    XML_SetUserData(parser, &familyData);
    XML_SetElementHandler(parser, startElementHandler, endElementHandler);
    FILE *file = openLocalizedFile(filename, locale);
    // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
    // are optional - failure here is okay because one of these optional files may not exist.
    if (file == NULL) {
        return;
    }
    char buffer[512];
    bool done = false;
    while (!done) {
        fgets(buffer, sizeof(buffer), file);
        int len = strlen(buffer);
        if (feof(file) != 0) {
            done = true;
        }
        XML_Parse(parser, buffer, len, done);
    }
    fclose(file);
    XML_ParserFree(parser);
}

void getSystemFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
    parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies);
}

void getFallbackFontFamilies(SkTDArray<FontFamily*> &fallbackFonts) {
    SkTDArray<FontFamily*> vendorFonts;
    parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts);
    parseConfigFile(VENDOR_FONTS_FILE, vendorFonts);

    // This loop inserts the vendor fallback fonts in the correct order in the
    // overall fallbacks list.
    int currentOrder = -1;
    for (int i = 0; i < vendorFonts.count(); ++i) {
        FontFamily* family = vendorFonts[i];
        int order = family->order;
        if (order < 0) {
            if (currentOrder < 0) {
                // Default case - just add it to the end of the fallback list
                *fallbackFonts.append() = family;
            } else {
                // no order specified on this font, but we're incrementing the order
                // based on an earlier order insertion request
                *fallbackFonts.insert(currentOrder++) = family;
            }
        } else {
            // Add the font into the fallback list in the specified order. Set
            // currentOrder for correct placement of other fonts in the vendor list.
            *fallbackFonts.insert(order) = family;
            currentOrder = order + 1;
        }
    }
}

/**
 * Loads data on font families from various expected configuration files. The
 * resulting data is returned in the given fontFamilies array.
 */
void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
    SkTDArray<FontFamily*> fallbackFonts;

    getSystemFontFamilies(fontFamilies);
    getFallbackFontFamilies(fallbackFonts);

    // Append all fallback fonts to system fonts
    for (int i = 0; i < fallbackFonts.count(); ++i) {
        *fontFamilies.append() = fallbackFonts[i];
    }
}

void getTestFontFamilies(SkTDArray<FontFamily*> &fontFamilies,
                         const char* testMainConfigFile,
                         const char* testFallbackConfigFile) {
    parseConfigFile(testMainConfigFile, fontFamilies);

    SkTDArray<FontFamily*> fallbackFonts;
    parseConfigFile(testFallbackConfigFile, fallbackFonts);

    // Append all fallback fonts to system fonts
    for (int i = 0; i < fallbackFonts.count(); ++i) {
        *fontFamilies.append() = fallbackFonts[i];
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "paddle/fluid/imperative/prepared_operator.h"

#include "paddle/fluid/framework/data_type_transform.h"
#include "paddle/fluid/framework/details/nan_inf_utils.h"
#include "paddle/fluid/imperative/infer_shape_context.h"

DECLARE_bool(check_nan_inf);

namespace paddle {
namespace imperative {

const std::shared_ptr<VariableWrapper>& GetVariableWrapper(
    const std::shared_ptr<paddle::imperative::VarBase>& var) {
  return var->SharedVar();
}

const std::shared_ptr<VariableWrapper>& GetVariableWrapper(
    const std::shared_ptr<VariableWrapper>& var) {
  return var;
}

const framework::Tensor* GetTensorFromVar(const framework::Variable& var) {
  if (var.IsType<framework::LoDTensor>()) {
    return &(var.Get<framework::LoDTensor>());
  } else if (var.IsType<framework::SelectedRows>()) {
    return &(var.Get<framework::SelectedRows>().value());
  } else {
    return nullptr;
  }
}

template <typename VarType>
static void HandleComplexGradToRealGrad(const NameVarMap<VarType>& outs) {
  for (auto& pair : outs) {
    for (auto& var : pair.second) {
      if (var == nullptr) {
        continue;
      }
      if (var->ForwardDataType() ==
          static_cast<framework::proto::VarType::Type>(-1)) {
        VLOG(6) << "Var (" << var->Name()
                << ")'s forward data type is not set.";
        continue;
      }
      if (!framework::IsComplexType(var->DataType()) ||
          framework::IsComplexType(var->ForwardDataType())) {
        continue;
      }
      const auto* tensor = GetTensorFromVar(var->Var());
      if (tensor && tensor->IsInitialized()) {
        VLOG(6) << "Transform " << framework::DataTypeToString(var->DataType())
                << " var `" << var->Name() << "` to "
                << framework::DataTypeToString(var->ForwardDataType())
                << " real var in dynamic graph.";
        framework::Tensor out;
        framework::TransComplexToReal(var->ForwardDataType(), var->DataType(),
                                      *tensor, &out);
        SetTensorToVariable(var->Var(), out, var->MutableVar());
      }
    }
  }
}

PreparedOp::PreparedOp(const framework::OperatorBase& op,
                       const framework::RuntimeContext& ctx,
                       const framework::OpKernelType& kernel_type,
                       const framework::OperatorWithKernel::OpKernelFunc& func,
                       platform::DeviceContext* dev_ctx)
    : op_(op),
      ctx_(ctx),
      kernel_type_(kernel_type),
      func_(func),
      dev_ctx_(dev_ctx) {}

template <typename VarType>
PreparedOp PrepareImpl(const NameVarMap<VarType>& ins,
                       const NameVarMap<VarType>& outs,
                       const framework::OperatorWithKernel& op,
                       const platform::Place& place,
                       const framework::AttributeMap& attrs,
                       const framework::AttributeMap& default_attrs) {
  platform::DeviceContextPool& pool = platform::DeviceContextPool::Instance();
  auto* dev_ctx = pool.Get(place);

  framework::RuntimeContext ctx({}, {});

#ifdef PADDLE_WITH_MKLDNN
  // MKLDNN variant of code reads attributes in some of GetKernelTypeForVar and
  // GetKernelType functions, so we need to copy the attributes there.
  // Const qualifier of Attrs had to be discarded to overwrite it.
  if (FLAGS_use_mkldnn) {
    auto& mutable_op_attrs = const_cast<framework::AttributeMap&>(op.Attrs());
    mutable_op_attrs = attrs;
  }
#endif

  // 1. get expected kernel key
  auto expected_kernel_key = op.GetExpectedKernelType(
      DygraphExecutionContext<VarType>(op, framework::Scope(), *dev_ctx, ctx,
                                       ins, outs, attrs, default_attrs));
  VLOG(3) << "expected_kernel_key:" << expected_kernel_key;

  // 2. check if op[type] has kernel registered.
  auto& all_op_kernels = op.AllOpKernels();
  auto kernels_iter = all_op_kernels.find(op.Type());
  PADDLE_ENFORCE_NE(
      kernels_iter, all_op_kernels.end(),
      platform::errors::NotFound(
          "There are no kernels which are registered in the %s operator.",
          op.Type()));

  auto& kernels = kernels_iter->second;
  auto kernel_iter = kernels.find(expected_kernel_key);
#ifdef PADDLE_WITH_XPU
  if (kernel_iter == kernels.end() &&
      is_xpu_place(expected_kernel_key.place_)) {
    VLOG(3) << "missing XPU kernel: " << op.Type()
            << ", expected_kernel_key:" << expected_kernel_key
            << ", fallbacking to CPU one!";
    expected_kernel_key.place_ = platform::CPUPlace();
    kernel_iter = kernels.find(expected_kernel_key);
  }
#endif
#ifdef PADDLE_WITH_ASCEND_CL
  if (kernel_iter == kernels.end() &&
      is_npu_place(expected_kernel_key.place_)) {
    VLOG(3) << "missing NPU kernel: " << op.Type()
            << ", expected_kernel_key:" << expected_kernel_key
            << ", fallbacking to CPU one!";
    expected_kernel_key.place_ = platform::CPUPlace();
    kernel_iter = kernels.find(expected_kernel_key);
  }
#endif
  // TODO(jiabin): Add operator.cc's line 1000 part back when we need that case
  PADDLE_ENFORCE_NE(kernel_iter, kernels.end(),
                    platform::errors::NotFound(
                        "Operator %s does not have kernel for %s.", op.Type(),
                        KernelTypeToString(expected_kernel_key)));

  if (!(expected_kernel_key.place_ == place)) {
    dev_ctx = pool.Get(expected_kernel_key.place_);
  }

  return PreparedOp(op, ctx, expected_kernel_key, kernel_iter->second, dev_ctx);
}

PreparedOp PreparedOp::Prepare(const NameVarMap<VarBase>& ins,
                               const NameVarMap<VarBase>& outs,
                               const framework::OperatorWithKernel& op,
                               const platform::Place& place,
                               const framework::AttributeMap& attrs,
                               const framework::AttributeMap& default_attrs) {
  return PrepareImpl<VarBase>(ins, outs, op, place, attrs, default_attrs);
}

PreparedOp PreparedOp::Prepare(const NameVarMap<VariableWrapper>& ins,
                               const NameVarMap<VariableWrapper>& outs,
                               const framework::OperatorWithKernel& op,
                               const platform::Place& place,
                               const framework::AttributeMap& attrs,
                               const framework::AttributeMap& default_attrs) {
  return PrepareImpl<VariableWrapper>(ins, outs, op, place, attrs,
                                      default_attrs);
}

template <typename VarType>
static void PreparedOpRunImpl(
    const framework::OperatorBase& op, const framework::RuntimeContext& ctx,
    const framework::OpKernelType& kernel_type,
    const framework::OperatorWithKernel::OpKernelFunc& func,
    platform::DeviceContext* dev_ctx, const NameVarMap<VarType>& ins,
    const NameVarMap<VarType>& outs, const framework::AttributeMap& attrs,
    const framework::AttributeMap& default_attrs) {
  // TODO(zjl): remove scope in dygraph
  framework::Scope scope;

  DygraphInferShapeContext<VarType> infer_shape_ctx(&ins, &outs, &attrs,
                                                    &default_attrs, op.Type());
  static_cast<const framework::OperatorWithKernel&>(op).InferShape(
      &infer_shape_ctx);

  func(DygraphExecutionContext<VarType>(op, scope, *dev_ctx, ctx, ins, outs,
                                        attrs, default_attrs));

  if (FLAGS_check_nan_inf) {
    framework::details::CheckOpHasNanOrInfInDygraph<VarType>(
        op.Type(), outs, dev_ctx->GetPlace());
  }

  /**
   * [ Why need handle complex gradient to real gradient? ]
   *
   * After the introduction of complex number calculations, Ops that support
   * complex number calculations generally support type promotion, such as
   * x(float32) + y(complex64) = out(complex64), then the type of the grad
   * tensor should be dout(complex64), dx(float32), dy (complex64).
   *
   * But because the dout is complex64, the dx is also complex64 after
   * grad op kernel executed, we need to recognize this situation and
   * convert dx to float32 type. HandleComplexGradToRealGrad does this thing.
   */
  if (framework::IsComplexType(kernel_type.data_type_)) {
    HandleComplexGradToRealGrad<VarType>(outs);
  }
}

void PreparedOp::Run(const NameVarMap<VarBase>& ins,
                     const NameVarMap<VarBase>& outs,
                     const framework::AttributeMap& attrs,
                     const framework::AttributeMap& default_attrs) {
  PreparedOpRunImpl<VarBase>(op_, ctx_, kernel_type_, func_, dev_ctx_, ins,
                             outs, attrs, default_attrs);
}

void PreparedOp::Run(const NameVarMap<VariableWrapper>& ins,
                     const NameVarMap<VariableWrapper>& outs,
                     const framework::AttributeMap& attrs,
                     const framework::AttributeMap& default_attrs) {
  PreparedOpRunImpl<VariableWrapper>(op_, ctx_, kernel_type_, func_, dev_ctx_,
                                     ins, outs, attrs, default_attrs);
}

}  // namespace imperative
}  // namespace paddle
<commit_msg>fix attr can not find in mkldnn, test=develop (#34567)<commit_after>// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "paddle/fluid/imperative/prepared_operator.h"

#include "paddle/fluid/framework/data_type_transform.h"
#include "paddle/fluid/framework/details/nan_inf_utils.h"
#include "paddle/fluid/imperative/infer_shape_context.h"

DECLARE_bool(check_nan_inf);

namespace paddle {
namespace imperative {

const std::shared_ptr<VariableWrapper>& GetVariableWrapper(
    const std::shared_ptr<paddle::imperative::VarBase>& var) {
  return var->SharedVar();
}

const std::shared_ptr<VariableWrapper>& GetVariableWrapper(
    const std::shared_ptr<VariableWrapper>& var) {
  return var;
}

const framework::Tensor* GetTensorFromVar(const framework::Variable& var) {
  if (var.IsType<framework::LoDTensor>()) {
    return &(var.Get<framework::LoDTensor>());
  } else if (var.IsType<framework::SelectedRows>()) {
    return &(var.Get<framework::SelectedRows>().value());
  } else {
    return nullptr;
  }
}

template <typename VarType>
static void HandleComplexGradToRealGrad(const NameVarMap<VarType>& outs) {
  for (auto& pair : outs) {
    for (auto& var : pair.second) {
      if (var == nullptr) {
        continue;
      }
      if (var->ForwardDataType() ==
          static_cast<framework::proto::VarType::Type>(-1)) {
        VLOG(6) << "Var (" << var->Name()
                << ")'s forward data type is not set.";
        continue;
      }
      if (!framework::IsComplexType(var->DataType()) ||
          framework::IsComplexType(var->ForwardDataType())) {
        continue;
      }
      const auto* tensor = GetTensorFromVar(var->Var());
      if (tensor && tensor->IsInitialized()) {
        VLOG(6) << "Transform " << framework::DataTypeToString(var->DataType())
                << " var `" << var->Name() << "` to "
                << framework::DataTypeToString(var->ForwardDataType())
                << " real var in dynamic graph.";
        framework::Tensor out;
        framework::TransComplexToReal(var->ForwardDataType(), var->DataType(),
                                      *tensor, &out);
        SetTensorToVariable(var->Var(), out, var->MutableVar());
      }
    }
  }
}

PreparedOp::PreparedOp(const framework::OperatorBase& op,
                       const framework::RuntimeContext& ctx,
                       const framework::OpKernelType& kernel_type,
                       const framework::OperatorWithKernel::OpKernelFunc& func,
                       platform::DeviceContext* dev_ctx)
    : op_(op),
      ctx_(ctx),
      kernel_type_(kernel_type),
      func_(func),
      dev_ctx_(dev_ctx) {}

template <typename VarType>
PreparedOp PrepareImpl(const NameVarMap<VarType>& ins,
                       const NameVarMap<VarType>& outs,
                       const framework::OperatorWithKernel& op,
                       const platform::Place& place,
                       const framework::AttributeMap& attrs,
                       const framework::AttributeMap& default_attrs) {
  platform::DeviceContextPool& pool = platform::DeviceContextPool::Instance();
  auto* dev_ctx = pool.Get(place);

  framework::RuntimeContext ctx({}, {});

#ifdef PADDLE_WITH_MKLDNN
  // MKLDNN variant of code reads attributes in some of GetKernelTypeForVar and
  // GetKernelType functions, so we need to copy the attributes there.
  // Const qualifier of Attrs had to be discarded to overwrite it.
  if (FLAGS_use_mkldnn) {
    auto& mutable_op_attrs = const_cast<framework::AttributeMap&>(op.Attrs());
    mutable_op_attrs = default_attrs;
    for (auto& attr : attrs) {
      mutable_op_attrs[attr.first] = attr.second;
    }
  }
#endif

  // 1. get expected kernel key
  auto expected_kernel_key = op.GetExpectedKernelType(
      DygraphExecutionContext<VarType>(op, framework::Scope(), *dev_ctx, ctx,
                                       ins, outs, attrs, default_attrs));
  VLOG(3) << "expected_kernel_key:" << expected_kernel_key;

  // 2. check if op[type] has kernel registered.
  auto& all_op_kernels = op.AllOpKernels();
  auto kernels_iter = all_op_kernels.find(op.Type());
  PADDLE_ENFORCE_NE(
      kernels_iter, all_op_kernels.end(),
      platform::errors::NotFound(
          "There are no kernels which are registered in the %s operator.",
          op.Type()));

  auto& kernels = kernels_iter->second;
  auto kernel_iter = kernels.find(expected_kernel_key);
#ifdef PADDLE_WITH_XPU
  if (kernel_iter == kernels.end() &&
      is_xpu_place(expected_kernel_key.place_)) {
    VLOG(3) << "missing XPU kernel: " << op.Type()
            << ", expected_kernel_key:" << expected_kernel_key
            << ", fallbacking to CPU one!";
    expected_kernel_key.place_ = platform::CPUPlace();
    kernel_iter = kernels.find(expected_kernel_key);
  }
#endif
#ifdef PADDLE_WITH_ASCEND_CL
  if (kernel_iter == kernels.end() &&
      is_npu_place(expected_kernel_key.place_)) {
    VLOG(3) << "missing NPU kernel: " << op.Type()
            << ", expected_kernel_key:" << expected_kernel_key
            << ", fallbacking to CPU one!";
    expected_kernel_key.place_ = platform::CPUPlace();
    kernel_iter = kernels.find(expected_kernel_key);
  }
#endif
  // TODO(jiabin): Add operator.cc's line 1000 part back when we need that case
  PADDLE_ENFORCE_NE(kernel_iter, kernels.end(),
                    platform::errors::NotFound(
                        "Operator %s does not have kernel for %s.", op.Type(),
                        KernelTypeToString(expected_kernel_key)));

  if (!(expected_kernel_key.place_ == place)) {
    dev_ctx = pool.Get(expected_kernel_key.place_);
  }

  return PreparedOp(op, ctx, expected_kernel_key, kernel_iter->second, dev_ctx);
}

PreparedOp PreparedOp::Prepare(const NameVarMap<VarBase>& ins,
                               const NameVarMap<VarBase>& outs,
                               const framework::OperatorWithKernel& op,
                               const platform::Place& place,
                               const framework::AttributeMap& attrs,
                               const framework::AttributeMap& default_attrs) {
  return PrepareImpl<VarBase>(ins, outs, op, place, attrs, default_attrs);
}

PreparedOp PreparedOp::Prepare(const NameVarMap<VariableWrapper>& ins,
                               const NameVarMap<VariableWrapper>& outs,
                               const framework::OperatorWithKernel& op,
                               const platform::Place& place,
                               const framework::AttributeMap& attrs,
                               const framework::AttributeMap& default_attrs) {
  return PrepareImpl<VariableWrapper>(ins, outs, op, place, attrs,
                                      default_attrs);
}

template <typename VarType>
static void PreparedOpRunImpl(
    const framework::OperatorBase& op, const framework::RuntimeContext& ctx,
    const framework::OpKernelType& kernel_type,
    const framework::OperatorWithKernel::OpKernelFunc& func,
    platform::DeviceContext* dev_ctx, const NameVarMap<VarType>& ins,
    const NameVarMap<VarType>& outs, const framework::AttributeMap& attrs,
    const framework::AttributeMap& default_attrs) {
  // TODO(zjl): remove scope in dygraph
  framework::Scope scope;

  DygraphInferShapeContext<VarType> infer_shape_ctx(&ins, &outs, &attrs,
                                                    &default_attrs, op.Type());
  static_cast<const framework::OperatorWithKernel&>(op).InferShape(
      &infer_shape_ctx);

  func(DygraphExecutionContext<VarType>(op, scope, *dev_ctx, ctx, ins, outs,
                                        attrs, default_attrs));

  if (FLAGS_check_nan_inf) {
    framework::details::CheckOpHasNanOrInfInDygraph<VarType>(
        op.Type(), outs, dev_ctx->GetPlace());
  }

  /**
   * [ Why need handle complex gradient to real gradient? ]
   *
   * After the introduction of complex number calculations, Ops that support
   * complex number calculations generally support type promotion, such as
   * x(float32) + y(complex64) = out(complex64), then the type of the grad
   * tensor should be dout(complex64), dx(float32), dy (complex64).
   *
   * But because the dout is complex64, the dx is also complex64 after
   * grad op kernel executed, we need to recognize this situation and
   * convert dx to float32 type. HandleComplexGradToRealGrad does this thing.
   */
  if (framework::IsComplexType(kernel_type.data_type_)) {
    HandleComplexGradToRealGrad<VarType>(outs);
  }
}

void PreparedOp::Run(const NameVarMap<VarBase>& ins,
                     const NameVarMap<VarBase>& outs,
                     const framework::AttributeMap& attrs,
                     const framework::AttributeMap& default_attrs) {
  PreparedOpRunImpl<VarBase>(op_, ctx_, kernel_type_, func_, dev_ctx_, ins,
                             outs, attrs, default_attrs);
}

void PreparedOp::Run(const NameVarMap<VariableWrapper>& ins,
                     const NameVarMap<VariableWrapper>& outs,
                     const framework::AttributeMap& attrs,
                     const framework::AttributeMap& default_attrs) {
  PreparedOpRunImpl<VariableWrapper>(op_, ctx_, kernel_type_, func_, dev_ctx_,
                                     ins, outs, attrs, default_attrs);
}

}  // namespace imperative
}  // namespace paddle
<|endoftext|>


<commit_before>#ifndef MJOLNIR_OMP_SYSTEM_HPP
#define MJOLNIR_OMP_SYSTEM_HPP
#include <mjolnir/util/aligned_allocator.hpp>
#include <mjolnir/omp/OpenMPSimulatorTraits.hpp>
#include <mjolnir/omp/RandomNumberGenerator.hpp>
#include <mjolnir/core/System.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT>
class System<OpenMPSimulatorTraits<realT, boundaryT>>
{
  public:
    using traits_type     = OpenMPSimulatorTraits<realT, boundaryT>;
    using real_type       = typename traits_type::real_type;
    using coordinate_type = typename traits_type::coordinate_type;
    using boundary_type   = typename traits_type::boundary_type;
    using topology_type   = Topology;
    using attribute_type  = std::map<std::string, real_type>;
    using rng_type        = RandomNumberGenerator<traits_type>;

    using string_type              = std::string;
    using particle_type            = Particle<real_type, coordinate_type>;
    using particle_view_type       = ParticleView<real_type, coordinate_type>;
    using particle_const_view_type = ParticleConstView<real_type, coordinate_type>;

    using real_container_type          = std::vector<real_type>;
    using coordinate_container_type    = std::vector<coordinate_type>;
    using string_container_type        = std::vector<std::string>;

    static constexpr std::size_t cache_alignment = 64;

    template<typename T>
    using cache_aligned_allocator = aligned_allocator<T, cache_alignment>;

  public:

    System(const std::size_t num_particles, const boundary_type& bound)
        : velocity_initialized_(false), boundary_(bound),
          attributes_(), num_particles_(num_particles),
          masses_   (num_particles), rmasses_   (num_particles),
          positions_(num_particles), velocities_(num_particles),
          forces_master_(num_particles),
          forces_threads_(omp_get_max_threads(),
              coordinate_container_type(num_particles),
              cache_aligned_allocator<coordinate_container_type>{}),
          names_    (num_particles), groups_    (num_particles)
    {}
    ~System() = default;

    void initialize(rng_type& rng)
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        // make all the particles inside the boundary
        for(auto& p : this->positions_)
        {
            p = this->boundary_.adjust_position(p);
        }

        if(this->velocity_initialized_)
        {
            MJOLNIR_LOG_NOTICE(
                "velocity is already given, nothing to initialize in System");
            return ;
        }
        assert(this->has_attribute("temperature"));

        const real_type kB    = physics::constants<real_type>::kB();
        const real_type T_ref = this->attribute("temperature");

        MJOLNIR_LOG_NOTICE("generating velocity with T = ", T_ref, "...");

        // generate Maxwell-Boltzmann distribution
        const real_type kBT = kB * T_ref;
        for(std::size_t i=0; i<this->size(); ++i)
        {
            const auto vel_coef = std::sqrt(kBT / this->mass(i));
            math::X(this->velocity(i)) = rng.gaussian(0, vel_coef);
            math::Y(this->velocity(i)) = rng.gaussian(0, vel_coef);
            math::Z(this->velocity(i)) = rng.gaussian(0, vel_coef);
        }
        MJOLNIR_LOG_NOTICE("done.");
        return;
    }

    coordinate_type adjust_direction(coordinate_type dr) const noexcept
    {return boundary_.adjust_direction(dr);}
    coordinate_type  adjust_position(coordinate_type dr) const noexcept
    {return boundary_.adjust_position(dr);}

    std::size_t size() const noexcept {return num_particles_;}

    particle_view_type operator[](std::size_t i) noexcept
    {
        return particle_view_type{
            masses_[i],    rmasses_[i],
            positions_[i], velocities_[i], forces_master_[i],
            names_[i],     groups_[i]
        };
    }
    particle_const_view_type operator[](std::size_t i) const noexcept
    {
        return particle_const_view_type{
            masses_[i],    rmasses_[i],
            positions_[i], velocities_[i], forces_master_[i],
            names_[i],     groups_[i]
        };
    }
    particle_view_type at(std::size_t i)
    {
        return particle_view_type{
            masses_.at(i),    rmasses_.at(i),
            positions_.at(i), velocities_.at(i), forces_master_.at(i),
            names_.at(i),     groups_.at(i)
        };
    }
    particle_const_view_type at(std::size_t i) const
    {
        return particle_const_view_type{
            masses_.at(i),    rmasses_.at(i),
            positions_.at(i), velocities_.at(i), forces_master_.at(i),
            names_.at(i),     groups_.at(i)
        };
    }

    real_type  mass (std::size_t i) const noexcept {return masses_[i];}
    real_type& mass (std::size_t i)       noexcept {return masses_[i];}
    real_type  rmass(std::size_t i) const noexcept {return rmasses_[i];}
    real_type& rmass(std::size_t i)       noexcept {return rmasses_[i];}

    coordinate_type const& position(std::size_t i) const noexcept {return positions_[i];}
    coordinate_type&       position(std::size_t i)       noexcept {return positions_[i];}
    coordinate_type const& velocity(std::size_t i) const noexcept {return velocities_[i];}
    coordinate_type&       velocity(std::size_t i)       noexcept {return velocities_[i];}
    coordinate_type const& force   (std::size_t i) const noexcept {return forces_master_[i];}
    coordinate_type&       force   (std::size_t i)       noexcept {return forces_master_[i];}

    coordinate_type const&
    force_thread(std::size_t thread_num, std::size_t particle_id) const noexcept
    {
        return forces_threads_[thread_num][particle_id];
    }
    coordinate_type&
    force_thread(std::size_t thread_num, std::size_t particle_id)       noexcept
    {
        return forces_threads_[thread_num][particle_id];
    }

    void preprocess_forces() noexcept { /*do nothing*/ }
    void postprocess_forces() noexcept
    {
#pragma omp parallel for
        for(std::size_t i=0; i<this->size(); ++i)
        {
            // sumup all the thread-local forces into the main force.
            // XXX: keep the values in the main force! Some pre-omp interactions
            //      may write its force in it. Clearing main force is a task
            //      for Integrators.
            for(std::size_t thread_id=0, max_threads=omp_get_max_threads();
                    thread_id < max_threads; ++thread_id)
            {
                this->force(i) += this->force_thread(thread_id, i);
                this->force_thread(thread_id, i) =
                    math::make_coordinate<coordinate_type>(0, 0, 0);
            }
        }
        return;
    }

    string_type const& name (std::size_t i) const noexcept {return names_[i];}
    string_type&       name (std::size_t i)       noexcept {return names_[i];}
    string_type const& group(std::size_t i) const noexcept {return groups_[i];}
    string_type&       group(std::size_t i)       noexcept {return groups_[i];}

    boundary_type&       boundary()       noexcept {return boundary_;}
    boundary_type const& boundary() const noexcept {return boundary_;}

    // system attributes like `reference temperature`, `ionic strength`, ...
    // assuming it will not be called so often.
    real_type  attribute(const std::string& key) const {return attributes_.at(key);}
    real_type& attribute(const std::string& key)       {return attributes_[key];}
    bool   has_attribute(const std::string& key) const {return attributes_.count(key) == 1;}
    attribute_type const& attributes() const noexcept {return attributes_;}

    bool  velocity_initialized() const noexcept {return velocity_initialized_;}
    bool& velocity_initialized()       noexcept {return velocity_initialized_;}

    coordinate_container_type const& forces() const noexcept {return forces_master_;}
    coordinate_container_type&       forces()       noexcept {return forces_master_;}

  private:

    bool           velocity_initialized_;
    boundary_type  boundary_;
    attribute_type attributes_;

    std::size_t                  num_particles_;
    real_container_type          masses_;
    real_container_type          rmasses_; // r for reciprocal
    coordinate_container_type    positions_;
    coordinate_container_type    velocities_;
    coordinate_container_type    forces_master_;
    // thread-local forces
    std::vector<coordinate_container_type,
                cache_aligned_allocator<coordinate_container_type>
        > forces_threads_;
    string_container_type        names_;
    string_container_type        groups_;

    // names and groups are in Topology class
};

#ifdef MJOLNIR_SEPARATE_BUILD
extern template class System<OpenMPSimulatorTraits<double, UnlimitedBoundary>>;
extern template class System<OpenMPSimulatorTraits<float,  UnlimitedBoundary>>;
extern template class System<OpenMPSimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class System<OpenMPSimulatorTraits<float,  CuboidalPeriodicBoundary>>;
#endif

} // mjolnir
#endif// MJOLNIR_SYSTEM_HPP
<commit_msg>feat: rename main force container<commit_after>#ifndef MJOLNIR_OMP_SYSTEM_HPP
#define MJOLNIR_OMP_SYSTEM_HPP
#include <mjolnir/util/aligned_allocator.hpp>
#include <mjolnir/omp/OpenMPSimulatorTraits.hpp>
#include <mjolnir/omp/RandomNumberGenerator.hpp>
#include <mjolnir/core/System.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT>
class System<OpenMPSimulatorTraits<realT, boundaryT>>
{
  public:
    using traits_type     = OpenMPSimulatorTraits<realT, boundaryT>;
    using real_type       = typename traits_type::real_type;
    using coordinate_type = typename traits_type::coordinate_type;
    using boundary_type   = typename traits_type::boundary_type;
    using topology_type   = Topology;
    using attribute_type  = std::map<std::string, real_type>;
    using rng_type        = RandomNumberGenerator<traits_type>;

    using string_type              = std::string;
    using particle_type            = Particle<real_type, coordinate_type>;
    using particle_view_type       = ParticleView<real_type, coordinate_type>;
    using particle_const_view_type = ParticleConstView<real_type, coordinate_type>;

    using real_container_type          = std::vector<real_type>;
    using coordinate_container_type    = std::vector<coordinate_type>;
    using string_container_type        = std::vector<std::string>;

    static constexpr std::size_t cache_alignment = 64;

    template<typename T>
    using cache_aligned_allocator = aligned_allocator<T, cache_alignment>;

  public:

    System(const std::size_t num_particles, const boundary_type& bound)
        : velocity_initialized_(false), boundary_(bound),
          attributes_(), num_particles_(num_particles),
          masses_   (num_particles), rmasses_   (num_particles),
          positions_(num_particles), velocities_(num_particles),
          forces_main_(num_particles),
          forces_threads_(omp_get_max_threads(),
              coordinate_container_type(num_particles),
              cache_aligned_allocator<coordinate_container_type>{}),
          names_    (num_particles), groups_    (num_particles)
    {}
    ~System() = default;

    void initialize(rng_type& rng)
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        // make all the particles inside the boundary
        for(auto& p : this->positions_)
        {
            p = this->boundary_.adjust_position(p);
        }

        if(this->velocity_initialized_)
        {
            MJOLNIR_LOG_NOTICE(
                "velocity is already given, nothing to initialize in System");
            return ;
        }
        assert(this->has_attribute("temperature"));

        const real_type kB    = physics::constants<real_type>::kB();
        const real_type T_ref = this->attribute("temperature");

        MJOLNIR_LOG_NOTICE("generating velocity with T = ", T_ref, "...");

        // generate Maxwell-Boltzmann distribution
        const real_type kBT = kB * T_ref;
        for(std::size_t i=0; i<this->size(); ++i)
        {
            const auto vel_coef = std::sqrt(kBT / this->mass(i));
            math::X(this->velocity(i)) = rng.gaussian(0, vel_coef);
            math::Y(this->velocity(i)) = rng.gaussian(0, vel_coef);
            math::Z(this->velocity(i)) = rng.gaussian(0, vel_coef);
        }
        MJOLNIR_LOG_NOTICE("done.");
        return;
    }

    coordinate_type adjust_direction(coordinate_type dr) const noexcept
    {return boundary_.adjust_direction(dr);}
    coordinate_type  adjust_position(coordinate_type dr) const noexcept
    {return boundary_.adjust_position(dr);}

    std::size_t size() const noexcept {return num_particles_;}

    particle_view_type operator[](std::size_t i) noexcept
    {
        return particle_view_type{
            masses_[i],    rmasses_[i],
            positions_[i], velocities_[i], forces_main_[i],
            names_[i],     groups_[i]
        };
    }
    particle_const_view_type operator[](std::size_t i) const noexcept
    {
        return particle_const_view_type{
            masses_[i],    rmasses_[i],
            positions_[i], velocities_[i], forces_main_[i],
            names_[i],     groups_[i]
        };
    }
    particle_view_type at(std::size_t i)
    {
        return particle_view_type{
            masses_.at(i),    rmasses_.at(i),
            positions_.at(i), velocities_.at(i), forces_main_.at(i),
            names_.at(i),     groups_.at(i)
        };
    }
    particle_const_view_type at(std::size_t i) const
    {
        return particle_const_view_type{
            masses_.at(i),    rmasses_.at(i),
            positions_.at(i), velocities_.at(i), forces_main_.at(i),
            names_.at(i),     groups_.at(i)
        };
    }

    real_type  mass (std::size_t i) const noexcept {return masses_[i];}
    real_type& mass (std::size_t i)       noexcept {return masses_[i];}
    real_type  rmass(std::size_t i) const noexcept {return rmasses_[i];}
    real_type& rmass(std::size_t i)       noexcept {return rmasses_[i];}

    coordinate_type const& position(std::size_t i) const noexcept {return positions_[i];}
    coordinate_type&       position(std::size_t i)       noexcept {return positions_[i];}
    coordinate_type const& velocity(std::size_t i) const noexcept {return velocities_[i];}
    coordinate_type&       velocity(std::size_t i)       noexcept {return velocities_[i];}
    coordinate_type const& force   (std::size_t i) const noexcept {return forces_main_[i];}
    coordinate_type&       force   (std::size_t i)       noexcept {return forces_main_[i];}

    coordinate_type const&
    force_thread(std::size_t thread_num, std::size_t particle_id) const noexcept
    {
        return forces_threads_[thread_num][particle_id];
    }
    coordinate_type&
    force_thread(std::size_t thread_num, std::size_t particle_id)       noexcept
    {
        return forces_threads_[thread_num][particle_id];
    }

    void preprocess_forces() noexcept { /*do nothing*/ }
    void postprocess_forces() noexcept
    {
#pragma omp parallel for
        for(std::size_t i=0; i<this->size(); ++i)
        {
            // sumup all the thread-local forces into the main force.
            // XXX: keep the values in the main force! Some pre-omp interactions
            //      may write its force in it. Clearing main force is a task
            //      for Integrators.
            for(std::size_t thread_id=0, max_threads=omp_get_max_threads();
                    thread_id < max_threads; ++thread_id)
            {
                this->force(i) += this->force_thread(thread_id, i);
                this->force_thread(thread_id, i) =
                    math::make_coordinate<coordinate_type>(0, 0, 0);
            }
        }
        return;
    }

    string_type const& name (std::size_t i) const noexcept {return names_[i];}
    string_type&       name (std::size_t i)       noexcept {return names_[i];}
    string_type const& group(std::size_t i) const noexcept {return groups_[i];}
    string_type&       group(std::size_t i)       noexcept {return groups_[i];}

    boundary_type&       boundary()       noexcept {return boundary_;}
    boundary_type const& boundary() const noexcept {return boundary_;}

    // system attributes like `reference temperature`, `ionic strength`, ...
    // assuming it will not be called so often.
    real_type  attribute(const std::string& key) const {return attributes_.at(key);}
    real_type& attribute(const std::string& key)       {return attributes_[key];}
    bool   has_attribute(const std::string& key) const {return attributes_.count(key) == 1;}
    attribute_type const& attributes() const noexcept {return attributes_;}

    bool  velocity_initialized() const noexcept {return velocity_initialized_;}
    bool& velocity_initialized()       noexcept {return velocity_initialized_;}

    coordinate_container_type const& forces() const noexcept {return forces_main_;}
    coordinate_container_type&       forces()       noexcept {return forces_main_;}

  private:

    bool           velocity_initialized_;
    boundary_type  boundary_;
    attribute_type attributes_;

    std::size_t                  num_particles_;
    real_container_type          masses_;
    real_container_type          rmasses_; // r for reciprocal
    coordinate_container_type    positions_;
    coordinate_container_type    velocities_;
    coordinate_container_type    forces_main_;
    // thread-local forces
    std::vector<coordinate_container_type,
                cache_aligned_allocator<coordinate_container_type>
        > forces_threads_;
    string_container_type        names_;
    string_container_type        groups_;

    // names and groups are in Topology class
};

#ifdef MJOLNIR_SEPARATE_BUILD
extern template class System<OpenMPSimulatorTraits<double, UnlimitedBoundary>>;
extern template class System<OpenMPSimulatorTraits<float,  UnlimitedBoundary>>;
extern template class System<OpenMPSimulatorTraits<double, CuboidalPeriodicBoundary>>;
extern template class System<OpenMPSimulatorTraits<float,  CuboidalPeriodicBoundary>>;
#endif

} // mjolnir
#endif// MJOLNIR_SYSTEM_HPP
<|endoftext|>


<commit_before>#include "BoundImpDirWrapper.h"
#include "PEFile.h"

using namespace pe;
size_t BoundImpDirWrapper::EntriesLimit = 1000;

/*
typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    NumberOfModuleForwarderRefs;
    // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
} IMAGE_BOUND_IMPORT_DESCRIPTOR,  *PIMAGE_BOUND_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_BOUND_FORWARDER_REF {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    Reserved;
} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;

*/

pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* BoundImpDirWrapper::boundImp()
{
    offset_t rva = getDirEntryAddress();

    BYTE *ptr = m_Exe->getContentAt(rva, Executable::RVA, sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR));
    if (ptr == NULL) return NULL;
    return (pe::IMAGE_BOUND_IMPORT_DESCRIPTOR*) ptr;
}

bool BoundImpDirWrapper::loadNextEntry(size_t entryNum)
{
    BoundEntryWrapper* imp = new BoundEntryWrapper(m_Exe, this, entryNum);
    if (!imp || !imp->getPtr()) return false;

    // TODO! do it in proper way!
    bool isOk = false;
    uint64_t offset = imp->getNumValue(BoundEntryWrapper::MODULE_NAME_OFFSET, &isOk);
    if (!isOk || offset == 0) {
        delete imp;
        return false;
    }
    entries.push_back(imp);
    return true;
}

bool BoundImpDirWrapper::wrap()
{
    clear();
    size_t oldCount = this->importsCount;
    this->importsCount = 0;

    if (!getDataDirectory()) {
        return (oldCount != this->importsCount); //has count changed
    }

    const size_t LIMIT = BoundImpDirWrapper::EntriesLimit;

    size_t cntr = 0;
    for (cntr = 0; cntr < LIMIT; cntr++) {
        if (loadNextEntry(cntr) == false) break;
    }

    this->importsCount = cntr;
    return (oldCount != this->importsCount); //has count changed
}

bufsize_t BoundImpDirWrapper::getSize()
{
    if (getPtr() == NULL) return 0;
    bufsize_t entrySize = static_cast<bufsize_t>(sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR));
    return entrySize * static_cast<bufsize_t>(this->entries.size());
}

//-------------------------------------------------------------

void* BoundEntryWrapper::getPtr()
{
    BoundImpDirWrapper* parent = dynamic_cast<BoundImpDirWrapper*> (this->getParentNode());
    if (!parent) return NULL;

    pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* firstEntry = parent->boundImp();
    if (firstEntry == NULL) return NULL;

    uint64_t descAddr = parent->getOffset(firstEntry);
    if (descAddr == INVALID_ADDR) return NULL;

    uint64_t entryOffset = descAddr + (this->entryNum * sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR));
    if (entryOffset == INVALID_ADDR) return NULL;

    BYTE *content =  this->m_Exe->getContentAt(entryOffset, Executable::RAW, sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR));
    if (!content) return NULL;

    return content;
}

bufsize_t BoundEntryWrapper::getSize()
{
    if (getPtr() == NULL) return 0;
    return sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR);
}

QString BoundEntryWrapper::getName()
{
    char* name = getLibraryName();
    if (!name) return "";
    return QString(name);
}

char* BoundEntryWrapper::getLibraryName()
{
    //----
    BoundImpDirWrapper* parent = dynamic_cast<BoundImpDirWrapper*> (this->getParentNode());
    if (!parent) return NULL;

    pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* firstEntry = parent->boundImp();
    if (firstEntry == NULL) return NULL;

    uint64_t offset = this->getOffset(firstEntry);
    if (offset == INVALID_ADDR) return NULL;
    //----
    pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* bImp = (pe::IMAGE_BOUND_IMPORT_DESCRIPTOR*) this->getPtr();
    if (bImp == NULL) return NULL;

    WORD mnOff = bImp->OffsetModuleName;

    offset += mnOff;

    char *ptr = (char*) m_Exe->getContentAt(offset, Executable::RAW, 1);
    return ptr;
}

void* BoundEntryWrapper::getFieldPtr(size_t fId, size_t subField)
{
    BoundImpDirWrapper* parent = dynamic_cast<BoundImpDirWrapper*> (this->getParentNode());
    if (!parent) return NULL;

    pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* bImp = (pe::IMAGE_BOUND_IMPORT_DESCRIPTOR*) this->getPtr();
    if (bImp == NULL) return NULL;

    switch (fId) {
        case TIMESTAMP : return &bImp->TimeDateStamp;
        case MODULE_NAME_OFFSET : return &bImp->OffsetModuleName;
        case MODULE_FORWARDERS_NUM : return &bImp->NumberOfModuleForwarderRefs;
    }
    return this->getPtr();
}

QString BoundEntryWrapper::getFieldName(size_t fieldId)
{
    switch (fieldId) {
        case TIMESTAMP : return "TimeDateStamp";
        case MODULE_NAME_OFFSET : return "OffsetModuleName";
        case MODULE_FORWARDERS_NUM : return "NumberOfModuleForwarderRefs";
    }
    return getName();
}

<commit_msg>[BUGFIX] In BoundImpDirWrapper: fixed leak in loadNextEntry<commit_after>#include "BoundImpDirWrapper.h"
#include "PEFile.h"

using namespace pe;
size_t BoundImpDirWrapper::EntriesLimit = 1000;

/*
typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    NumberOfModuleForwarderRefs;
    // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
} IMAGE_BOUND_IMPORT_DESCRIPTOR,  *PIMAGE_BOUND_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_BOUND_FORWARDER_REF {
    DWORD   TimeDateStamp;
    WORD    OffsetModuleName;
    WORD    Reserved;
} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;

*/

pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* BoundImpDirWrapper::boundImp()
{
    offset_t rva = getDirEntryAddress();

    BYTE *ptr = m_Exe->getContentAt(rva, Executable::RVA, sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR));
    if (ptr == NULL) return NULL;
    return (pe::IMAGE_BOUND_IMPORT_DESCRIPTOR*) ptr;
}

bool BoundImpDirWrapper::loadNextEntry(size_t entryNum)
{
    BoundEntryWrapper* imp = new BoundEntryWrapper(m_Exe, this, entryNum);
    if (!imp || !imp->getPtr()) {
        delete imp;
        return false;
    }
    // TODO! do it in proper way!
    bool isOk = false;
    uint64_t offset = imp->getNumValue(BoundEntryWrapper::MODULE_NAME_OFFSET, &isOk);
    if (!isOk || offset == 0) {
        delete imp;
        return false;
    }
    entries.push_back(imp);
    return true;
}

bool BoundImpDirWrapper::wrap()
{
    clear();
    size_t oldCount = this->importsCount;
    this->importsCount = 0;

    if (!getDataDirectory()) {
        return (oldCount != this->importsCount); //has count changed
    }

    const size_t LIMIT = BoundImpDirWrapper::EntriesLimit;

    size_t cntr = 0;
    for (cntr = 0; cntr < LIMIT; cntr++) {
        if (loadNextEntry(cntr) == false) break;
    }

    this->importsCount = cntr;
    return (oldCount != this->importsCount); //has count changed
}

bufsize_t BoundImpDirWrapper::getSize()
{
    if (getPtr() == NULL) return 0;
    bufsize_t entrySize = static_cast<bufsize_t>(sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR));
    return entrySize * static_cast<bufsize_t>(this->entries.size());
}

//-------------------------------------------------------------

void* BoundEntryWrapper::getPtr()
{
    BoundImpDirWrapper* parent = dynamic_cast<BoundImpDirWrapper*> (this->getParentNode());
    if (!parent) return NULL;

    pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* firstEntry = parent->boundImp();
    if (firstEntry == NULL) return NULL;

    uint64_t descAddr = parent->getOffset(firstEntry);
    if (descAddr == INVALID_ADDR) return NULL;

    uint64_t entryOffset = descAddr + (this->entryNum * sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR));
    if (entryOffset == INVALID_ADDR) return NULL;

    BYTE *content =  this->m_Exe->getContentAt(entryOffset, Executable::RAW, sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR));
    if (!content) return NULL;

    return content;
}

bufsize_t BoundEntryWrapper::getSize()
{
    if (getPtr() == NULL) return 0;
    return sizeof(pe::IMAGE_BOUND_IMPORT_DESCRIPTOR);
}

QString BoundEntryWrapper::getName()
{
    char* name = getLibraryName();
    if (!name) return "";
    return QString(name);
}

char* BoundEntryWrapper::getLibraryName()
{
    //----
    BoundImpDirWrapper* parent = dynamic_cast<BoundImpDirWrapper*> (this->getParentNode());
    if (!parent) return NULL;

    pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* firstEntry = parent->boundImp();
    if (firstEntry == NULL) return NULL;

    uint64_t offset = this->getOffset(firstEntry);
    if (offset == INVALID_ADDR) return NULL;
    //----
    pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* bImp = (pe::IMAGE_BOUND_IMPORT_DESCRIPTOR*) this->getPtr();
    if (bImp == NULL) return NULL;

    WORD mnOff = bImp->OffsetModuleName;

    offset += mnOff;

    char *ptr = (char*) m_Exe->getContentAt(offset, Executable::RAW, 1);
    return ptr;
}

void* BoundEntryWrapper::getFieldPtr(size_t fId, size_t subField)
{
    BoundImpDirWrapper* parent = dynamic_cast<BoundImpDirWrapper*> (this->getParentNode());
    if (!parent) return NULL;

    pe::IMAGE_BOUND_IMPORT_DESCRIPTOR* bImp = (pe::IMAGE_BOUND_IMPORT_DESCRIPTOR*) this->getPtr();
    if (bImp == NULL) return NULL;

    switch (fId) {
        case TIMESTAMP : return &bImp->TimeDateStamp;
        case MODULE_NAME_OFFSET : return &bImp->OffsetModuleName;
        case MODULE_FORWARDERS_NUM : return &bImp->NumberOfModuleForwarderRefs;
    }
    return this->getPtr();
}

QString BoundEntryWrapper::getFieldName(size_t fieldId)
{
    switch (fieldId) {
        case TIMESTAMP : return "TimeDateStamp";
        case MODULE_NAME_OFFSET : return "OffsetModuleName";
        case MODULE_FORWARDERS_NUM : return "NumberOfModuleForwarderRefs";
    }
    return getName();
}

<|endoftext|>