<commit_before>#include <SKryptonWebView.h>

static bool initialized = false;

JNIEXPORT jlong JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_initialize_1N(JNIEnv* env, jobject obj,
                                                                      jstring jurl) {
    if (!initialized) {
        QtWebEngine::initialize();
        initialized = true;
    }
    auto url = StringFromJstring(env, jurl);
    auto ref = env->NewWeakGlobalRef(obj);
    auto view = new SKryptonWebView { ref, url };
    view->connect(view, &QWebEngineView::loadStarted, view, &SKryptonWebView::loadStarted);
    view->connect(view, &QWebEngineView::loadProgress, view, &SKryptonWebView::loadProgress);
    view->connect(view, &QWebEngineView::loadFinished, view, &SKryptonWebView::loadFinished);
    return (jlong) view->getContainer();
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_load_1N(JNIEnv* env, jobject obj, jstring jurl) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    auto url = StringFromJstring(env, jurl);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->load(QUrl { url.c_str() }); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to load url " + url);
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_back_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->back(); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to go back");
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_forward_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->back(); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to go forward");
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_reload_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->back(); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to reload");
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_stop_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->back(); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to stop");
    }
}

JNIEXPORT jobject JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_getSettings_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        auto settingsPointer = (jlong) view->settings();
        auto jSettings = NewObject(env, "com.waicool20.skrypton.jni.objects.SKryptonWebSettings", "(J)V",
                                   settingsPointer);
        if (jSettings) return jSettings.value();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to retrieve settings");
    return {};
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_setZoomFactor_1N(JNIEnv* env, jobject obj, jdouble factor) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->setZoomFactor(factor); });
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to set zoom factor to " + to_string(factor));

}

JNIEXPORT jdouble JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_zoomFactor_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->zoomFactor();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to get zoom factor");
    return {};
}

JNIEXPORT jbyteArray JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_takeScreenshot_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        if (view->isHidden()) {
            ThrowNewError(env, LOG_PREFIX + "Window must be showing to take screenshot");
            return {};
        }
        QPixmap pixmap { view->size() };

        std::mutex mutex;
        std::condition_variable cv;

        auto isDone = false;
        SKryptonApp::runOnMainThread([&pixmap, &isDone, view, &cv] {
            view->render(&pixmap, QPoint(), QRegion(view->rect()));
            isDone = true;
            cv.notify_one();
        });

        std::unique_lock<std::mutex> lock(mutex);
        cv.wait(lock, [&]{ return isDone; });

        QByteArray byteArray;
        QBuffer buffer(&byteArray);
        pixmap.save(&buffer, "PNG");
        auto arr = env->NewByteArray(byteArray.size());
        env->SetByteArrayRegion(arr, 0, byteArray.size() - 1, (jbyte*) byteArray.data());
        return arr;
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to take screenshot");
    return {};
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_sendEvent_1N(JNIEnv* env, jobject obj, jobject jEvent) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    auto opt2 = PointerFromCPointer<QEvent>(env, jEvent);
    if (opt && opt2) {
        SKryptonWebView* view = opt.value()->getWebView();
        QEvent* event = opt2.value();
        for (auto child : view->children()) {
            if (QWidget* widget = dynamic_cast<QWidget*>(child)) {
                QApplication::postEvent(widget, event);
                break;
            }
        }
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to pass event");
    }
}

JNIEXPORT jboolean JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_isLoading_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->isLoading();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to check if loading");
    return {};
}

JNIEXPORT jstring JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_url_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        auto url = view->url().toString().toStdString();
        return JstringFromString(env, url);
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to check if loading");
    return {};
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_runJavaScript_1N(JNIEnv* env, jobject obj, jstring content,
                                                                         jobject callback) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        auto qContent = QString::fromStdString(StringFromJstring(env, content));
        auto gCallback = env->NewGlobalRef(callback);
        view->page()->runJavaScript(qContent, [gCallback](const QVariant& v) {
            auto localEnv = GetLocalJNIEnvRef();
            CallMethod<void*>(localEnv, gCallback, "run", "()V");
            localEnv->DeleteGlobalRef(gCallback);
        });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to execute Javascript");
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_loadHtml_1N(JNIEnv* env, jobject obj, jstring content,
                                                                    jstring baseUrl) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        auto qContent = QString::fromStdString(StringFromJstring(env, content));
        auto qBaseUrl = QString::fromStdString(StringFromJstring(env, baseUrl));
        SKryptonApp::runOnMainThread([=] {
            view->setHtml(qContent, qBaseUrl);
        });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to load html content");
    }
}

JNIEXPORT jboolean JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_isShowingCursor_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->isShowingCursor();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to check if we should show cursor");
    return {};
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_setShowingCursor_1N(JNIEnv* env, jobject obj, jboolean should) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        view->setShowCursor(should);
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to set show cursor value");
    }
}

JNIEXPORT jint JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_getCursorX_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->getVirtualCursor()->x();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to set get cursorX");
    return {};
}

JNIEXPORT jint JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_getCursorY_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->getVirtualCursor()->y();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to get cursorY");
    return {};
}
<commit_msg>Fixing some copypasta mistakes<commit_after>#include <SKryptonWebView.h>

static bool initialized = false;

JNIEXPORT jlong JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_initialize_1N(JNIEnv* env, jobject obj,
                                                                      jstring jurl) {
    if (!initialized) {
        QtWebEngine::initialize();
        initialized = true;
    }
    auto url = StringFromJstring(env, jurl);
    auto ref = env->NewWeakGlobalRef(obj);
    auto view = new SKryptonWebView { ref, url };
    view->connect(view, &QWebEngineView::loadStarted, view, &SKryptonWebView::loadStarted);
    view->connect(view, &QWebEngineView::loadProgress, view, &SKryptonWebView::loadProgress);
    view->connect(view, &QWebEngineView::loadFinished, view, &SKryptonWebView::loadFinished);
    return (jlong) view->getContainer();
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_load_1N(JNIEnv* env, jobject obj, jstring jurl) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    auto url = StringFromJstring(env, jurl);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->load(QUrl { url.c_str() }); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to load url " + url);
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_back_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->back(); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to go back");
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_forward_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->forward(); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to go forward");
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_reload_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->reload(); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to reload");
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_stop_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->stop(); });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to stop");
    }
}

JNIEXPORT jobject JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_getSettings_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        auto settingsPointer = (jlong) view->settings();
        auto jSettings = NewObject(env, "com.waicool20.skrypton.jni.objects.SKryptonWebSettings", "(J)V",
                                   settingsPointer);
        if (jSettings) return jSettings.value();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to retrieve settings");
    return {};
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_setZoomFactor_1N(JNIEnv* env, jobject obj, jdouble factor) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        SKryptonApp::runOnMainThread([=] { view->setZoomFactor(factor); });
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to set zoom factor to " + to_string(factor));

}

JNIEXPORT jdouble JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_zoomFactor_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->zoomFactor();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to get zoom factor");
    return {};
}

JNIEXPORT jbyteArray JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_takeScreenshot_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        if (view->isHidden()) {
            ThrowNewError(env, LOG_PREFIX + "Window must be showing to take screenshot");
            return {};
        }
        QPixmap pixmap { view->size() };

        std::mutex mutex;
        std::condition_variable cv;

        auto isDone = false;
        SKryptonApp::runOnMainThread([&pixmap, &isDone, view, &cv] {
            view->render(&pixmap, QPoint(), QRegion(view->rect()));
            isDone = true;
            cv.notify_one();
        });

        std::unique_lock<std::mutex> lock(mutex);
        cv.wait(lock, [&]{ return isDone; });

        QByteArray byteArray;
        QBuffer buffer(&byteArray);
        pixmap.save(&buffer, "PNG");
        auto arr = env->NewByteArray(byteArray.size());
        env->SetByteArrayRegion(arr, 0, byteArray.size() - 1, (jbyte*) byteArray.data());
        return arr;
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to take screenshot");
    return {};
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_sendEvent_1N(JNIEnv* env, jobject obj, jobject jEvent) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    auto opt2 = PointerFromCPointer<QEvent>(env, jEvent);
    if (opt && opt2) {
        SKryptonWebView* view = opt.value()->getWebView();
        QEvent* event = opt2.value();
        for (auto child : view->children()) {
            if (QWidget* widget = dynamic_cast<QWidget*>(child)) {
                QApplication::postEvent(widget, event);
                break;
            }
        }
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to pass event");
    }
}

JNIEXPORT jboolean JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_isLoading_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->isLoading();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to check if loading");
    return {};
}

JNIEXPORT jstring JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_url_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        auto url = view->url().toString().toStdString();
        return JstringFromString(env, url);
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to get url");
    return {};
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_runJavaScript_1N(JNIEnv* env, jobject obj, jstring content,
                                                                         jobject callback) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        auto qContent = QString::fromStdString(StringFromJstring(env, content));
        auto gCallback = env->NewGlobalRef(callback);
        view->page()->runJavaScript(qContent, [gCallback](const QVariant& v) {
            auto localEnv = GetLocalJNIEnvRef();
            CallMethod<void*>(localEnv, gCallback, "run", "()V");
            localEnv->DeleteGlobalRef(gCallback);
        });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to execute Javascript");
    }
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_loadHtml_1N(JNIEnv* env, jobject obj, jstring content,
                                                                    jstring baseUrl) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        auto qContent = QString::fromStdString(StringFromJstring(env, content));
        auto qBaseUrl = QString::fromStdString(StringFromJstring(env, baseUrl));
        SKryptonApp::runOnMainThread([=] {
            view->setHtml(qContent, qBaseUrl);
        });
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to load html content");
    }
}

