<commit_before>/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 "reflection.h"

#include "class_linker.h"
#include "jni_internal.h"
#include "object.h"
#include "object_utils.h"

#include "JniConstants.h" // Last to avoid problems with LOG redefinition.

namespace art {

Method* gBoolean_valueOf;
Method* gByte_valueOf;
Method* gCharacter_valueOf;
Method* gDouble_valueOf;
Method* gFloat_valueOf;
Method* gInteger_valueOf;
Method* gLong_valueOf;
Method* gShort_valueOf;

void InitBoxingMethods() {
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  gBoolean_valueOf = class_linker->FindSystemClass("Ljava/lang/Boolean;")->FindDeclaredDirectMethod("valueOf", "(Z)Ljava/lang/Boolean;");
  gByte_valueOf = class_linker->FindSystemClass("Ljava/lang/Byte;")->FindDeclaredDirectMethod("valueOf", "(B)Ljava/lang/Byte;");
  gCharacter_valueOf = class_linker->FindSystemClass("Ljava/lang/Character;")->FindDeclaredDirectMethod("valueOf", "(C)Ljava/lang/Character;");
  gDouble_valueOf = class_linker->FindSystemClass("Ljava/lang/Double;")->FindDeclaredDirectMethod("valueOf", "(D)Ljava/lang/Double;");
  gFloat_valueOf = class_linker->FindSystemClass("Ljava/lang/Float;")->FindDeclaredDirectMethod("valueOf", "(F)Ljava/lang/Float;");
  gInteger_valueOf = class_linker->FindSystemClass("Ljava/lang/Integer;")->FindDeclaredDirectMethod("valueOf", "(I)Ljava/lang/Integer;");
  gLong_valueOf = class_linker->FindSystemClass("Ljava/lang/Long;")->FindDeclaredDirectMethod("valueOf", "(J)Ljava/lang/Long;");
  gShort_valueOf = class_linker->FindSystemClass("Ljava/lang/Short;")->FindDeclaredDirectMethod("valueOf", "(S)Ljava/lang/Short;");
}

jobject InvokeMethod(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs) {
  Thread* self = Thread::Current();
  ScopedThreadStateChange tsc(self, Thread::kRunnable);

  jmethodID mid = env->FromReflectedMethod(javaMethod);
  Method* m = reinterpret_cast<Method*>(mid);

  Class* declaring_class = m->GetDeclaringClass();
  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaring_class, true)) {
    return NULL;
  }

  Object* receiver = NULL;
  if (!m->IsStatic()) {
    // Check that the receiver is non-null and an instance of the field's declaring class.
    receiver = Decode<Object*>(env, javaReceiver);
    if (!VerifyObjectInClass(env, receiver, declaring_class)) {
      return NULL;
    }

    // Find the actual implementation of the virtual method.
    m = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(m);
    mid = reinterpret_cast<jmethodID>(m);
  }

  // Get our arrays of arguments and their types, and check they're the same size.
  ObjectArray<Object>* objects = Decode<ObjectArray<Object>*>(env, javaArgs);
  MethodHelper mh(m);
  const DexFile::TypeList* classes = mh.GetParameterTypeList();
  uint32_t classes_size = classes == NULL ? 0 : classes->Size();
  uint32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
  if (arg_count != classes_size) {
    self->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
        "wrong number of arguments; expected %d, got %d",
        classes_size, arg_count);
    return NULL;
  }

  // Translate javaArgs to a jvalue[].
  UniquePtr<jvalue[]> args(new jvalue[arg_count]);
  JValue* decoded_args = reinterpret_cast<JValue*>(args.get());
  for (uint32_t i = 0; i < arg_count; ++i) {
    Object* arg = objects->Get(i);
    Class* dst_class = mh.GetClassFromTypeIdx(classes->GetTypeItem(i).type_idx_);
    if (dst_class->IsPrimitive()) {
      std::string what(StringPrintf("argument %d", i + 1)); // Humans count from 1.
      if (!UnboxPrimitive(env, arg, dst_class, decoded_args[i], what.c_str())) {
        return NULL;
      }
    } else {
      args[i].l = AddLocalReference<jobject>(env, arg);
    }
  }

  // Invoke the method.
  JValue value = InvokeWithJValues(env, javaReceiver, mid, args.get());

  // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
  if (self->IsExceptionPending()) {
    jthrowable th = env->ExceptionOccurred();
    env->ExceptionClear();
    jclass exception_class = env->FindClass("java/lang/reflect/InvocationTargetException");
    jmethodID mid = env->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
    jobject exception_instance = env->NewObject(exception_class, mid, th);
    env->Throw(reinterpret_cast<jthrowable>(exception_instance));
    return NULL;
  }

  // Box if necessary and return.
  BoxPrimitive(env, mh.GetReturnType()->GetPrimitiveType(), value);
  return AddLocalReference<jobject>(env, value.l);
}

bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c) {
  const char* exception = NULL;
  if (o == NULL) {
    exception = "java/lang/NullPointerException";
  } else if (!o->InstanceOf(c)) {
    exception = "java/lang/IllegalArgumentException";
  }
  if (exception != NULL) {
    std::string expected_class_name(PrettyDescriptor(c));
    std::string actual_class_name(PrettyTypeOf(o));
    jniThrowExceptionFmt(env, exception, "expected receiver of type %s, but got %s",
                         expected_class_name.c_str(), actual_class_name.c_str());
    return false;
  }
  return true;
}

/*
 * Convert primitive, boxed data from "srcPtr" to "dstPtr".
 *
 * Section v2 2.6 lists the various conversions and promotions.  We
 * allow the "widening" and "identity" conversions, but don't allow the
 * "narrowing" conversions.
 *
 * Allowed:
 *  byte to short, int, long, float, double
 *  short to int, long, float double
 *  char to int, long, float, double
 *  int to long, float, double
 *  long to float, double
 *  float to double
 * Values of types byte, char, and short are "internally" widened to int.
 *
 * Returns the width in 32-bit words of the destination primitive, or
 * -1 if the conversion is not allowed.
 */
bool ConvertPrimitiveValue(Primitive::Type srcType, Primitive::Type dstType,
                           const JValue& src, JValue& dst) {
  CHECK(srcType != Primitive::kPrimNot && dstType != Primitive::kPrimNot);
  switch (dstType) {
  case Primitive::kPrimBoolean:
  case Primitive::kPrimChar:
  case Primitive::kPrimByte:
    if (srcType == dstType) {
      dst.i = src.i;
      return true;
    }
    break;
  case Primitive::kPrimShort:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimShort) {
      dst.i = src.i;
      return true;
    }
    break;
  case Primitive::kPrimInt:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
        srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
      dst.i = src.i;
      return true;
    }
    break;
  case Primitive::kPrimLong:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
        srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
      dst.j = src.i;
      return true;
    } else if (srcType == Primitive::kPrimLong) {
      dst.j = src.j;
      return true;
    }
    break;
  case Primitive::kPrimFloat:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
        srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
      dst.f = src.i;
      return true;
    } else if (srcType == Primitive::kPrimLong) {
      dst.f = src.j;
      return true;
    } else if (srcType == Primitive::kPrimFloat) {
      dst.i = src.i;
      return true;
    }
    break;
  case Primitive::kPrimDouble:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
        srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
      dst.d = src.i;
      return true;
    } else if (srcType == Primitive::kPrimLong) {
      dst.d = src.j;
      return true;
    } else if (srcType == Primitive::kPrimFloat) {
      dst.d = src.f;
      return true;
    } else if (srcType == Primitive::kPrimDouble) {
      dst.j = src.j;
      return true;
    }
    break;
  default:
    break;
  }
  Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                        "invalid primitive conversion from %s to %s",
                                        PrettyDescriptor(srcType).c_str(),
                                        PrettyDescriptor(dstType).c_str());
  return false;
}

void BoxPrimitive(JNIEnv*, Primitive::Type src_class, JValue& value) {
  if (src_class == Primitive::kPrimNot) {
    return;
  }

  Method* m = NULL;
  switch (src_class) {
  case Primitive::kPrimBoolean:
    m = gBoolean_valueOf;
    break;
  case Primitive::kPrimByte:
    m = gByte_valueOf;
    break;
  case Primitive::kPrimChar:
    m = gCharacter_valueOf;
    break;
  case Primitive::kPrimDouble:
    m = gDouble_valueOf;
    break;
  case Primitive::kPrimFloat:
    m = gFloat_valueOf;
    break;
  case Primitive::kPrimInt:
    m = gInteger_valueOf;
    break;
  case Primitive::kPrimLong:
    m = gLong_valueOf;
    break;
  case Primitive::kPrimShort:
    m = gShort_valueOf;
    break;
  case Primitive::kPrimVoid:
    // There's no such thing as a void field, and void methods invoked via reflection return null.
    value.l = NULL;
    return;
  default:
    LOG(FATAL) << static_cast<int>(src_class);
  }

  Thread* self = Thread::Current();
  ScopedThreadStateChange tsc(self, Thread::kRunnable);
  JValue args[1];
  args[0].j = 0;
  m->Invoke(self, NULL, args, &value);
}

bool UnboxPrimitive(JNIEnv*, Object* o, Class* dst_class, JValue& unboxed_value, const char* what) {
  if (!dst_class->IsPrimitive()) {
    if (o != NULL && !o->InstanceOf(dst_class)) {
      Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                            "boxed object for %s should have type %s, but got %s",
                                            what,
                                            PrettyDescriptor(dst_class).c_str(),
                                            PrettyTypeOf(o).c_str());
      return false;
    }
    unboxed_value.l = o;
    return true;
  } else if (dst_class->GetPrimitiveType() == Primitive::kPrimVoid) {
    Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                          "can't unbox %s to void",
                                          what);
    return false;
  }

  if (o == NULL) {
    Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                          "%s should have type %s, got null",
                                          what,
                                          PrettyDescriptor(dst_class).c_str());
    return false;
  }

  JValue boxed_value = { 0 };
  std::string src_descriptor(ClassHelper(o->GetClass()).GetDescriptor());
  Class* src_class = NULL;
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  Field* primitive_field = o->GetClass()->GetIFields()->Get(0);
  if (src_descriptor == "Ljava/lang/Boolean;") {
    src_class = class_linker->FindPrimitiveClass('Z');
    boxed_value.i = primitive_field->GetBoolean(o);  // and extend read value to 32bits
  } else if (src_descriptor == "Ljava/lang/Byte;") {
    src_class = class_linker->FindPrimitiveClass('B');
    boxed_value.i = primitive_field->GetByte(o);  // and extend read value to 32bits
  } else if (src_descriptor == "Ljava/lang/Character;") {
    src_class = class_linker->FindPrimitiveClass('C');
    boxed_value.i = primitive_field->GetChar(o);  // and extend read value to 32bits
  } else if (src_descriptor == "Ljava/lang/Float;") {
    src_class = class_linker->FindPrimitiveClass('F');
    boxed_value.f = primitive_field->GetFloat(o);
  } else if (src_descriptor == "Ljava/lang/Double;") {
    src_class = class_linker->FindPrimitiveClass('D');
    boxed_value.d = primitive_field->GetDouble(o);
  } else if (src_descriptor == "Ljava/lang/Integer;") {
    src_class = class_linker->FindPrimitiveClass('I');
    boxed_value.i = primitive_field->GetInt(o);
  } else if (src_descriptor == "Ljava/lang/Long;") {
    src_class = class_linker->FindPrimitiveClass('J');
    boxed_value.j = primitive_field->GetLong(o);
  } else if (src_descriptor == "Ljava/lang/Short;") {
    src_class = class_linker->FindPrimitiveClass('S');
    boxed_value.i = primitive_field->GetShort(o);  // and extend read value to 32bits
  } else {
    Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                          "%s should have type %s, got %s",
                                          what,
                                          PrettyDescriptor(dst_class).c_str(),
                                          PrettyDescriptor(src_descriptor.c_str()).c_str());
    return false;
  }

  return ConvertPrimitiveValue(src_class->GetPrimitiveType(), dst_class->GetPrimitiveType(),
                               boxed_value, unboxed_value);
}

}  // namespace art
<commit_msg>Fix boxing; my invoke stub changes broke this.<commit_after>/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 "reflection.h"

