<commit_before>// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "config.h"

#if ENABLE(WORKERS)

#include "v8_binding.h"
#include "v8_custom.h"
#include "v8_proxy.h"

#include "ExceptionCode.h"
#include "Frame.h"
#include "MessagePort.h"
#include "V8Document.h"
#include "V8HTMLDocument.h"
#include "V8ObjectEventListener.h"
#include "Worker.h"
#include "WorkerContextExecutionProxy.h"

namespace WebCore {

CALLBACK_FUNC_DECL(WorkerConstructor) {
  INC_STATS(L"DOM.Worker.Constructor");

  if (!WorkerContextExecutionProxy::isWebWorkersEnabled()) {
    V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Worker is not enabled.");
    return v8::Undefined();
  }

  if (!args.IsConstructCall()) {
    V8Proxy::ThrowError(V8Proxy::TYPE_ERROR,
        "DOM object constructor cannot be called as a function.");
    return v8::Undefined();
  }

  if (args.Length() == 0) {
    V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments");
    return v8::Undefined();
  }

  v8::TryCatch try_catch;
  v8::Handle<v8::String> script_url = args[0]->ToString();
  if (try_catch.HasCaught()) {
    v8::ThrowException(try_catch.Exception());
    return v8::Undefined();
  }
  if (script_url.IsEmpty()) {
    return v8::Undefined();
  }

  // Get the document.
  Frame* frame = V8Proxy::retrieveFrame();
  if (!frame)
    return v8::Undefined();
  Document* document = frame->document();

  // Create the worker object.
  // Note: it's OK to let this RefPtr go out of scope because we also call
  // SetDOMWrapper(), which effectively holds a reference to obj.
  ExceptionCode ec = 0;
  RefPtr<Worker> obj = Worker::create(
      ToWebCoreString(script_url), document, ec);

  // Setup the standard wrapper object internal fields.
  v8::Handle<v8::Object> wrapper_object = args.Holder();
  V8Proxy::SetDOMWrapper(
      wrapper_object, V8ClassIndex::WORKER, obj.get());

  obj->ref();
  V8Proxy::SetJSWrapperForActiveDOMObject(
      obj.get(), v8::Persistent<v8::Object>::New(wrapper_object));

  return wrapper_object;
}

// TODO(mbelshe) - merge these with XHR's CreateHiddenXHRDependency

// Use an array to hold dependents. It works like a ref-counted scheme.
// A value can be added more than once to the xhr object.
static void CreateHiddenDependency(v8::Local<v8::Object> object,
                                   v8::Local<v8::Value> value) {
  ASSERT(V8Proxy::GetDOMWrapperType(object) ==
      V8ClassIndex::WORKER);
  v8::Local<v8::Value> cache =
      object->GetInternalField(V8Custom::kWorkerRequestCacheIndex);
  if (cache->IsNull() || cache->IsUndefined()) {
    cache = v8::Array::New();
    object->SetInternalField(V8Custom::kWorkerRequestCacheIndex, cache);
  }

  v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache);
  cache_array->Set(v8::Integer::New(cache_array->Length()), value);
}

static void RemoveHiddenDependency(v8::Local<v8::Object> object,
                                   v8::Local<v8::Value> value) {
  ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKER);
  v8::Local<v8::Value> cache =
      object->GetInternalField(V8Custom::kWorkerRequestCacheIndex);
  ASSERT(cache->IsArray());
  v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache);
  for (int i = cache_array->Length() - 1; i >= 0; i--) {
    v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i));
    if (cached->StrictEquals(value)) {
      cache_array->Delete(i);
      return;
    }
  }

  // We should only get here if we try to remove an event listener that was
  // never added.
}

ACCESSOR_GETTER(WorkerOnmessage) {
  INC_STATS(L"DOM.Worker.onmessage._get");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, info.Holder());
  if (imp->onmessage()) {
    V8ObjectEventListener* listener =
        static_cast<V8ObjectEventListener*>(imp->onmessage());
    v8::Local<v8::Object> v8_listener = listener->getListenerObject();
    return v8_listener;
  }
  return v8::Undefined();
}

ACCESSOR_SETTER(WorkerOnmessage) {
  INC_STATS(L"DOM.Worker.onmessage._set");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, info.Holder());
  V8ObjectEventListener* old_listener =
      static_cast<V8ObjectEventListener*>(imp->onmessage());
  if (value->IsNull()) {
    if (old_listener) {
      v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject();
      RemoveHiddenDependency(info.Holder(), old_v8_listener);
    }

    // Clear the listener
    imp->setOnmessage(0);

  } else {
    V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext());
    if (!proxy)
      return;

    RefPtr<EventListener> listener =
      proxy->FindOrCreateObjectEventListener(value, false);
    if (listener) {
      if (old_listener) {
        v8::Local<v8::Object> old_v8_listener =
            old_listener->getListenerObject();
        RemoveHiddenDependency(info.Holder(), old_v8_listener);
      }

      imp->setOnmessage(listener);
      CreateHiddenDependency(info.Holder(), value);
    }
  }
}

ACCESSOR_GETTER(WorkerOnerror) {
  INC_STATS(L"DOM.Worker.onerror._get");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, info.Holder());
  if (imp->onerror()) {
    V8ObjectEventListener* listener =
        static_cast<V8ObjectEventListener*>(imp->onerror());
    v8::Local<v8::Object> v8_listener = listener->getListenerObject();
    return v8_listener;
  }
  return v8::Undefined();
}

ACCESSOR_SETTER(WorkerOnerror) {
  INC_STATS(L"DOM.Worker.onerror._set");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, info.Holder());
  V8ObjectEventListener* old_listener =
      static_cast<V8ObjectEventListener*>(imp->onerror());
  if (value->IsNull()) {
    if (old_listener) {
      v8::Local<v8::Object> old_v8_listener =
          old_listener->getListenerObject();
      RemoveHiddenDependency(info.Holder(), old_v8_listener);
    }

    // Clear the listener
    imp->setOnerror(0);
  } else {
    V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext());
    if (!proxy)
      return;

    RefPtr<EventListener> listener =
      proxy->FindOrCreateObjectEventListener(value, false);
    if (listener) {
      if (old_listener) {
        v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject();
        RemoveHiddenDependency(info.Holder(), old_v8_listener);
      }

      imp->setOnerror(listener);
      CreateHiddenDependency(info.Holder(), value);
    }
  }
}

CALLBACK_FUNC_DECL(WorkerAddEventListener) {
  INC_STATS(L"DOM.Worker.addEventListener()");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, args.Holder());

  V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext());
  if (!proxy)
    return v8::Undefined();

  RefPtr<EventListener> listener =
      proxy->FindOrCreateObjectEventListener(args[1], false);
  if (listener) {
    String type = ToWebCoreString(args[0]);
    bool useCapture = args[2]->BooleanValue();
    imp->addEventListener(type, listener, useCapture);

    CreateHiddenDependency(args.Holder(), args[1]);
  }
  return v8::Undefined();
}

CALLBACK_FUNC_DECL(WorkerRemoveEventListener) {
  INC_STATS(L"DOM.Worker.removeEventListener()");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, args.Holder());

  V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext());
  if (!proxy)
    return v8::Undefined();  // probably leaked

  RefPtr<EventListener> listener =
    proxy->FindObjectEventListener(args[1], false);

  if (listener) {
    String type = ToWebCoreString(args[0]);
    bool useCapture = args[2]->BooleanValue();
    imp->removeEventListener(type, listener.get(), useCapture);

    RemoveHiddenDependency(args.Holder(), args[1]);
  }

  return v8::Undefined();
}

}  // namespace WebCore

#endif  // ENABLE(WORKERS)
<commit_msg>Fix worker constructor so that nested worker can be created. Review URL: http://codereview.chromium.org/67093<commit_after>// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "config.h"

#if ENABLE(WORKERS)

#include "v8_binding.h"
#include "v8_custom.h"
#include "v8_proxy.h"

#include "ExceptionCode.h"
#include "Frame.h"
#include "MessagePort.h"
#include "V8Document.h"
#include "V8HTMLDocument.h"
#include "V8ObjectEventListener.h"
#include "Worker.h"
#include "WorkerContext.h"
#include "WorkerContextExecutionProxy.h"

namespace WebCore {

CALLBACK_FUNC_DECL(WorkerConstructor) {
  INC_STATS(L"DOM.Worker.Constructor");

  if (!WorkerContextExecutionProxy::isWebWorkersEnabled()) {
    V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Worker is not enabled.");
    return v8::Undefined();
  }

  if (!args.IsConstructCall()) {
    V8Proxy::ThrowError(V8Proxy::TYPE_ERROR,
        "DOM object constructor cannot be called as a function.");
    return v8::Undefined();
  }

  if (args.Length() == 0) {
    V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments");
    return v8::Undefined();
  }

  v8::TryCatch try_catch;
  v8::Handle<v8::String> script_url = args[0]->ToString();
  if (try_catch.HasCaught()) {
    v8::ThrowException(try_catch.Exception());
    return v8::Undefined();
  }
  if (script_url.IsEmpty()) {
    return v8::Undefined();
  }

  // Get the script execution context.
  ScriptExecutionContext* context = 0;
  WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve();
  if (proxy)
    context = proxy->workerContext();
  else {
    Frame* frame = V8Proxy::retrieveFrame();
    if (!frame)
      return v8::Undefined();
    context = frame->document();
  }

  // Create the worker object.
  // Note: it's OK to let this RefPtr go out of scope because we also call
  // SetDOMWrapper(), which effectively holds a reference to obj.
  ExceptionCode ec = 0;
  RefPtr<Worker> obj = Worker::create(
      ToWebCoreString(script_url), context, ec);

  // Setup the standard wrapper object internal fields.
  v8::Handle<v8::Object> wrapper_object = args.Holder();
  V8Proxy::SetDOMWrapper(
      wrapper_object, V8ClassIndex::WORKER, obj.get());

  obj->ref();
  V8Proxy::SetJSWrapperForActiveDOMObject(
      obj.get(), v8::Persistent<v8::Object>::New(wrapper_object));

  return wrapper_object;
}

// TODO(mbelshe) - merge these with XHR's CreateHiddenXHRDependency

// Use an array to hold dependents. It works like a ref-counted scheme.
// A value can be added more than once to the xhr object.
static void CreateHiddenDependency(v8::Local<v8::Object> object,
                                   v8::Local<v8::Value> value) {
  ASSERT(V8Proxy::GetDOMWrapperType(object) ==
      V8ClassIndex::WORKER);
  v8::Local<v8::Value> cache =
      object->GetInternalField(V8Custom::kWorkerRequestCacheIndex);
  if (cache->IsNull() || cache->IsUndefined()) {
    cache = v8::Array::New();
    object->SetInternalField(V8Custom::kWorkerRequestCacheIndex, cache);
  }

  v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache);
  cache_array->Set(v8::Integer::New(cache_array->Length()), value);
}

