forked from I2P_Developers/i2p.i2p
Added some more header files, and fixed much of the build system.
This commit is contained in:
@ -48,7 +48,8 @@ lazy val macosx = (project in file("macosx"))
|
||||
lazy val root = (project in file("."))
|
||||
.aggregate(common, browserbundle, macosx)
|
||||
|
||||
scalacOptions in Compile := Seq("-deprecated")
|
||||
javacOptions ++= Seq("-source", "1.7", "-target", "1.7")
|
||||
scalacOptions in Compile := Seq("-deprecated","-target:jvm-1.7")
|
||||
|
||||
fork := true
|
||||
|
||||
|
@ -15,18 +15,14 @@ lazy val warsForCopy = new File(i2pBuildDir, "webapps").list.filter { f => f.end
|
||||
lazy val jarsForCopy = new File(i2pBuildDir, "lib").list.filter { f => f.endsWith(".jar") }
|
||||
|
||||
|
||||
// Pointing the resources directory to the "installer" directory
|
||||
resourceDirectory in Compile := baseDirectory.value / ".." / ".." / "installer" / "resources"
|
||||
|
||||
// Unmanaged base will be included in a fat jar
|
||||
unmanagedBase in Compile := baseDirectory.value / ".." / ".." / "pkg-temp" / "lib"
|
||||
|
||||
|
||||
// Unmanaged classpath will be available at compile time
|
||||
unmanagedClasspath in Compile ++= Seq(
|
||||
baseDirectory.value / ".." / ".." / "pkg-temp" / "lib" / "*.jar"
|
||||
baseDirectory.value / ".." / ".." / "pkg-temp" / "lib" / "router.jar",
|
||||
baseDirectory.value / ".." / ".." / "pkg-temp" / "lib" / "i2p.jar"
|
||||
)
|
||||
|
||||
unmanagedBase in Compile := baseDirectory.value / ".." / ".." / "pkg-temp" / "lib"
|
||||
|
||||
assemblyOption in assembly := (assemblyOption in assembly).value.copy(includeScala = false, includeDependency = false)
|
||||
|
||||
assemblyExcludedJars in assembly := {
|
||||
@ -34,76 +30,6 @@ assemblyExcludedJars in assembly := {
|
||||
cp filter { c => jarsForCopy.toList.contains(c.data.getName) }
|
||||
}
|
||||
|
||||
/*
|
||||
javacOptions ++= Seq("-source", "1.7", "-target", "1.7")
|
||||
scalacOptions in Compile := Seq("-deprecated","-target:jvm-1.7")
|
||||
|
||||
assemblyJarName in assembly := s"package.jar"
|
||||
|
||||
// TODO: MEEH: Add assemblyExcludedJars and load the router from own jar files, to handle upgrades better.
|
||||
// In fact, most likely the bundle never would need an update except for the router jars/wars.
|
||||
|
||||
convertToICNSTask := {
|
||||
println("TODO")
|
||||
}
|
||||
|
||||
cleanAllTask := {
|
||||
clean.value
|
||||
IO.delete(bundleBuildPath)
|
||||
}
|
||||
|
||||
buildDeployZipTask := {
|
||||
println(s"Starting the zip file build process. This might take a while..")
|
||||
if (!bundleBuildPath.exists()) bundleBuildPath.mkdir()
|
||||
val sourceDir = i2pBuildDir
|
||||
def recursiveListFiles(f: File): Array[File] = {
|
||||
val these = f.listFiles
|
||||
these ++ these.filter { f => f.isDirectory }.flatMap(recursiveListFiles).filter(!_.isDirectory)
|
||||
}
|
||||
def zip(out: String, files: Iterable[String]) = {
|
||||
import java.io.{ BufferedInputStream, FileInputStream, FileOutputStream }
|
||||
import java.util.zip.{ ZipEntry, ZipOutputStream }
|
||||
|
||||
val zip = new ZipOutputStream(new FileOutputStream(out))
|
||||
|
||||
files.foreach { name =>
|
||||
val fname = sourceDir.toURI.relativize(new File(name).toURI).toString
|
||||
//println(s"Zipping ${fname}")
|
||||
if (!new File(name).isDirectory) {
|
||||
zip.putNextEntry(new ZipEntry(fname))
|
||||
val in = new BufferedInputStream(new FileInputStream(name))
|
||||
var b = in.read()
|
||||
while (b > -1) {
|
||||
zip.write(b)
|
||||
b = in.read()
|
||||
}
|
||||
in.close()
|
||||
zip.closeEntry()
|
||||
}
|
||||
}
|
||||
zip.close()
|
||||
}
|
||||
val fileList = recursiveListFiles(sourceDir.getCanonicalFile).toList
|
||||
val zipFileName = new File(bundleBuildPath, "i2pbase.zip").getCanonicalPath
|
||||
zip(zipFileName, fileList.map { f => f.toString }.toIterable)
|
||||
zipFileName.toString
|
||||
}
|
||||
|
||||
buildAppBundleTask := {
|
||||
println(s"Building Mac OS X bundle for I2P version ${i2pVersion}.")
|
||||
if (!bundleBuildPath.exists()) bundleBuildPath.mkdir()
|
||||
val paths = Map[String,File](
|
||||
"execBundlePath" -> new File(bundleBuildPath, "I2P.app/Contents/MacOS"),
|
||||
"resBundlePath" -> new File(bundleBuildPath, "I2P.app/Contents/Resources")
|
||||
)
|
||||
paths.map { case (s,p) => p.mkdirs() }
|
||||
|
||||
val launcherBinary = Some(assembly.value)
|
||||
launcherBinary.map { l => IO.copyFile( new File(l.toString), new File(paths.get("execBundlePath").get, "I2P") ) }
|
||||
|
||||
val zipFilePath = Some(buildDeployZipTask.value)
|
||||
|
||||
val zipFileOrigin = new File(zipFilePath.get)
|
||||
IO.copyFile(zipFileOrigin, new File(paths.get("resBundlePath").get, "i2pbase.zip"))
|
||||
println(s"Zip placed into bundle :)")
|
||||
|
||||
}
|
||||
*/
|
||||
|
63
launchers/macosx/obj-cpp/PidWatcher.h
Normal file
63
launchers/macosx/obj-cpp/PidWatcher.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/event.h>
|
||||
#include <functional>
|
||||
|
||||
#include "neither/either.hpp"
|
||||
#include "AppDelegate.h"
|
||||
|
||||
using callbackType = void (CFFileDescriptorRef, CFOptionFlags, void *);
|
||||
using HandleFunction = std::function<void(int)>;
|
||||
/*
|
||||
class CallbackWrapper
|
||||
{
|
||||
CallbackWrapper(HandleFunction func) : mCallback(func);
|
||||
void operator(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) {
|
||||
struct kevent kev;
|
||||
int fd = CFFileDescriptorGetNativeDescriptor(fdref);
|
||||
kevent(fd, NULL, 0, &kev, 1, NULL);
|
||||
// take action on death of process here
|
||||
NSLog(@"process with pid '%u' died\n", (unsigned int)kev.ident);
|
||||
|
||||
mCallback(0);
|
||||
CFFileDescriptorInvalidate(fdref);
|
||||
CFRelease(fdref);
|
||||
}
|
||||
|
||||
private:
|
||||
HandleFunction mCallback;
|
||||
};
|
||||
*/
|
||||
|
||||
static void noteProcDeath(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) {
|
||||
struct kevent kev;
|
||||
int fd = CFFileDescriptorGetNativeDescriptor(fdref);
|
||||
kevent(fd, NULL, 0, &kev, 1, NULL);
|
||||
// take action on death of process here
|
||||
NSLog(@"process with pid '%u' died\n", (unsigned int)kev.ident);
|
||||
sendUserNotification(APP_IDSTR, @"The I2P router has stopped.");
|
||||
CFFileDescriptorInvalidate(fdref);
|
||||
CFRelease(fdref); // the CFFileDescriptorRef is no longer of any use in this example
|
||||
}
|
||||
// one argument, an integer pid to watch, required
|
||||
int watchPid(int pid, callbackType callback = noteProcDeath) {
|
||||
int fd = kqueue();
|
||||
struct kevent kev;
|
||||
EV_SET(&kev, pid, EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL);
|
||||
kevent(fd, &kev, 1, NULL, 0, NULL);
|
||||
CFFileDescriptorRef fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd, true, callback, NULL);
|
||||
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
|
||||
CFRunLoopSourceRef source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
|
||||
CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode);
|
||||
CFRelease(source);
|
||||
/*
|
||||
seconds
|
||||
The length of time to run the run loop. If 0, only one pass is made through the run loop before returning;
|
||||
if multiple sources or timers are ready to fire immediately, only one (possibly two if one is a version
|
||||
0 source) will be fired, regardless of the value of returnAfterSourceHandled.
|
||||
*/
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
return 0;
|
||||
}
|
@ -21,12 +21,13 @@ rule ar
|
||||
description = AR $out
|
||||
|
||||
rule cleanup
|
||||
command = rm -fr *.o clauncher I2PLauncher.app
|
||||
command = rm -fr *.o clauncher I2PLauncher.app base.zip
|
||||
|
||||
# TODO: There must exists a cleaner way to solve this.
|
||||
rule bundledir
|
||||
command = mkdir -p I2PLauncher.app/Contents/{MacOS,Resources,Frameworks} $
|
||||
&& cp Info.plist I2PLauncher.app/Contents/Info.plist $
|
||||
&& cd ../../../pkg-temp && zip -r7 ../base.zip * && cd - && mv ../../../base.zip base.zip $
|
||||
&& cp base.zip I2PLauncher.app/Contents/Resources/base.zip $
|
||||
&& cp ../target/scala-2.11/routerLauncher-assembly-0.1.0-SNAPSHOT.jar I2PLauncher.app/Contents/Resources/launcher.jar
|
||||
|
||||
|
9
launchers/macosx/obj-cpp/fullBuild.sh
Executable file
9
launchers/macosx/obj-cpp/fullBuild.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
cd ../../..
|
||||
ant preppkg-osx-only
|
||||
cd pkg-temp
|
||||
zip -r7 $DIR/base.zip *
|
||||
echo "[+] Done building base.zip from ant's pkg-temp."
|
||||
ninja appbundle
|
||||
|
461
launchers/macosx/obj-cpp/include/any.hpp
Normal file
461
launchers/macosx/obj-cpp/include/any.hpp
Normal file
@ -0,0 +1,461 @@
|
||||
//
|
||||
// Implementation of N4562 std::experimental::any (merged into C++17) for C++11 compilers.
|
||||
//
|
||||
// See also:
|
||||
// + http://en.cppreference.com/w/cpp/any
|
||||
// + http://en.cppreference.com/w/cpp/experimental/any
|
||||
// + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any
|
||||
// + https://cplusplus.github.io/LWG/lwg-active.html#2509
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2016 Denilson das Merc<72>s Amorim
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef LINB_ANY_HPP
|
||||
#define LINB_ANY_HPP
|
||||
#pragma once
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace linb
|
||||
{
|
||||
|
||||
class bad_any_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
const char* what() const noexcept override
|
||||
{
|
||||
return "bad any cast";
|
||||
}
|
||||
};
|
||||
|
||||
class any final
|
||||
{
|
||||
public:
|
||||
/// Constructs an object of type any with an empty state.
|
||||
any() :
|
||||
vtable(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/// Constructs an object of type any with an equivalent state as other.
|
||||
any(const any& rhs) :
|
||||
vtable(rhs.vtable)
|
||||
{
|
||||
if(!rhs.empty())
|
||||
{
|
||||
rhs.vtable->copy(rhs.storage, this->storage);
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs an object of type any with a state equivalent to the original state of other.
|
||||
/// rhs is left in a valid but otherwise unspecified state.
|
||||
any(any&& rhs) noexcept :
|
||||
vtable(rhs.vtable)
|
||||
{
|
||||
if(!rhs.empty())
|
||||
{
|
||||
rhs.vtable->move(rhs.storage, this->storage);
|
||||
rhs.vtable = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// Same effect as this->clear().
|
||||
~any()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
/// Constructs an object of type any that contains an object of type T direct-initialized with std::forward<ValueType>(value).
|
||||
///
|
||||
/// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed.
|
||||
/// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed.
|
||||
template<typename ValueType, typename = typename std::enable_if<!std::is_same<typename std::decay<ValueType>::type, any>::value>::type>
|
||||
any(ValueType&& value)
|
||||
{
|
||||
static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
|
||||
"T shall satisfy the CopyConstructible requirements.");
|
||||
this->construct(std::forward<ValueType>(value));
|
||||
}
|
||||
|
||||
/// Has the same effect as any(rhs).swap(*this). No effects if an exception is thrown.
|
||||
any& operator=(const any& rhs)
|
||||
{
|
||||
any(rhs).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Has the same effect as any(std::move(rhs)).swap(*this).
|
||||
///
|
||||
/// The state of *this is equivalent to the original state of rhs and rhs is left in a valid
|
||||
/// but otherwise unspecified state.
|
||||
any& operator=(any&& rhs) noexcept
|
||||
{
|
||||
any(std::move(rhs)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Has the same effect as any(std::forward<ValueType>(value)).swap(*this). No effect if a exception is thrown.
|
||||
///
|
||||
/// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed.
|
||||
/// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed.
|
||||
template<typename ValueType, typename = typename std::enable_if<!std::is_same<typename std::decay<ValueType>::type, any>::value>::type>
|
||||
any& operator=(ValueType&& value)
|
||||
{
|
||||
static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
|
||||
"T shall satisfy the CopyConstructible requirements.");
|
||||
any(std::forward<ValueType>(value)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// If not empty, destroys the contained object.
|
||||
void clear() noexcept
|
||||
{
|
||||
if(!empty())
|
||||
{
|
||||
this->vtable->destroy(storage);
|
||||
this->vtable = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if *this has no contained object, otherwise false.
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return this->vtable == nullptr;
|
||||
}
|
||||
|
||||
/// If *this has a contained object of type T, typeid(T); otherwise typeid(void).
|
||||
const std::type_info& type() const noexcept
|
||||
{
|
||||
return empty()? typeid(void) : this->vtable->type();
|
||||
}
|
||||
|
||||
/// Exchange the states of *this and rhs.
|
||||
void swap(any& rhs) noexcept
|
||||
{
|
||||
if(this->vtable != rhs.vtable)
|
||||
{
|
||||
any tmp(std::move(rhs));
|
||||
|
||||
// move from *this to rhs.
|
||||
rhs.vtable = this->vtable;
|
||||
if(this->vtable != nullptr)
|
||||
{
|
||||
this->vtable->move(this->storage, rhs.storage);
|
||||
//this->vtable = nullptr; -- uneeded, see below
|
||||
}
|
||||
|
||||
// move from tmp (previously rhs) to *this.
|
||||
this->vtable = tmp.vtable;
|
||||
if(tmp.vtable != nullptr)
|
||||
{
|
||||
tmp.vtable->move(tmp.storage, this->storage);
|
||||
tmp.vtable = nullptr;
|
||||
}
|
||||
}
|
||||
else // same types
|
||||
{
|
||||
if(this->vtable != nullptr)
|
||||
this->vtable->swap(this->storage, rhs.storage);
|
||||
}
|
||||
}
|
||||
|
||||
private: // Storage and Virtual Method Table
|
||||
|
||||
union storage_union
|
||||
{
|
||||
using stack_storage_t = typename std::aligned_storage<2 * sizeof(void*), std::alignment_of<void*>::value>::type;
|
||||
|
||||
void* dynamic;
|
||||
stack_storage_t stack; // 2 words for e.g. shared_ptr
|
||||
};
|
||||
|
||||
/// Base VTable specification.
|
||||
struct vtable_type
|
||||
{
|
||||
// Note: The caller is responssible for doing .vtable = nullptr after destructful operations
|
||||
// such as destroy() and/or move().
|
||||
|
||||
/// The type of the object this vtable is for.
|
||||
const std::type_info& (*type)() noexcept;
|
||||
|
||||
/// Destroys the object in the union.
|
||||
/// The state of the union after this call is unspecified, caller must ensure not to use src anymore.
|
||||
void(*destroy)(storage_union&) noexcept;
|
||||
|
||||
/// Copies the **inner** content of the src union into the yet unitialized dest union.
|
||||
/// As such, both inner objects will have the same state, but on separate memory locations.
|
||||
void(*copy)(const storage_union& src, storage_union& dest);
|
||||
|
||||
/// Moves the storage from src to the yet unitialized dest union.
|
||||
/// The state of src after this call is unspecified, caller must ensure not to use src anymore.
|
||||
void(*move)(storage_union& src, storage_union& dest) noexcept;
|
||||
|
||||
/// Exchanges the storage between lhs and rhs.
|
||||
void(*swap)(storage_union& lhs, storage_union& rhs) noexcept;
|
||||
};
|
||||
|
||||
/// VTable for dynamically allocated storage.
|
||||
template<typename T>
|
||||
struct vtable_dynamic
|
||||
{
|
||||
static const std::type_info& type() noexcept
|
||||
{
|
||||
return typeid(T);
|
||||
}
|
||||
|
||||
static void destroy(storage_union& storage) noexcept
|
||||
{
|
||||
//assert(reinterpret_cast<T*>(storage.dynamic));
|
||||
delete reinterpret_cast<T*>(storage.dynamic);
|
||||
}
|
||||
|
||||
static void copy(const storage_union& src, storage_union& dest)
|
||||
{
|
||||
dest.dynamic = new T(*reinterpret_cast<const T*>(src.dynamic));
|
||||
}
|
||||
|
||||
static void move(storage_union& src, storage_union& dest) noexcept
|
||||
{
|
||||
dest.dynamic = src.dynamic;
|
||||
src.dynamic = nullptr;
|
||||
}
|
||||
|
||||
static void swap(storage_union& lhs, storage_union& rhs) noexcept
|
||||
{
|
||||
// just exchage the storage pointers.
|
||||
std::swap(lhs.dynamic, rhs.dynamic);
|
||||
}
|
||||
};
|
||||
|
||||
/// VTable for stack allocated storage.
|
||||
template<typename T>
|
||||
struct vtable_stack
|
||||
{
|
||||
static const std::type_info& type() noexcept
|
||||
{
|
||||
return typeid(T);
|
||||
}
|
||||
|
||||
static void destroy(storage_union& storage) noexcept
|
||||
{
|
||||
reinterpret_cast<T*>(&storage.stack)->~T();
|
||||
}
|
||||
|
||||
static void copy(const storage_union& src, storage_union& dest)
|
||||
{
|
||||
new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
|
||||
}
|
||||
|
||||
static void move(storage_union& src, storage_union& dest) noexcept
|
||||
{
|
||||
// one of the conditions for using vtable_stack is a nothrow move constructor,
|
||||
// so this move constructor will never throw a exception.
|
||||
new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
|
||||
destroy(src);
|
||||
}
|
||||
|
||||
static void swap(storage_union& lhs, storage_union& rhs) noexcept
|
||||
{
|
||||
storage_union tmp_storage;
|
||||
move(rhs, tmp_storage);
|
||||
move(lhs, rhs);
|
||||
move(tmp_storage, lhs);
|
||||
}
|
||||
};
|
||||
|
||||
/// Whether the type T must be dynamically allocated or can be stored on the stack.
|
||||
template<typename T>
|
||||
struct requires_allocation :
|
||||
std::integral_constant<bool,
|
||||
!(std::is_nothrow_move_constructible<T>::value // N4562 <20>6.3/3 [any.class]
|
||||
&& sizeof(T) <= sizeof(storage_union::stack)
|
||||
&& std::alignment_of<T>::value <= std::alignment_of<storage_union::stack_storage_t>::value)>
|
||||
{};
|
||||
|
||||
/// Returns the pointer to the vtable of the type T.
|
||||
template<typename T>
|
||||
static vtable_type* vtable_for_type()
|
||||
{
|
||||
using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
|
||||
static vtable_type table = {
|
||||
VTableType::type, VTableType::destroy,
|
||||
VTableType::copy, VTableType::move,
|
||||
VTableType::swap,
|
||||
};
|
||||
return &table;
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
friend const T* any_cast(const any* operand) noexcept;
|
||||
template<typename T>
|
||||
friend T* any_cast(any* operand) noexcept;
|
||||
|
||||
/// Same effect as is_same(this->type(), t);
|
||||
bool is_typed(const std::type_info& t) const
|
||||
{
|
||||
return is_same(this->type(), t);
|
||||
}
|
||||
|
||||
/// Checks if two type infos are the same.
|
||||
///
|
||||
/// If ANY_IMPL_FAST_TYPE_INFO_COMPARE is defined, checks only the address of the
|
||||
/// type infos, otherwise does an actual comparision. Checking addresses is
|
||||
/// only a valid approach when there's no interaction with outside sources
|
||||
/// (other shared libraries and such).
|
||||
static bool is_same(const std::type_info& a, const std::type_info& b)
|
||||
{
|
||||
#ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE
|
||||
return &a == &b;
|
||||
#else
|
||||
return a == b;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Casts (with no type_info checks) the storage pointer as const T*.
|
||||
template<typename T>
|
||||
const T* cast() const noexcept
|
||||
{
|
||||
return requires_allocation<typename std::decay<T>::type>::value?
|
||||
reinterpret_cast<const T*>(storage.dynamic) :
|
||||
reinterpret_cast<const T*>(&storage.stack);
|
||||
}
|
||||
|
||||
/// Casts (with no type_info checks) the storage pointer as T*.
|
||||
template<typename T>
|
||||
T* cast() noexcept
|
||||
{
|
||||
return requires_allocation<typename std::decay<T>::type>::value?
|
||||
reinterpret_cast<T*>(storage.dynamic) :
|
||||
reinterpret_cast<T*>(&storage.stack);
|
||||
}
|
||||
|
||||
private:
|
||||
storage_union storage; // on offset(0) so no padding for align
|
||||
vtable_type* vtable;
|
||||
|
||||
template<typename ValueType, typename T>
|
||||
typename std::enable_if<requires_allocation<T>::value>::type
|
||||
do_construct(ValueType&& value)
|
||||
{
|
||||
storage.dynamic = new T(std::forward<ValueType>(value));
|
||||
}
|
||||
|
||||
template<typename ValueType, typename T>
|
||||
typename std::enable_if<!requires_allocation<T>::value>::type
|
||||
do_construct(ValueType&& value)
|
||||
{
|
||||
new (&storage.stack) T(std::forward<ValueType>(value));
|
||||
}
|
||||
|
||||
/// Chooses between stack and dynamic allocation for the type decay_t<ValueType>,
|
||||
/// assigns the correct vtable, and constructs the object on our storage.
|
||||
template<typename ValueType>
|
||||
void construct(ValueType&& value)
|
||||
{
|
||||
using T = typename std::decay<ValueType>::type;
|
||||
|
||||
this->vtable = vtable_for_type<T>();
|
||||
|
||||
do_construct<ValueType,T>(std::forward<ValueType>(value));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p, std::true_type)
|
||||
{
|
||||
return std::move(*p);
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p, std::false_type)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs *any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand), or throws bad_any_cast on failure.
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast(const any& operand)
|
||||
{
|
||||
auto p = any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(&operand);
|
||||
if(p == nullptr) throw bad_any_cast();
|
||||
return *p;
|
||||
}
|
||||
|
||||
/// Performs *any_cast<remove_reference_t<ValueType>>(&operand), or throws bad_any_cast on failure.
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast(any& operand)
|
||||
{
|
||||
auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
|
||||
if(p == nullptr) throw bad_any_cast();
|
||||
return *p;
|
||||
}
|
||||
|
||||
///
|
||||
/// If ANY_IMPL_ANYCAST_MOVEABLE is not defined, does as N4562 specifies:
|
||||
/// Performs *any_cast<remove_reference_t<ValueType>>(&operand), or throws bad_any_cast on failure.
|
||||
///
|
||||
/// If ANY_IMPL_ANYCAST_MOVEABLE is defined, does as LWG Defect 2509 specifies:
|
||||
/// If ValueType is MoveConstructible and isn't a lvalue reference, performs
|
||||
/// std::move(*any_cast<remove_reference_t<ValueType>>(&operand)), otherwise
|
||||
/// *any_cast<remove_reference_t<ValueType>>(&operand). Throws bad_any_cast on failure.
|
||||
///
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast(any&& operand)
|
||||
{
|
||||
#ifdef ANY_IMPL_ANY_CAST_MOVEABLE
|
||||
// https://cplusplus.github.io/LWG/lwg-active.html#2509
|
||||
using can_move = std::integral_constant<bool,
|
||||
std::is_move_constructible<ValueType>::value
|
||||
&& !std::is_lvalue_reference<ValueType>::value>;
|
||||
#else
|
||||
using can_move = std::false_type;
|
||||
#endif
|
||||
|
||||
auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
|
||||
if(p == nullptr) throw bad_any_cast();
|
||||
return detail::any_cast_move_if_true<ValueType>(p, can_move());
|
||||
}
|
||||
|
||||
/// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object
|
||||
/// contained by operand, otherwise nullptr.
|
||||
template<typename T>
|
||||
inline const T* any_cast(const any* operand) noexcept
|
||||
{
|
||||
if(operand == nullptr || !operand->is_typed(typeid(T)))
|
||||
return nullptr;
|
||||
else
|
||||
return operand->cast<T>();
|
||||
}
|
||||
|
||||
/// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object
|
||||
/// contained by operand, otherwise nullptr.
|
||||
template<typename T>
|
||||
inline T* any_cast(any* operand) noexcept
|
||||
{
|
||||
if(operand == nullptr || !operand->is_typed(typeid(T)))
|
||||
return nullptr;
|
||||
else
|
||||
return operand->cast<T>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
inline void swap(linb::any& lhs, linb::any& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
168
launchers/macosx/obj-cpp/include/fn.h
Normal file
168
launchers/macosx/obj-cpp/include/fn.h
Normal file
@ -0,0 +1,168 @@
|
||||
#ifndef FN_H
|
||||
#define FN_H
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
/*
|
||||
* higher-order functions
|
||||
*
|
||||
* Read
|
||||
* http://blog.madhukaraphatak.com/functional-programming-in-c++/
|
||||
*
|
||||
*
|
||||
* Lamda fingerprint:
|
||||
namespace {
|
||||
struct f {
|
||||
void operator()(int) {
|
||||
// do something
|
||||
}
|
||||
};
|
||||
}
|
||||
*
|
||||
*
|
||||
*
|
||||
template <typename Collection,typename unop>
|
||||
void for_each(Collection col, unop op){
|
||||
std::for_each(col.begin(),col.end(),op);
|
||||
}
|
||||
|
||||
Usage:
|
||||
|
||||
auto lambda_echo = [](int i ) { std::cout << i << std::endl; };
|
||||
std::vector<int> col{20,24,37,42,23,45,37};
|
||||
for_each(col,lambda_echo);
|
||||
|
||||
*/
|
||||
template <typename Collection,typename unop>
|
||||
void for_each(Collection col, unop op){
|
||||
std::for_each(col.begin(),col.end(),op);
|
||||
}
|
||||
|
||||
/**
|
||||
* map
|
||||
*
|
||||
* Usage example:
|
||||
auto addOne = [](int i) { return i+1;};
|
||||
auto returnCol = map(col,addOne);
|
||||
for_each(returnCol,lambda_echo);
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
template <typename Collection,typename unop>
|
||||
Collection map(Collection col,unop op) {
|
||||
std::transform(col.begin(),col.end(),col.begin(),op);
|
||||
return col;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Filter usage:
|
||||
|
||||
auto filteredCol = filter(col,[](int value){ return value > 30;});
|
||||
for_each(filteredCol,lambda_echo);
|
||||
*/
|
||||
|
||||
template <typename Collection,typename Predicate>
|
||||
Collection filterNot(Collection col,Predicate predicate ) {
|
||||
auto returnIterator = std::remove_if(col.begin(),col.end(),predicate);
|
||||
col.erase(returnIterator,std::end(col));
|
||||
return col;
|
||||
}
|
||||
|
||||
template <typename Collection,typename Predicate>
|
||||
Collection filter(Collection col,Predicate predicate) {
|
||||
//capture the predicate in order to be used inside function
|
||||
auto fnCol = filterNot(col,[predicate](typename Collection::value_type i) { return !predicate(i);});
|
||||
return fnCol;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Alternative map implementations
|
||||
*
|
||||
**/
|
||||
template<class F, class T, class U=decltype(std::declval<F>()(std::declval<T>()))>
|
||||
std::vector<U> fmap(F f, const std::vector<T>& vec)
|
||||
{
|
||||
std::vector<U> result;
|
||||
std::transform(vec.begin(), vec.end(), std::back_inserter(result), f);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class F, class T, class U=decltype(std::declval<F>()(std::declval<T>()))>
|
||||
std::shared_ptr<U> fmap(F f, const std::shared_ptr<T>& p)
|
||||
{
|
||||
if (p == nullptr) return nullptr;
|
||||
else return std::shared_ptr<U>(new U(f(*p)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Experimental code - should not be in production
|
||||
*/
|
||||
|
||||
namespace Experimental {
|
||||
template <typename T>
|
||||
T min3(const T& a, const T& b, const T& c)
|
||||
{
|
||||
return std::min(std::min(a, b), c);
|
||||
}
|
||||
|
||||
class LevenshteinDistance
|
||||
{
|
||||
mutable std::vector<std::vector<unsigned int> > matrix_;
|
||||
|
||||
public:
|
||||
explicit LevenshteinDistance(size_t initial_size = 8)
|
||||
: matrix_(initial_size, std::vector<unsigned int>(initial_size))
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int operator()(const std::string& s, const std::string& t) const
|
||||
{
|
||||
const size_t m = s.size();
|
||||
const size_t n = t.size();
|
||||
// The distance between a string and the empty string is the string's length
|
||||
if (m == 0) {
|
||||
return n;
|
||||
}
|
||||
if (n == 0) {
|
||||
return m;
|
||||
}
|
||||
// Size the matrix as necessary
|
||||
if (matrix_.size() < m + 1) {
|
||||
matrix_.resize(m + 1, matrix_[0]);
|
||||
}
|
||||
if (matrix_[0].size() < n + 1) {
|
||||
for (auto& mat : matrix_) {
|
||||
mat.resize(n + 1);
|
||||
}
|
||||
}
|
||||
// The top row and left column are prefixes that can be reached by
|
||||
// insertions and deletions alone
|
||||
unsigned int i, j;
|
||||
for (i = 1; i <= m; ++i) {
|
||||
matrix_[i][0] = i;
|
||||
}
|
||||
for (j = 1; j <= n; ++j) {
|
||||
matrix_[0][j] = j;
|
||||
}
|
||||
// Fill in the rest of the matrix
|
||||
for (j = 1; j <= n; ++j) {
|
||||
for (i = 1; i <= m; ++i) {
|
||||
unsigned int substitution_cost = s[i - 1] == t[j - 1] ? 0 : 1;
|
||||
matrix_[i][j] =
|
||||
min3(matrix_[i - 1][j] + 1, // Deletion
|
||||
matrix_[i][j - 1] + 1, // Insertion
|
||||
matrix_[i - 1][j - 1] + substitution_cost); // Substitution
|
||||
}
|
||||
}
|
||||
return matrix_[m][n];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // FN_H
|
Reference in New Issue
Block a user