#include "class_linker.h"
#include "jni_internal.h"
#include "object.h"
#include "object_utils.h"

#include "JniConstants.h" // Last to avoid problems with LOG redefinition.

namespace art {

Method* gBoolean_valueOf;
Method* gByte_valueOf;
Method* gCharacter_valueOf;
Method* gDouble_valueOf;
Method* gFloat_valueOf;
Method* gInteger_valueOf;
Method* gLong_valueOf;
Method* gShort_valueOf;

void InitBoxingMethods() {
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  gBoolean_valueOf = class_linker->FindSystemClass("Ljava/lang/Boolean;")->FindDeclaredDirectMethod("valueOf", "(Z)Ljava/lang/Boolean;");
  gByte_valueOf = class_linker->FindSystemClass("Ljava/lang/Byte;")->FindDeclaredDirectMethod("valueOf", "(B)Ljava/lang/Byte;");
  gCharacter_valueOf = class_linker->FindSystemClass("Ljava/lang/Character;")->FindDeclaredDirectMethod("valueOf", "(C)Ljava/lang/Character;");
  gDouble_valueOf = class_linker->FindSystemClass("Ljava/lang/Double;")->FindDeclaredDirectMethod("valueOf", "(D)Ljava/lang/Double;");
  gFloat_valueOf = class_linker->FindSystemClass("Ljava/lang/Float;")->FindDeclaredDirectMethod("valueOf", "(F)Ljava/lang/Float;");
  gInteger_valueOf = class_linker->FindSystemClass("Ljava/lang/Integer;")->FindDeclaredDirectMethod("valueOf", "(I)Ljava/lang/Integer;");
  gLong_valueOf = class_linker->FindSystemClass("Ljava/lang/Long;")->FindDeclaredDirectMethod("valueOf", "(J)Ljava/lang/Long;");
  gShort_valueOf = class_linker->FindSystemClass("Ljava/lang/Short;")->FindDeclaredDirectMethod("valueOf", "(S)Ljava/lang/Short;");
}

jobject InvokeMethod(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs) {
  Thread* self = Thread::Current();
  ScopedThreadStateChange tsc(self, Thread::kRunnable);

  jmethodID mid = env->FromReflectedMethod(javaMethod);
  Method* m = reinterpret_cast<Method*>(mid);

  Class* declaring_class = m->GetDeclaringClass();
  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaring_class, true)) {
    return NULL;
  }

  Object* receiver = NULL;
  if (!m->IsStatic()) {
    // Check that the receiver is non-null and an instance of the field's declaring class.
    receiver = Decode<Object*>(env, javaReceiver);
    if (!VerifyObjectInClass(env, receiver, declaring_class)) {
      return NULL;
    }

    // Find the actual implementation of the virtual method.
    m = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(m);
    mid = reinterpret_cast<jmethodID>(m);
  }

  // Get our arrays of arguments and their types, and check they're the same size.
  ObjectArray<Object>* objects = Decode<ObjectArray<Object>*>(env, javaArgs);
  MethodHelper mh(m);
  const DexFile::TypeList* classes = mh.GetParameterTypeList();
  uint32_t classes_size = classes == NULL ? 0 : classes->Size();
  uint32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
  if (arg_count != classes_size) {
    self->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
        "wrong number of arguments; expected %d, got %d",
        classes_size, arg_count);
    return NULL;
  }

  // Translate javaArgs to a jvalue[].
  UniquePtr<jvalue[]> args(new jvalue[arg_count]);
  JValue* decoded_args = reinterpret_cast<JValue*>(args.get());
  for (uint32_t i = 0; i < arg_count; ++i) {
    Object* arg = objects->Get(i);
    Class* dst_class = mh.GetClassFromTypeIdx(classes->GetTypeItem(i).type_idx_);
    if (dst_class->IsPrimitive()) {
      std::string what(StringPrintf("argument %d", i + 1)); // Humans count from 1.
      if (!UnboxPrimitive(env, arg, dst_class, decoded_args[i], what.c_str())) {
        return NULL;
      }
    } else {
      args[i].l = AddLocalReference<jobject>(env, arg);
    }
  }

  // Invoke the method.
  JValue value = InvokeWithJValues(env, javaReceiver, mid, args.get());

  // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
  if (self->IsExceptionPending()) {
    jthrowable th = env->ExceptionOccurred();
    env->ExceptionClear();
    jclass exception_class = env->FindClass("java/lang/reflect/InvocationTargetException");
    jmethodID mid = env->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
    jobject exception_instance = env->NewObject(exception_class, mid, th);
    env->Throw(reinterpret_cast<jthrowable>(exception_instance));
    return NULL;
  }

  // Box if necessary and return.
  BoxPrimitive(env, mh.GetReturnType()->GetPrimitiveType(), value);
  return AddLocalReference<jobject>(env, value.l);
}

bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c) {
  const char* exception = NULL;
  if (o == NULL) {
    exception = "java/lang/NullPointerException";
  } else if (!o->InstanceOf(c)) {
    exception = "java/lang/IllegalArgumentException";
  }
  if (exception != NULL) {
    std::string expected_class_name(PrettyDescriptor(c));
    std::string actual_class_name(PrettyTypeOf(o));
    jniThrowExceptionFmt(env, exception, "expected receiver of type %s, but got %s",
                         expected_class_name.c_str(), actual_class_name.c_str());
    return false;
  }
  return true;
}

/*
 * Convert primitive, boxed data from "srcPtr" to "dstPtr".
 *
 * Section v2 2.6 lists the various conversions and promotions.  We
 * allow the "widening" and "identity" conversions, but don't allow the
 * "narrowing" conversions.
 *
 * Allowed:
 *  byte to short, int, long, float, double
 *  short to int, long, float double
 *  char to int, long, float, double
 *  int to long, float, double
 *  long to float, double
 *  float to double
 * Values of types byte, char, and short are "internally" widened to int.
 *
 * Returns the width in 32-bit words of the destination primitive, or
 * -1 if the conversion is not allowed.
 */
bool ConvertPrimitiveValue(Primitive::Type srcType, Primitive::Type dstType,
                           const JValue& src, JValue& dst) {
  CHECK(srcType != Primitive::kPrimNot && dstType != Primitive::kPrimNot);
  switch (dstType) {
  case Primitive::kPrimBoolean:
  case Primitive::kPrimChar:
  case Primitive::kPrimByte:
    if (srcType == dstType) {
      dst.i = src.i;
      return true;
    }
    break;
  case Primitive::kPrimShort:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimShort) {
      dst.i = src.i;
      return true;
    }
    break;
  case Primitive::kPrimInt:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
        srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
      dst.i = src.i;
      return true;
    }
    break;
  case Primitive::kPrimLong:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
        srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
      dst.j = src.i;
      return true;
    } else if (srcType == Primitive::kPrimLong) {
      dst.j = src.j;
      return true;
    }
    break;
  case Primitive::kPrimFloat:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
        srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
      dst.f = src.i;
      return true;
    } else if (srcType == Primitive::kPrimLong) {
      dst.f = src.j;
      return true;
    } else if (srcType == Primitive::kPrimFloat) {
      dst.i = src.i;
      return true;
    }
    break;
  case Primitive::kPrimDouble:
    if (srcType == Primitive::kPrimByte || srcType == Primitive::kPrimChar ||
        srcType == Primitive::kPrimShort || srcType == Primitive::kPrimInt) {
      dst.d = src.i;
      return true;
    } else if (srcType == Primitive::kPrimLong) {
      dst.d = src.j;
      return true;
    } else if (srcType == Primitive::kPrimFloat) {
      dst.d = src.f;
      return true;
    } else if (srcType == Primitive::kPrimDouble) {
      dst.j = src.j;
      return true;
    }
    break;
  default:
    break;
  }
  Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                        "invalid primitive conversion from %s to %s",
                                        PrettyDescriptor(srcType).c_str(),
                                        PrettyDescriptor(dstType).c_str());
  return false;
}

void BoxPrimitive(JNIEnv*, Primitive::Type src_class, JValue& value) {
  if (src_class == Primitive::kPrimNot) {
    return;
  }

  Method* m = NULL;
  switch (src_class) {
  case Primitive::kPrimBoolean:
    m = gBoolean_valueOf;
    break;
  case Primitive::kPrimByte:
    m = gByte_valueOf;
    break;
  case Primitive::kPrimChar:
    m = gCharacter_valueOf;
    break;
  case Primitive::kPrimDouble:
    m = gDouble_valueOf;
    break;
  case Primitive::kPrimFloat:
    m = gFloat_valueOf;
    break;
  case Primitive::kPrimInt:
    m = gInteger_valueOf;
    break;
  case Primitive::kPrimLong:
    m = gLong_valueOf;
    break;
  case Primitive::kPrimShort:
    m = gShort_valueOf;
    break;
  case Primitive::kPrimVoid:
    // There's no such thing as a void field, and void methods invoked via reflection return null.
    value.l = NULL;
    return;
  default:
    LOG(FATAL) << static_cast<int>(src_class);
  }

  Thread* self = Thread::Current();
  ScopedThreadStateChange tsc(self, Thread::kRunnable);
  JValue args[1] = { value };
  m->Invoke(self, NULL, args, &value);
}

bool UnboxPrimitive(JNIEnv*, Object* o, Class* dst_class, JValue& unboxed_value, const char* what) {
  if (!dst_class->IsPrimitive()) {
    if (o != NULL && !o->InstanceOf(dst_class)) {
      Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                            "boxed object for %s should have type %s, but got %s",
                                            what,
                                            PrettyDescriptor(dst_class).c_str(),
                                            PrettyTypeOf(o).c_str());
      return false;
    }
    unboxed_value.l = o;
    return true;
  } else if (dst_class->GetPrimitiveType() == Primitive::kPrimVoid) {
    Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                          "can't unbox %s to void",
                                          what);
    return false;
  }

  if (o == NULL) {
    Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                          "%s should have type %s, got null",
                                          what,
                                          PrettyDescriptor(dst_class).c_str());
    return false;
  }

  JValue boxed_value = { 0 };
  std::string src_descriptor(ClassHelper(o->GetClass()).GetDescriptor());
  Class* src_class = NULL;
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  Field* primitive_field = o->GetClass()->GetIFields()->Get(0);
  if (src_descriptor == "Ljava/lang/Boolean;") {
    src_class = class_linker->FindPrimitiveClass('Z');
    boxed_value.i = primitive_field->GetBoolean(o);  // and extend read value to 32bits
  } else if (src_descriptor == "Ljava/lang/Byte;") {
    src_class = class_linker->FindPrimitiveClass('B');
    boxed_value.i = primitive_field->GetByte(o);  // and extend read value to 32bits
  } else if (src_descriptor == "Ljava/lang/Character;") {
    src_class = class_linker->FindPrimitiveClass('C');
    boxed_value.i = primitive_field->GetChar(o);  // and extend read value to 32bits
  } else if (src_descriptor == "Ljava/lang/Float;") {
    src_class = class_linker->FindPrimitiveClass('F');
    boxed_value.f = primitive_field->GetFloat(o);
  } else if (src_descriptor == "Ljava/lang/Double;") {
    src_class = class_linker->FindPrimitiveClass('D');
    boxed_value.d = primitive_field->GetDouble(o);
  } else if (src_descriptor == "Ljava/lang/Integer;") {
    src_class = class_linker->FindPrimitiveClass('I');
    boxed_value.i = primitive_field->GetInt(o);
  } else if (src_descriptor == "Ljava/lang/Long;") {
    src_class = class_linker->FindPrimitiveClass('J');
    boxed_value.j = primitive_field->GetLong(o);
  } else if (src_descriptor == "Ljava/lang/Short;") {
    src_class = class_linker->FindPrimitiveClass('S');
    boxed_value.i = primitive_field->GetShort(o);  // and extend read value to 32bits
  } else {
    Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
                                          "%s should have type %s, got %s",
                                          what,
                                          PrettyDescriptor(dst_class).c_str(),
                                          PrettyDescriptor(src_descriptor.c_str()).c_str());
    return false;
  }

  return ConvertPrimitiveValue(src_class->GetPrimitiveType(), dst_class->GetPrimitiveType(),
                               boxed_value, unboxed_value);
}

}  // namespace art
<|endoftext|>