JNIEXPORT jboolean JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_isShowingCursor_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->isShowingCursor();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to check if we should show cursor");
    return {};
}

JNIEXPORT void JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_setShowingCursor_1N(JNIEnv* env, jobject obj, jboolean should) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        view->setShowCursor(should);
    } else {
        ThrowNewError(env, LOG_PREFIX + "Failed to set show cursor value");
    }
}

JNIEXPORT jint JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_getCursorX_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->getVirtualCursor()->x();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to set get cursorX");
    return {};
}

JNIEXPORT jint JNICALL
Java_com_waicool20_skrypton_jni_objects_SKryptonWebView_getCursorY_1N(JNIEnv* env, jobject obj) {
    auto opt = PointerFromCPointer<SKryptonWebViewContainer>(env, obj);
    if (opt) {
        SKryptonWebView* view = opt.value()->getWebView();
        return view->getVirtualCursor()->y();
    }
    ThrowNewError(env, LOG_PREFIX + "Failed to get cursorY");
    return {};
}
<|endoftext|>


<commit_before>// Copyright 2022 The XLS Authors
//
// 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.

// Driver for the XLS AOT compilation process.
// Uses the JIT to produce and object file, creates a header file and source to
// wrap (i.e., simplify) execution of the generated code, and writes the trio to
// disk.

#include "google/protobuf/text_format.h"
#include "absl/flags/flag.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/strip.h"
#include "absl/strings/substitute.h"
#include "xls/common/file/filesystem.h"
#include "xls/common/init_xls.h"
#include "xls/common/logging/logging.h"
#include "xls/common/status/status_macros.h"
#include "xls/ir/function.h"
#include "xls/ir/ir_parser.h"
#include "xls/jit/function_jit.h"

ABSL_FLAG(std::string, input, "", "Path to the IR to compile.");
ABSL_FLAG(std::string, top, "",
          "IR function to compile. "
          "If unspecified, the package top function will be used - "
          "in that case, the package-scoping mangling will be removed.");
ABSL_FLAG(std::string, namespaces, "",
          "Comma-separated list of namespaces into which to place the "
          "generated code. Earlier-specified namespaces enclose "
          "later-specified.");
ABSL_FLAG(std::string, output_object, "",
          "Path at which to write the output object file.");
ABSL_FLAG(std::string, output_header, "",
          "Path at which to write the output header file.");
ABSL_FLAG(std::string, output_source, "",
          "Path at which to write the output object-wrapping source file.");

namespace xls {

// Produces a simple header file containing a call with the same name as the
// target function (with the package name prefix removed).
absl::StatusOr<std::string> GenerateHeader(
    Package* p, Function* f, const std::vector<std::string>& namespaces) {
  constexpr std::string_view kTemplate =
      R"(// AUTO-GENERATED FILE! DO NOT EDIT!
#include "absl/status/statusor.h"
#include "xls/ir/value.h"
{{open_ns}}
absl::StatusOr<xls::Value> {{wrapper_fn_name}}({{wrapper_params}});
{{close_ns}})";

  absl::flat_hash_map<std::string, std::string> substitution_map;
  std::string package_prefix = absl::StrCat("__", p->name(), "__");
  substitution_map["{{wrapper_fn_name}}"] =
      absl::StripPrefix(f->name(), package_prefix);

  std::vector<std::string> params;
  for (const Param* param : f->params()) {
    params.push_back(absl::StrCat("const ::xls::Value& ", param->name()));
  }
  substitution_map["{{wrapper_params}}"] = absl::StrJoin(params, ", ");

  if (namespaces.empty()) {
    substitution_map["{{open_ns}}"] = "";
    substitution_map["{{close_ns}}"] = "";
  } else {
    substitution_map["{{open_ns}}"] =
        absl::StrFormat("\nnamespace %s {\n", absl::StrJoin(namespaces, "::"));
    substitution_map["{{close_ns}}"] = absl::StrFormat(
        "\n}  // namespace %s\n", absl::StrJoin(namespaces, "::"));
  }

  return absl::StrReplaceAll(kTemplate, substitution_map);
}

// Generates a source file to wrap invocation of the generated function.
// This is more complicated than one might expect due to the fact that we need
// to use some LLVM internals (via the LlvmTypeConverter) to know how to convert
// an XLS Value into a bit buffer packed in the manner expected by LLVM.
// We also need to know the arguments and return types of the function for the
// same reason. This requires having those types described in this source file.
// To do that, we encode the Function's FunctionType as a text-format proto and
// decode it on first execution.
// On that note, we do as much work as we can in one-time initialization to
// reduce the tax paid during normal execution.
absl::StatusOr<std::string> GenerateWrapperSource(
    Function* f, const JitObjectCode& object_code,
    const std::string& header_path,
    const std::vector<std::string>& namespaces) {
  constexpr std::string_view kTemplate =
      R"~(// AUTO-GENERATED FILE! DO NOT EDIT!
#include "{{header_path}}"

#include <cstdint>
#include <memory>
#include <vector>

#include "absl/types/span.h"
#include "xls/common/status/status_macros.h"
#include "xls/ir/events.h"
#include "xls/ir/nodes.h"
#include "xls/ir/type.h"
#include "xls/jit/aot_runtime.h"
#include "xls/jit/jit_runtime.h"

extern "C" {
void {{extern_fn}}(const uint8_t* const* inputs,
                   uint8_t* const* outputs,
                   uint8_t* temp_buffer,
                   ::xls::InterpreterEvents* events,
                   ::xls::JitRuntime* runtime);
}
{{open_ns}}
constexpr std::string_view kFnTypeProto = R"({{type_textproto}})";

// We have to put "once" flags in different namespaces so their definitions
// don't collide.
namespace {{private_ns}} {
absl::once_flag once;
std::unique_ptr<xls::aot_compile::GlobalData> global_data;

void OnceInit() {
  global_data = xls::aot_compile::InitGlobalData(kFnTypeProto);
}
}  //  namespace {{private_ns}}

absl::StatusOr<::xls::Value> {{wrapper_fn_name}}({{wrapper_params}}) {
  absl::call_once({{private_ns}}::once, {{private_ns}}::OnceInit);

{{arg_buffer_decls}}
  uint8_t* arg_buffers[] = {{arg_buffer_collector}};
  uint8_t result_buffer[{{result_size}}] = { 0 };
  XLS_RETURN_IF_ERROR(
          {{private_ns}}::global_data->jit_runtime->PackArgs(
          {{{param_names}}},
          {{private_ns}}::global_data->param_types,
          absl::MakeSpan(arg_buffers)));

  uint8_t* output_buffers[1] = {result_buffer};
  std::vector<uint8_t> temp_buffers({{temp_buffer_size}});
  ::xls::InterpreterEvents events;
  {{extern_fn}}(arg_buffers, output_buffers, temp_buffers.data(),
                &events, {{private_ns}}::global_data->jit_runtime.get());

  ::xls::Value result = {{private_ns}}::global_data->jit_runtime->UnpackBuffer(
      result_buffer, {{private_ns}}::global_data->fn_type->return_type());
  return result;
}

{{close_ns}}
)~";

  absl::flat_hash_map<std::string, std::string> substitution_map;
  substitution_map["{{header_path}}"] = header_path;
  substitution_map["{{extern_fn}}"] = object_code.function_name;
  substitution_map["{{temp_buffer_size}}"] =
      absl::StrCat(object_code.temp_buffer_size);

  if (namespaces.empty()) {
    substitution_map["{{open_ns}}"] = "";
    substitution_map["{{close_ns}}"] = "";
  } else {
    substitution_map["{{open_ns}}"] =
        absl::StrFormat("namespace %s {", absl::StrJoin(namespaces, "::"));
    substitution_map["{{close_ns}}"] =
        absl::StrFormat("}  // namespace %s", absl::StrJoin(namespaces, "::"));
  }

  int64_t return_type_bytes = object_code.return_buffer_size;

  std::vector<std::string> params;
  std::vector<std::string> param_names;
  std::vector<std::string> arg_buffer_decls;
  std::vector<std::string> arg_buffer_names;
  for (int64_t i = 0; i < f->params().size(); ++i) {
    Param* param = f->param(i);
    params.push_back(absl::StrCat("const ::xls::Value& ", param->name()));
    param_names.push_back(std::string(param->name()));
    arg_buffer_decls.push_back(
        absl::StrFormat("  uint8_t %s_buffer[%d];", param->name(),
                        object_code.parameter_buffer_sizes[i]));
    arg_buffer_names.push_back(absl::StrCat(param->name(), "_buffer"));
  }
  substitution_map["{{wrapper_params}}"] = absl::StrJoin(params, ", ");
  substitution_map["{{param_names}}"] = absl::StrJoin(param_names, ", ");
  substitution_map["{{arg_buffer_decls}}"] =
      absl::StrJoin(arg_buffer_decls, "\n");
  substitution_map["{{arg_buffer_collector}}"] =
      absl::StrFormat("{%s}", absl::StrJoin(arg_buffer_names, ", "));
  substitution_map["{{result_size}}"] = absl::StrCat(return_type_bytes);

  std::string type_textproto;
  google::protobuf::TextFormat::PrintToString(f->GetType()->ToProto(), &type_textproto);
  substitution_map["{{type_textproto}}"] = type_textproto;

  substitution_map["{{private_ns}}"] = absl::StrCat(f->name(), "__once_ns_");

  std::string package_prefix = absl::StrCat("__", f->package()->name(), "__");
  substitution_map["{{wrapper_fn_name}}"] =
      absl::StripPrefix(f->name(), package_prefix);
  return absl::StrReplaceAll(kTemplate, substitution_map);
}