static void RemoveHiddenDependency(v8::Local<v8::Object> object,
                                   v8::Local<v8::Value> value) {
  ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKER);
  v8::Local<v8::Value> cache =
      object->GetInternalField(V8Custom::kWorkerRequestCacheIndex);
  ASSERT(cache->IsArray());
  v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache);
  for (int i = cache_array->Length() - 1; i >= 0; i--) {
    v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i));
    if (cached->StrictEquals(value)) {
      cache_array->Delete(i);
      return;
    }
  }

  // We should only get here if we try to remove an event listener that was
  // never added.
}

ACCESSOR_GETTER(WorkerOnmessage) {
  INC_STATS(L"DOM.Worker.onmessage._get");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, info.Holder());
  if (imp->onmessage()) {
    V8ObjectEventListener* listener =
        static_cast<V8ObjectEventListener*>(imp->onmessage());
    v8::Local<v8::Object> v8_listener = listener->getListenerObject();
    return v8_listener;
  }
  return v8::Undefined();
}

ACCESSOR_SETTER(WorkerOnmessage) {
  INC_STATS(L"DOM.Worker.onmessage._set");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, info.Holder());
  V8ObjectEventListener* old_listener =
      static_cast<V8ObjectEventListener*>(imp->onmessage());
  if (value->IsNull()) {
    if (old_listener) {
      v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject();
      RemoveHiddenDependency(info.Holder(), old_v8_listener);
    }

    // Clear the listener
    imp->setOnmessage(0);

  } else {
    V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext());
    if (!proxy)
      return;

    RefPtr<EventListener> listener =
      proxy->FindOrCreateObjectEventListener(value, false);
    if (listener) {
      if (old_listener) {
        v8::Local<v8::Object> old_v8_listener =
            old_listener->getListenerObject();
        RemoveHiddenDependency(info.Holder(), old_v8_listener);
      }

      imp->setOnmessage(listener);
      CreateHiddenDependency(info.Holder(), value);
    }
  }
}

ACCESSOR_GETTER(WorkerOnerror) {
  INC_STATS(L"DOM.Worker.onerror._get");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, info.Holder());
  if (imp->onerror()) {
    V8ObjectEventListener* listener =
        static_cast<V8ObjectEventListener*>(imp->onerror());
    v8::Local<v8::Object> v8_listener = listener->getListenerObject();
    return v8_listener;
  }
  return v8::Undefined();
}

ACCESSOR_SETTER(WorkerOnerror) {
  INC_STATS(L"DOM.Worker.onerror._set");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, info.Holder());
  V8ObjectEventListener* old_listener =
      static_cast<V8ObjectEventListener*>(imp->onerror());
  if (value->IsNull()) {
    if (old_listener) {
      v8::Local<v8::Object> old_v8_listener =
          old_listener->getListenerObject();
      RemoveHiddenDependency(info.Holder(), old_v8_listener);
    }

    // Clear the listener
    imp->setOnerror(0);
  } else {
    V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext());
    if (!proxy)
      return;

    RefPtr<EventListener> listener =
      proxy->FindOrCreateObjectEventListener(value, false);
    if (listener) {
      if (old_listener) {
        v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject();
        RemoveHiddenDependency(info.Holder(), old_v8_listener);
      }

      imp->setOnerror(listener);
      CreateHiddenDependency(info.Holder(), value);
    }
  }
}

CALLBACK_FUNC_DECL(WorkerAddEventListener) {
  INC_STATS(L"DOM.Worker.addEventListener()");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, args.Holder());

  V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext());
  if (!proxy)
    return v8::Undefined();

  RefPtr<EventListener> listener =
      proxy->FindOrCreateObjectEventListener(args[1], false);
  if (listener) {
    String type = ToWebCoreString(args[0]);
    bool useCapture = args[2]->BooleanValue();
    imp->addEventListener(type, listener, useCapture);

    CreateHiddenDependency(args.Holder(), args[1]);
  }
  return v8::Undefined();
}

CALLBACK_FUNC_DECL(WorkerRemoveEventListener) {
  INC_STATS(L"DOM.Worker.removeEventListener()");
  Worker* imp = V8Proxy::ToNativeObject<Worker>(
      V8ClassIndex::WORKER, args.Holder());

  V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext());
  if (!proxy)
    return v8::Undefined();  // probably leaked

  RefPtr<EventListener> listener =
    proxy->FindObjectEventListener(args[1], false);

  if (listener) {
    String type = ToWebCoreString(args[0]);
    bool useCapture = args[2]->BooleanValue();
    imp->removeEventListener(type, listener.get(), useCapture);

    RemoveHiddenDependency(args.Holder(), args[1]);
  }

  return v8::Undefined();
}

}  // namespace WebCore

#endif  // ENABLE(WORKERS)
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/support/platform_support.h"

#include "base/android/jni_android.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string16.h"
#include "base/string_piece.h"
#include "base/test/test_support_android.h"
#include "googleurl/src/gurl.h"
#include "grit/webkit_resources.h"
#include "net/android/network_library.h"
#include "media/base/android/media_player_listener.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/support/test_webkit_platform_support.h"
#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"

namespace {

// The place where the Android layout test script will put the required tools
// and resources. Must keep consistent with DEVICE_DRT_DIR in
// WebKit/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py.
const char kDumpRenderTreeDir[] = "/data/local/tmp/drt";

}

namespace webkit_support {

void BeforeInitialize(bool unit_test_mode) {
  base::InitAndroidTestPaths();

  // Place cache under kDumpRenderTreeDir to allow the NRWT script to clear it.
  FilePath path(kDumpRenderTreeDir);
  path = path.Append("cache");
  PathService::Override(base::DIR_CACHE, path);

  // Set XML_CATALOG_FILES environment variable to blank to prevent libxml from
  // loading and complaining the non-exsistent /etc/xml/catalog file.
  setenv("XML_CATALOG_FILES", "", 0);

  JNIEnv* env = base::android::AttachCurrentThread();
  net::android::RegisterNetworkLibrary(env);

  if (!unit_test_mode)
    media::MediaPlayerListener::RegisterMediaPlayerListener(env);
}

void AfterInitialize(bool unit_test_mode) {
  FilePath data_path(kDumpRenderTreeDir);
  data_path = data_path.Append("DumpRenderTree.pak");
  ResourceBundle::InitSharedInstanceWithPakPath(data_path);

  if (unit_test_mode)
    return;

  // We enable file-over-http to bridge the file protocol to http protocol
  // in here, which can
  // (1) run the layout tests on android target device, but never need to
  // push the test files and corresponding resources to device, which saves
  // huge running time.
  // (2) still run non-http layout (tests not under LayoutTests/http) tests
  // via file protocol without breaking test environment / convention of webkit
  // layout tests, which are followed by current all webkit ports.
  SimpleResourceLoaderBridge::AllowFileOverHTTP(
      "third_party/WebKit/LayoutTests/",
      GURL("http://127.0.0.1:8000/all-tests/"));
}

void BeforeShutdown() {
  ResourceBundle::CleanupSharedInstance();
}

void AfterShutdown() {
}

}  // namespace webkit_support

string16 TestWebKitPlatformSupport::GetLocalizedString(int message_id) {
  return ResourceBundle::GetSharedInstance().GetLocalizedString(message_id);
}

base::StringPiece TestWebKitPlatformSupport::GetDataResource(
    int resource_id,
    ui::ScaleFactor scale_factor) {
  FilePath resources_path(kDumpRenderTreeDir);
  resources_path = resources_path.Append("DumpRenderTree_resources");
  switch (resource_id) {
    case IDR_BROKENIMAGE: {
      CR_DEFINE_STATIC_LOCAL(std::string, broken_image_data, ());
      if (broken_image_data.empty()) {
        FilePath path = resources_path.Append("missingImage.gif");
        bool success = file_util::ReadFileToString(path, &broken_image_data);
        if (!success)
          LOG(FATAL) << "Failed reading: " << path.value();
      }
      return broken_image_data;
    }
    case IDR_TEXTAREA_RESIZER: {
      CR_DEFINE_STATIC_LOCAL(std::string, resize_corner_data, ());
      if (resize_corner_data.empty()) {
        FilePath path = resources_path.Append("textAreaResizeCorner.png");
        bool success = file_util::ReadFileToString(path, &resize_corner_data);
        if (!success)
          LOG(FATAL) << "Failed reading: " << path.value();
      }
      return resize_corner_data;
    }
  }

  return ResourceBundle::GetSharedInstance().GetRawDataResource(
      resource_id, scale_factor);
}
<commit_msg>Register Android's media/ and net/ JNI bindings when running DumpRenderTree.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/support/platform_support.h"

#include "base/android/jni_android.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string16.h"
#include "base/string_piece.h"
#include "base/test/test_support_android.h"
#include "googleurl/src/gurl.h"
#include "grit/webkit_resources.h"
#include "net/android/network_library.h"
#include "net/android/net_jni_registrar.h"
#include "media/base/android/media_jni_registrar.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/support/test_webkit_platform_support.h"
#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"

namespace {

// The place where the Android layout test script will put the required tools
// and resources. Must keep consistent with DEVICE_DRT_DIR in
// WebKit/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py.
const char kDumpRenderTreeDir[] = "/data/local/tmp/drt";

}