<commit_before>#ifndef regex_impl_hh_INCLUDED
#define regex_impl_hh_INCLUDED

#include "exception.hh"
#include "flags.hh"
#include "ref_ptr.hh"
#include "unicode.hh"
#include "utf8.hh"
#include "utf8_iterator.hh"
#include "vector.hh"

#include <string.h>

namespace Kakoune
{

enum class MatchDirection
{
    Forward,
    Backward
};

struct CompiledRegex : RefCountable
{
    enum Op : char
    {
        Match,
        Literal,
        LiteralIgnoreCase,
        AnyChar,
        Matcher,
        Jump,
        Split_PrioritizeParent,
        Split_PrioritizeChild,
        Save,
        LineStart,
        LineEnd,
        WordBoundary,
        NotWordBoundary,
        SubjectBegin,
        SubjectEnd,
        LookAhead,
        NegativeLookAhead,
        LookBehind,
        NegativeLookBehind,
    };

    struct Instruction
    {
        Op op;
        mutable bool processed;
        mutable bool scheduled;
        uint32_t param;
    };
    static_assert(sizeof(Instruction) == 8, "");

    explicit operator bool() const { return not instructions.empty(); }

    Vector<Instruction> instructions;
    Vector<std::function<bool (Codepoint)>> matchers;
    Vector<Codepoint> lookarounds;
    MatchDirection direction;
    size_t save_count;

    struct StartChars { bool map[256]; };
    std::unique_ptr<StartChars> start_chars;
};

CompiledRegex compile_regex(StringView re, MatchDirection direction = MatchDirection::Forward);

enum class RegexExecFlags
{
    None              = 0,
    Search            = 1 << 0,
    NotBeginOfLine    = 1 << 1,
    NotEndOfLine      = 1 << 2,
    NotBeginOfWord    = 1 << 3,
    NotEndOfWord      = 1 << 4,
    NotBeginOfSubject = 1 << 5,
    NotInitialNull    = 1 << 6,
    AnyMatch          = 1 << 7,
    NoSaves           = 1 << 8,
    PrevAvailable     = 1 << 9,
};

constexpr bool with_bit_ops(Meta::Type<RegexExecFlags>) { return true; }

template<typename Iterator, MatchDirection direction>
struct ChooseUtf8It
{
    using Type = utf8::iterator<Iterator>;
};

template<typename Iterator>
struct ChooseUtf8It<Iterator, MatchDirection::Backward>
{
    using Type = std::reverse_iterator<utf8::iterator<Iterator>>;
};

template<typename Iterator, MatchDirection direction>
class ThreadedRegexVM
{
public:
    ThreadedRegexVM(const CompiledRegex& program)
      : m_program{program}
      {
          kak_assert(m_program);
          if (direction != program.direction)
              throw runtime_error{"Regex and VM direction mismatch"};
      }

    ThreadedRegexVM(const ThreadedRegexVM&) = delete;
    ThreadedRegexVM& operator=(const ThreadedRegexVM&) = delete;

    ~ThreadedRegexVM()
    {
        for (auto* saves : m_saves)
        {
            for (size_t i = m_program.save_count-1; i > 0; --i)
                saves->pos[i].~Iterator();
            saves->~Saves();
            ::operator delete(saves);
        }
    }

    bool exec(Iterator begin, Iterator end, RegexExecFlags flags)
    {
        const bool forward = direction == MatchDirection::Forward;
        const bool prev_avail = flags & RegexExecFlags::PrevAvailable;
        m_begin = Utf8It{utf8::iterator<Iterator>{forward ? begin : end,
                                                  prev_avail ? begin-1 : begin, end}};
        m_end = Utf8It{utf8::iterator<Iterator>{forward ? end : begin,
                                                prev_avail ? begin-1 : begin, end}};
        m_flags = flags;

        if (flags & RegexExecFlags::NotInitialNull and m_begin == m_end)
            return false;

        Vector<Thread> current_threads, next_threads;

        const bool no_saves = (m_flags & RegexExecFlags::NoSaves);
        Utf8It start{m_begin};

        const bool* start_chars = m_program.start_chars ? m_program.start_chars->map : nullptr;

        if (flags & RegexExecFlags::Search)
            to_next_start(start, m_end, start_chars);

        if (exec_from(start, no_saves ? nullptr : new_saves<false>(nullptr),
                      current_threads, next_threads))
            return true;

        if (not (flags & RegexExecFlags::Search))
            return false;

        do
        {
            to_next_start(++start, m_end, start_chars);
            if (exec_from(start, no_saves ? nullptr : new_saves<false>(nullptr),
                          current_threads, next_threads))
                return true;
        }
        while (start != m_end);

        return false;
    }

    ArrayView<const Iterator> captures() const
    {
        if (m_captures)
            return { m_captures->pos, m_program.save_count };
        return {};
    }

private:
    struct Saves
    {
        int refcount;
        Iterator pos[1];
    };

    template<bool copy>
    Saves* new_saves(Iterator* pos)
    {
        kak_assert(not copy or pos != nullptr);
        const auto count = m_program.save_count;
        if (not m_free_saves.empty())
        {
            Saves* res = m_free_saves.back();
            m_free_saves.pop_back();
            res->refcount = 1;
            if (copy)
                std::copy(pos, pos + count, res->pos);
            else
                std::fill(res->pos, res->pos + count, Iterator{});

            return res;
        }

        void* ptr = ::operator new (sizeof(Saves) + (count-1) * sizeof(Iterator));
        Saves* saves = new (ptr) Saves{1, {copy ? pos[0] : Iterator{}}};
        for (size_t i = 1; i < count; ++i)
            new (&saves->pos[i]) Iterator{copy ? pos[i] : Iterator{}};
        m_saves.push_back(saves);
        return saves;
    }

    void release_saves(Saves* saves)
    {
        if (saves and --saves->refcount == 0)
            m_free_saves.push_back(saves);
    };

    struct Thread
    {
        uint32_t inst;
        Saves* saves;
    };

    using Utf8It = typename ChooseUtf8It<Iterator, direction>::Type;

    enum class StepResult { Consumed, Matched, Failed };

    // Steps a thread until it consumes the current character, matches or fail
    StepResult step(const Utf8It& pos, Thread& thread, Vector<Thread>& threads)
    {
        while (true)
        {
            auto& inst = m_program.instructions[thread.inst++];
            if (inst.processed)
                return StepResult::Failed;
            inst.processed = true;

            switch (inst.op)
            {
                case CompiledRegex::Literal:
                    if (pos != m_end and inst.param == *pos)
                        return StepResult::Consumed;
                    return StepResult::Failed;
                case CompiledRegex::LiteralIgnoreCase:
                    if (pos != m_end and inst.param == to_lower(*pos))
                        return StepResult::Consumed;
                    return StepResult::Failed;
                case CompiledRegex::AnyChar:
                    return StepResult::Consumed;
                case CompiledRegex::Jump:
                    thread.inst = inst.param;
                    break;
                case CompiledRegex::Split_PrioritizeParent:
                {
                    if (thread.saves)
                        ++thread.saves->refcount;
                    threads.push_back({inst.param, thread.saves});
                    break;
                }
                case CompiledRegex::Split_PrioritizeChild:
                {
                    if (thread.saves)
                        ++thread.saves->refcount;
                    threads.push_back({thread.inst, thread.saves});
                    thread.inst = inst.param;
                    break;
                }
                case CompiledRegex::Save:
                {
                    if (thread.saves == nullptr)
                        break;
                    if (thread.saves->refcount > 1)
                    {
                        --thread.saves->refcount;
                        thread.saves = new_saves<true>(thread.saves->pos);
                    }
                    thread.saves->pos[inst.param] = get_base(pos);
                    break;
                }
                case CompiledRegex::Matcher:
                    if (pos == m_end)
                        return StepResult::Failed;
                    return m_program.matchers[inst.param](*pos) ?
                        StepResult::Consumed : StepResult::Failed;
                case CompiledRegex::LineStart:
                    if (not is_line_start(pos))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::LineEnd:
                    if (not is_line_end(pos))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::WordBoundary:
                    if (not is_word_boundary(pos))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::NotWordBoundary:
                    if (is_word_boundary(pos))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::SubjectBegin:
                    if (pos != m_begin or (m_flags & RegexExecFlags::NotBeginOfSubject))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::SubjectEnd:
                    if (pos != m_end)
                        return StepResult::Failed;
                    break;
                case CompiledRegex::LookAhead:
                case CompiledRegex::NegativeLookAhead:
                {
                    auto ref = m_program.lookarounds.begin() + inst.param;
                    for (auto it = pos; *ref != -1 and it != m_end; ++it, ++ref)
                        if (*it != *ref)
                            break;
                    if ((inst.op == CompiledRegex::LookAhead and *ref != -1) or
                        (inst.op == CompiledRegex::NegativeLookAhead and *ref == -1))
                        return StepResult::Failed;
                    break;
                }
                case CompiledRegex::LookBehind:
                case CompiledRegex::NegativeLookBehind:
                {
                    auto ref = m_program.lookarounds.begin() + inst.param;
                    for (auto it = pos; *ref != -1 and it > m_begin; --it, ++ref)
                        if (*(it-1) != *ref)
                            break;
                    if ((inst.op == CompiledRegex::LookBehind and *ref != -1) or
                        (inst.op == CompiledRegex::NegativeLookBehind and *ref == -1))
                        return StepResult::Failed;
                    break;
                }
                case CompiledRegex::Match:
                    return StepResult::Matched;
            }
        }
        return StepResult::Failed;
    }

    bool exec_from(Utf8It pos, Saves* initial_saves, Vector<Thread>& current_threads, Vector<Thread>& next_threads)
    {
        current_threads.push_back({0, initial_saves});
        next_threads.clear();

        bool found_match = false;
        while (true) // Iterate on all codepoints and once at the end
        {
            for (auto& inst : m_program.instructions)
            {
                inst.processed = false;
                inst.scheduled = false;
            }

            while (not current_threads.empty())
            {
                auto thread = current_threads.back();
                current_threads.pop_back();
                switch (step(pos, thread, current_threads))
                {
                case StepResult::Matched:
                    if ((pos != m_end and not (m_flags & RegexExecFlags::Search)) or
                        (m_flags & RegexExecFlags::NotInitialNull and pos == m_begin))
                    {
                        release_saves(thread.saves);
                        continue;
                    }

                    release_saves(m_captures);
                    m_captures = thread.saves;
                    if (pos == m_end or (m_flags & RegexExecFlags::AnyMatch))
                        return true;

                    found_match = true;
                    current_threads.clear(); // remove this and lower priority threads
                    break;
                case StepResult::Failed:
                    release_saves(thread.saves);
                    break;
                case StepResult::Consumed:
                    if (m_program.instructions[thread.inst].scheduled)
                    {
                        release_saves(thread.saves);
                        continue;
                    }
                    m_program.instructions[thread.inst].scheduled = true;
                    next_threads.push_back(thread);
                    break;
                }
            }
            if (pos == m_end or next_threads.empty())
                return found_match;

            std::swap(current_threads, next_threads);
            std::reverse(current_threads.begin(), current_threads.end());
            ++pos;
        }
    }