absl::Status RealMain(const std::string& input_ir_path, std::string top,
                      const std::string& output_object_path,
                      const std::string& output_header_path,
                      const std::string& output_source_path,
                      const std::vector<std::string>& namespaces) {
  XLS_ASSIGN_OR_RETURN(std::string input_ir, GetFileContents(input_ir_path));
  XLS_ASSIGN_OR_RETURN(std::unique_ptr<Package> package,
                       Parser::ParsePackage(input_ir, input_ir_path));

  Function* f;
  std::string package_prefix = absl::StrCat("__", package->name(), "__");
  if (top.empty()) {
    XLS_ASSIGN_OR_RETURN(f, package->GetTopAsFunction());
  } else {
    XLS_ASSIGN_OR_RETURN(f, package->GetFunction(top));
  }
  XLS_ASSIGN_OR_RETURN(JitObjectCode object_code,
                       FunctionJit::CreateObjectCode(f));
  XLS_RETURN_IF_ERROR(SetFileContents(
      output_object_path, std::string(object_code.object_code.begin(),
                                      object_code.object_code.end())));

  XLS_ASSIGN_OR_RETURN(std::string header_text,
                       GenerateHeader(package.get(), f, namespaces));
  XLS_RETURN_IF_ERROR(SetFileContents(output_header_path, header_text));

  XLS_ASSIGN_OR_RETURN(
      std::string source_text,
      GenerateWrapperSource(f, object_code, output_header_path, namespaces));
  XLS_RETURN_IF_ERROR(SetFileContents(output_source_path, source_text));

  return absl::OkStatus();
}

}  // namespace xls

int main(int argc, char** argv) {
  xls::InitXls(argv[0], argc, argv);
  std::string input_ir_path = absl::GetFlag(FLAGS_input);
  XLS_QCHECK(!input_ir_path.empty())
      << "--input must be specified." << std::endl;

  std::string top = absl::GetFlag(FLAGS_top);

  std::string output_object_path = absl::GetFlag(FLAGS_output_object);
  std::string output_header_path = absl::GetFlag(FLAGS_output_header);
  std::string output_source_path = absl::GetFlag(FLAGS_output_source);
  XLS_QCHECK(!output_object_path.empty() && !output_header_path.empty() &&
             !output_source_path.empty())
      << "All of --output_{object,header,source}_path must be specified.";

  std::vector<std::string> namespaces;
  std::string namespaces_string = absl::GetFlag(FLAGS_namespaces);
  if (!namespaces_string.empty()) {
    namespaces = absl::StrSplit(namespaces_string, ',');
  }
  absl::Status status =
      xls::RealMain(input_ir_path, top, output_object_path, output_header_path,
                    output_source_path, namespaces);
  if (!status.ok()) {
    std::cout << status.message();
    return 1;
  }

  return 0;
}
<commit_msg>Add continuation point argument to AOT function.<commit_after>// Copyright 2022 The XLS Authors
//
// 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.

// Driver for the XLS AOT compilation process.
// Uses the JIT to produce and object file, creates a header file and source to
// wrap (i.e., simplify) execution of the generated code, and writes the trio to
// disk.

#include "google/protobuf/text_format.h"
#include "absl/flags/flag.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/strip.h"
#include "absl/strings/substitute.h"
#include "xls/common/file/filesystem.h"
#include "xls/common/init_xls.h"
#include "xls/common/logging/logging.h"
#include "xls/common/status/status_macros.h"
#include "xls/ir/function.h"
#include "xls/ir/ir_parser.h"
#include "xls/jit/function_jit.h"

ABSL_FLAG(std::string, input, "", "Path to the IR to compile.");
ABSL_FLAG(std::string, top, "",
          "IR function to compile. "
          "If unspecified, the package top function will be used - "
          "in that case, the package-scoping mangling will be removed.");
ABSL_FLAG(std::string, namespaces, "",
          "Comma-separated list of namespaces into which to place the "
          "generated code. Earlier-specified namespaces enclose "
          "later-specified.");
ABSL_FLAG(std::string, output_object, "",
          "Path at which to write the output object file.");
ABSL_FLAG(std::string, output_header, "",
          "Path at which to write the output header file.");
ABSL_FLAG(std::string, output_source, "",
          "Path at which to write the output object-wrapping source file.");

namespace xls {

// Produces a simple header file containing a call with the same name as the
// target function (with the package name prefix removed).
absl::StatusOr<std::string> GenerateHeader(
    Package* p, Function* f, const std::vector<std::string>& namespaces) {
  constexpr std::string_view kTemplate =
      R"(// AUTO-GENERATED FILE! DO NOT EDIT!
#include "absl/status/statusor.h"
#include "xls/ir/value.h"
{{open_ns}}
absl::StatusOr<xls::Value> {{wrapper_fn_name}}({{wrapper_params}});
{{close_ns}})";

  absl::flat_hash_map<std::string, std::string> substitution_map;
  std::string package_prefix = absl::StrCat("__", p->name(), "__");
  substitution_map["{{wrapper_fn_name}}"] =
      absl::StripPrefix(f->name(), package_prefix);

  std::vector<std::string> params;
  for (const Param* param : f->params()) {
    params.push_back(absl::StrCat("const ::xls::Value& ", param->name()));
  }
  substitution_map["{{wrapper_params}}"] = absl::StrJoin(params, ", ");

  if (namespaces.empty()) {
    substitution_map["{{open_ns}}"] = "";
    substitution_map["{{close_ns}}"] = "";
  } else {
    substitution_map["{{open_ns}}"] =
        absl::StrFormat("\nnamespace %s {\n", absl::StrJoin(namespaces, "::"));
    substitution_map["{{close_ns}}"] = absl::StrFormat(
        "\n}  // namespace %s\n", absl::StrJoin(namespaces, "::"));
  }

  return absl::StrReplaceAll(kTemplate, substitution_map);
}

// Generates a source file to wrap invocation of the generated function.
// This is more complicated than one might expect due to the fact that we need
// to use some LLVM internals (via the LlvmTypeConverter) to know how to convert
// an XLS Value into a bit buffer packed in the manner expected by LLVM.
// We also need to know the arguments and return types of the function for the
// same reason. This requires having those types described in this source file.
// To do that, we encode the Function's FunctionType as a text-format proto and
// decode it on first execution.
// On that note, we do as much work as we can in one-time initialization to
// reduce the tax paid during normal execution.
absl::StatusOr<std::string> GenerateWrapperSource(
    Function* f, const JitObjectCode& object_code,
    const std::string& header_path,
    const std::vector<std::string>& namespaces) {
  constexpr std::string_view kTemplate =
      R"~(// AUTO-GENERATED FILE! DO NOT EDIT!
#include "{{header_path}}"

#include <cstdint>
#include <memory>
#include <vector>

#include "absl/types/span.h"
#include "xls/common/status/status_macros.h"
#include "xls/ir/events.h"
#include "xls/ir/nodes.h"
#include "xls/ir/type.h"
#include "xls/jit/aot_runtime.h"
#include "xls/jit/jit_runtime.h"

extern "C" {
void {{extern_fn}}(const uint8_t* const* inputs,
                   uint8_t* const* outputs,
                   uint8_t* temp_buffer,
                   ::xls::InterpreterEvents* events,
                   ::xls::JitRuntime* runtime,
                   int64_t continuation_point);
}
{{open_ns}}
constexpr std::string_view kFnTypeProto = R"({{type_textproto}})";

// We have to put "once" flags in different namespaces so their definitions
// don't collide.
namespace {{private_ns}} {
absl::once_flag once;
std::unique_ptr<xls::aot_compile::GlobalData> global_data;

void OnceInit() {
  global_data = xls::aot_compile::InitGlobalData(kFnTypeProto);
}
}  //  namespace {{private_ns}}

absl::StatusOr<::xls::Value> {{wrapper_fn_name}}({{wrapper_params}}) {
  absl::call_once({{private_ns}}::once, {{private_ns}}::OnceInit);

{{arg_buffer_decls}}
  uint8_t* arg_buffers[] = {{arg_buffer_collector}};
  uint8_t result_buffer[{{result_size}}] = { 0 };
  XLS_RETURN_IF_ERROR(
          {{private_ns}}::global_data->jit_runtime->PackArgs(
          {{{param_names}}},
          {{private_ns}}::global_data->param_types,
          absl::MakeSpan(arg_buffers)));

  uint8_t* output_buffers[1] = {result_buffer};
  std::vector<uint8_t> temp_buffers({{temp_buffer_size}});
  ::xls::InterpreterEvents events;
  {{extern_fn}}(arg_buffers, output_buffers, temp_buffers.data(),
                &events, {{private_ns}}::global_data->jit_runtime.get(),
                /*continuation_point=*/0);

  ::xls::Value result = {{private_ns}}::global_data->jit_runtime->UnpackBuffer(
      result_buffer, {{private_ns}}::global_data->fn_type->return_type());
  return result;
}

{{close_ns}}
)~";

  absl::flat_hash_map<std::string, std::string> substitution_map;
  substitution_map["{{header_path}}"] = header_path;
  substitution_map["{{extern_fn}}"] = object_code.function_name;
  substitution_map["{{temp_buffer_size}}"] =
      absl::StrCat(object_code.temp_buffer_size);

  if (namespaces.empty()) {
    substitution_map["{{open_ns}}"] = "";
    substitution_map["{{close_ns}}"] = "";
  } else {
    substitution_map["{{open_ns}}"] =
        absl::StrFormat("namespace %s {", absl::StrJoin(namespaces, "::"));
    substitution_map["{{close_ns}}"] =
        absl::StrFormat("}  // namespace %s", absl::StrJoin(namespaces, "::"));
  }

  int64_t return_type_bytes = object_code.return_buffer_size;

  std::vector<std::string> params;
  std::vector<std::string> param_names;
  std::vector<std::string> arg_buffer_decls;
  std::vector<std::string> arg_buffer_names;
  for (int64_t i = 0; i < f->params().size(); ++i) {
    Param* param = f->param(i);
    params.push_back(absl::StrCat("const ::xls::Value& ", param->name()));
    param_names.push_back(std::string(param->name()));
    arg_buffer_decls.push_back(
        absl::StrFormat("  uint8_t %s_buffer[%d];", param->name(),
                        object_code.parameter_buffer_sizes[i]));
    arg_buffer_names.push_back(absl::StrCat(param->name(), "_buffer"));
  }
  substitution_map["{{wrapper_params}}"] = absl::StrJoin(params, ", ");
  substitution_map["{{param_names}}"] = absl::StrJoin(param_names, ", ");
  substitution_map["{{arg_buffer_decls}}"] =
      absl::StrJoin(arg_buffer_decls, "\n");
  substitution_map["{{arg_buffer_collector}}"] =
      absl::StrFormat("{%s}", absl::StrJoin(arg_buffer_names, ", "));
  substitution_map["{{result_size}}"] = absl::StrCat(return_type_bytes);

  std::string type_textproto;
  google::protobuf::TextFormat::PrintToString(f->GetType()->ToProto(), &type_textproto);
  substitution_map["{{type_textproto}}"] = type_textproto;

  substitution_map["{{private_ns}}"] = absl::StrCat(f->name(), "__once_ns_");

  std::string package_prefix = absl::StrCat("__", f->package()->name(), "__");
  substitution_map["{{wrapper_fn_name}}"] =
      absl::StripPrefix(f->name(), package_prefix);
  return absl::StrReplaceAll(kTemplate, substitution_map);
}