namespace webkit_support {

void BeforeInitialize(bool unit_test_mode) {
  base::InitAndroidTestPaths();

  // Place cache under kDumpRenderTreeDir to allow the NRWT script to clear it.
  FilePath path(kDumpRenderTreeDir);
  path = path.Append("cache");
  PathService::Override(base::DIR_CACHE, path);

  // Set XML_CATALOG_FILES environment variable to blank to prevent libxml from
  // loading and complaining the non-exsistent /etc/xml/catalog file.
  setenv("XML_CATALOG_FILES", "", 0);

  JNIEnv* env = base::android::AttachCurrentThread();
  net::android::RegisterNetworkLibrary(env);

  // Chromium binaries will register their Jni bindings through the library
  // loader that is part of content/. WebKit uses a different path, so the
  // bindings have to be initialized separately as well.
  if (!unit_test_mode) {
    media::RegisterJni(env);
    net::android::RegisterJni(env);
  }
}

void AfterInitialize(bool unit_test_mode) {
  FilePath data_path(kDumpRenderTreeDir);
  data_path = data_path.Append("DumpRenderTree.pak");
  ResourceBundle::InitSharedInstanceWithPakPath(data_path);

  if (unit_test_mode)
    return;

  // We enable file-over-http to bridge the file protocol to http protocol
  // in here, which can
  // (1) run the layout tests on android target device, but never need to
  // push the test files and corresponding resources to device, which saves
  // huge running time.
  // (2) still run non-http layout (tests not under LayoutTests/http) tests
  // via file protocol without breaking test environment / convention of webkit
  // layout tests, which are followed by current all webkit ports.
  SimpleResourceLoaderBridge::AllowFileOverHTTP(
      "third_party/WebKit/LayoutTests/",
      GURL("http://127.0.0.1:8000/all-tests/"));
}

void BeforeShutdown() {
  ResourceBundle::CleanupSharedInstance();
}

void AfterShutdown() {
}

}  // namespace webkit_support

string16 TestWebKitPlatformSupport::GetLocalizedString(int message_id) {
  return ResourceBundle::GetSharedInstance().GetLocalizedString(message_id);
}

base::StringPiece TestWebKitPlatformSupport::GetDataResource(
    int resource_id,
    ui::ScaleFactor scale_factor) {
  FilePath resources_path(kDumpRenderTreeDir);
  resources_path = resources_path.Append("DumpRenderTree_resources");
  switch (resource_id) {
    case IDR_BROKENIMAGE: {
      CR_DEFINE_STATIC_LOCAL(std::string, broken_image_data, ());
      if (broken_image_data.empty()) {
        FilePath path = resources_path.Append("missingImage.gif");
        bool success = file_util::ReadFileToString(path, &broken_image_data);
        if (!success)
          LOG(FATAL) << "Failed reading: " << path.value();
      }
      return broken_image_data;
    }
    case IDR_TEXTAREA_RESIZER: {
      CR_DEFINE_STATIC_LOCAL(std::string, resize_corner_data, ());
      if (resize_corner_data.empty()) {
        FilePath path = resources_path.Append("textAreaResizeCorner.png");
        bool success = file_util::ReadFileToString(path, &resize_corner_data);
        if (!success)
          LOG(FATAL) << "Failed reading: " << path.value();
      }
      return resize_corner_data;
    }
  }

  return ResourceBundle::GetSharedInstance().GetRawDataResource(
      resource_id, scale_factor);
}
<|endoftext|>


<commit_before>#include <storm/texture_png.h>

#include <iterator>
#include <vector>

#include <storm/exception.h>

#define LODEPNG_NO_COMPILE_ENCODER
#define LODEPNG_NO_COMPILE_DISK
#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
#define LODEPNG_NO_COMPILE_CPP

// The following preprocessor directives add the 'storm_' prefix to all public
// lodepng symbols so libstorm can be safely linked to binaries that already
// use lodepng.

#define LODEPNG_VERSION_STRING           STORM_LODEPNG_VERSION_STRING
#define lodepng_default_decompress_settings \
    storm_lodepng_default_decompress_settings
#define lodepng_decode_memory            storm_lodepng_decode_memory
#define lodepng_decode32                 storm_lodepng_decode32
#define lodepng_decode24                 storm_lodepng_decode24
#define lodepng_error_text               storm_lodepng_error_text
#define lodepng_decompress_settings_init storm_lodepng_decompress_settings_init
#define lodepng_color_mode_init          storm_lodepng_color_mode_init
#define lodepng_color_mode_cleanup       storm_lodepng_color_mode_cleanup
#define lodepng_color_mode_copy          storm_lodepng_color_mode_copy
#define lodepng_palette_clear            storm_lodepng_palette_clear
#define lodepng_palette_add              storm_lodepng_palette_add
#define lodepng_get_bpp                  storm_lodepng_get_bpp
#define lodepng_get_channels             storm_lodepng_get_channels
#define lodepng_is_greyscale_type        storm_lodepng_is_greyscale_type
#define lodepng_is_alpha_type            storm_lodepng_is_alpha_type
#define lodepng_is_palette_type          storm_lodepng_is_palette_type
#define lodepng_has_palette_alpha        storm_lodepng_has_palette_alpha
#define lodepng_can_have_alpha           storm_lodepng_can_have_alpha
#define lodepng_get_raw_size             storm_lodepng_get_raw_size
#define lodepng_get_raw_size_lct         storm_lodepng_get_raw_size_lct
#define lodepng_info_init                storm_lodepng_info_init
#define lodepng_info_cleanup             storm_lodepng_info_cleanup
#define lodepng_info_copy                storm_lodepng_info_copy
#define lodepng_info_swap                storm_lodepng_info_swap
#define lodepng_convert                  storm_lodepng_convert
#define lodepng_decoder_settings_init    storm_lodepng_decoder_settings_init
#define lodepng_state_init               storm_lodepng_state_init
#define lodepng_state_cleanup            storm_lodepng_state_cleanup
#define lodepng_state_copy               storm_lodepng_state_copy
#define lodepng_decode                   storm_lodepng_decode
#define lodepng_inspect                  storm_lodepng_inspect
#define lodepng_chunk_length             storm_lodepng_chunk_length
#define lodepng_chunk_type               storm_lodepng_chunk_type
#define lodepng_chunk_type_equals        storm_lodepng_chunk_type_equals
#define lodepng_chunk_ancillary          storm_lodepng_chunk_ancillary
#define lodepng_chunk_private            storm_lodepng_chunk_private
#define lodepng_chunk_safetocopy         storm_lodepng_chunk_safetocopy
#define lodepng_chunk_data               storm_lodepng_chunk_data
#define lodepng_chunk_data_const         storm_lodepng_chunk_data_const
#define lodepng_chunk_check_crc          storm_lodepng_chunk_check_crc
#define lodepng_chunk_generate_crc       storm_lodepng_chunk_generate_crc
#define lodepng_chunk_next               storm_lodepng_chunk_next
#define lodepng_chunk_next_const         storm_lodepng_chunk_next_const
#define lodepng_chunk_append             storm_lodepng_chunk_append
#define lodepng_chunk_create             storm_lodepng_chunk_create
#define lodepng_crc32                    storm_lodepng_crc32
#define lodepng_inflate                  storm_lodepng_inflate
#define lodepng_zlib_decompress          storm_lodepng_zlib_decompress
#define lodepng_zlib_compress            storm_lodepng_zlib_compress
#define lodepng_huffman_code_lengths     storm_lodepng_huffman_code_lengths
#define lodepng_deflate                  storm_lodepng_deflate
#define lodepng_read32bitInt             storm_lodepng_read32bitInt

#include <lodepng.cpp>

namespace storm {

Texture::Pointer parsePng(
    BinaryInputStream &stream, const Texture::LoadingParameters &parameters )
{
    const std::vector<uint8_t> buffer(
        std::istream_iterator<uint8_t> {*stream},
        std::istream_iterator<uint8_t> {} );

    uint8_t *texels = nullptr;
    unsigned width = 0;
    unsigned height = 0;

    if( const unsigned error = lodepng_decode32(
            &texels, &width, &height, buffer.data(), buffer.size()) ) {
        if( texels ) {
            lodepng_free( texels );
        }

        throw ResourceLoadingError() <<
            "Couldn't read a PNG texture: " << lodepng_error_text( error );
    }

    Texture::Separate2dDescription description;
    if( parameters.defaultColorSpace == Texture::ColorSpace::sRGB )
        description.format = Texture::Format::SrgbaNormUint8;
    else
        description.format = Texture::Format::RgbaNormUint8;
    description.width = width;
    description.height = height;
    description.mipLevels = 1;
    description.resourceType = ResourceType::Static;

    Texture::Pointer texture = Texture::create( description );

    Texture::Separate2dRegion region;
    region.mipLevel = 0;
    region.x = 0;
    region.y = 0;
    region.width = width;
    region.height = height;

    texture->setTexels( region, texels );

    lodepng_free( texels );

    return texture;
}

}
<commit_msg>Fixed a texture loading issue<commit_after>#include <storm/texture_png.h>

#include <iterator>
#include <vector>

#include <storm/exception.h>

#define LODEPNG_NO_COMPILE_ENCODER
#define LODEPNG_NO_COMPILE_DISK
#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
#define LODEPNG_NO_COMPILE_CPP

// The following preprocessor directives add the 'storm_' prefix to all public
// lodepng symbols so libstorm can be safely linked to binaries that already
// use lodepng.

#define LODEPNG_VERSION_STRING           STORM_LODEPNG_VERSION_STRING
#define lodepng_default_decompress_settings \
    storm_lodepng_default_decompress_settings