    void to_next_start(Utf8It& start, const Utf8It& end, const bool* start_chars)
    {
        if (not start_chars)
            return;

        while (start != end and *start >= 0 and *start < 256 and
               not start_chars[*start])
            ++start;
    }

    bool is_line_start(const Utf8It& pos) const
    {
        if (not (m_flags & RegexExecFlags::PrevAvailable) and pos == m_begin)
            return not (m_flags & RegexExecFlags::NotBeginOfLine);
        return *(pos-1) == '\n';
    }

    bool is_line_end(const Utf8It& pos) const
    {
        if (pos == m_end)
            return not (m_flags & RegexExecFlags::NotEndOfLine);
        return *pos == '\n';
    }

    bool is_word_boundary(const Utf8It& pos) const
    {
        if (not (m_flags & RegexExecFlags::PrevAvailable) and pos == m_begin)
            return not (m_flags & RegexExecFlags::NotBeginOfWord);
        if (pos == m_end)
            return not (m_flags & RegexExecFlags::NotEndOfWord);
        return is_word(*(pos-1)) != is_word(*pos);
    }

    static const Iterator& get_base(const utf8::iterator<Iterator>& it) { return it.base(); }
    static Iterator get_base(const std::reverse_iterator<utf8::iterator<Iterator>>& it) { return it.base().base(); }

    const CompiledRegex& m_program;

    Utf8It m_begin;
    Utf8It m_end;
    RegexExecFlags m_flags;

    Vector<Saves*> m_saves;
    Vector<Saves*> m_free_saves;

    Saves* m_captures = nullptr;
};

template<typename It, MatchDirection direction = MatchDirection::Forward>
bool regex_match(It begin, It end, const CompiledRegex& re, RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It, direction> vm{re};
    return vm.exec(begin, end, (RegexExecFlags)(flags & ~(RegexExecFlags::Search)) |
                               RegexExecFlags::AnyMatch | RegexExecFlags::NoSaves);
}

template<typename It, MatchDirection direction = MatchDirection::Forward>
bool regex_match(It begin, It end, Vector<It>& captures, const CompiledRegex& re,
                 RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It, direction> vm{re};
    if (vm.exec(begin, end,  flags & ~(RegexExecFlags::Search)))
    {
        std::copy(vm.captures().begin(), vm.captures().end(), std::back_inserter(captures));
        return true;
    }
    return false;
}

template<typename It, MatchDirection direction = MatchDirection::Forward>
bool regex_search(It begin, It end, const CompiledRegex& re,
                  RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It, direction> vm{re};
    return vm.exec(begin, end, flags | RegexExecFlags::Search | RegexExecFlags::AnyMatch | RegexExecFlags::NoSaves);
}

template<typename It, MatchDirection direction = MatchDirection::Forward>
bool regex_search(It begin, It end, Vector<It>& captures, const CompiledRegex& re,
                  RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It, direction> vm{re};
    if (vm.exec(begin, end, flags | RegexExecFlags::Search))
    {
        std::copy(vm.captures().begin(), vm.captures().end(), std::back_inserter(captures));
        return true;
    }
    return false;
}

}

#endif // regex_impl_hh_INCLUDED
<commit_msg>Regex: use std::conditional instead of custom template class to choose Utf8It<commit_after>#ifndef regex_impl_hh_INCLUDED
#define regex_impl_hh_INCLUDED

#include "exception.hh"
#include "flags.hh"
#include "ref_ptr.hh"
#include "unicode.hh"
#include "utf8.hh"
#include "utf8_iterator.hh"
#include "vector.hh"

#include <string.h>

namespace Kakoune
{

enum class MatchDirection
{
    Forward,
    Backward
};

struct CompiledRegex : RefCountable
{
    enum Op : char
    {
        Match,
        Literal,
        LiteralIgnoreCase,
        AnyChar,
        Matcher,
        Jump,
        Split_PrioritizeParent,
        Split_PrioritizeChild,
        Save,
        LineStart,
        LineEnd,
        WordBoundary,
        NotWordBoundary,
        SubjectBegin,
        SubjectEnd,
        LookAhead,
        NegativeLookAhead,
        LookBehind,
        NegativeLookBehind,
    };

    struct Instruction
    {
        Op op;
        mutable bool processed;
        mutable bool scheduled;
        uint32_t param;
    };
    static_assert(sizeof(Instruction) == 8, "");

    explicit operator bool() const { return not instructions.empty(); }

    Vector<Instruction> instructions;
    Vector<std::function<bool (Codepoint)>> matchers;
    Vector<Codepoint> lookarounds;
    MatchDirection direction;
    size_t save_count;

    struct StartChars { bool map[256]; };
    std::unique_ptr<StartChars> start_chars;
};

CompiledRegex compile_regex(StringView re, MatchDirection direction = MatchDirection::Forward);

enum class RegexExecFlags
{
    None              = 0,
    Search            = 1 << 0,
    NotBeginOfLine    = 1 << 1,
    NotEndOfLine      = 1 << 2,
    NotBeginOfWord    = 1 << 3,
    NotEndOfWord      = 1 << 4,
    NotBeginOfSubject = 1 << 5,
    NotInitialNull    = 1 << 6,
    AnyMatch          = 1 << 7,
    NoSaves           = 1 << 8,
    PrevAvailable     = 1 << 9,
};

constexpr bool with_bit_ops(Meta::Type<RegexExecFlags>) { return true; }

template<typename Iterator, MatchDirection direction>
class ThreadedRegexVM
{
public:
    ThreadedRegexVM(const CompiledRegex& program)
      : m_program{program}
      {
          kak_assert(m_program);
          if (direction != program.direction)
              throw runtime_error{"Regex and VM direction mismatch"};
      }

    ThreadedRegexVM(const ThreadedRegexVM&) = delete;
    ThreadedRegexVM& operator=(const ThreadedRegexVM&) = delete;

    ~ThreadedRegexVM()
    {
        for (auto* saves : m_saves)
        {
            for (size_t i = m_program.save_count-1; i > 0; --i)
                saves->pos[i].~Iterator();
            saves->~Saves();
            ::operator delete(saves);
        }
    }

    bool exec(Iterator begin, Iterator end, RegexExecFlags flags)
    {
        const bool forward = direction == MatchDirection::Forward;
        const bool prev_avail = flags & RegexExecFlags::PrevAvailable;
        m_begin = Utf8It{utf8::iterator<Iterator>{forward ? begin : end,
                                                  prev_avail ? begin-1 : begin, end}};
        m_end = Utf8It{utf8::iterator<Iterator>{forward ? end : begin,
                                                prev_avail ? begin-1 : begin, end}};
        m_flags = flags;

        if (flags & RegexExecFlags::NotInitialNull and m_begin == m_end)
            return false;

        Vector<Thread> current_threads, next_threads;

        const bool no_saves = (m_flags & RegexExecFlags::NoSaves);
        Utf8It start{m_begin};

        const bool* start_chars = m_program.start_chars ? m_program.start_chars->map : nullptr;

        if (flags & RegexExecFlags::Search)
            to_next_start(start, m_end, start_chars);

        if (exec_from(start, no_saves ? nullptr : new_saves<false>(nullptr),
                      current_threads, next_threads))
            return true;

        if (not (flags & RegexExecFlags::Search))
            return false;

        do
        {
            to_next_start(++start, m_end, start_chars);
            if (exec_from(start, no_saves ? nullptr : new_saves<false>(nullptr),
                          current_threads, next_threads))
                return true;
        }
        while (start != m_end);

        return false;
    }

    ArrayView<const Iterator> captures() const
    {
        if (m_captures)
            return { m_captures->pos, m_program.save_count };
        return {};
    }

private:
    struct Saves
    {
        int refcount;
        Iterator pos[1];
    };

    template<bool copy>
    Saves* new_saves(Iterator* pos)
    {
        kak_assert(not copy or pos != nullptr);
        const auto count = m_program.save_count;
        if (not m_free_saves.empty())
        {
            Saves* res = m_free_saves.back();
            m_free_saves.pop_back();
            res->refcount = 1;
            if (copy)
                std::copy(pos, pos + count, res->pos);
            else
                std::fill(res->pos, res->pos + count, Iterator{});

            return res;
        }

        void* ptr = ::operator new (sizeof(Saves) + (count-1) * sizeof(Iterator));
        Saves* saves = new (ptr) Saves{1, {copy ? pos[0] : Iterator{}}};
        for (size_t i = 1; i < count; ++i)
            new (&saves->pos[i]) Iterator{copy ? pos[i] : Iterator{}};
        m_saves.push_back(saves);
        return saves;
    }

    void release_saves(Saves* saves)
    {
        if (saves and --saves->refcount == 0)
            m_free_saves.push_back(saves);
    };

    struct Thread
    {
        uint32_t inst;
        Saves* saves;
    };

    using Utf8It = std::conditional_t<direction == MatchDirection::Forward,
                                      utf8::iterator<Iterator>,
                                      std::reverse_iterator<utf8::iterator<Iterator>>>;

    enum class StepResult { Consumed, Matched, Failed };

    // Steps a thread until it consumes the current character, matches or fail
    StepResult step(const Utf8It& pos, Thread& thread, Vector<Thread>& threads)
    {
        while (true)
        {
            auto& inst = m_program.instructions[thread.inst++];
            if (inst.processed)
                return StepResult::Failed;
            inst.processed = true;

            switch (inst.op)
            {
                case CompiledRegex::Literal:
                    if (pos != m_end and inst.param == *pos)
                        return StepResult::Consumed;
                    return StepResult::Failed;
                case CompiledRegex::LiteralIgnoreCase:
                    if (pos != m_end and inst.param == to_lower(*pos))
                        return StepResult::Consumed;
                    return StepResult::Failed;
                case CompiledRegex::AnyChar:
                    return StepResult::Consumed;
                case CompiledRegex::Jump:
                    thread.inst = inst.param;
                    break;
                case CompiledRegex::Split_PrioritizeParent:
                {
                    if (thread.saves)
                        ++thread.saves->refcount;
                    threads.push_back({inst.param, thread.saves});
                    break;
                }
                case CompiledRegex::Split_PrioritizeChild:
                {
                    if (thread.saves)
                        ++thread.saves->refcount;
                    threads.push_back({thread.inst, thread.saves});
                    thread.inst = inst.param;
                    break;
                }
                case CompiledRegex::Save:
                {
                    if (thread.saves == nullptr)
                        break;
                    if (thread.saves->refcount > 1)
                    {
                        --thread.saves->refcount;
                        thread.saves = new_saves<true>(thread.saves->pos);
                    }
                    thread.saves->pos[inst.param] = get_base(pos);
                    break;
                }
                case CompiledRegex::Matcher:
                    if (pos == m_end)
                        return StepResult::Failed;
                    return m_program.matchers[inst.param](*pos) ?
                        StepResult::Consumed : StepResult::Failed;
                case CompiledRegex::LineStart:
                    if (not is_line_start(pos))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::LineEnd:
                    if (not is_line_end(pos))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::WordBoundary:
                    if (not is_word_boundary(pos))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::NotWordBoundary:
                    if (is_word_boundary(pos))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::SubjectBegin:
                    if (pos != m_begin or (m_flags & RegexExecFlags::NotBeginOfSubject))
                        return StepResult::Failed;
                    break;
                case CompiledRegex::SubjectEnd:
                    if (pos != m_end)
                        return StepResult::Failed;
                    break;
                case CompiledRegex::LookAhead:
                case CompiledRegex::NegativeLookAhead:
                {
                    auto ref = m_program.lookarounds.begin() + inst.param;
                    for (auto it = pos; *ref != -1 and it != m_end; ++it, ++ref)
                        if (*it != *ref)
                            break;
                    if ((inst.op == CompiledRegex::LookAhead and *ref != -1) or
                        (inst.op == CompiledRegex::NegativeLookAhead and *ref == -1))
                        return StepResult::Failed;
                    break;
                }
                case CompiledRegex::LookBehind:
                case CompiledRegex::NegativeLookBehind:
                {
                    auto ref = m_program.lookarounds.begin() + inst.param;
                    for (auto it = pos; *ref != -1 and it > m_begin; --it, ++ref)
                        if (*(it-1) != *ref)
                            break;
                    if ((inst.op == CompiledRegex::LookBehind and *ref != -1) or
                        (inst.op == CompiledRegex::NegativeLookBehind and *ref == -1))
                        return StepResult::Failed;
                    break;
                }
                case CompiledRegex::Match:
                    return StepResult::Matched;
            }
        }
        return StepResult::Failed;
    }

