<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "jni.h"
#include "YGJNIVanilla.h"
#include <yoga/YGNode.h>
#include <cstring>
#include "YGJNI.h"
#include "common.h"
#include "YGJTypesVanilla.h"
#include <yoga/log.h>
#include <iostream>
#include <memory>
#include "YogaJniException.h"

using namespace facebook::yoga::vanillajni;
using facebook::yoga::detail::Log;

static inline ScopedLocalRef<jobject> YGNodeJobject(
    YGNodeRef node,
    void* layoutContext) {
  return reinterpret_cast<PtrJNodeMapVanilla*>(layoutContext)->ref(node);
}

static inline YGNodeRef _jlong2YGNodeRef(jlong addr) {
  return reinterpret_cast<YGNodeRef>(static_cast<intptr_t>(addr));
}

static inline YGConfigRef _jlong2YGConfigRef(jlong addr) {
  return reinterpret_cast<YGConfigRef>(static_cast<intptr_t>(addr));
}

static jlong jni_YGConfigNewJNI(JNIEnv* env, jobject obj) {
  return reinterpret_cast<jlong>(YGConfigNew());
}

static void jni_YGConfigFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  // unique_ptr will destruct the underlying global_ref, if present.
  auto context = std::unique_ptr<ScopedGlobalRef<jobject>>{
      static_cast<ScopedGlobalRef<jobject>*>(YGConfigGetContext(config))};
  YGConfigFree(config);
}

static void jni_YGConfigSetExperimentalFeatureEnabledJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jint feature,
    jboolean enabled) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetExperimentalFeatureEnabled(
      config, static_cast<YGExperimentalFeature>(feature), enabled);
}

static void jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviourJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jboolean enabled) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(config, enabled);
}

static void jni_YGConfigSetUseWebDefaultsJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jboolean useWebDefaults) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetUseWebDefaults(config, useWebDefaults);
}

static void jni_YGConfigSetPrintTreeFlagJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jboolean enable) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetPrintTreeFlag(config, enable);
}

static void jni_YGConfigSetPointScaleFactorJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jfloat pixelsInPoint) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetPointScaleFactor(config, pixelsInPoint);
}

static void YGPrint(YGNodeRef node, void* layoutContext) {
  if (auto obj = YGNodeJobject(node, layoutContext)) {
    // TODO cout << obj.get()->toString() << endl;
  } else {
    Log::log(
        node,
        YGLogLevelError,
        nullptr,
        "Java YGNode was GCed during layout calculation\n");
  }
}

static void jni_YGConfigSetUseLegacyStretchBehaviourJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jboolean useLegacyStretchBehaviour) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetUseLegacyStretchBehaviour(config, useLegacyStretchBehaviour);
}

static jlong jni_YGNodeNewJNI(JNIEnv* env, jobject obj) {
  const YGNodeRef node = YGNodeNew();
  node->setContext(YGNodeContext{}.asVoidPtr);
  node->setPrintFunc(YGPrint);
  return reinterpret_cast<jlong>(node);
}

static jlong jni_YGNodeNewWithConfigJNI(
    JNIEnv* env,
    jobject obj,
    jlong configPointer) {
  const YGNodeRef node = YGNodeNewWithConfig(_jlong2YGConfigRef(configPointer));
  node->setContext(YGNodeContext{}.asVoidPtr);
  return reinterpret_cast<jlong>(node);
}

static int YGJNILogFunc(
    const YGConfigRef config,
    const YGNodeRef node,
    YGLogLevel level,
    void* layoutContext,
    const char* format,
    va_list args) {
  int result = vsnprintf(NULL, 0, format, args);
  std::vector<char> buffer(1 + result);
  vsnprintf(buffer.data(), buffer.size(), format, args);

  auto jloggerPtr =
      static_cast<ScopedGlobalRef<jobject>*>(YGConfigGetContext(config));
  if (jloggerPtr != nullptr) {
    if (*jloggerPtr) {
      JNIEnv* env = getCurrentEnv();

      jclass cl = env->FindClass("Lcom/facebook/yoga/YogaLogLevel;");
      static const jmethodID smethodId =
          facebook::yoga::vanillajni::getStaticMethodId(
              env, cl, "fromInt", "(I)Lcom/facebook/yoga/YogaLogLevel;");
      ScopedLocalRef<jobject> logLevel =
          facebook::yoga::vanillajni::callStaticObjectMethod(
              env, cl, smethodId, level);

      auto objectClass = facebook::yoga::vanillajni::make_local_ref(
          env, env->GetObjectClass((*jloggerPtr).get()));
      static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId(
          env,
          objectClass.get(),
          "log",
          "(Lcom/facebook/yoga/YogaLogLevel;Ljava/lang/String;)V");
      facebook::yoga::vanillajni::callVoidMethod(
          env,
          (*jloggerPtr).get(),
          methodId,
          logLevel.get(),
          env->NewStringUTF(buffer.data()));
    }
  }

  return result;
}