#define lodepng_decode_memory            storm_lodepng_decode_memory
#define lodepng_decode32                 storm_lodepng_decode32
#define lodepng_decode24                 storm_lodepng_decode24
#define lodepng_error_text               storm_lodepng_error_text
#define lodepng_decompress_settings_init storm_lodepng_decompress_settings_init
#define lodepng_color_mode_init          storm_lodepng_color_mode_init
#define lodepng_color_mode_cleanup       storm_lodepng_color_mode_cleanup
#define lodepng_color_mode_copy          storm_lodepng_color_mode_copy
#define lodepng_palette_clear            storm_lodepng_palette_clear
#define lodepng_palette_add              storm_lodepng_palette_add
#define lodepng_get_bpp                  storm_lodepng_get_bpp
#define lodepng_get_channels             storm_lodepng_get_channels
#define lodepng_is_greyscale_type        storm_lodepng_is_greyscale_type
#define lodepng_is_alpha_type            storm_lodepng_is_alpha_type
#define lodepng_is_palette_type          storm_lodepng_is_palette_type
#define lodepng_has_palette_alpha        storm_lodepng_has_palette_alpha
#define lodepng_can_have_alpha           storm_lodepng_can_have_alpha
#define lodepng_get_raw_size             storm_lodepng_get_raw_size
#define lodepng_get_raw_size_lct         storm_lodepng_get_raw_size_lct
#define lodepng_info_init                storm_lodepng_info_init
#define lodepng_info_cleanup             storm_lodepng_info_cleanup
#define lodepng_info_copy                storm_lodepng_info_copy
#define lodepng_info_swap                storm_lodepng_info_swap
#define lodepng_convert                  storm_lodepng_convert
#define lodepng_decoder_settings_init    storm_lodepng_decoder_settings_init
#define lodepng_state_init               storm_lodepng_state_init
#define lodepng_state_cleanup            storm_lodepng_state_cleanup
#define lodepng_state_copy               storm_lodepng_state_copy
#define lodepng_decode                   storm_lodepng_decode
#define lodepng_inspect                  storm_lodepng_inspect
#define lodepng_chunk_length             storm_lodepng_chunk_length
#define lodepng_chunk_type               storm_lodepng_chunk_type
#define lodepng_chunk_type_equals        storm_lodepng_chunk_type_equals
#define lodepng_chunk_ancillary          storm_lodepng_chunk_ancillary
#define lodepng_chunk_private            storm_lodepng_chunk_private
#define lodepng_chunk_safetocopy         storm_lodepng_chunk_safetocopy
#define lodepng_chunk_data               storm_lodepng_chunk_data
#define lodepng_chunk_data_const         storm_lodepng_chunk_data_const
#define lodepng_chunk_check_crc          storm_lodepng_chunk_check_crc
#define lodepng_chunk_generate_crc       storm_lodepng_chunk_generate_crc
#define lodepng_chunk_next               storm_lodepng_chunk_next
#define lodepng_chunk_next_const         storm_lodepng_chunk_next_const
#define lodepng_chunk_append             storm_lodepng_chunk_append
#define lodepng_chunk_create             storm_lodepng_chunk_create
#define lodepng_crc32                    storm_lodepng_crc32
#define lodepng_inflate                  storm_lodepng_inflate
#define lodepng_zlib_decompress          storm_lodepng_zlib_decompress
#define lodepng_zlib_compress            storm_lodepng_zlib_compress
#define lodepng_huffman_code_lengths     storm_lodepng_huffman_code_lengths
#define lodepng_deflate                  storm_lodepng_deflate
#define lodepng_read32bitInt             storm_lodepng_read32bitInt

#include <lodepng.cpp>

namespace storm {

Texture::Pointer parsePng(
    BinaryInputStream &stream, const Texture::LoadingParameters &parameters )
{
    const std::vector<char> buffer(
        std::istreambuf_iterator<char> {*stream},
        std::istreambuf_iterator<char> {} );

    uint8_t *texels = nullptr;
    unsigned width = 0;
    unsigned height = 0;

    if( const unsigned error = lodepng_decode32(
            &texels,
            &width,
            &height,
            reinterpret_cast<const uint8_t*>(buffer.data()),
            buffer.size()) ) {
        if( texels ) {
            lodepng_free( texels );
        }

        throw ResourceLoadingError() <<
            "Couldn't read a PNG texture: " << lodepng_error_text( error );
    }

    Texture::Separate2dDescription description;
    if( parameters.defaultColorSpace == Texture::ColorSpace::sRGB )
        description.format = Texture::Format::SrgbaNormUint8;
    else
        description.format = Texture::Format::RgbaNormUint8;
    description.width = width;
    description.height = height;
    description.mipLevels = 1;
    description.resourceType = ResourceType::Static;

    Texture::Pointer texture = Texture::create( description );

    Texture::Separate2dRegion region;
    region.mipLevel = 0;
    region.x = 0;
    region.y = 0;
    region.width = width;
    region.height = height;

    texture->setTexels( region, texels );

    lodepng_free( texels );

    return texture;
}

}
<|endoftext|>


<commit_before>/*
	N-Queens problem:
    Find a way to place N non-attacking queens on an N×N chessboard
*/

#include <iostream>

using namespace std;

const int MaxQueens = 40;
bool board[MaxQueens][MaxQueens];

void initBoard(const int size) {
	int r, c;
	for (r = 0; r < size; r++)
		for (c = 0; c < size; c++)
			board[r][c] = false;
}

void showBoard(const int size) {
	int r, c;
	for (r = 0; r < size; r++) {
		for (c = 0; c < size; c++) {
			if (board[r][c])
				cout << 'Q';
			else
				cout << '.';
			cout << ' ';
		}
		cout << '\n';
	}
}

bool isSafe(const int row, const int col, const int size) {
	int r, c;
	// check along the column
	for (r = 0; r < size; r++)
		if (board[r][col])
			return false;

	// check along the row
	for (c = 0; c < col; c++)
		if (board[row][c])
			return false;

	// check diagonally
	for (c = col-1, r = row-1; c >= 0 && r >= 0; c--, r--)
		if (board[r][c])
			return false;
	for (c = col-1, r = row+1; c >= 0 && r < size; c--, r++)
		if (board[r][c])
			return false;

	return true;
}

bool canPlaceQueens(const int col, const int size) {
	if (col == size)
		return true;

	for (int row = 0; row < size; row++) {
		if (isSafe(row, col, size)) {
			board[row][col] = true;
			if (canPlaceQueens(col+1, size))
				return true;
			board[row][col] = false;
		}
	}

	return false;
}

int main()
{
    int N;		// number of queens to place = N, size of board = NxN
	cout << "Enter the number of queens to place (max " << MaxQueens << ") : ";
    cin >> N;

    initBoard(N);

	if (canPlaceQueens(0, N)) {
		cout << "Found a way!\n";
		showBoard(N);
	}
	else
		cout << "Couldn\'t find a way to place " << N << " queens on a " << N << "x" << N << " board\n";

    return 0;
}
<commit_msg>Modified N-Queens<commit_after>/*
	N-Queens problem:
	Find a way to place N non-attacking queens on an N×N chessboard
*/

#include <iostream>

using namespace std;

const int MaxQueens = 40;
bool board[MaxQueens][MaxQueens];

void initBoard(const int size) {
	int r, c;
	for (r = 0; r < size; r++)
		for (c = 0; c < size; c++)
			board[r][c] = false;
}

void showBoard(const int size) {
	int r, c;
	for (r = 0; r < size; r++) {
		for (c = 0; c < size; c++) {
			if (board[r][c])
				cout << 'Q';
			else
				cout << '.';
			cout << ' ';
		}
		cout << '\n';
	}
}

bool isSafe(const int row, const int col, const int size) {
	int r, c;
	// check along the column
	for (r = 0; r < size; r++)
		if (board[r][col])
			return false;

	// check along the row
	for (c = 0; c < col; c++)
		if (board[row][c])
			return false;

	// check diagonally
	for (c = col-1, r = row-1; c >= 0 && r >= 0; c--, r--)
		if (board[r][c])
			return false;
	for (c = col-1, r = row+1; c >= 0 && r < size; c--, r++)
		if (board[r][c])
			return false;

	return true;
}

bool canPlaceQueens(const int col, const int size) {
	if (col == size)
		return true;

	for (int row = 0; row < size; row++) {
		if (isSafe(row, col, size)) {
			board[row][col] = true;
			if (canPlaceQueens(col+1, size))
				return true;
			board[row][col] = false;
		}
	}

	return false;
}

int main()
{
	int N;		// number of queens to place = N, size of board = NxN
	cout << "Enter the number of queens to place (max " << MaxQueens << ") : ";
	cin >> N;

	initBoard(N);

	if (canPlaceQueens(0, N)) {
		cout << "Found a way!\n";
		showBoard(N);
	}
	else
		cout << "Couldn\'t find a way to place " << N << " queens on a " << N << "x" << N << " board\n";

	return 0;
}
<|endoftext|>


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

#include "support/archive.h"

#include <cstring>
#include "support/utilities.h"

static const char* const magic = "!<arch>\n";

class ArchiveMemberHeader {
 public:
  uint8_t fileName[16];
  uint8_t timestamp[12];
  uint8_t UID[6];
  uint8_t GID[6];
  uint8_t accessMode[8];
  uint8_t size[10];  // Size of data only, not including padding or header
  uint8_t magic[2];

  std::string getName() const;
  // Members are not larger than 4GB
  uint32_t getSize() const;
};

std::string ArchiveMemberHeader::getName() const {
  char endChar;
  if (fileName[0] == '/') {
    // Special name (string table or reference, or symbol table)
    endChar = ' ';
  } else {
    endChar = '/';  // regular name
  }
  auto* end =
      static_cast<const uint8_t*>(memchr(fileName, endChar, sizeof(fileName)));
  if (!end) end = fileName + sizeof(fileName);
  return std::string((char*)(fileName), end - fileName);
}

uint32_t ArchiveMemberHeader::getSize() const {
  auto* end = static_cast<const char*>(memchr(size, ' ', sizeof(size)));
  std::string sizeString((const char*)size, end);
  auto sizeInt = std::stoll(sizeString, nullptr, 10);
  if (sizeInt < 0 || sizeInt >= std::numeric_limits<uint32_t>::max()) {
    wasm::Fatal() << "Malformed archive: size parsing failed\n";
  }
  return static_cast<uint32_t>(sizeInt);
}