    bool exec_from(Utf8It pos, Saves* initial_saves, Vector<Thread>& current_threads, Vector<Thread>& next_threads)
    {
        current_threads.push_back({0, initial_saves});
        next_threads.clear();

        bool found_match = false;
        while (true) // Iterate on all codepoints and once at the end
        {
            for (auto& inst : m_program.instructions)
            {
                inst.processed = false;
                inst.scheduled = false;
            }

            while (not current_threads.empty())
            {
                auto thread = current_threads.back();
                current_threads.pop_back();
                switch (step(pos, thread, current_threads))
                {
                case StepResult::Matched:
                    if ((pos != m_end and not (m_flags & RegexExecFlags::Search)) or
                        (m_flags & RegexExecFlags::NotInitialNull and pos == m_begin))
                    {
                        release_saves(thread.saves);
                        continue;
                    }

                    release_saves(m_captures);
                    m_captures = thread.saves;
                    if (pos == m_end or (m_flags & RegexExecFlags::AnyMatch))
                        return true;

                    found_match = true;
                    current_threads.clear(); // remove this and lower priority threads
                    break;
                case StepResult::Failed:
                    release_saves(thread.saves);
                    break;
                case StepResult::Consumed:
                    if (m_program.instructions[thread.inst].scheduled)
                    {
                        release_saves(thread.saves);
                        continue;
                    }
                    m_program.instructions[thread.inst].scheduled = true;
                    next_threads.push_back(thread);
                    break;
                }
            }
            if (pos == m_end or next_threads.empty())
                return found_match;

            std::swap(current_threads, next_threads);
            std::reverse(current_threads.begin(), current_threads.end());
            ++pos;
        }
    }

    void to_next_start(Utf8It& start, const Utf8It& end, const bool* start_chars)
    {
        if (not start_chars)
            return;

        while (start != end and *start >= 0 and *start < 256 and
               not start_chars[*start])
            ++start;
    }

    bool is_line_start(const Utf8It& pos) const
    {
        if (not (m_flags & RegexExecFlags::PrevAvailable) and pos == m_begin)
            return not (m_flags & RegexExecFlags::NotBeginOfLine);
        return *(pos-1) == '\n';
    }

    bool is_line_end(const Utf8It& pos) const
    {
        if (pos == m_end)
            return not (m_flags & RegexExecFlags::NotEndOfLine);
        return *pos == '\n';
    }

    bool is_word_boundary(const Utf8It& pos) const
    {
        if (not (m_flags & RegexExecFlags::PrevAvailable) and pos == m_begin)
            return not (m_flags & RegexExecFlags::NotBeginOfWord);
        if (pos == m_end)
            return not (m_flags & RegexExecFlags::NotEndOfWord);
        return is_word(*(pos-1)) != is_word(*pos);
    }

    static const Iterator& get_base(const utf8::iterator<Iterator>& it) { return it.base(); }
    static Iterator get_base(const std::reverse_iterator<utf8::iterator<Iterator>>& it) { return it.base().base(); }

    const CompiledRegex& m_program;

    Utf8It m_begin;
    Utf8It m_end;
    RegexExecFlags m_flags;

    Vector<Saves*> m_saves;
    Vector<Saves*> m_free_saves;

    Saves* m_captures = nullptr;
};

template<typename It, MatchDirection direction = MatchDirection::Forward>
bool regex_match(It begin, It end, const CompiledRegex& re, RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It, direction> vm{re};
    return vm.exec(begin, end, (RegexExecFlags)(flags & ~(RegexExecFlags::Search)) |
                               RegexExecFlags::AnyMatch | RegexExecFlags::NoSaves);
}

template<typename It, MatchDirection direction = MatchDirection::Forward>
bool regex_match(It begin, It end, Vector<It>& captures, const CompiledRegex& re,
                 RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It, direction> vm{re};
    if (vm.exec(begin, end,  flags & ~(RegexExecFlags::Search)))
    {
        std::copy(vm.captures().begin(), vm.captures().end(), std::back_inserter(captures));
        return true;
    }
    return false;
}

template<typename It, MatchDirection direction = MatchDirection::Forward>
bool regex_search(It begin, It end, const CompiledRegex& re,
                  RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It, direction> vm{re};
    return vm.exec(begin, end, flags | RegexExecFlags::Search | RegexExecFlags::AnyMatch | RegexExecFlags::NoSaves);
}

template<typename It, MatchDirection direction = MatchDirection::Forward>
bool regex_search(It begin, It end, Vector<It>& captures, const CompiledRegex& re,
                  RegexExecFlags flags = RegexExecFlags::None)
{
    ThreadedRegexVM<It, direction> vm{re};
    if (vm.exec(begin, end, flags | RegexExecFlags::Search))
    {
        std::copy(vm.captures().begin(), vm.captures().end(), std::back_inserter(captures));
        return true;
    }
    return false;
}

}

#endif // regex_impl_hh_INCLUDED
<|endoftext|>


<commit_before>#define BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
#include "boost/compute.hpp"

#include "Canvas.h"
#include "Triangle.h"
#include "draw_triangle.h"

#include <vector>
#include <iostream>
#include <string>
#include <exception>

using namespace std;
namespace bc = boost::compute;

bc::kernel make_kernel(const bc::context& ctx, const char* source, std::string name);

int main(int argc, char** argv)
{
  bc::device device = bc::system::default_device();
  bc::context context(device);
  bc::command_queue queue(context, device);
  bc::kernel kernel;

  try
  {
    kernel = make_kernel(context, garth_kernels::draw_triangles.c_str(), "draw_triangles");
  }
  catch (bc::opencl_error& ex)
  {
    cout << "Boost.Compute error: " << ex.error_string() << endl;
    cout << "Boost.Compute error_code: " << ex.error_code() << endl;
    return 1;
  }
  catch (exception& ex)
  {
    cout << "WTF HAPPENED?!?!~?! - " << ex.what() << endl;
    return 1;
  }

  cout << "Default device: " << device.name() << endl;

  // Settings:
  uint32_t num_triangles = 10,
           canvas_width = 100,
           canvas_height = 100;

  // Create RNG
  std::default_random_engine rng;
  std::uniform_int_distribution<uint8_t> random_color(0,255);

  // Create Triangle buffer:
  vector<Triangle> triangles(num_triangles);
  for(auto& t : triangles)
  {
    t.c.Red = random_color(rng);
    t.c.Green = random_color(rng);
    t.c.Blue = random_color(rng);
  }
  Canvas canvas(canvas_width, canvas_height);

  // Create memory buffers for the input and output:
  bc::buffer buffer_triangles(context, sizeof(triangles));
  bc::buffer buffer_canvas(context, sizeof(canvas));

  // Set the kernel arguments:
  kernel.set_arg(0, buffer_triangles);
  kernel.set_arg(1, num_triangles);
  kernel.set_arg(2, buffer_canvas);
  kernel.set_arg(3, canvas_width);
  kernel.set_arg(4, canvas_height);

  // Write the data to the device:
  queue.enqueue_write_buffer(buffer_triangles, 0, sizeof(triangles.data()), triangles.data());
  queue.enqueue_write_buffer(buffer_canvas, 0, sizeof(canvas.getCanvas().data()), canvas.getCanvas().data());

  // Calculate local/global group sizes:
  bc::extents<2> offsetRange(0);
  bc::extents<2> globalRange = { 10, 10 };
  bc::extents<2> localRange = { 10, 10 };

  // Run kernel:
  queue.enqueue_nd_range_kernel(kernel, offsetRange, globalRange, localRange);

  // transfer results back to the host
  queue.enqueue_read_buffer(buffer_canvas, 0, sizeof(canvas.getCanvas().data()), canvas.getCanvas().data());

  canvas.save("triangles.png");
  return 0;
}

bc::kernel make_kernel(const bc::context& context, const char* source, std::string name)
{
    // setup compilation flags for the program
    std::string options;

    // create and build the program
    bc::program program =
        bc::program::build_with_source(source, context, options.c_str());

    // create and return the kernel
    return program.create_kernel(name);
}
<commit_msg>Clang support<commit_after>#define BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
#include "boost/compute.hpp"

#include "Canvas.h"
#include "Triangle.h"
#include "draw_triangle.h"

#include <vector>
#include <iostream>
#include <string>
#include <exception>

using namespace std;
namespace bc = boost::compute;

bc::kernel make_kernel(const bc::context& ctx, const char* source, std::string name);

int main(int argc, char** argv)
{
  bc::device device = bc::system::default_device();
  bc::context context(device);
  bc::command_queue queue(context, device);
  bc::kernel kernel;

  try
  {
    kernel = make_kernel(context, garth_kernels::draw_triangles.c_str(), "draw_triangles");
  }
  catch (bc::opencl_error& ex)
  {
    cout << "Boost.Compute error: " << ex.error_string() << endl;
    cout << "Boost.Compute error_code: " << ex.error_code() << endl;
    return 1;
  }
  catch (exception& ex)
  {
    cout << "WTF HAPPENED?!?!~?! - " << ex.what() << endl;
    return 1;
  }

  cout << "Default device: " << device.name() << endl;

  // Settings:
  uint32_t num_triangles = 10,
           canvas_width = 100,
           canvas_height = 100;

  // Create RNG
  std::default_random_engine rng;
  std::uniform_int_distribution<uint8_t> random_color(0,255);

  // Create Triangle buffer:
  vector<Triangle> triangles(num_triangles);
  for(auto& t : triangles)
  {
    t.c.Red = random_color(rng);
    t.c.Green = random_color(rng);
    t.c.Blue = random_color(rng);
  }
  Canvas canvas(canvas_width, canvas_height);

  // Create memory buffers for the input and output:
  bc::buffer buffer_triangles(context, sizeof(triangles));
  bc::buffer buffer_canvas(context, sizeof(canvas));

  // Set the kernel arguments:
  kernel.set_arg(0, buffer_triangles);
  kernel.set_arg(1, num_triangles);
  kernel.set_arg(2, buffer_canvas);
  kernel.set_arg(3, canvas_width);
  kernel.set_arg(4, canvas_height);

  // Write the data to the device:
  queue.enqueue_write_buffer(buffer_triangles, 0, sizeof(triangles.data()), triangles.data());
  queue.enqueue_write_buffer(buffer_canvas, 0, sizeof(canvas.getCanvas().data()), canvas.getCanvas().data());

  // Calculate local/global group sizes:
  bc::extents<2> offsetRange(0);
  bc::extents<2> globalRange;
  globalRange[0] = 10;
  globalRange[1] = 10;

  bc::extents<2> localRange;
  localRange[0] = 10;
  localRange[1] = 10;

  // Run kernel:
  queue.enqueue_nd_range_kernel(kernel, offsetRange, globalRange, localRange);

  // transfer results back to the host
  queue.enqueue_read_buffer(buffer_canvas, 0, sizeof(canvas.getCanvas().data()), canvas.getCanvas().data());

  canvas.save("triangles.png");
  return 0;
}