absl::Status RealMain(const std::string& input_ir_path, std::string top,
                      const std::string& output_object_path,
                      const std::string& output_header_path,
                      const std::string& output_source_path,
                      const std::vector<std::string>& namespaces) {
  XLS_ASSIGN_OR_RETURN(std::string input_ir, GetFileContents(input_ir_path));
  XLS_ASSIGN_OR_RETURN(std::unique_ptr<Package> package,
                       Parser::ParsePackage(input_ir, input_ir_path));

  Function* f;
  std::string package_prefix = absl::StrCat("__", package->name(), "__");
  if (top.empty()) {
    XLS_ASSIGN_OR_RETURN(f, package->GetTopAsFunction());
  } else {
    XLS_ASSIGN_OR_RETURN(f, package->GetFunction(top));
  }
  XLS_ASSIGN_OR_RETURN(JitObjectCode object_code,
                       FunctionJit::CreateObjectCode(f));
  XLS_RETURN_IF_ERROR(SetFileContents(
      output_object_path, std::string(object_code.object_code.begin(),
                                      object_code.object_code.end())));

  XLS_ASSIGN_OR_RETURN(std::string header_text,
                       GenerateHeader(package.get(), f, namespaces));
  XLS_RETURN_IF_ERROR(SetFileContents(output_header_path, header_text));

  XLS_ASSIGN_OR_RETURN(
      std::string source_text,
      GenerateWrapperSource(f, object_code, output_header_path, namespaces));
  XLS_RETURN_IF_ERROR(SetFileContents(output_source_path, source_text));

  return absl::OkStatus();
}

}  // namespace xls