Archive::Archive(Buffer& b, bool& error) : data(b) {
  error = false;
  if (data.size() < strlen(magic) ||
      memcmp(data.data(), magic, strlen(magic))) {
    error = true;
    return;
  }

  // We require GNU format archives. So the first member may be named "/" and it
  // points to the symbol table.  The next member may optionally be "//" and
  // point to a string table if a filename is too large to fit in the 16-char
  // name field of the header.
  child_iterator it = child_begin(false);
  if (it.hasError()) {
    error = true;
    return;
  }
  child_iterator end = child_end();
  if (it == end) return;  // Empty archive.

  const Child* c = &*it;

  auto increment = [&]() {
    ++it;
    error = it.hasError();
    if (error) return true;
    c = &*it;
    return false;
  };

  std::string name = c->getRawName();
  if (name == "/") {
    symbolTable = c->getBuffer();
    if (increment() || it == end) return;
    name = c->getRawName();
  }

  if (name == "//") {
    stringTable = c->getBuffer();
    if (increment() || it == end) return;
    setFirstRegular(*c);
    return;
  }
  if (name[0] != '/') {
    setFirstRegular(*c);
    return;
  }
  // Not a GNU archive.
  error = true;
}

Archive::Child::Child(const Archive* parent, const uint8_t* data, bool* error)
    : parent(parent), data(data) {
  if (!data) return;
  len = sizeof(ArchiveMemberHeader) + getHeader()->getSize();
  startOfFile = sizeof(ArchiveMemberHeader);
}

uint32_t Archive::Child::getSize() const { return len - startOfFile; }

Archive::SubBuffer Archive::Child::getBuffer() const {
  return {data + startOfFile, getSize()};
}

std::string Archive::Child::getRawName() const {
  return getHeader()->getName();
}

Archive::Child Archive::Child::getNext(bool& error) const {
  size_t toSkip = len;
  // Members are aligned to even byte boundaries.
  if (toSkip & 1) ++toSkip;
  const uint8_t* nextLoc = data + toSkip;
  if (nextLoc >= (uint8_t*)&*parent->data.end()) {  // End of the archive.
    return Child();
  }

  return Child(parent, nextLoc, &error);
}

std::string Archive::Child::getName() const {
  std::string name = getRawName();
  // Check if it's a special name.
  if (name[0] == '/') {
    if (name.size() == 1) {  // Linker member.
      return name;
    }
    if (name.size() == 2 && name[1] == '/') {  // String table.
      return name;
    }
    // It's a long name.
    // Get the offset.
    int offset = std::stoi(name.substr(1), nullptr, 10);

    // Verify it.
    if (offset < 0 || (unsigned)offset >= parent->stringTable.len) {
      wasm::Fatal() << "Malformed archive: name parsing failed\n";
    }

    std::string addr(parent->stringTable.data + offset,
                     parent->stringTable.data + parent->stringTable.len);

    // GNU long file names end with a "/\n".
    size_t end = addr.find('\n');
    return addr.substr(0, end - 1);
  }
  // It's a simple name.
  if (name[name.size() - 1] == '/') {
    return name.substr(0, name.size() - 1);
  }
  return name;
}

Archive::child_iterator Archive::child_begin(bool SkipInternal) const {
  if (data.size() == 0) return child_end();

  if (SkipInternal) {
    child_iterator it;
    it.child = Child(this, firstRegularData, &it.error);
    return it;
  }

  auto* loc = (const uint8_t*)data.data() + strlen(magic);
  child_iterator it;
  it.child = Child(this, loc, &it.error);
  return it;
}

Archive::child_iterator Archive::child_end() const { return Child(); }

namespace {
struct Symbol {
  uint32_t symbolIndex;
  uint32_t stringIndex;
  void next(Archive::SubBuffer& symbolTable) {
    // Symbol table entries are NUL-terminated. Skip past the next NUL.
    stringIndex = strchr((char*)symbolTable.data + stringIndex, '\0') -
                  (char*)symbolTable.data + 1;
    ++symbolIndex;
  }
};
}

static uint32_t read32be(const uint8_t* buf) {
  return static_cast<uint32_t>(buf[0]) << 24 |
         static_cast<uint32_t>(buf[1]) << 16 |
         static_cast<uint32_t>(buf[2]) << 8 | static_cast<uint32_t>(buf[3]);
}

void Archive::dump() const {
  printf("Archive data %p len %lu, firstRegularData %p\n", data.data(),
         data.size(), firstRegularData);
  printf("Symbol table %p, len %u\n", symbolTable.data, symbolTable.len);
  printf("string table %p, len %u\n", stringTable.data, stringTable.len);
  const uint8_t* buf = symbolTable.data;
  if (!buf) {
    for (auto c = child_begin(), e = child_end(); c != e; ++c) {
      printf("Child %p, len %u, name %s, size %u\n", c->data, c->len,
             c->getName().c_str(), c->getSize());
    }
    return;
  }
  uint32_t symbolCount = read32be(buf);
  printf("Symbol count %u\n", symbolCount);
  buf += sizeof(uint32_t) + (symbolCount * sizeof(uint32_t));
  uint32_t string_start_offset = buf - symbolTable.data;
  Symbol sym = {0, string_start_offset};
  while (sym.symbolIndex != symbolCount) {
    printf("Symbol %u, offset %u\n", sym.symbolIndex, sym.stringIndex);
    // get the member
    uint32_t offset = read32be(symbolTable.data + sym.symbolIndex * 4);
    auto* loc = (const uint8_t*)&data[offset];
    child_iterator it;
    it.child = Child(this, loc, &it.error);
    printf("Child %p, len %u\n", it.child.data, it.child.len);
  }
}
<commit_msg>fix archive.cpp on 32-bit<commit_after>/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "support/archive.h"

#include <cstring>
#include "support/utilities.h"

static const char* const magic = "!<arch>\n";

class ArchiveMemberHeader {
 public:
  uint8_t fileName[16];
  uint8_t timestamp[12];
  uint8_t UID[6];
  uint8_t GID[6];
  uint8_t accessMode[8];
  uint8_t size[10];  // Size of data only, not including padding or header
  uint8_t magic[2];

  std::string getName() const;
  // Members are not larger than 4GB
  uint32_t getSize() const;
};

std::string ArchiveMemberHeader::getName() const {
  char endChar;
  if (fileName[0] == '/') {
    // Special name (string table or reference, or symbol table)
    endChar = ' ';
  } else {
    endChar = '/';  // regular name
  }
  auto* end =
      static_cast<const uint8_t*>(memchr(fileName, endChar, sizeof(fileName)));
  if (!end) end = fileName + sizeof(fileName);
  return std::string((char*)(fileName), end - fileName);
}

uint32_t ArchiveMemberHeader::getSize() const {
  auto* end = static_cast<const char*>(memchr(size, ' ', sizeof(size)));
  std::string sizeString((const char*)size, end);
  auto sizeInt = std::stoll(sizeString, nullptr, 10);
  if (sizeInt < 0 || sizeInt >= std::numeric_limits<uint32_t>::max()) {
    wasm::Fatal() << "Malformed archive: size parsing failed\n";
  }
  return static_cast<uint32_t>(sizeInt);
}

Archive::Archive(Buffer& b, bool& error) : data(b) {
  error = false;
  if (data.size() < strlen(magic) ||
      memcmp(data.data(), magic, strlen(magic))) {
    error = true;
    return;
  }

  // We require GNU format archives. So the first member may be named "/" and it
  // points to the symbol table.  The next member may optionally be "//" and
  // point to a string table if a filename is too large to fit in the 16-char
  // name field of the header.
  child_iterator it = child_begin(false);
  if (it.hasError()) {
    error = true;
    return;
  }
  child_iterator end = child_end();
  if (it == end) return;  // Empty archive.

  const Child* c = &*it;

  auto increment = [&]() {
    ++it;
    error = it.hasError();
    if (error) return true;
    c = &*it;
    return false;
  };

  std::string name = c->getRawName();
  if (name == "/") {
    symbolTable = c->getBuffer();
    if (increment() || it == end) return;
    name = c->getRawName();
  }

  if (name == "//") {
    stringTable = c->getBuffer();
    if (increment() || it == end) return;
    setFirstRegular(*c);
    return;
  }
  if (name[0] != '/') {
    setFirstRegular(*c);
    return;
  }
  // Not a GNU archive.
  error = true;
}

Archive::Child::Child(const Archive* parent, const uint8_t* data, bool* error)
    : parent(parent), data(data) {
  if (!data) return;
  len = sizeof(ArchiveMemberHeader) + getHeader()->getSize();
  startOfFile = sizeof(ArchiveMemberHeader);
}

uint32_t Archive::Child::getSize() const { return len - startOfFile; }

Archive::SubBuffer Archive::Child::getBuffer() const {
  return {data + startOfFile, getSize()};
}

std::string Archive::Child::getRawName() const {
  return getHeader()->getName();
}

Archive::Child Archive::Child::getNext(bool& error) const {
  size_t toSkip = len;
  // Members are aligned to even byte boundaries.
  if (toSkip & 1) ++toSkip;
  const uint8_t* nextLoc = data + toSkip;
  if (nextLoc >= (uint8_t*)&*parent->data.end()) {  // End of the archive.
    return Child();
  }

  return Child(parent, nextLoc, &error);
}

std::string Archive::Child::getName() const {
  std::string name = getRawName();
  // Check if it's a special name.
  if (name[0] == '/') {
    if (name.size() == 1) {  // Linker member.
      return name;
    }
    if (name.size() == 2 && name[1] == '/') {  // String table.
      return name;
    }
    // It's a long name.
    // Get the offset.
    int offset = std::stoi(name.substr(1), nullptr, 10);

    // Verify it.
    if (offset < 0 || (unsigned)offset >= parent->stringTable.len) {
      wasm::Fatal() << "Malformed archive: name parsing failed\n";
    }

    std::string addr(parent->stringTable.data + offset,
                     parent->stringTable.data + parent->stringTable.len);

    // GNU long file names end with a "/\n".
    size_t end = addr.find('\n');
    return addr.substr(0, end - 1);
  }
  // It's a simple name.
  if (name[name.size() - 1] == '/') {
    return name.substr(0, name.size() - 1);
  }
  return name;
}