bc::kernel make_kernel(const bc::context& context, const char* source, std::string name)
{
    // setup compilation flags for the program
    std::string options;

    // create and build the program
    bc::program program =
        bc::program::build_with_source(source, context, options.c_str());

    // create and return the kernel
    return program.create_kernel(name);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Zcash developers
// Original code from: https://gist.github.com/laanwj/0e689cfa37b52bcbbb44

/*

To set up a new alert system
----------------------------

Create a new alert key pair:
openssl ecparam -name secp256k1 -genkey -param_enc explicit -outform PEM -out data.pem

Get the private key in hex:
openssl ec -in data.pem -outform DER | tail -c 279 | xxd -p -c 279

Get the public key in hex:
openssl ec -in data.pem -pubout -outform DER | tail -c 65 | xxd -p -c 65

Update the public keys found in chainparams.cpp.

To send an alert message
------------------------

Copy the private keys into alertkeys.h.

Modify the alert parameters, id and message found in this file.

Build and run with -sendalert or -printalert.

./zcashd -printtoconsole -sendalert

One minute after starting up, the alert will be broadcast. It is then
flooded through the network until the nRelayUntil time, and will be
active until nExpiration OR the alert is cancelled.

If you make a mistake, send another alert with nCancel set to cancel
the bad alert.

*/

#include "main.h"
#include "net.h"
#include "alert.h"
#include "init.h"

#include "util.h"
#include "utiltime.h"
#include "key.h"
#include "clientversion.h"
#include "chainparams.h"

#include "alertkeys.h"

static const int64_t DAYS = 24 * 60 * 60;

void ThreadSendAlert()
{
    if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert"))
        return;

    MilliSleep(60*1000); // Wait a minute so we get connected

    //
    // Alerts are relayed around the network until nRelayUntil, flood
    // filling to every node.
    // After the relay time is past, new nodes are told about alerts
    // when they connect to peers, until either nExpiration or
    // the alert is cancelled by a newer alert.
    // Nodes never save alerts to disk, they are in-memory-only.
    //
    CAlert alert;
    alert.nRelayUntil   = GetTime() + 15 * 60;
    alert.nExpiration   = GetTime() + 365 * 60 * 60;
    alert.nID           = 1000;  // use https://z.cash to keep track of alert IDs
    alert.nCancel       = 0;   // cancels previous messages up to this ID number

    // These versions are protocol versions
    // 60002 : 0.7.*
    // 70001 : 0.8.*
    // 70002 : 0.9.*
    alert.nMinVer       = 70002;
    alert.nMaxVer       = 70002;

    //
    // main.cpp:
    //  1000 for Misc warnings like out of disk space and clock is wrong
    //  2000 for longer invalid proof-of-work chain
    //  Higher numbers mean higher priority
    alert.nPriority     = 5000;
    alert.strComment    = "";
    alert.strStatusBar  = "URGENT: Upgrade required: see https://z.cash";

    // Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done:
    // alert.setSubVer.insert(std::string("/Satoshi:0.7.2/"));

    // Sign
    const CChainParams& chainparams = Params();
    std::string networkID = chainparams.NetworkIDString();
    bool fIsTestNet = networkID.compare("test") == 0;
    std::vector<unsigned char> vchTmp(ParseHex(fIsTestNet ? pszTestNetPrivKey : pszPrivKey));
    CPrivKey vchPrivKey(vchTmp.begin(), vchTmp.end());

    CDataStream sMsg(SER_NETWORK, CLIENT_VERSION);
    sMsg << *(CUnsignedAlert*)&alert;
    alert.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
    CKey key;
    if (!key.SetPrivKey(vchPrivKey, false))
    {
        printf("ThreadSendAlert() : key.SetPrivKey failed\n");
        return;
    }
    if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
    {
        printf("ThreadSendAlert() : key.Sign failed\n");
        return;
    }

    // Test
    CDataStream sBuffer(SER_NETWORK, CLIENT_VERSION);
    sBuffer << alert;
    CAlert alert2;
    sBuffer >> alert2;
    if (!alert2.CheckSignature(chainparams.AlertKey()))
    {
        printf("ThreadSendAlert() : CheckSignature failed\n");
        return;
    }
    assert(alert2.vchMsg == alert.vchMsg);
    assert(alert2.vchSig == alert.vchSig);
    alert.SetNull();
    printf("\nThreadSendAlert:\n");
    printf("hash=%s\n", alert2.GetHash().ToString().c_str());
    printf("%s\n", alert2.ToString().c_str());
    printf("vchMsg=%s\n", HexStr(alert2.vchMsg).c_str());
    printf("vchSig=%s\n", HexStr(alert2.vchSig).c_str());

    // Confirm
    if (!mapArgs.count("-sendalert"))
        return;
    while (vNodes.size() < 1 && !ShutdownRequested())
        MilliSleep(500);
    if (ShutdownRequested())
        return;
#if 0
#ifdef QT_GUI
    if (ThreadSafeMessageBox("Send alert?", "ThreadSendAlert", wxYES_NO | wxNO_DEFAULT) != wxYES)
        return;
    if (ThreadSafeMessageBox("Send alert, are you sure?", "ThreadSendAlert", wxYES_NO | wxNO_DEFAULT) != wxYES)
    {
        ThreadSafeMessageBox("Nothing sent", "ThreadSendAlert", wxOK);
        return;
    }
#endif
#endif
    // Send
    printf("ThreadSendAlert() : Sending alert\n");
    int nSent = 0;
    {
        LOCK(cs_vNodes);
        BOOST_FOREACH(CNode* pnode, vNodes)
        {
            if (alert2.RelayTo(pnode))
            {
                printf("ThreadSendAlert() : Sent alert to %s\n", pnode->addr.ToString().c_str());
                nSent++;
            }
        }
    }
    printf("ThreadSendAlert() : Alert sent to %d nodes\n", nSent);
}
<commit_msg>Update alert protocol version comment.<commit_after>// Copyright (c) 2016 The Zcash developers
// Original code from: https://gist.github.com/laanwj/0e689cfa37b52bcbbb44

/*

To set up a new alert system
----------------------------

Create a new alert key pair:
openssl ecparam -name secp256k1 -genkey -param_enc explicit -outform PEM -out data.pem

Get the private key in hex:
openssl ec -in data.pem -outform DER | tail -c 279 | xxd -p -c 279

Get the public key in hex:
openssl ec -in data.pem -pubout -outform DER | tail -c 65 | xxd -p -c 65

Update the public keys found in chainparams.cpp.

To send an alert message
------------------------

Copy the private keys into alertkeys.h.

Modify the alert parameters, id and message found in this file.

Build and run with -sendalert or -printalert.

./zcashd -printtoconsole -sendalert

One minute after starting up, the alert will be broadcast. It is then
flooded through the network until the nRelayUntil time, and will be
active until nExpiration OR the alert is cancelled.

If you make a mistake, send another alert with nCancel set to cancel
the bad alert.

*/

#include "main.h"
#include "net.h"
#include "alert.h"
#include "init.h"

#include "util.h"
#include "utiltime.h"
#include "key.h"
#include "clientversion.h"
#include "chainparams.h"

#include "alertkeys.h"

static const int64_t DAYS = 24 * 60 * 60;

void ThreadSendAlert()
{
    if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert"))
        return;

    MilliSleep(60*1000); // Wait a minute so we get connected

    //
    // Alerts are relayed around the network until nRelayUntil, flood
    // filling to every node.
    // After the relay time is past, new nodes are told about alerts
    // when they connect to peers, until either nExpiration or
    // the alert is cancelled by a newer alert.
    // Nodes never save alerts to disk, they are in-memory-only.
    //
    CAlert alert;
    alert.nRelayUntil   = GetTime() + 15 * 60;
    alert.nExpiration   = GetTime() + 365 * 60 * 60;
    alert.nID           = 1000;  // use https://z.cash to keep track of alert IDs
    alert.nCancel       = 0;   // cancels previous messages up to this ID number

    // These versions are protocol versions
    // 70002 : 0.11.2.*
    alert.nMinVer       = 70002;
    alert.nMaxVer       = 70002;

    //
    // main.cpp:
    //  1000 for Misc warnings like out of disk space and clock is wrong
    //  2000 for longer invalid proof-of-work chain
    //  Higher numbers mean higher priority
    alert.nPriority     = 5000;
    alert.strComment    = "";
    alert.strStatusBar  = "URGENT: Upgrade required: see https://z.cash";

    // Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done:
    // alert.setSubVer.insert(std::string("/Satoshi:0.7.2/"));

    // Sign
    const CChainParams& chainparams = Params();
    std::string networkID = chainparams.NetworkIDString();
    bool fIsTestNet = networkID.compare("test") == 0;
    std::vector<unsigned char> vchTmp(ParseHex(fIsTestNet ? pszTestNetPrivKey : pszPrivKey));
    CPrivKey vchPrivKey(vchTmp.begin(), vchTmp.end());

    CDataStream sMsg(SER_NETWORK, CLIENT_VERSION);
    sMsg << *(CUnsignedAlert*)&alert;
    alert.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
    CKey key;
    if (!key.SetPrivKey(vchPrivKey, false))
    {
        printf("ThreadSendAlert() : key.SetPrivKey failed\n");
        return;
    }
    if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
    {
        printf("ThreadSendAlert() : key.Sign failed\n");
        return;
    }

    // Test
    CDataStream sBuffer(SER_NETWORK, CLIENT_VERSION);
    sBuffer << alert;
    CAlert alert2;
    sBuffer >> alert2;
    if (!alert2.CheckSignature(chainparams.AlertKey()))
    {
        printf("ThreadSendAlert() : CheckSignature failed\n");
        return;
    }
    assert(alert2.vchMsg == alert.vchMsg);
    assert(alert2.vchSig == alert.vchSig);
    alert.SetNull();
    printf("\nThreadSendAlert:\n");
    printf("hash=%s\n", alert2.GetHash().ToString().c_str());
    printf("%s\n", alert2.ToString().c_str());
    printf("vchMsg=%s\n", HexStr(alert2.vchMsg).c_str());
    printf("vchSig=%s\n", HexStr(alert2.vchSig).c_str());

    // Confirm
    if (!mapArgs.count("-sendalert"))
        return;
    while (vNodes.size() < 1 && !ShutdownRequested())
        MilliSleep(500);
    if (ShutdownRequested())
        return;
#if 0
#ifdef QT_GUI
    if (ThreadSafeMessageBox("Send alert?", "ThreadSendAlert", wxYES_NO | wxNO_DEFAULT) != wxYES)
        return;
    if (ThreadSafeMessageBox("Send alert, are you sure?", "ThreadSendAlert", wxYES_NO | wxNO_DEFAULT) != wxYES)
    {
        ThreadSafeMessageBox("Nothing sent", "ThreadSendAlert", wxOK);
        return;
    }
#endif
#endif
    // Send
    printf("ThreadSendAlert() : Sending alert\n");
    int nSent = 0;
    {
        LOCK(cs_vNodes);
        BOOST_FOREACH(CNode* pnode, vNodes)
        {
            if (alert2.RelayTo(pnode))
            {
                printf("ThreadSendAlert() : Sent alert to %s\n", pnode->addr.ToString().c_str());
                nSent++;
            }
        }
    }
    printf("ThreadSendAlert() : Alert sent to %d nodes\n", nSent);
}
<|endoftext|>


<commit_before>#include<string>
#include<iostream>
#include<cstdio>
#include<sstream>
#include<iomanip>
#include<fstream>
#include<cstdlib>
#include<unistd.h>
#include"server_io.h"

int respondValidating(int submission_id)
{
   ostringstream sout;
   sout << "respond_validating.py " << submission_id;
   system(sout.str().c_str());
   return 0;
}

int fetchSubmission(submission &sub)
{
   FILE *Pipe = popen("fetch_submission.py", "r");
   fscanf(Pipe, "%d", &sub.submission_id);
   if(sub.submission_id < 0){
      pclose(Pipe);
      return sub.submission_id;
   }
   fscanf(Pipe, "%d", &sub.problem_id);
   fscanf(Pipe, "%d", &sub.problem_type);
   fscanf(Pipe, "%d", &sub.submitter_id);
   char buff[30];
   fscanf(Pipe, "%s", buff);
   pclose(Pipe);
   if(string(buff) == "c++11"){
      sub.lang = "c++";
      sub.std = "c++11";
   }else if(string(buff) == "c++"){
      sub.lang = "c++";
      sub.std = "";
   }else if(string(buff) == "c"){
      sub.lang = "c";
      sub.std = "";
   }else{
      sub.lang = "c++";
      sub.std = "c++11";
   }
   return 0;
}

int downloadTestdata(submission &sub)
{
   ostringstream sout;
   sout << "./testdata/" << setfill('0') << setw(4) << sub.problem_id;
   sout << "/input";
   string dir(sout.str());

   sout.str("");
   sout << "fetch_testdata_meta.py " << sub.problem_id;
   FILE *Pipe = popen(sout.str().c_str(), "r");
   fscanf(Pipe, "%d", &sub.testdata_count);
   for(int i = 0; i < sub.testdata_count; ++i){
      int testdata_id;
      long long timestamp;
      fscanf(Pipe, "%d %lld", &testdata_id, &timestamp);
      bool flag = true;
      sout.str("");
      sout << dir << setfill('0') << setw(3) << i;
      string td(sout.str());
      ifstream fin(td + ".meta");
      long long ts;
      if(fin >> ts){
         if(ts == timestamp){
            flag = false;
         }
      }
      fin.close();
      if(flag){
         //need to renew td
         sout.str("");
         sout << testdata_id << ' ' << sub.problem_id << ' ' << i;
         system(("fetch_testdata.py " + sout.str()).c_str());
         ofstream fout(td + ".meta");
         fout << timestamp << endl;
      }
   }
   pclose(Pipe);
   return 0;
}

int fetchProblem(submission &sub)
{
   //get submission code
   char *buff = new char[5*1024*1024];
   ostringstream sout;
   sout << "fetch_code.py " << sub.submission_id;
   FILE* Pipe = popen(sout.str().c_str(), "r");
   sout.str("");
   while(fgets(buff, 5*1024*1024, Pipe) != NULL)
      sout << buff;
   sub.code = sout.str();
   pclose(Pipe);

   //get sjcode
   sout.str("");
   sout << "fetch_sjcode.py " << sub.problem_id;
   Pipe = popen(sout.str().c_str(), "r");
   sout.str("");
   while(fgets(buff, 5*1024*1024, Pipe) != NULL)
      sout << buff;
   sub.sjcode = sout.str();
   pclose(Pipe);

   //get interlib
   sout.str("");
   sout << "fetch_interlib.py " << sub.problem_id;
   Pipe = popen(sout.str().c_str(), "r");
   sout.str("");
   while(fgets(buff, 5*1024*1024, Pipe) != NULL)
      sout << buff;
   sub.interlib = sout.str();
   pclose(Pipe);

   delete [] buff;
   //check if testdata dir exists
   sout.str("");
   sout << "./testdata/";
   sout << setfill('0') << setw(4) << sub.problem_id;
   string testdata_dir(sout.str());
   if(access(testdata_dir.c_str(), F_OK)){
      system(("mkdir " + testdata_dir + " 2>/dev/null").c_str());
   }

   //download testdata
   if(downloadTestdata(sub) == -1){
      return -1;
   }

   //get memlimit, timelimit
   sout.str("");
   sout << "fetch_limits.py " << sub.problem_id;
   Pipe = popen(sout.str().c_str(), "r");
   for(int i = 0; i < sub.testdata_count; ++i){
      fscanf(Pipe, "%d %d", &sub.time_limit[i], &sub.mem_limit[i]);
   }
   pclose(Pipe);

   //Only have Batch judge now, haven't done anything for `special`
   //`interactive`, `output only` yet

   return 0;
}

int sendResult(submission &sub, int verdict, bool done)
{
   ostringstream sout;
   sout << "update_verdict.py " << sub.submission_id << ' ';
   if(verdict == CE){
      sout << "CE";
   }else if(verdict == ER){
      sout << "ER";
   }else{
      for(int i = 0; i < sub.testdata_count; ++i){
         sout << fromVerdict(sub.verdict[i]).toAbr() << '/';
         sout << sub.time[i] << '/';
         sout << sub.mem[i] << '/';

         cerr << "td" << i << " : time " << sub.time[i];
         cerr << " mem " << sub.mem[i];
         cerr << " verdict " << fromVerdict(sub.verdict[i]).toStr();
         cerr << endl;
      }
   }
   if(done){
      sout << " OK";
   }else{
      sout << " NO";
   }
   system(sout.str().c_str());
   return 0;
   /*
   if(verdict != CE){
      for(int i = 0; i < sub.testdata_count; ++i){
         verdict = max(verdict, sub.verdict[i]);
         cerr << "td" << i << " : time " << sub.time[i];
         cerr << " mem " << sub.mem[i];
         cerr << " verdict " << fromVerdict(sub.verdict[i]).toStr();
         cerr << endl;
      }
   }
   ostringstream sout;
   sout << "update_verdict.py" << ' ' << sub.submission_id << ' ';
   //sout << "'"<< fromVerdict(verdict).toStr() << "'";
   sout << "'"<< fromVerdict(verdict).toAbr() << "'";
   system(sout.str().c_str());
   return 0;
   */
}

<commit_msg>wont halt if no td<commit_after>#include<string>
#include<iostream>
#include<cstdio>
#include<sstream>
#include<iomanip>
#include<fstream>
#include<cstdlib>
#include<unistd.h>
#include"server_io.h"

int respondValidating(int submission_id)
{
   ostringstream sout;
   sout << "respond_validating.py " << submission_id;
   system(sout.str().c_str());
   return 0;
}

int fetchSubmission(submission &sub)
{
   FILE *Pipe = popen("fetch_submission.py", "r");
   fscanf(Pipe, "%d", &sub.submission_id);
   if(sub.submission_id < 0){
      pclose(Pipe);
      return sub.submission_id;
   }
   fscanf(Pipe, "%d", &sub.problem_id);
   fscanf(Pipe, "%d", &sub.problem_type);
   fscanf(Pipe, "%d", &sub.submitter_id);
   char buff[30];
   fscanf(Pipe, "%s", buff);
   pclose(Pipe);
   if(string(buff) == "c++11"){
      sub.lang = "c++";
      sub.std = "c++11";
   }else if(string(buff) == "c++"){
      sub.lang = "c++";
      sub.std = "";
   }else if(string(buff) == "c"){
      sub.lang = "c";
      sub.std = "";
   }else{
      sub.lang = "c++";
      sub.std = "c++11";
   }
   return 0;
}

int downloadTestdata(submission &sub)
{
   ostringstream sout;
   sout << "./testdata/" << setfill('0') << setw(4) << sub.problem_id;
   sout << "/input";
   string dir(sout.str());

   sout.str("");
   sout << "fetch_testdata_meta.py " << sub.problem_id;
   FILE *Pipe = popen(sout.str().c_str(), "r");
   fscanf(Pipe, "%d", &sub.testdata_count);
   for(int i = 0; i < sub.testdata_count; ++i){
      int testdata_id;
      long long timestamp;
      fscanf(Pipe, "%d %lld", &testdata_id, &timestamp);
      bool flag = true;
      sout.str("");
      sout << dir << setfill('0') << setw(3) << i;
      string td(sout.str());
      ifstream fin(td + ".meta");
      long long ts;
      if(fin >> ts){
         if(ts == timestamp){
            flag = false;
         }
      }
      fin.close();
      if(flag){
         //need to renew td
         sout.str("");
         sout << testdata_id << ' ' << sub.problem_id << ' ' << i;
         system(("fetch_testdata.py " + sout.str()).c_str());
         ofstream fout(td + ".meta");
         fout << timestamp << endl;
      }
   }
   pclose(Pipe);
   return 0;
}

int fetchProblem(submission &sub)
{
   //get submission code
   char *buff = new char[5*1024*1024];
   ostringstream sout;
   sout << "fetch_code.py " << sub.submission_id;
   FILE* Pipe = popen(sout.str().c_str(), "r");
   sout.str("");
   while(fgets(buff, 5*1024*1024, Pipe) != NULL)
      sout << buff;
   sub.code = sout.str();
   pclose(Pipe);

   //get sjcode
   sout.str("");
   sout << "fetch_sjcode.py " << sub.problem_id;
   Pipe = popen(sout.str().c_str(), "r");
   sout.str("");
   while(fgets(buff, 5*1024*1024, Pipe) != NULL)
      sout << buff;
   sub.sjcode = sout.str();
   pclose(Pipe);

   //get interlib
   sout.str("");
   sout << "fetch_interlib.py " << sub.problem_id;
   Pipe = popen(sout.str().c_str(), "r");
   sout.str("");
   while(fgets(buff, 5*1024*1024, Pipe) != NULL)
      sout << buff;
   sub.interlib = sout.str();
   pclose(Pipe);

   delete [] buff;
   //check if testdata dir exists
   sout.str("");
   sout << "./testdata/";
   sout << setfill('0') << setw(4) << sub.problem_id;
   string testdata_dir(sout.str());
   if(access(testdata_dir.c_str(), F_OK)){
      system(("mkdir " + testdata_dir + " 2>/dev/null").c_str());
   }

   //download testdata
   if(downloadTestdata(sub) == -1){
      return -1;
   }

   //get memlimit, timelimit
   sout.str("");
   sout << "fetch_limits.py " << sub.problem_id;
   Pipe = popen(sout.str().c_str(), "r");
   for(int i = 0; i < sub.testdata_count; ++i){
      fscanf(Pipe, "%d %d", &sub.time_limit[i], &sub.mem_limit[i]);
   }
   pclose(Pipe);

   //Only have Batch judge now, haven't done anything for `special`
   //`interactive`, `output only` yet

   return 0;
}

int sendResult(submission &sub, int verdict, bool done)
{
   ostringstream sout;
   sout << "update_verdict.py " << sub.submission_id << ' ';
   if(verdict == CE){
      sout << "CE";
   }else if(verdict == ER){
      sout << "ER";
   }else{
      for(int i = 0; i < sub.testdata_count; ++i){
         sout << fromVerdict(sub.verdict[i]).toAbr() << '/';
         sout << sub.time[i] << '/';
         sout << sub.mem[i] << '/';

         cerr << "td" << i << " : time " << sub.time[i];
         cerr << " mem " << sub.mem[i];
         cerr << " verdict " << fromVerdict(sub.verdict[i]).toStr();
         cerr << endl;
      }
   }
   if(done){
      sout << " OK OK";
   }else{
      sout << " NO NO";
   }
   system(sout.str().c_str());
   return 0;
   /*
   if(verdict != CE){
      for(int i = 0; i < sub.testdata_count; ++i){
         verdict = max(verdict, sub.verdict[i]);
         cerr << "td" << i << " : time " << sub.time[i];
         cerr << " mem " << sub.mem[i];
         cerr << " verdict " << fromVerdict(sub.verdict[i]).toStr();
         cerr << endl;
      }
   }
   ostringstream sout;
   sout << "update_verdict.py" << ' ' << sub.submission_id << ' ';
   //sout << "'"<< fromVerdict(verdict).toStr() << "'";
   sout << "'"<< fromVerdict(verdict).toAbr() << "'";
   system(sout.str().c_str());
   return 0;
   */
}

<|endoftext|>


<commit_before><commit_msg>Inspector: optimize Probe's window-temperature<commit_after><|endoftext|>


<commit_before>/*
*  hooks.cpp
*  StatusSpec project
*
*  Copyright (c) 2014 thesupremecommander
*  BSD 2-Clause License
*  http://opensource.org/licenses/BSD-2-Clause
*
*/

#include "hooks.h"

void StatusSpecUnloader::ReadyToUnload(SourceHook::Plugin plug) {};

SourceHook::Impl::CSourceHookImpl g_SourceHook;
SourceHook::ISourceHook *g_SHPtr = &g_SourceHook;
int g_PLID = 0;

SH_DECL_MANUALHOOK5_void(C_TFPlayer_CalcView, OFFSET_CALCVIEW, 0, 0, Vector &, QAngle &, float &, float &, float &);
SH_DECL_MANUALHOOK3_void(C_TFPlayer_GetGlowEffectColor, OFFSET_GETGLOWEFFECTCOLOR, 0, 0, float *, float *, float *);
SH_DECL_MANUALHOOK0(C_TFPlayer_GetObserverMode, OFFSET_GETOBSERVERMODE, 0, 0, int);
SH_DECL_MANUALHOOK0(C_TFPlayer_GetObserverTarget, OFFSET_GETOBSERVERTARGET, 0, 0, C_BaseEntity *);
SH_DECL_MANUALHOOK0_void(C_TFPlayer_UpdateGlowEffect, OFFSET_UPDATEGLOWEFFECT, 0, 0);
SH_DECL_HOOK1_void(IBaseClientDLL, FrameStageNotify, SH_NOATTRIB, 0, ClientFrameStage_t);
SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool);
SH_DECL_HOOK1(IGameEventManager2, FireEventClientSide, SH_NOATTRIB, 0, bool, IGameEvent *);
SH_DECL_HOOK1(IGameResources, GetPlayerName, SH_NOATTRIB, 0, const char *, int);
SH_DECL_HOOK3_void(IPanel, PaintTraverse, SH_NOATTRIB, 0, VPANEL, bool, bool);
SH_DECL_HOOK3_void(IPanel, SendMessage, SH_NOATTRIB, 0, VPANEL, KeyValues *, VPANEL);
SH_DECL_HOOK2(IVEngineClient, GetPlayerInfo, SH_NOATTRIB, 0, bool, int, player_info_t *);