static void jni_YGConfigSetLoggerJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jobject logger) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  auto context =
      reinterpret_cast<ScopedGlobalRef<jobject>*>(YGConfigGetContext(config));

  if (logger) {
    if (context == nullptr) {
      context = new ScopedGlobalRef<jobject>();
      YGConfigSetContext(config, context);
    }

    *context = newGlobalRef(env, logger);
    config->setLogger(YGJNILogFunc);
  } else {
    if (context != nullptr) {
      delete context;
      YGConfigSetContext(config, nullptr);
    }
    config->setLogger(nullptr);
  }
}

static void jni_YGNodeFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) {
  if (nativePointer == 0) {
    return;
  }
  const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
  YGNodeFree(node);
}

static void jni_YGNodeResetJNI(JNIEnv* env, jobject obj, jlong nativePointer) {
  const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
  void* context = node->getContext();
  YGNodeReset(node);
  node->setContext(context);
}

static void jni_YGNodeInsertChildJNI(<commit_msg>Don't call config->setLogger(nullptr) directly to avoid having no logger at all<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "jni.h"
#include "YGJNIVanilla.h"
#include <yoga/YGNode.h>
#include <cstring>
#include "YGJNI.h"
#include "common.h"
#include "YGJTypesVanilla.h"
#include <yoga/log.h>
#include <iostream>
#include <memory>
#include "YogaJniException.h"

using namespace facebook::yoga::vanillajni;
using facebook::yoga::detail::Log;

static inline ScopedLocalRef<jobject> YGNodeJobject(
    YGNodeRef node,
    void* layoutContext) {
  return reinterpret_cast<PtrJNodeMapVanilla*>(layoutContext)->ref(node);
}

static inline YGNodeRef _jlong2YGNodeRef(jlong addr) {
  return reinterpret_cast<YGNodeRef>(static_cast<intptr_t>(addr));
}

static inline YGConfigRef _jlong2YGConfigRef(jlong addr) {
  return reinterpret_cast<YGConfigRef>(static_cast<intptr_t>(addr));
}

static jlong jni_YGConfigNewJNI(JNIEnv* env, jobject obj) {
  return reinterpret_cast<jlong>(YGConfigNew());
}

static void jni_YGConfigFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  // unique_ptr will destruct the underlying global_ref, if present.
  auto context = std::unique_ptr<ScopedGlobalRef<jobject>>{
      static_cast<ScopedGlobalRef<jobject>*>(YGConfigGetContext(config))};
  YGConfigFree(config);
}

static void jni_YGConfigSetExperimentalFeatureEnabledJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jint feature,
    jboolean enabled) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetExperimentalFeatureEnabled(
      config, static_cast<YGExperimentalFeature>(feature), enabled);
}

static void jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviourJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jboolean enabled) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(config, enabled);
}

static void jni_YGConfigSetUseWebDefaultsJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jboolean useWebDefaults) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetUseWebDefaults(config, useWebDefaults);
}

static void jni_YGConfigSetPrintTreeFlagJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jboolean enable) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetPrintTreeFlag(config, enable);
}

static void jni_YGConfigSetPointScaleFactorJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jfloat pixelsInPoint) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetPointScaleFactor(config, pixelsInPoint);
}

static void YGPrint(YGNodeRef node, void* layoutContext) {
  if (auto obj = YGNodeJobject(node, layoutContext)) {
    // TODO cout << obj.get()->toString() << endl;
  } else {
    Log::log(
        node,
        YGLogLevelError,
        nullptr,
        "Java YGNode was GCed during layout calculation\n");
  }
}