Archive::child_iterator Archive::child_begin(bool SkipInternal) const {
  if (data.size() == 0) return child_end();

  if (SkipInternal) {
    child_iterator it;
    it.child = Child(this, firstRegularData, &it.error);
    return it;
  }

  auto* loc = (const uint8_t*)data.data() + strlen(magic);
  child_iterator it;
  it.child = Child(this, loc, &it.error);
  return it;
}

Archive::child_iterator Archive::child_end() const { return Child(); }

namespace {
struct Symbol {
  uint32_t symbolIndex;
  uint32_t stringIndex;
  void next(Archive::SubBuffer& symbolTable) {
    // Symbol table entries are NUL-terminated. Skip past the next NUL.
    stringIndex = strchr((char*)symbolTable.data + stringIndex, '\0') -
                  (char*)symbolTable.data + 1;
    ++symbolIndex;
  }
};
}

static uint32_t read32be(const uint8_t* buf) {
  return static_cast<uint32_t>(buf[0]) << 24 |
         static_cast<uint32_t>(buf[1]) << 16 |
         static_cast<uint32_t>(buf[2]) << 8 | static_cast<uint32_t>(buf[3]);
}

void Archive::dump() const {
  printf("Archive data %p len %lu, firstRegularData %p\n", data.data(),
         (long unsigned)data.size(), firstRegularData);
  printf("Symbol table %p, len %u\n", symbolTable.data, symbolTable.len);
  printf("string table %p, len %u\n", stringTable.data, stringTable.len);
  const uint8_t* buf = symbolTable.data;
  if (!buf) {
    for (auto c = child_begin(), e = child_end(); c != e; ++c) {
      printf("Child %p, len %u, name %s, size %u\n", c->data, c->len,
             c->getName().c_str(), c->getSize());
    }
    return;
  }
  uint32_t symbolCount = read32be(buf);
  printf("Symbol count %u\n", symbolCount);
  buf += sizeof(uint32_t) + (symbolCount * sizeof(uint32_t));
  uint32_t string_start_offset = buf - symbolTable.data;
  Symbol sym = {0, string_start_offset};
  while (sym.symbolIndex != symbolCount) {
    printf("Symbol %u, offset %u\n", sym.symbolIndex, sym.stringIndex);
    // get the member
    uint32_t offset = read32be(symbolTable.data + sym.symbolIndex * 4);
    auto* loc = (const uint8_t*)&data[offset];
    child_iterator it;
    it.child = Child(this, loc, &it.error);
    printf("Child %p, len %u\n", it.child.data, it.child.len);
  }
}
<|endoftext|>


<commit_before>// Time:  O(n * logk) ~ O(n * k)
// Space: O(n + k)

// Heap solution. (308ms)
class Solution {
public:
    /**
     * @param n a positive integer
     * @param primes the given prime list
     * @return the nth super ugly number
     */
    int nthSuperUglyNumber(int n, vector<int>& primes) {
        priority_queue<pair<int, int>,
                       vector<pair<int, int>>,
                       greater<pair<int, int>>> heap;
        vector<int> uglies(n), idx(primes.size()), ugly_by_last_prime(n);
        uglies[0] = 1;

        for (int i = 0; i < primes.size(); ++i) {
            heap.push({primes[i], i});
        }
        for (int i = 1; i < n; ++i) {
            int k;
            tie(uglies[i], k) = heap.top();
            heap.pop();
            ugly_by_last_prime[i] = k;
            while (ugly_by_last_prime[++idx[k]] > k);  // worst time: O(k)
            heap.push({uglies[idx[k]] * primes[k], k});
        }
        return uglies[n - 1];
    }
};
<commit_msg>Update super-ugly-number.cpp<commit_after>// Time:  O(n * logk) ~ O(n * k)
// Space: O(n + k)

// Heap solution. (308ms)
class Solution {
public:
    /**
     * @param n a positive integer
     * @param primes the given prime list
     * @return the nth super ugly number
     */
    int nthSuperUglyNumber(int n, vector<int>& primes) {
        priority_queue<pair<int, int>,
                       vector<pair<int, int>>,
                       greater<pair<int, int>>> heap;
        vector<int> uglies(n), idx(primes.size()), ugly_by_last_prime(n);
        uglies[0] = 1;

        for (int i = 0; i < primes.size(); ++i) {
            heap.emplace(primes[i], i);
        }
        for (int i = 1; i < n; ++i) {
            int k;
            tie(uglies[i], k) = heap.top();
            heap.pop();
            ugly_by_last_prime[i] = k;
            while (ugly_by_last_prime[++idx[k]] > k);  // worst time: O(k)
            heap.emplace(uglies[idx[k]] * primes[k], k);
        }
        return uglies[n - 1];
    }
};
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "$Id$"
/*
COPYING CONDITIONS NOTICE:

  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation, and provided that the
  following conditions are met:

      * Redistributions of source code must retain this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below).

      * Redistributions in binary form must reproduce this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below) in the documentation and/or other materials
        provided with the distribution.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  02110-1301, USA.

COPYRIGHT NOTICE:

  TokuDB, Tokutek Fractal Tree Indexing Library.
  Copyright (C) 2007-2013 Tokutek, Inc.

DISCLAIMER:

  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.

UNIVERSITY PATENT NOTICE:

  The technology is licensed by the Massachusetts Institute of
  Technology, Rutgers State University of New Jersey, and the Research
  Foundation of State University of New York at Stony Brook under
  United States of America Serial No. 11/760379 and to the patents
  and/or patent applications resulting from it.

PATENT MARKING NOTICE:

  This software is covered by US Patent No. 8,185,551.
  This software is covered by US Patent No. 8,489,638.

PATENT RIGHTS GRANT:

  "THIS IMPLEMENTATION" means the copyrightable works distributed by
  Tokutek as part of the Fractal Tree project.

  "PATENT CLAIMS" means the claims of patents that are owned or
  licensable by Tokutek, both currently or in the future; and that in
  the absence of this license would be infringed by THIS
  IMPLEMENTATION or by using or running THIS IMPLEMENTATION.

  "PATENT CHALLENGE" shall mean a challenge to the validity,
  patentability, enforceability and/or non-infringement of any of the
  PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.

  Tokutek hereby grants to you, for the term and geographical scope of
  the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
  irrevocable (except as stated in this section) patent license to
  make, have made, use, offer to sell, sell, import, transfer, and
  otherwise run, modify, and propagate the contents of THIS
  IMPLEMENTATION, where such license applies only to the PATENT
  CLAIMS.  This grant does not include claims that would be infringed
  only as a consequence of further modifications of THIS
  IMPLEMENTATION.  If you or your agent or licensee institute or order
  or agree to the institution of patent litigation against any entity
  (including a cross-claim or counterclaim in a lawsuit) alleging that
  THIS IMPLEMENTATION constitutes direct or contributory patent
  infringement, or inducement of patent infringement, then any rights
  granted to you under this License shall terminate as of the date
  such litigation is filed.  If you or your agent or exclusive
  licensee institute or order or agree to the institution of a PATENT
  CHALLENGE, then Tokutek may terminate any rights granted to you
  under this License.
*/

#ident "Copyright (c) 2007-2013 Tokutek Inc.  All rights reserved."
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
/**
 * Test that various queries behave correctly
 *
 * Zardosht says:
 *
 * write a test that inserts a bunch of elements into the tree,
 * and then verify that the following types of queries work:
 * - db->get
 * - next
 * - prev
 * - set_range
 * - set_range_reverse
 * - first
 * - last
 * - current
 *
 * do it on a table with:
 * - just a leaf node
 * - has internal nodes (make node size 4K and bn size 1K)
 * - big cachetable such that everything fits
 * - small cachetable such that not a lot fits
 *
 * make sure APIs are the callback APIs (getf_XXX)
 * make sure your callbacks all return TOKUDB_CURSOR_CONTINUE,
 * so we ensure that returning TOKUDB_CURSOR_CONTINUE does not
 * mess anything up.
 */

#include "test.h"

/**
 * Calculate or verify that a value for a given key is correct
 * Returns 0 if the value is correct, nonzero otherwise.
 */
static void get_value_by_key(DBT * key, DBT * value)
{
    // keys/values are always stored in the DBT in net order
    int * CAST_FROM_VOIDP(k, key->data);
    int v = toku_ntohl(*k) * 2 + 1;
    memcpy(value->data, &v, sizeof(int));
}

static void init_env(DB_ENV ** env, size_t ct_size)
{
    int r;
    const int envflags = DB_INIT_MPOOL | DB_CREATE | DB_THREAD |
        DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN | DB_PRIVATE;

    printf("initializing environment\n");

    toku_os_recursive_delete(TOKU_TEST_FILENAME);
    r = toku_os_mkdir(TOKU_TEST_FILENAME, 0755); { int chk_r = r; CKERR(chk_r); }

    r = db_env_create(env, 0); { int chk_r = r; CKERR(chk_r); }
    assert(ct_size < 1024 * 1024 * 1024L);
    r = (*env)->set_cachesize(*env, 0, ct_size, 1); { int chk_r = r; CKERR(chk_r); }
    r = (*env)->open(*env, TOKU_TEST_FILENAME, envflags, 0755); { int chk_r = r; CKERR(chk_r); }
}

static void init_db(DB_ENV * env, DB ** db)
{
    int r;
    const int node_size = 4096;
    const int bn_size = 1024;

    printf("initializing db\n");

    DB_TXN * txn;
    r = db_create(db, env, 0); { int chk_r = r; CKERR(chk_r); }
    r = (*db)->set_readpagesize(*db, bn_size); { int chk_r = r; CKERR(chk_r); }
    r = (*db)->set_pagesize(*db, node_size); { int chk_r = r; CKERR(chk_r); }
    r = env->txn_begin(env, nullptr, &txn, 0); { int chk_r = r; CKERR(chk_r); }
    r = (*db)->open(*db, txn, "db", nullptr, DB_BTREE, DB_CREATE, 0644); { int chk_r = r; CKERR(chk_r); }
    r = txn->commit(txn, 0); { int chk_r = r; CKERR(chk_r); }
}