int Hooks::AddHook_C_TFPlayer_GetGlowEffectColor(C_TFPlayer *instance, void(*hook)(float *, float *, float *)) {
	return SH_ADD_MANUALVPHOOK(C_TFPlayer_GetGlowEffectColor, instance, hook, false);
}

int Hooks::AddHook_IBaseClientDLL_FrameStageNotify(IBaseClientDLL *instance, void(*hook)(ClientFrameStage_t)) {
	return SH_ADD_HOOK(IBaseClientDLL, FrameStageNotify, instance, hook, false);
}

int Hooks::AddHook_IGameEventManager2_FireEvent(IGameEventManager2 *instance, bool(*hook)(IGameEvent *, bool)) {
	return SH_ADD_HOOK(IGameEventManager2, FireEvent, instance, hook, false);
}

int Hooks::AddHook_IGameEventManager2_FireEventClientSide(IGameEventManager2 *instance, bool(*hook)(IGameEvent *)) {
	return SH_ADD_HOOK(IGameEventManager2, FireEventClientSide, instance, hook, false);
}

int Hooks::AddHook_IGameResources_GetPlayerName(IGameResources *instance, const char *(*hook)(int)) {
	return SH_ADD_HOOK(IGameResources, GetPlayerName, instance, hook, false);
}