static void jni_YGConfigSetUseLegacyStretchBehaviourJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jboolean useLegacyStretchBehaviour) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  YGConfigSetUseLegacyStretchBehaviour(config, useLegacyStretchBehaviour);
}

static jlong jni_YGNodeNewJNI(JNIEnv* env, jobject obj) {
  const YGNodeRef node = YGNodeNew();
  node->setContext(YGNodeContext{}.asVoidPtr);
  node->setPrintFunc(YGPrint);
  return reinterpret_cast<jlong>(node);
}

static jlong jni_YGNodeNewWithConfigJNI(
    JNIEnv* env,
    jobject obj,
    jlong configPointer) {
  const YGNodeRef node = YGNodeNewWithConfig(_jlong2YGConfigRef(configPointer));
  node->setContext(YGNodeContext{}.asVoidPtr);
  return reinterpret_cast<jlong>(node);
}

static int YGJNILogFunc(
    const YGConfigRef config,
    const YGNodeRef node,
    YGLogLevel level,
    void* layoutContext,
    const char* format,
    va_list args) {
  int result = vsnprintf(NULL, 0, format, args);
  std::vector<char> buffer(1 + result);
  vsnprintf(buffer.data(), buffer.size(), format, args);

  auto jloggerPtr =
      static_cast<ScopedGlobalRef<jobject>*>(YGConfigGetContext(config));
  if (jloggerPtr != nullptr) {
    if (*jloggerPtr) {
      JNIEnv* env = getCurrentEnv();

      jclass cl = env->FindClass("Lcom/facebook/yoga/YogaLogLevel;");
      static const jmethodID smethodId =
          facebook::yoga::vanillajni::getStaticMethodId(
              env, cl, "fromInt", "(I)Lcom/facebook/yoga/YogaLogLevel;");
      ScopedLocalRef<jobject> logLevel =
          facebook::yoga::vanillajni::callStaticObjectMethod(
              env, cl, smethodId, level);

      auto objectClass = facebook::yoga::vanillajni::make_local_ref(
          env, env->GetObjectClass((*jloggerPtr).get()));
      static const jmethodID methodId = facebook::yoga::vanillajni::getMethodId(
          env,
          objectClass.get(),
          "log",
          "(Lcom/facebook/yoga/YogaLogLevel;Ljava/lang/String;)V");
      facebook::yoga::vanillajni::callVoidMethod(
          env,
          (*jloggerPtr).get(),
          methodId,
          logLevel.get(),
          env->NewStringUTF(buffer.data()));
    }
  }

  return result;
}

static void jni_YGConfigSetLoggerJNI(
    JNIEnv* env,
    jobject obj,
    jlong nativePointer,
    jobject logger) {
  const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
  auto context =
      reinterpret_cast<ScopedGlobalRef<jobject>*>(YGConfigGetContext(config));

  if (logger) {
    if (context == nullptr) {
      context = new ScopedGlobalRef<jobject>();
      YGConfigSetContext(config, context);
    }

    *context = newGlobalRef(env, logger);
    config->setLogger(YGJNILogFunc);
  } else {
    if (context != nullptr) {
      delete context;
      YGConfigSetContext(config, nullptr);
    }
    YGConfigSetLogger(config, nullptr);
  }
}

static void jni_YGNodeFreeJNI(JNIEnv* env, jobject obj, jlong nativePointer) {
  if (nativePointer == 0) {
    return;
  }
  const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
  YGNodeFree(node);
}

static void jni_YGNodeResetJNI(JNIEnv* env, jobject obj, jlong nativePointer) {
  const YGNodeRef node = _jlong2YGNodeRef(nativePointer);
  void* context = node->getContext();
  YGNodeReset(node);
  node->setContext(context);
}

static void jni_YGNodeInsertChildJNI(
{'fraction_non_alphanumeric': 0.10356381358513554, 'fraction_numerical': 0.0024367956137678953, 'mean_word_length': 4.467527060782681, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3402700', 'n_tokens_mistral': 4496, 'n_tokens_neox': 4433, 'n_words': 886}