static void cleanup_env_and_db(DB_ENV * env, DB * db)
{
    int r;

    printf("cleaning up environment and db\n");
    r = db->close(db, 0); { int chk_r = r; CKERR(chk_r); }
    r = env->close(env, 0); { int chk_r = r; CKERR(chk_r); }
}

static int get_last_key_cb(const DBT *key, const DBT *value, void *extra) {
    if (key->data) {
        invariant(value == NULL);
        int expected_key = *(int*)extra;
        int found_key = *(int*)key->data;
        invariant(expected_key == (int)ntohl(found_key));
    }
    return 0;
}

static void check_dbt_matches(DB *db, int expect_r, int key) {
    int r = db->get_last_key(db, get_last_key_cb, &key);
    CKERR2(r, expect_r);
}

static void check_last_key_matches(DB *db, int expect_r, int key) {
    check_dbt_matches(db, expect_r, key);
    check_dbt_matches(db, expect_r, key);
    check_dbt_matches(db, expect_r, key);
}

static void do_test(size_t ct_size, int num_keys)
{
    int i, r;
    DB * db;
    DB_ENV * env;
    DB_TXN *txn = nullptr;
    DB_TXN *txn2 = nullptr;
    uint64_t loops_run = 0;
    (void)txn2;

    printf("doing tests for ct_size %lu, num_keys %d\n",
            ct_size, num_keys);

    // initialize everything and insert data
    init_env(&env, ct_size);
    assert(env != nullptr);
    init_db(env, &db);
    assert(db != nullptr);

    r = env->txn_begin(env, nullptr, &txn, 0);
    CKERR(r);
    DBT key, value;
    for (i = 0; i < num_keys; i++) {
        int v, k = toku_htonl(i);
        dbt_init(&key, &k, sizeof(int));
        dbt_init(&value, &v, sizeof(int));
        get_value_by_key(&key, &value);
        r = db->put(db, txn, &key, &value, 0);
        CKERR(r);
    }
    CKERR(r);

    int expect_r = num_keys == 0 ? DB_NOTFOUND : 0;
    check_last_key_matches(db, expect_r, num_keys - 1);

    r = txn->commit(txn, 0);
    check_last_key_matches(db, expect_r, num_keys - 1);

    if (num_keys == 0) {
        goto cleanup;
    }
//    r = env->txn_begin(env, nullptr, &txn2, 0);
//    CKERR(r);
    r = env->txn_begin(env, nullptr, &txn, 0);
    CKERR(r);

    r = db->del(db, txn, &key, 0);
    check_last_key_matches(db, 0, num_keys - 1);

    r = txn->commit(txn, 0);
    check_last_key_matches(db, 0, num_keys - 1);

//    r = txn2->commit(txn2, 0);
    check_last_key_matches(db, 0, num_keys - 1);

    //Run Garbage collection (NOTE does not work when everything fits in root??? WHY)
    r = db->hot_optimize(db, nullptr, nullptr, nullptr, nullptr, &loops_run);
    CKERR(r);

    r = env->txn_checkpoint(env, 0, 0, 0);
    CKERR(r);

    //Run Garbage collection (NOTE does not work when everything fits in root??? WHY)
    r = db->hot_optimize(db, nullptr, nullptr, nullptr, nullptr, &loops_run);
    CKERR(r);

    r = env->txn_checkpoint(env, 0, 0, 0);
    CKERR(r);
    //NOTE: tried overkill (double optimize, double checkpoint.. gc still doesn't happen for everything in root in single basement

    if (num_keys < 128) {
        //TODO: HACK Fix this hack.
        // Fits in root (in one basement).. no garbage collection so original still found
        check_last_key_matches(db, 0, num_keys - 1);
    } else {
        if (num_keys >= 2) {
            check_last_key_matches(db, 0, num_keys - 2);
        } else {
            //Useless case until/unless I can get garbage collection in root working
            check_last_key_matches(db, DB_NOTFOUND, num_keys - 1);
        }
    }
cleanup:
    cleanup_env_and_db(env, db);
}

int test_main(int argc, char * const argv[])
{
    default_parse_args(argc, argv);

    for (int i = 0; i <= 2; i++) {
        do_test(1024*1024, i);
    }
    for (int i = 4; i <= 1024; i*=i) {
        do_test(1024*1024, i);
    }

    return 0;
}

<commit_msg>refs Tokutek/mongo#886 Clean up test (don't repeat test 3 times), run several more cases<commit_after>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "$Id$"
/*
COPYING CONDITIONS NOTICE:

  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation, and provided that the
  following conditions are met:

      * Redistributions of source code must retain this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below).

      * Redistributions in binary form must reproduce this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below) in the documentation and/or other materials
        provided with the distribution.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  02110-1301, USA.

COPYRIGHT NOTICE:

  TokuDB, Tokutek Fractal Tree Indexing Library.
  Copyright (C) 2007-2013 Tokutek, Inc.

DISCLAIMER:

  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.

UNIVERSITY PATENT NOTICE:

  The technology is licensed by the Massachusetts Institute of
  Technology, Rutgers State University of New Jersey, and the Research
  Foundation of State University of New York at Stony Brook under
  United States of America Serial No. 11/760379 and to the patents
  and/or patent applications resulting from it.

PATENT MARKING NOTICE:

  This software is covered by US Patent No. 8,185,551.
  This software is covered by US Patent No. 8,489,638.

PATENT RIGHTS GRANT:

  "THIS IMPLEMENTATION" means the copyrightable works distributed by
  Tokutek as part of the Fractal Tree project.

  "PATENT CLAIMS" means the claims of patents that are owned or
  licensable by Tokutek, both currently or in the future; and that in
  the absence of this license would be infringed by THIS
  IMPLEMENTATION or by using or running THIS IMPLEMENTATION.

  "PATENT CHALLENGE" shall mean a challenge to the validity,
  patentability, enforceability and/or non-infringement of any of the
  PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.

  Tokutek hereby grants to you, for the term and geographical scope of
  the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
  irrevocable (except as stated in this section) patent license to
  make, have made, use, offer to sell, sell, import, transfer, and
  otherwise run, modify, and propagate the contents of THIS
  IMPLEMENTATION, where such license applies only to the PATENT
  CLAIMS.  This grant does not include claims that would be infringed
  only as a consequence of further modifications of THIS
  IMPLEMENTATION.  If you or your agent or licensee institute or order
  or agree to the institution of patent litigation against any entity
  (including a cross-claim or counterclaim in a lawsuit) alleging that
  THIS IMPLEMENTATION constitutes direct or contributory patent
  infringement, or inducement of patent infringement, then any rights
  granted to you under this License shall terminate as of the date
  such litigation is filed.  If you or your agent or exclusive
  licensee institute or order or agree to the institution of a PATENT
  CHALLENGE, then Tokutek may terminate any rights granted to you
  under this License.
*/

#ident "Copyright (c) 2007-2013 Tokutek Inc.  All rights reserved."
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
/**
 * Test that various queries behave correctly
 *
 * Zardosht says:
 *
 * write a test that inserts a bunch of elements into the tree,
 * and then verify that the following types of queries work:
 * - db->get
 * - next
 * - prev
 * - set_range
 * - set_range_reverse
 * - first
 * - last
 * - current
 *
 * do it on a table with:
 * - just a leaf node
 * - has internal nodes (make node size 4K and bn size 1K)
 * - big cachetable such that everything fits
 * - small cachetable such that not a lot fits
 *
 * make sure APIs are the callback APIs (getf_XXX)
 * make sure your callbacks all return TOKUDB_CURSOR_CONTINUE,
 * so we ensure that returning TOKUDB_CURSOR_CONTINUE does not
 * mess anything up.
 */

#include "test.h"

/**
 * Calculate or verify that a value for a given key is correct
 * Returns 0 if the value is correct, nonzero otherwise.
 */
static void get_value_by_key(DBT * key, DBT * value)
{
    // keys/values are always stored in the DBT in net order
    int * CAST_FROM_VOIDP(k, key->data);
    int v = toku_ntohl(*k) * 2 + 1;
    memcpy(value->data, &v, sizeof(int));
}

static void init_env(DB_ENV ** env, size_t ct_size)
{
    int r;
    const int envflags = DB_INIT_MPOOL | DB_CREATE | DB_THREAD |
        DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN | DB_PRIVATE;

    printf("initializing environment\n");

    toku_os_recursive_delete(TOKU_TEST_FILENAME);
    r = toku_os_mkdir(TOKU_TEST_FILENAME, 0755); { int chk_r = r; CKERR(chk_r); }

    r = db_env_create(env, 0); { int chk_r = r; CKERR(chk_r); }
    assert(ct_size < 1024 * 1024 * 1024L);
    r = (*env)->set_cachesize(*env, 0, ct_size, 1); { int chk_r = r; CKERR(chk_r); }
    r = (*env)->open(*env, TOKU_TEST_FILENAME, envflags, 0755); { int chk_r = r; CKERR(chk_r); }
}

static void init_db(DB_ENV * env, DB ** db)
{
    int r;
    const int node_size = 4096;
    const int bn_size = 1024;

    printf("initializing db\n");

    DB_TXN * txn;
    r = db_create(db, env, 0); { int chk_r = r; CKERR(chk_r); }
    r = (*db)->set_readpagesize(*db, bn_size); { int chk_r = r; CKERR(chk_r); }
    r = (*db)->set_pagesize(*db, node_size); { int chk_r = r; CKERR(chk_r); }
    r = env->txn_begin(env, nullptr, &txn, 0); { int chk_r = r; CKERR(chk_r); }
    r = (*db)->open(*db, txn, "db", nullptr, DB_BTREE, DB_CREATE, 0644); { int chk_r = r; CKERR(chk_r); }
    r = txn->commit(txn, 0); { int chk_r = r; CKERR(chk_r); }
}