int Hooks::AddHook_IPanel_PaintTraverse(vgui::IPanel *instance, void(*hook)(vgui::VPANEL, bool, bool)) {
	return SH_ADD_HOOK(IPanel, PaintTraverse, instance, hook, false);
}

int Hooks::AddHook_IPanel_SendMessage(vgui::IPanel *instance, void(*hook)(vgui::VPANEL, KeyValues *, vgui::VPANEL)) {
	return SH_ADD_HOOK(IPanel, SendMessage, instance, hook, false);
}

int Hooks::AddHook_IVEngineClient_GetPlayerInfo(IVEngineClient *instance, bool(*hook)(int, player_info_t *)) {
	return SH_ADD_HOOK(IVEngineClient, GetPlayerInfo, instance, hook, false);
}

void Hooks::CallFunc_C_TFPlayer_CalcView(C_TFPlayer *instance, Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov) {
	SH_MCALL(instance, C_TFPlayer_CalcView)(eyeOrigin, eyeAngles, zNear, zFar, fov);
}

int Hooks::CallFunc_C_TFPlayer_GetObserverMode(C_TFPlayer *instance) {
	return SH_MCALL(instance, C_TFPlayer_GetObserverMode)();
}

C_BaseEntity *Hooks::CallFunc_C_TFPlayer_GetObserverTarget(C_TFPlayer *instance) {
	return SH_MCALL(instance, C_TFPlayer_GetObserverTarget)();
}

void Hooks::CallFunc_C_TFPlayer_UpdateGlowEffect(C_TFPlayer *instance) {
	SH_MCALL(instance, C_TFPlayer_UpdateGlowEffect)();
}

void Hooks::Pause() {
	g_SourceHook.PausePlugin(g_PLID);
}

bool Hooks::RemoveHook(int hookID) {
	return SH_REMOVE_HOOK_ID(hookID);
}

void Hooks::Unload() {
	g_SourceHook.UnloadPlugin(g_PLID, new StatusSpecUnloader());
}

void Hooks::Unpause() {
	g_SourceHook.UnpausePlugin(g_PLID);
}<commit_msg>Make sure to use SH_STATIC macros for hooking functions.<commit_after>/*
*  hooks.cpp
*  StatusSpec project
*
*  Copyright (c) 2014 thesupremecommander
*  BSD 2-Clause License
*  http://opensource.org/licenses/BSD-2-Clause
*
*/

#include "hooks.h"

void StatusSpecUnloader::ReadyToUnload(SourceHook::Plugin plug) {};

SourceHook::Impl::CSourceHookImpl g_SourceHook;
SourceHook::ISourceHook *g_SHPtr = &g_SourceHook;
int g_PLID = 0;

SH_DECL_MANUALHOOK5_void(C_TFPlayer_CalcView, OFFSET_CALCVIEW, 0, 0, Vector &, QAngle &, float &, float &, float &);
SH_DECL_MANUALHOOK3_void(C_TFPlayer_GetGlowEffectColor, OFFSET_GETGLOWEFFECTCOLOR, 0, 0, float *, float *, float *);
SH_DECL_MANUALHOOK0(C_TFPlayer_GetObserverMode, OFFSET_GETOBSERVERMODE, 0, 0, int);
SH_DECL_MANUALHOOK0(C_TFPlayer_GetObserverTarget, OFFSET_GETOBSERVERTARGET, 0, 0, C_BaseEntity *);
SH_DECL_MANUALHOOK0_void(C_TFPlayer_UpdateGlowEffect, OFFSET_UPDATEGLOWEFFECT, 0, 0);
SH_DECL_HOOK1_void(IBaseClientDLL, FrameStageNotify, SH_NOATTRIB, 0, ClientFrameStage_t);
SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent *, bool);
SH_DECL_HOOK1(IGameEventManager2, FireEventClientSide, SH_NOATTRIB, 0, bool, IGameEvent *);
SH_DECL_HOOK1(IGameResources, GetPlayerName, SH_NOATTRIB, 0, const char *, int);
SH_DECL_HOOK3_void(IPanel, PaintTraverse, SH_NOATTRIB, 0, VPANEL, bool, bool);
SH_DECL_HOOK3_void(IPanel, SendMessage, SH_NOATTRIB, 0, VPANEL, KeyValues *, VPANEL);
SH_DECL_HOOK2(IVEngineClient, GetPlayerInfo, SH_NOATTRIB, 0, bool, int, player_info_t *);

int Hooks::AddHook_C_TFPlayer_GetGlowEffectColor(C_TFPlayer *instance, void(*hook)(float *, float *, float *)) {
	return SH_ADD_MANUALVPHOOK(C_TFPlayer_GetGlowEffectColor, instance, SH_STATIC(hook), false);
}

int Hooks::AddHook_IBaseClientDLL_FrameStageNotify(IBaseClientDLL *instance, void(*hook)(ClientFrameStage_t)) {
	return SH_ADD_HOOK(IBaseClientDLL, FrameStageNotify, instance, SH_STATIC(hook), false);
}

int Hooks::AddHook_IGameEventManager2_FireEvent(IGameEventManager2 *instance, bool(*hook)(IGameEvent *, bool)) {
	return SH_ADD_HOOK(IGameEventManager2, FireEvent, instance, SH_STATIC(hook), false);
}

int Hooks::AddHook_IGameEventManager2_FireEventClientSide(IGameEventManager2 *instance, bool(*hook)(IGameEvent *)) {
	return SH_ADD_HOOK(IGameEventManager2, FireEventClientSide, instance, SH_STATIC(hook), false);
}

int Hooks::AddHook_IGameResources_GetPlayerName(IGameResources *instance, const char *(*hook)(int)) {
	return SH_ADD_HOOK(IGameResources, GetPlayerName, instance, SH_STATIC(hook), false);
}

int Hooks::AddHook_IPanel_PaintTraverse(vgui::IPanel *instance, void(*hook)(vgui::VPANEL, bool, bool)) {
	return SH_ADD_HOOK(IPanel, PaintTraverse, instance, SH_STATIC(hook), false);
}

int Hooks::AddHook_IPanel_SendMessage(vgui::IPanel *instance, void(*hook)(vgui::VPANEL, KeyValues *, vgui::VPANEL)) {
	return SH_ADD_HOOK(IPanel, SendMessage, instance, SH_STATIC(hook), false);
}

int Hooks::AddHook_IVEngineClient_GetPlayerInfo(IVEngineClient *instance, bool(*hook)(int, player_info_t *)) {
	return SH_ADD_HOOK(IVEngineClient, GetPlayerInfo, instance, SH_STATIC(hook), false);
}

void Hooks::CallFunc_C_TFPlayer_CalcView(C_TFPlayer *instance, Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov) {
	SH_MCALL(instance, C_TFPlayer_CalcView)(eyeOrigin, eyeAngles, zNear, zFar, fov);
}

int Hooks::CallFunc_C_TFPlayer_GetObserverMode(C_TFPlayer *instance) {
	return SH_MCALL(instance, C_TFPlayer_GetObserverMode)();
}

C_BaseEntity *Hooks::CallFunc_C_TFPlayer_GetObserverTarget(C_TFPlayer *instance) {
	return SH_MCALL(instance, C_TFPlayer_GetObserverTarget)();
}

void Hooks::CallFunc_C_TFPlayer_UpdateGlowEffect(C_TFPlayer *instance) {
	SH_MCALL(instance, C_TFPlayer_UpdateGlowEffect)();
}

void Hooks::Pause() {
	g_SourceHook.PausePlugin(g_PLID);
}

bool Hooks::RemoveHook(int hookID) {
	return SH_REMOVE_HOOK_ID(hookID);
}

void Hooks::Unload() {
	g_SourceHook.UnloadPlugin(g_PLID, new StatusSpecUnloader());
}

void Hooks::Unpause() {
	g_SourceHook.UnpausePlugin(g_PLID);
}<|endoftext|>