int main(int argc, char** argv) {
  xls::InitXls(argv[0], argc, argv);
  std::string input_ir_path = absl::GetFlag(FLAGS_input);
  XLS_QCHECK(!input_ir_path.empty())
      << "--input must be specified." << std::endl;

  std::string top = absl::GetFlag(FLAGS_top);

  std::string output_object_path = absl::GetFlag(FLAGS_output_object);
  std::string output_header_path = absl::GetFlag(FLAGS_output_header);
  std::string output_source_path = absl::GetFlag(FLAGS_output_source);
  XLS_QCHECK(!output_object_path.empty() && !output_header_path.empty() &&
             !output_source_path.empty())
      << "All of --output_{object,header,source}_path must be specified.";

  std::vector<std::string> namespaces;
  std::string namespaces_string = absl::GetFlag(FLAGS_namespaces);
  if (!namespaces_string.empty()) {
    namespaces = absl::StrSplit(namespaces_string, ',');
  }
  absl::Status status =
      xls::RealMain(input_ir_path, top, output_object_path, output_header_path,
                    output_source_path, namespaces);
  if (!status.ok()) {
    std::cout << status.message();
    return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Fix build. linux_util.h caused a weird compile error when #included on Windows.<commit_after><|endoftext|>


<commit_before>#include "config.h"

#ifdef NEED_MINPUT_LIST
#include "minput_list.h"
#endif

#include <string>
#include <sstream>
#include <string.h>
#include <locale.h>
#include "m17n.hh"

#define complain()\
    fprintf(stderr, "Bad things happened at %s:%d.\n", __FILE__, __LINE__)

enum { NLINE = 1024 };
char *mygetline(const char *prompt)
{
    static char line[NLINE];
    printf("%s", prompt);
    if (fgets(line, NLINE, stdin)) {
        int n = strlen(line);
        if (line[n - 1] == '\n') {
            line[n - 1] = '\0';
        }
        return line;
    } else {
        return NULL;
    }
}

int mtext_print(FILE *of, MText *text)
{
    size_t bufsize = (mtext_len(text) + 1) * 6;
    unsigned char *buf = new unsigned char[bufsize];

    m17n::Converter conv = mconv_buffer_converter(Mnil, buf, bufsize);
    mconv_encode(conv, text);
    buf[conv.id->nbytes] = '\0';

    int re = fprintf(of, "%s(%lu/%lu)", buf, (unsigned long) strlen((char*)buf), (unsigned long) bufsize);
    delete [] buf;
    return re;
}

int msymbol_print(FILE *of, MSymbol sym)
{
    return fprintf(of, "%s", msymbol_name(sym));
}

int mplist_print_text_values(FILE *of, MPlist *plist, const char *sep)
{
    int re = 0;
    re += fprintf(of, "[%d]", plist ? mplist_length(plist) : 0);
    bool first = true;
    for (; plist; plist = mplist_next(plist)) {
        if (!first) {
            re += fprintf(of, "%s", sep);
        }
        first = false;
        mtext_print(of, (MText*)mplist_value(plist));
    }
    return re;
}

void *mplist_sub(MPlist *head, size_t idx) {
    while (idx--) {
        if (!head) {
            return NULL;
        }
        head = mplist_next(head);
    }
    return mplist_value(head);
}

int get_page_size(MSymbol mlang, MSymbol mname, int fallback)
{
    MPlist* plist = minput_get_variable(
            mlang, mname, msymbol("candidates-group-size"));
    if (plist == NULL) {
        if (mlang == Mt && mname == Mnil) {
            return fallback;
        } else {
            // tail recursion
            return get_page_size(Mt, Mnil, fallback);
        }
    }
    void *head = mplist_value(plist);
    return (int) (intptr_t) mplist_sub((MPlist*) head, 3);
}

int process_sym_stepped(MInputContext *ic, MSymbol sym)
{
    int re;
    if (minput_filter(ic, sym, NULL)) {
        printf("-%s:", msymbol_name(sym));
        re = 0;
    } else {
        m17n::Text converted = mtext();
        re = minput_lookup(ic, sym, NULL, converted);
        // Non-zero return values of minput_lookup() signify that the
        // character was not handled by the mim. According to libm17n
        // documentation, this is an error. But in practice this
        // should be interpreted as "let the character through";
        // The character shall be appended after ic->produced.

        printf("%s%s:", re ? "!" : "+", msymbol_name(sym));
        mtext_print(stdout, converted);
    }
    printf(":");
    mtext_print(stdout, ic->preedit);
#ifdef SHOW_CAND
    printf(":");
    if (ic->candidate_show && ic->candidate_list) {
        if (mplist_key(ic->candidate_list) == Mtext) {
            mtext_print(stdout, (MText*)mplist_value(ic->candidate_list));
        } else {
            mplist_print_text_values(stdout, ic->candidate_list, ",");
        }
    }
#endif
    printf("\n");
    return re;
}

int process_sym_unstepped(MInputContext *ic, MSymbol sym)
{
    int re;
    if (minput_filter(ic, sym, NULL)) {
        re = 0;
    } else {
        m17n::Text converted = mtext();
        re = minput_lookup(ic, sym, NULL, converted);
        mtext_print(stdout, converted);
    }
    if (re) {
        printf("%s", sym == Mnil ? "" : msymbol_name(sym));
    }
    // TODO Candidate list
    return re;
}

void list_mim() {
    // minput_list() returns a MPlist of MPlist's...
    MPlist *imlist = minput_list(Mnil);
    int n = mplist_length(imlist);
    printf("%d\n", n);
    for (; n--; imlist = mplist_next(imlist)) {
        MPlist *info = (MPlist*) mplist_value(imlist);

        MSymbol lang = (MSymbol) mplist_value(info);
        info = mplist_next(info);

        MSymbol name = (MSymbol) mplist_value(info);
        info = mplist_next(info);

        if (((MSymbol) mplist_value(info)) != Mt) {
            // Not sane
            continue;
        }

        msymbol_print(stdout, lang);
        printf(" ");
        msymbol_print(stdout, name);
        printf("\n");
    }
}

const char ps1[] = "\033[31m>\033[m ";
const char ps2[] = "\033[35m>>\033[m ";

typedef int (*process_func)(MInputContext*, MSymbol);
struct proc {
    process_func func;
    const char* header;
    const char* footer;
} procs[] = {
    {process_sym_stepped, "sym:converted:preedit\n", ""},
    {process_sym_unstepped, "-> ", "\n"},
};

#ifdef STEP
const proc* the_proc = &procs[0];
#else
const proc* the_proc = &procs[1];
#endif

int main()
{
    setlocale(LC_ALL, "");

    M17N_INIT();
    list_mim();

    char *line;
    while ((line = mygetline(ps1))) {
        std::istringstream ssym_line(line);
        std::string lang, name;
        if (!(ssym_line >> lang >> name && ssym_line.eof())) {
            fprintf(stderr, "Input format: $lang $name.  "
                    "Type EOF (CTRL-D) to exit.\n");
            continue;
        }
        m17n::Symbol mlang = msymbol(lang.c_str());
        m17n::Symbol mname = msymbol(name.c_str());
        if (!(mlang && mname)) {
            complain();
            continue;
        }
        m17n::InputMethod mim = minput_open_im(mlang, mname, 0);
        if (!mim) {
            fprintf(stderr, "Seems there is no such MIM.\n");
            continue;
        }

        fprintf(stderr, "page size is %d\n", get_page_size(mlang, mname, 10));
#ifdef SHOW_DESC
        // Show description
        m17n::Text mdesc = minput_get_description(mlang, mname);
        if (!mdesc) {
            complain();
            continue;
        }
        mtext_print(stdout, mdesc);
        printf("\n");
#endif

        // Create a context for a test session
        m17n::InputContext mic = minput_create_ic(mim, NULL);
        if (!mic) {
            fprintf(stderr, "Unable to create input context\n");
            continue;
        }
        fprintf(stderr, "Test session started.  Type emtpy line to exit.\n");
        while ((line = mygetline(ps2))) {
            if (line[0] == '\0') {
                fprintf(stderr, "End test session\n");
                break;
            }
            printf("%s", the_proc->header);
            const char *p;
            char buf[2] = " ";
            for (p = line; *p; p++) {
                buf[0] = *p;
                m17n::Symbol sym_char = msymbol(buf);
                the_proc->func(mic, sym_char);
            }
            the_proc->func(mic, Mnil);
            printf("%s", the_proc->footer);
            minput_reset_ic(mic);
        }
    }
    fprintf(stderr, "\n");

    M17N_FINI();
    return 0;
}

<commit_msg>fix test build<commit_after>#include "config.h"

#ifdef NEED_MINPUT_LIST
#include "minput_list.h"
#endif

#include <stdint.h>
#include <string>
#include <sstream>
#include <string.h>
#include <locale.h>
#include "m17n.hh"

#define complain()\
    fprintf(stderr, "Bad things happened at %s:%d.\n", __FILE__, __LINE__)

enum { NLINE = 1024 };
char *mygetline(const char *prompt)
{
    static char line[NLINE];
    printf("%s", prompt);
    if (fgets(line, NLINE, stdin)) {
        int n = strlen(line);
        if (line[n - 1] == '\n') {
            line[n - 1] = '\0';
        }
        return line;
    } else {
        return NULL;
    }
}

int mtext_print(FILE *of, MText *text)
{
    size_t bufsize = (mtext_len(text) + 1) * 6;
    unsigned char *buf = new unsigned char[bufsize];

    m17n::Converter conv = mconv_buffer_converter(Mnil, buf, bufsize);
    mconv_encode(conv, text);
    buf[conv.id->nbytes] = '\0';

    int re = fprintf(of, "%s(%lu/%lu)", buf, (unsigned long) strlen((char*)buf), (unsigned long) bufsize);
    delete [] buf;
    return re;
}

int msymbol_print(FILE *of, MSymbol sym)
{
    return fprintf(of, "%s", msymbol_name(sym));
}

int mplist_print_text_values(FILE *of, MPlist *plist, const char *sep)
{
    int re = 0;
    re += fprintf(of, "[%d]", plist ? mplist_length(plist) : 0);
    bool first = true;
    for (; plist; plist = mplist_next(plist)) {
        if (!first) {
            re += fprintf(of, "%s", sep);
        }
        first = false;
        mtext_print(of, (MText*)mplist_value(plist));
    }
    return re;
}

void *mplist_sub(MPlist *head, size_t idx) {
    while (idx--) {
        if (!head) {
            return NULL;
        }
        head = mplist_next(head);
    }
    return mplist_value(head);
}

int get_page_size(MSymbol mlang, MSymbol mname, int fallback)
{
    MPlist* plist = minput_get_variable(
            mlang, mname, msymbol("candidates-group-size"));
    if (plist == NULL) {
        if (mlang == Mt && mname == Mnil) {
            return fallback;
        } else {
            // tail recursion
            return get_page_size(Mt, Mnil, fallback);
        }
    }
    void *head = mplist_value(plist);
    return (int) (intptr_t) mplist_sub((MPlist*) head, 3);
}

int process_sym_stepped(MInputContext *ic, MSymbol sym)
{
    int re;
    if (minput_filter(ic, sym, NULL)) {
        printf("-%s:", msymbol_name(sym));
        re = 0;
    } else {
        m17n::Text converted = mtext();
        re = minput_lookup(ic, sym, NULL, converted);
        // Non-zero return values of minput_lookup() signify that the
        // character was not handled by the mim. According to libm17n
        // documentation, this is an error. But in practice this
        // should be interpreted as "let the character through";
        // The character shall be appended after ic->produced.

        printf("%s%s:", re ? "!" : "+", msymbol_name(sym));
        mtext_print(stdout, converted);
    }
    printf(":");
    mtext_print(stdout, ic->preedit);
#ifdef SHOW_CAND
    printf(":");
    if (ic->candidate_show && ic->candidate_list) {
        if (mplist_key(ic->candidate_list) == Mtext) {
            mtext_print(stdout, (MText*)mplist_value(ic->candidate_list));
        } else {
            mplist_print_text_values(stdout, ic->candidate_list, ",");
        }
    }
#endif
    printf("\n");
    return re;
}

int process_sym_unstepped(MInputContext *ic, MSymbol sym)
{
    int re;
    if (minput_filter(ic, sym, NULL)) {
        re = 0;
    } else {
        m17n::Text converted = mtext();
        re = minput_lookup(ic, sym, NULL, converted);
        mtext_print(stdout, converted);
    }
    if (re) {
        printf("%s", sym == Mnil ? "" : msymbol_name(sym));
    }
    // TODO Candidate list
    return re;
}

void list_mim() {
    // minput_list() returns a MPlist of MPlist's...
    MPlist *imlist = minput_list(Mnil);
    int n = mplist_length(imlist);
    printf("%d\n", n);
    for (; n--; imlist = mplist_next(imlist)) {
        MPlist *info = (MPlist*) mplist_value(imlist);

        MSymbol lang = (MSymbol) mplist_value(info);
        info = mplist_next(info);

        MSymbol name = (MSymbol) mplist_value(info);
        info = mplist_next(info);

        if (((MSymbol) mplist_value(info)) != Mt) {
            // Not sane
            continue;
        }

        msymbol_print(stdout, lang);
        printf(" ");
        msymbol_print(stdout, name);
        printf("\n");
    }
}

const char ps1[] = "\033[31m>\033[m ";
const char ps2[] = "\033[35m>>\033[m ";

typedef int (*process_func)(MInputContext*, MSymbol);
struct proc {
    process_func func;
    const char* header;
    const char* footer;
} procs[] = {
    {process_sym_stepped, "sym:converted:preedit\n", ""},
    {process_sym_unstepped, "-> ", "\n"},
};

#ifdef STEP
const proc* the_proc = &procs[0];
#else
const proc* the_proc = &procs[1];
#endif

int main()
{
    setlocale(LC_ALL, "");

    M17N_INIT();
    list_mim();

    char *line;
    while ((line = mygetline(ps1))) {
        std::istringstream ssym_line(line);
        std::string lang, name;
        if (!(ssym_line >> lang >> name && ssym_line.eof())) {
            fprintf(stderr, "Input format: $lang $name.  "
                    "Type EOF (CTRL-D) to exit.\n");
            continue;
        }
        m17n::Symbol mlang = msymbol(lang.c_str());
        m17n::Symbol mname = msymbol(name.c_str());
        if (!(mlang && mname)) {
            complain();
            continue;
        }
        m17n::InputMethod mim = minput_open_im(mlang, mname, 0);
        if (!mim) {
            fprintf(stderr, "Seems there is no such MIM.\n");
            continue;
        }

        fprintf(stderr, "page size is %d\n", get_page_size(mlang, mname, 10));
#ifdef SHOW_DESC
        // Show description
        m17n::Text mdesc = minput_get_description(mlang, mname);
        if (!mdesc) {
            complain();
            continue;
        }
        mtext_print(stdout, mdesc);
        printf("\n");
#endif

        // Create a context for a test session
        m17n::InputContext mic = minput_create_ic(mim, NULL);
        if (!mic) {
            fprintf(stderr, "Unable to create input context\n");
            continue;
        }
        fprintf(stderr, "Test session started.  Type emtpy line to exit.\n");
        while ((line = mygetline(ps2))) {
            if (line[0] == '\0') {
                fprintf(stderr, "End test session\n");
                break;
            }
            printf("%s", the_proc->header);
            const char *p;
            char buf[2] = " ";
            for (p = line; *p; p++) {
                buf[0] = *p;
                m17n::Symbol sym_char = msymbol(buf);
                the_proc->func(mic, sym_char);
            }
            the_proc->func(mic, Mnil);
            printf("%s", the_proc->footer);
            minput_reset_ic(mic);
        }
    }
    fprintf(stderr, "\n");

    M17N_FINI();
    return 0;
}

<|endoftext|>


<commit_before>/*
   Clique: a scalable implementation of the multifrontal algorithm

   Copyright (C) 2011 Jack Poulson, Lexing Ying, and
   The University of Texas at Austin

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "clique.hpp"
using namespace elemental;

void Usage()
{
    std::cout << "PanelLDL <nx> <ny> <nz> <cutoff>\n"
              << "<nx>: size of panel in x direction\n"
              << "<ny>: size of panel in y direction\n"
              << "<nz>: size of panel in z direction\n"
              << "<cutoff>: minimum required leaf size\n" << std::endl;
}

int ReorderedIndexRecursion
( int x, int y, int z, int nx, int ny, int nz,
  int stepsLeft, int cutoff, int offset )
{
    const int size = nx*ny*nz;
#ifndef RELEASE
    if( stepsLeft != 0 && size == 0 )
        throw std::logic_error("Null supernode in the upper tree");
#endif
    if( stepsLeft == 0 && size <= cutoff )
    {
        // We have satisfied the nested dissection constraints
        return offset + (x+y*nx+z*nx*ny);
    }
    else if( nx >= ny )
    {
        // Partition the X dimension
        const int middle = (nx-1)/2;
        if( x < middle )
        {
            return ReorderedIndexRecursion
            ( x, y, z, middle, ny, nz,
              std::max(stepsLeft-1,0), cutoff, offset );
        }
        else if( x == middle )
        {
            return offset + std::max(nx-1,0)*ny*nz + (y+z*ny);
        }
        else // x > middle
        {
            return ReorderedIndexRecursion
            ( x-middle-1, y, z, std::max(nx-middle-1,0), ny, nz,
              std::max(stepsLeft-1,0), cutoff, offset+middle*ny*nz );
        }
    }
    else
    {
        // Partition the Y dimension
        const int middle = (ny-1)/2;
        if( y < middle )
        {
            return ReorderedIndexRecursion
            ( x, y, z, nx, middle, nz,
              std::max(stepsLeft-1,0), cutoff, offset );
        }
        else if( y == middle )
        {
            return offset + nx*std::max(ny-1,0)*nz + (x+z*nx);
        }
        else // y > middle
        {
            return ReorderedIndexRecursion
            ( x, y-middle-1, z, nx, std::max(ny-middle-1,0), nz,
              std::max(stepsLeft-1,0), cutoff, offset+nx*middle*nz );
        }
    }
}

int ReorderedIndex
( int x, int y, int z, int nx, int ny, int nz,
  int minBalancedDepth, int cutoff )
{
#ifndef RELEASE
    PushCallStack("ReorderedIndex");
#endif
    int index = ReorderedIndexRecursion
    ( x, y, z, nx, ny, nz, minBalancedDepth, cutoff, 0 );
#ifndef RELEASE
    PopCallStack();
#endif
    return index;
}

int
main( int argc, char* argv[] )
{
    clique::Initialize( argc, argv );
    mpi::Comm comm = mpi::COMM_WORLD;
    const int commRank = mpi::CommRank( comm );
    const int commSize = mpi::CommSize( comm );

    // Ensure that we have a power of two number of processes
    unsigned temp = commSize;
    unsigned log2CommSize = 0;
    while( temp >>= 1 )
        ++log2CommSize;
    if( 1u<<log2CommSize != commSize )
    {
        if( commRank == 0 )
        {
            std::cerr << "Must use a power of two number of processes"
                      << std::endl;
        }
        clique::Finalize();
        return 0;
    }

    if( argc < 5 )
    {
        if( commRank == 0 )
            Usage();
        clique::Finalize();
        return 0;
    }

    int argNum = 1;
    const int nx = atoi( argv[argNum++] );
    const int ny = atoi( argv[argNum++] );
    const int nz = atoi( argv[argNum++] );
    const int cutoff = atoi( argv[argNum++] );
    if( commRank == 0 )
        std::cout << "(nx,ny,nz)=(" << nx << "," << ny << "," << nz << ")\n"
                  << "cutoff=" << cutoff << std::endl;

    // Fill the distributed portion of the structure
    int nxSub=nx, nySub=ny, xOffset=0, yOffset=0;
    clique::symbolic::DistSymmOrig distOrig;
    distOrig.supernodes.resize( log2CommSize );
    for( int s=0; s<log2CommSize; ++s )
    {
        clique::symbolic::DistSymmOrigSupernode& sn =
            distOrig.supernodes[log2CommSize-(s+1)];
        if( nxSub >= nySub )
        {
            // Form the structure of a partition of the X dimension
            sn.size = nySub*nz;
            sn.offset =
                ReorderedIndex
                ( xOffset, yOffset, 0, nx, ny, nz, log2CommSize, cutoff );

            int numJoins = 0;
            if( yOffset-1 >= 0 )
                ++numJoins;
            if( yOffset+nySub < ny )
                ++numJoins;
            sn.lowerStruct.resize( numJoins*nz );

            int joinOffset = 0;
            if( yOffset-1 >= 0 )
            {
                for( int i=0; i<nz; ++i )
                    sn.lowerStruct[i] = ReorderedIndex
                    ( xOffset, yOffset-1, 0, nx, ny, nz, log2CommSize, cutoff );
                joinOffset += nz;
            }
            if( yOffset+nySub < ny )
            {
                for( int i=0; i<nz; ++i )
                    sn.lowerStruct[joinOffset+i] = ReorderedIndex
                    ( xOffset, yOffset+nySub, 0, nx, ny, nz,
                      log2CommSize, cutoff );
            }

            // Pick the new offsets and sizes based upon whether or not the
            // (log2CommSize-s)'th bit of our rank is nonzero.
            // HERE
        }
        else
        {
            // Form the structure of a partition of the Y dimension
            sn.size = nxSub*nz;
            sn.offset =
                ReorderedIndex
                ( xOffset, yOffset, 0, nx, ny, nz, log2CommSize, cutoff );

            int numJoins = 0;
            if( xOffset-1 >= 0 )
                ++numJoins;
            if( xOffset+nxSub < nx )
                ++numJoins;
            sn.lowerStruct.resize( numJoins*nz );

            int joinOffset = 0;
            if( xOffset-1 >= 0 )
            {
                for( int i=0; i<nz; ++i )
                    sn.lowerStruct[i] = ReorderedIndex
                    ( xOffset-1, yOffset, 0, nx, ny, nz, log2CommSize, cutoff );
                joinOffset += nz;
            }
            if( xOffset+nxSub < nx )
            {
                for( int i=0; i<nz; ++i )
                    sn.lowerStruct[joinOffset+i] = ReorderedIndex
                    ( xOffset+nxSub, yOffset, 0, nx, ny, nz,
                      log2CommSize, cutoff );
            }

            // Pick the new offsets and sizes based upon whether or not the
            // (log2CommSize-s)'th bit of our rank is nonzero.
            // HERE
        }
    }
    // TODO: Form the local portion of the structure.

    // TODO: Call the symbolic factorization routine
    // TODO: Call the numerical factorization routine
    // TODO: Call a solve routine

    clique::Finalize();
    return 0;
}

<commit_msg>Adding more to the original structure formation.<commit_after>/*
   Clique: a scalable implementation of the multifrontal algorithm

   Copyright (C) 2011 Jack Poulson, Lexing Ying, and
   The University of Texas at Austin

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "clique.hpp"
using namespace elemental;

void Usage()
{
    std::cout << "PanelLDL <nx> <ny> <nz> <cutoff>\n"
              << "<nx>: size of panel in x direction\n"
              << "<ny>: size of panel in y direction\n"
              << "<nz>: size of panel in z direction\n"
              << "<cutoff>: minimum required leaf size\n" << std::endl;
}

int ReorderedIndexRecursion
( int x, int y, int z, int nx, int ny, int nz,
  int stepsLeft, int cutoff, int offset );

int ReorderedIndex
( int x, int y, int z, int nx, int ny, int nz,
  int minBalancedDepth, int cutoff );

void
FillOrigStruct
( int nx, int ny, int nz, int cutoff, int commRank, int log2CommSize,
  clique::symbolic::LocalSymmOrig& localOrig,
  clique::symbolic::DistSymmOrig& distOrig );

void
FillDistOrigStruct
( int nx, int ny, int nz, int& nxSub, int& nySub, int& xOffset, int& yOffset,
  int cutoff, int commRank, int log2CommSize,
  clique::symbolic::DistSymmOrig& SOrig );

void
FillLocalOrigStruct
( int nx, int ny, int nz, int nxSub, int nySub, int xOffset, int yOffset,
  int cutoff,
  clique::symbolic::LocalSymmOrig& SOrig );

int
main( int argc, char* argv[] )
{
    clique::Initialize( argc, argv );
    mpi::Comm comm = mpi::COMM_WORLD;
    const int commRank = mpi::CommRank( comm );
    const int commSize = mpi::CommSize( comm );

    // Ensure that we have a power of two number of processes
    unsigned temp = commSize;
    unsigned log2CommSize = 0;
    while( temp >>= 1 )
        ++log2CommSize;
    if( 1u<<log2CommSize != commSize )
    {
        if( commRank == 0 )
        {
            std::cerr << "Must use a power of two number of processes"
                      << std::endl;
        }
        clique::Finalize();
        return 0;
    }

    if( argc < 5 )
    {
        if( commRank == 0 )
            Usage();
        clique::Finalize();
        return 0;
    }

    int argNum = 1;
    const int nx = atoi( argv[argNum++] );
    const int ny = atoi( argv[argNum++] );
    const int nz = atoi( argv[argNum++] );
    const int cutoff = atoi( argv[argNum++] );
    if( commRank == 0 )
        std::cout << "(nx,ny,nz)=(" << nx << "," << ny << "," << nz << ")\n"
                  << "cutoff=" << cutoff << std::endl;

    // Fill the distributed portion of the original structure
    clique::symbolic::DistSymmOrig distSOrig;
    clique::symbolic::LocalSymmOrig localSOrig;
    FillOrigStruct
    ( nx, ny, nz, cutoff, commRank, log2CommSize, localSOrig, distSOrig );

    // TODO: Call the symbolic factorization routine
    // TODO: Call the numerical factorization routine
    // TODO: Call a solve routine

    clique::Finalize();
    return 0;
}

int ReorderedIndexRecursion
( int x, int y, int z, int nx, int ny, int nz,
  int stepsLeft, int cutoff, int offset )
{
    const int size = nx*ny*nz;
#ifndef RELEASE
    if( stepsLeft != 0 && size == 0 )
        throw std::logic_error("Null supernode in the upper tree");
#endif
    if( stepsLeft == 0 && size <= cutoff )
    {
        // We have satisfied the nested dissection constraints
        return offset + (x+y*nx+z*nx*ny);
    }
    else if( nx >= ny )
    {
        // Partition the X dimension
        const int middle = (nx-1)/2;
        if( x < middle )
        {
            return ReorderedIndexRecursion
            ( x, y, z, middle, ny, nz,
              std::max(stepsLeft-1,0), cutoff, offset );
        }
        else if( x == middle )
        {
            return offset + std::max(nx-1,0)*ny*nz + (y+z*ny);
        }
        else // x > middle
        {
            return ReorderedIndexRecursion
            ( x-middle-1, y, z, std::max(nx-middle-1,0), ny, nz,
              std::max(stepsLeft-1,0), cutoff, offset+middle*ny*nz );
        }
    }
    else
    {
        // Partition the Y dimension
        const int middle = (ny-1)/2;
        if( y < middle )
        {
            return ReorderedIndexRecursion
            ( x, y, z, nx, middle, nz,
              std::max(stepsLeft-1,0), cutoff, offset );
        }
        else if( y == middle )
        {
            return offset + nx*std::max(ny-1,0)*nz + (x+z*nx);
        }
        else // y > middle
        {
            return ReorderedIndexRecursion
            ( x, y-middle-1, z, nx, std::max(ny-middle-1,0), nz,
              std::max(stepsLeft-1,0), cutoff, offset+nx*middle*nz );
        }
    }
}

int ReorderedIndex
( int x, int y, int z, int nx, int ny, int nz,
  int minBalancedDepth, int cutoff )
{
#ifndef RELEASE
    PushCallStack("ReorderedIndex");
#endif
    int index = ReorderedIndexRecursion
    ( x, y, z, nx, ny, nz, minBalancedDepth, cutoff, 0 );
#ifndef RELEASE
    PopCallStack();
#endif
    return index;
}

void
FillOrigStruct
( int nx, int ny, int nz, int cutoff, int commRank, int log2CommSize,
  clique::symbolic::LocalSymmOrig& localSOrig,
  clique::symbolic::DistSymmOrig& distSOrig )
{
    int nxSub=nx, nySub=ny, xOffset=0, yOffset=0;
    FillDistOrigStruct
    ( nx, ny, nz, nxSub, nySub, xOffset, yOffset,
      cutoff, commRank, log2CommSize, distSOrig );
    FillLocalOrigStruct
    ( nx, ny, nz, nxSub, nySub, xOffset, yOffset, cutoff, localSOrig );
}

void
FillDistOrigStruct
( int nx, int ny, int nz, int& nxSub, int& nySub, int& xOffset, int& yOffset,
  int cutoff, int commRank, int log2CommSize,
  clique::symbolic::DistSymmOrig& SOrig )
{
    SOrig.supernodes.resize( log2CommSize );
    // Fill the distributed nodes
    for( int s=log2CommSize-1; s>0; --s )
    {
        clique::symbolic::DistSymmOrigSupernode& sn = SOrig.supernodes[s];
        const bool powerOfTwo = 1u<<(s-1);
        const bool onLeft = (commRank&powerOfTwo) == 0;
        if( nxSub >= nySub )
        {
            // Form the structure of a partition of the X dimension
            sn.size = nySub*nz;
            sn.offset =
                ReorderedIndex
                ( xOffset, yOffset, 0, nx, ny, nz, log2CommSize, cutoff );
            const int middle = (nxSub-1)/2;

            int numJoins = 0;
            if( yOffset-1 >= 0 )
                ++numJoins;
            if( yOffset+nySub < ny )
                ++numJoins;
            sn.lowerStruct.resize( numJoins*nz );

            int joinOffset = 0;
            if( yOffset-1 >= 0 )
            {
                for( int i=0; i<nz; ++i )
                    sn.lowerStruct[i] = ReorderedIndex
                    ( xOffset+middle, yOffset-1, 0, nx, ny, nz,
                      log2CommSize, cutoff );
                joinOffset += nz;
            }
            if( yOffset+nySub < ny )
            {
                for( int i=0; i<nz; ++i )
                    sn.lowerStruct[joinOffset+i] = ReorderedIndex
                    ( xOffset+middle, yOffset+nySub, 0, nx, ny, nz,
                      log2CommSize, cutoff );
            }

            // Pick the new offsets and sizes based upon our rank
            if( onLeft )
            {
                xOffset = xOffset;
                nxSub = middle;
            }
            else
            {
                xOffset = xOffset+middle+1;
                nxSub = std::max(nxSub-middle-1,0);
            }
        }
        else
        {
            // Form the structure of a partition of the Y dimension
            sn.size = nxSub*nz;
            sn.offset =
                ReorderedIndex
                ( xOffset, yOffset, 0, nx, ny, nz, log2CommSize, cutoff );
            const int middle = (nySub-1)/2;

            int numJoins = 0;
            if( xOffset-1 >= 0 )
                ++numJoins;
            if( xOffset+nxSub < nx )
                ++numJoins;
            sn.lowerStruct.resize( numJoins*nz );

            int joinOffset = 0;
            if( xOffset-1 >= 0 )
            {
                for( int i=0; i<nz; ++i )
                    sn.lowerStruct[i] = ReorderedIndex
                    ( xOffset-1, yOffset+middle, 0, nx, ny, nz,
                      log2CommSize, cutoff );
                joinOffset += nz;
            }
            if( xOffset+nxSub < nx )
            {
                for( int i=0; i<nz; ++i )
                    sn.lowerStruct[joinOffset+i] = ReorderedIndex
                    ( xOffset+nxSub, yOffset+middle, 0, nx, ny, nz,
                      log2CommSize, cutoff );
            }

            // Pick the new offsets and sizes based upon our rank
            if( onLeft )
            {
                yOffset = yOffset;
                nySub = middle;
            }
            else
            {
                yOffset = yOffset+middle+1;
                nySub = std::max(nySub-middle-1,0);
            }
        }
    }
    // Fill the bottom node, which is only owned by a single process
    clique::symbolic::DistSymmOrigSupernode& sn = SOrig.supernodes[0];
    if( nxSub >= nySub )
    {
        // Form the structure of a partition of the X dimension
        sn.size = nySub*nz;
        sn.offset =
            ReorderedIndex
            ( xOffset, yOffset, 0, nx, ny, nz, log2CommSize, cutoff );
        const int middle = (nxSub-1)/2;

        int numJoins = 0;
        if( yOffset-1 >= 0 )
            ++numJoins;
        if( yOffset+nySub < ny )
            ++numJoins;
        sn.lowerStruct.resize( numJoins*nz );

        int joinOffset = 0;
        if( yOffset-1 >= 0 )
        {
            for( int i=0; i<nz; ++i )
                sn.lowerStruct[i] = ReorderedIndex
                ( xOffset+middle, yOffset-1, 0, nx, ny, nz,
                  log2CommSize, cutoff );
            joinOffset += nz;
        }
        if( yOffset+nySub < ny )
        {
            for( int i=0; i<nz; ++i )
                sn.lowerStruct[joinOffset+i] = ReorderedIndex
                ( xOffset+middle, yOffset+nySub, 0, nx, ny, nz,
                  log2CommSize, cutoff );
        }
    }
    else
    {
        // Form the structure of a partition of the Y dimension
        sn.size = nxSub*nz;
        sn.offset =
            ReorderedIndex
            ( xOffset, yOffset, 0, nx, ny, nz, log2CommSize, cutoff );
        const int middle = (nySub-1)/2;

        int numJoins = 0;
        if( xOffset-1 >= 0 )
            ++numJoins;
        if( xOffset+nxSub < nx )
            ++numJoins;
        sn.lowerStruct.resize( numJoins*nz );

        int joinOffset = 0;
        if( xOffset-1 >= 0 )
        {
            for( int i=0; i<nz; ++i )
                sn.lowerStruct[i] = ReorderedIndex
                ( xOffset-1, yOffset+middle, 0, nx, ny, nz,
                  log2CommSize, cutoff );
            joinOffset += nz;
        }
        if( xOffset+nxSub < nx )
        {
            for( int i=0; i<nz; ++i )
                sn.lowerStruct[joinOffset+i] = ReorderedIndex
                ( xOffset+nxSub, yOffset+middle, 0, nx, ny, nz,
                  log2CommSize, cutoff );
        }
    }
}

void
FillLocalOrigStruct
( int nx, int ny, int nz, int nxSub, int nySub, int xOffset, int yOffset,
  int cutoff,
  clique::symbolic::LocalSymmOrig& SOrig )
{
    // HERE
    // First count the depth, resize, and then run the actual fill
}

<|endoftext|>


<commit_before>// Unit Test (random number generator)

#include <gtest/gtest.h>

#include <map>
#include "random.h"
using namespace nmlib;

TEST(random,uniform){
  int n=1000000, k=10;
  double sgm1 = sqrt((1.0/k)*(1-1.0/k));  // stddev of binomial dist B(1/k)
  std::map<int,int> count;

  init_rand(12345ULL);
  for(int i=0; i<n; i++) count[int(urand()*k)]++;
  for(int i=0; i<k; i++) EXPECT_NEAR(count[i]*1.0/n, 1.0/k, 3*sgm1/sqrt(n));
}

TEST(random,white){
  int n=1000000;
  double s01=0,x0=0,x1=0;

  init_rand(12345ULL);
  for(int i=0; i<n; i++){
    x0=x1;
    x1=urand()-0.5;
    s01+=x0*x1;
  }
  s01/=n;  // autocorrelation E X(t)X(t+1)

  double sgm1=1.0/12;  // stddev of x0*x1 = (stddev of x0)^2
  EXPECT_NEAR(fabs(s01), 0, 3*sgm1/sqrt(n));
}

TEST(random,lowdiscrepancy){
  int n=10000, k=10, bb[]={2,3,5,7,11,13}, dim=sizeof(bb)/sizeof(bb[0]);

  // van der Corput sequence
  for(int i=0; i<dim; i++){
    int base=bb[i];
    std::map<int,int> count;
    for(int seq=1; seq<=n; seq++) count[int(corput(seq,base)*k)]++;
    for(int j=0; j<k; j++) EXPECT_NEAR(count[j], n/k, log(n)/log(base)*5);
  }

  // Halton sequence
  {
    std::map<int,int> cnt[dim];
    for(int seq=1; seq<=n; seq++){
      Matrix x=halton(seq,dim);
      for(int d=0; d<dim; d++) cnt[d][int(x(d)*k)]++;
    }
    for(int d=0; d<dim; d++)
      for(int j=0; j<k; j++) EXPECT_NEAR(cnt[d][j], n/k, log(n)/log(bb[d])*5);  // uniform

    double cov=0;
    for(int seq=1; seq<=n; seq++){
      Matrix x=halton(seq,2);
      cov+=x(0)*x(1);
    }
    cov=cov/n-0.5*0.5;
    EXPECT_NEAR(cov,0,5.0/n);  // no correlation

    EXPECT_THROW(halton(0,7), std::runtime_error);  // max dimension
  }
}
<commit_msg>Fix VC++ build error (const array size)<commit_after>// Unit Test (random number generator)

#include <gtest/gtest.h>

#include <map>
#include "random.h"
using namespace nmlib;

TEST(random,uniform){
  int n=1000000, k=10;
  double sgm1 = sqrt((1.0/k)*(1-1.0/k));  // stddev of binomial dist B(1/k)
  std::map<int,int> count;

  init_rand(12345ULL);
  for(int i=0; i<n; i++) count[int(urand()*k)]++;
  for(int i=0; i<k; i++) EXPECT_NEAR(count[i]*1.0/n, 1.0/k, 3*sgm1/sqrt(n));
}

TEST(random,white){
  int n=1000000;
  double s01=0,x0=0,x1=0;

  init_rand(12345ULL);
  for(int i=0; i<n; i++){
    x0=x1;
    x1=urand()-0.5;
    s01+=x0*x1;
  }
  s01/=n;  // autocorrelation E X(t)X(t+1)

  double sgm1=1.0/12;  // stddev of x0*x1 = (stddev of x0)^2
  EXPECT_NEAR(fabs(s01), 0, 3*sgm1/sqrt(n));
}

TEST(random,lowdiscrepancy){
  int n=10000, k=10, bb[]={2,3,5,7,11,13};
  const int dim=sizeof(bb)/sizeof(bb[0]);

  // van der Corput sequence
  for(int i=0; i<dim; i++){
    int base=bb[i];
    std::map<int,int> count;
    for(int seq=1; seq<=n; seq++) count[int(corput(seq,base)*k)]++;
    for(int j=0; j<k; j++) EXPECT_NEAR(count[j], n/k, log(n)/log(base)*5);
  }

  // Halton sequence
  {
    std::map<int,int> cnt[dim];
    for(int seq=1; seq<=n; seq++){
      Matrix x=halton(seq,dim);
      for(int d=0; d<dim; d++) cnt[d][int(x(d)*k)]++;
    }
    for(int d=0; d<dim; d++)
      for(int j=0; j<k; j++) EXPECT_NEAR(cnt[d][j], n/k, log(n)/log(bb[d])*5);  // uniform

    double cov=0;
    for(int seq=1; seq<=n; seq++){
      Matrix x=halton(seq,2);
      cov+=x(0)*x(1);
    }
    cov=cov/n-0.5*0.5;
    EXPECT_NEAR(cov,0,5.0/n);  // no correlation

    EXPECT_THROW(halton(0,7), std::runtime_error);  // max dimension
  }
}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  viewport_preview_editor_plugin.cpp                                   */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "viewport_preview_editor_plugin.h"

bool EditorInspectorPluginViewportPreview::can_handle(Object *p_object) {
	return Object::cast_to<Viewport>(p_object) != nullptr;
}

void EditorInspectorPluginViewportPreview::parse_begin(Object *p_object) {
	Viewport *viewport = Object::cast_to<Viewport>(p_object);

	TexturePreview *viewport_preview = memnew(TexturePreview(viewport->get_texture(), false));
	viewport_preview->get_texture_display()->set_flip_v(true); // flip as ViewportTexture in 3.x is upside-down.

	// Otherwise `viewport_preview`'s `texture_display` doesn't update properly when `viewport`'s size changes.
	viewport->connect("size_changed", viewport_preview->get_texture_display(), "update");
	add_custom_control(viewport_preview);
}

ViewportPreviewEditorPlugin::ViewportPreviewEditorPlugin(EditorNode *p_node) {
	Ref<EditorInspectorPluginViewportPreview> plugin;
	plugin.instance();
	add_inspector_plugin(plugin);
}
<commit_msg>Revert "Fix ViewportPreview upside-down in 3.x."<commit_after>/*************************************************************************/
/*  viewport_preview_editor_plugin.cpp                                   */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "viewport_preview_editor_plugin.h"

bool EditorInspectorPluginViewportPreview::can_handle(Object *p_object) {
	return Object::cast_to<Viewport>(p_object) != nullptr;
}

void EditorInspectorPluginViewportPreview::parse_begin(Object *p_object) {
	Viewport *viewport = Object::cast_to<Viewport>(p_object);

	TexturePreview *viewport_preview = memnew(TexturePreview(viewport->get_texture(), false));
	// Otherwise `viewport_preview`'s `texture_display` doesn't update properly when `viewport`'s size changes.
	viewport->connect("size_changed", viewport_preview->get_texture_display(), "update");
	add_custom_control(viewport_preview);
}

ViewportPreviewEditorPlugin::ViewportPreviewEditorPlugin(EditorNode *p_node) {
	Ref<EditorInspectorPluginViewportPreview> plugin;
	plugin.instance();
	add_inspector_plugin(plugin);
}
<|endoftext|>