static void cleanup_env_and_db(DB_ENV * env, DB * db)
{
    int r;

    printf("cleaning up environment and db\n");
    r = db->close(db, 0); { int chk_r = r; CKERR(chk_r); }
    r = env->close(env, 0); { int chk_r = r; CKERR(chk_r); }
}

static int get_last_key_cb(const DBT *key, const DBT *value, void *extra) {
    if (key->data) {
        invariant_null(value);
        int expected_key = *(int*)extra;
        int found_key = *(int*)key->data;
        invariant(expected_key == (int)ntohl(found_key));
    }
    return 0;
}

static void check_last_key_matches(DB *db, int expect_r, int key) {
    int r = db->get_last_key(db, get_last_key_cb, &key);
    CKERR2(r, expect_r);
}

static void do_test(size_t ct_size, int num_keys)
{
    int i, r;
    DB * db;
    DB_ENV * env;
    DB_TXN *txn = nullptr;
    DB_TXN *txn2 = nullptr;
    uint64_t loops_run = 0;
    (void)txn2;

    printf("doing tests for ct_size %lu, num_keys %d\n",
            ct_size, num_keys);

    // initialize everything and insert data
    init_env(&env, ct_size);
    assert(env != nullptr);
    init_db(env, &db);
    assert(db != nullptr);

    r = env->txn_begin(env, nullptr, &txn, 0);
    CKERR(r);
    DBT key, value;
    for (i = 0; i < num_keys; i++) {
        int v, k = toku_htonl(i);
        dbt_init(&key, &k, sizeof(int));
        dbt_init(&value, &v, sizeof(int));
        get_value_by_key(&key, &value);
        r = db->put(db, txn, &key, &value, 0);
        CKERR(r);
    }
    CKERR(r);

    int expect_r = num_keys == 0 ? DB_NOTFOUND : 0;
    check_last_key_matches(db, expect_r, num_keys - 1);

    r = txn->commit(txn, 0);
    check_last_key_matches(db, expect_r, num_keys - 1);

    if (num_keys == 0) {
        goto cleanup;
    }
//    r = env->txn_begin(env, nullptr, &txn2, 0);
//    CKERR(r);
    r = env->txn_begin(env, nullptr, &txn, 0);
    CKERR(r);

    r = db->del(db, txn, &key, 0);
    check_last_key_matches(db, 0, num_keys - 1);

    r = txn->commit(txn, 0);
    check_last_key_matches(db, 0, num_keys - 1);

//    r = txn2->commit(txn2, 0);
    check_last_key_matches(db, 0, num_keys - 1);

    //Run Garbage collection (NOTE does not work when everything fits in root??? WHY)
    r = db->hot_optimize(db, nullptr, nullptr, nullptr, nullptr, &loops_run);
    CKERR(r);

    r = env->txn_checkpoint(env, 0, 0, 0);
    CKERR(r);

    //Run Garbage collection (NOTE does not work when everything fits in root??? WHY)
    r = db->hot_optimize(db, nullptr, nullptr, nullptr, nullptr, &loops_run);
    CKERR(r);

    r = env->txn_checkpoint(env, 0, 0, 0);
    CKERR(r);
    //NOTE: tried overkill (double optimize, double checkpoint.. gc still doesn't happen for everything in root in single basement

    if (num_keys < 128) {
        //TODO: HACK Fix this hack.
        // Fits in root (in one basement).. no garbage collection so original still found
        check_last_key_matches(db, 0, num_keys - 1);
    } else {
        if (num_keys >= 2) {
            check_last_key_matches(db, 0, num_keys - 2);
        } else {
            //Useless case until/unless I can get garbage collection in root working
            check_last_key_matches(db, DB_NOTFOUND, num_keys - 1);
        }
    }
cleanup:
    cleanup_env_and_db(env, db);
}

int test_main(int argc, char * const argv[])
{
    default_parse_args(argc, argv);

    for (int i = 0; i <= 2; i++) {
        do_test(1024*1024, i);
    }
    for (int i = 4; i <= 1024; i*=2) {
        do_test(1024*1024, i);
    }

    return 0;
}

<|endoftext|>


<commit_before>#ifndef AMGCL_PERF_COUNTER_MPI_AGGREGATOR_HPP
#define AMGCL_PERF_COUNTER_MPI_AGGREGATOR_HPP

/*
The MIT License

Copyright (c) 2012-2018 Denis Demidov <dennis.demidov@gmail.com>
Copyright (c) 2016 Mohammad Siahatgar <siahatgar@luis.uni-hannover.de>

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.
*/

/**
 * \file   amgcl/perf_counter/mpi_aggregator.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Aggregate performace counter over MPI.
 */

#include <cmath>
#include <boost/type_traits.hpp>
#include <boost/functional/hash.hpp>
#include <amgcl/mpi/util.hpp>

namespace amgcl {
namespace perf_counter {

template <class Counter, bool SingleReaderPerNode = true>
class mpi_aggregator {
    public:
        typedef typename Counter::value_type value_type;

        mpi_aggregator() : world(MPI_COMM_WORLD), dtype(amgcl::mpi::datatype<value_type>::get()) {
            if (SingleReaderPerNode) {
                typedef boost::integral_constant<bool, sizeof(size_t) == sizeof(int)>::type _32bit;

                char node_name[MPI_MAX_PROCESSOR_NAME];
                int node_name_len, node_master;

                MPI_Get_processor_name(node_name, &node_name_len);
                MPI_Comm_split(world, name_hash(node_name, _32bit()), world.rank, &node_comm);
                MPI_Allreduce(&world.rank, &node_master, 1, MPI_INT, MPI_MIN, node_comm);

                reader = (world.rank == node_master);
                MPI_Comm_split(world, reader, world.rank, &reader_comm);
            }
        }

        ~mpi_aggregator() {
            if (SingleReaderPerNode) {
                MPI_Comm_free(&node_comm);
                MPI_Comm_free(&reader_comm);
            }
        }

        static const char* units() {
            return Counter::units();
        }

        value_type current() {
            value_type gval;

            if (SingleReaderPerNode) {
                if (reader) {
                    value_type lval = counter.current();
                    MPI_Allreduce(&lval, &gval, 1, dtype, MPI_SUM, reader_comm);
                }

                MPI_Bcast(&gval, 1, dtype, 0, node_comm);
            } else {
                value_type lval = counter.current();
                MPI_Allreduce(&lval, &gval, 1, dtype, MPI_SUM, world);
            }

            return gval;
        }
    private:
        amgcl::mpi::communicator world;
        MPI_Datatype dtype;

        bool reader;
        MPI_Comm node_comm, reader_comm;

        Counter counter;

        int name_hash(const char *name, boost::true_type) {
            return boost::hash<std::string>()(name);
        }

        int name_hash(const char *name, boost::false_type) {
            union {
                size_t full;
                struct {
                    int lo, hi;
                };
            } h;

            h.full = boost::hash<std::string>()(name);
            return std::abs(h.lo ^ h.hi);
        }
};

} // namespace perf_counter
} // namespace amgcl

#endif
<commit_msg>Get rid of boost::hash<commit_after>#ifndef AMGCL_PERF_COUNTER_MPI_AGGREGATOR_HPP
#define AMGCL_PERF_COUNTER_MPI_AGGREGATOR_HPP

/*
The MIT License

Copyright (c) 2012-2018 Denis Demidov <dennis.demidov@gmail.com>
Copyright (c) 2016 Mohammad Siahatgar <siahatgar@luis.uni-hannover.de>

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.
*/

/**
 * \file   amgcl/perf_counter/mpi_aggregator.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Aggregate performace counter over MPI.
 */

#include <functional>
#include <cmath>
#include <boost/type_traits.hpp>
#include <amgcl/mpi/util.hpp>

namespace amgcl {
namespace perf_counter {

template <class Counter, bool SingleReaderPerNode = true>
class mpi_aggregator {
    public:
        typedef typename Counter::value_type value_type;

        mpi_aggregator() : world(MPI_COMM_WORLD), dtype(amgcl::mpi::datatype<value_type>::get()) {
            if (SingleReaderPerNode) {
                typedef boost::integral_constant<bool, sizeof(size_t) == sizeof(int)>::type _32bit;

                char node_name[MPI_MAX_PROCESSOR_NAME];
                int node_name_len, node_master;

                MPI_Get_processor_name(node_name, &node_name_len);
                MPI_Comm_split(world, name_hash(node_name, _32bit()), world.rank, &node_comm);
                MPI_Allreduce(&world.rank, &node_master, 1, MPI_INT, MPI_MIN, node_comm);

                reader = (world.rank == node_master);
                MPI_Comm_split(world, reader, world.rank, &reader_comm);
            }
        }

        ~mpi_aggregator() {
            if (SingleReaderPerNode) {
                MPI_Comm_free(&node_comm);
                MPI_Comm_free(&reader_comm);
            }
        }

        static const char* units() {
            return Counter::units();
        }

        value_type current() {
            value_type gval;

            if (SingleReaderPerNode) {
                if (reader) {
                    value_type lval = counter.current();
                    MPI_Allreduce(&lval, &gval, 1, dtype, MPI_SUM, reader_comm);
                }

                MPI_Bcast(&gval, 1, dtype, 0, node_comm);
            } else {
                value_type lval = counter.current();
                MPI_Allreduce(&lval, &gval, 1, dtype, MPI_SUM, world);
            }

            return gval;
        }
    private:
        amgcl::mpi::communicator world;
        MPI_Datatype dtype;

        bool reader;
        MPI_Comm node_comm, reader_comm;

        Counter counter;

        int name_hash(const char *name, boost::true_type) {
            return std::hash<std::string>()(name);
        }

        int name_hash(const char *name, boost::false_type) {
            union {
                size_t full;
                struct {
                    int lo, hi;
                };
            } h;

            h.full = std::hash<std::string>()(name);
            return std::abs(h.lo ^ h.hi);
        }
};

} // namespace perf_counter
} // namespace amgcl

#endif
<|endoftext|>