Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: native extension: support older C++ ABIs #806

Merged
merged 18 commits into from
Oct 2, 2023
Merged
39 changes: 37 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -121,7 +121,7 @@ jobs:
- name: Build
run: npm run compile

platform-check:
centos-build-check:
runs-on: ubuntu-latest
strategy:
fail-fast: false
@@ -130,7 +130,7 @@ jobs:
include:
- container: 'centos:7'
- cmd: 'curl -sL https://rpm.nodesource.com/setup_${NODE_VERSION}.x | bash - && yum install -y nodejs gcc-c++ make'
name: Platform check - ${{ matrix.container }} - Node.js ${{ matrix.nodejs }}
name: CentOS build check - ${{ matrix.container }} - Node.js ${{ matrix.nodejs }}
container: ${{ matrix.container }}
env:
NODE_VERSION: ${{ matrix.nodejs }}
@@ -146,6 +146,41 @@ jobs:
- name: Run tests
run: npm run test

centos-prebuild-check:
needs: [prebuilds-linux]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
container: ['centos:7']
nodejs: [14, 16]
include:
- container: 'centos:7'
nodejs: 14
cmd: 'curl -sL https://rpm.nodesource.com/setup_14.x | bash - && yum install -y nodejs'
- container: 'centos:7'
nodejs: 16
cmd: 'yum install https://rpm.nodesource.com/pub_16.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm -y && yum install nodejs -y --setopt=nodesource-nodejs.module_hotfixes=1'
name: Centos check - ${{ matrix.container }} - Node.js ${{ matrix.nodejs }}
container: ${{ matrix.container }}
env:
NODE_VERSION: ${{ matrix.nodejs }}
steps:
- name: Setup container
run: ${{ matrix.cmd }}
- name: Checkout
uses: actions/checkout@v3
- name: Download
uses: actions/download-artifact@v3
- name: copy prebuilds
run: |
mkdir -p prebuilds
cp -r prebuilds-linux/* prebuilds
- name: Install npm dependencies
run: npm ci --ignore-scripts --no-optional --loglevel verbose
- name: Run tests
run: npm run test

e2e-local:
runs-on: ubuntu-latest
strategy:
3 changes: 2 additions & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
@@ -34,7 +34,8 @@
"/WX"
],
"defines": [
"NOMINMAX"
"NOMINMAX",
"_WIN32_WINNT=0x0602"
],
"msvs_settings": {
"VCCLCompilerTool": {
57 changes: 22 additions & 35 deletions src/native_ext/memory_profiling.cpp
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
#include "khash.h"
#include "util/platform.h"
#include <v8-profiler.h>
#include <vector>
#include "tinystl/vector.h"

namespace Splunk {
namespace Profiling {
@@ -16,8 +16,8 @@ enum MemoryProfilingStringIndex {
V8String_MAX
};

struct BFSNode {
BFSNode(v8::AllocationProfile::Node* node, uint32_t parentId) : node(node), parentId(parentId) {}
struct DFSNode {
DFSNode(v8::AllocationProfile::Node* node, uint32_t parentId) : node(node), parentId(parentId) {}
v8::AllocationProfile::Node* node;
uint32_t parentId;
};
@@ -31,11 +31,11 @@ struct MemoryProfiling {
uint64_t generation = 0;
// Used to keep track which were the new samples added to the allocation profile.
khash_t(SampleId) * tracking;
std::vector<BFSNode> stack;
bool isRunning = false;
tinystl::vector<DFSNode> stack;
bool v8ProfilerRunning = false;
};

MemoryProfiling* profiling = nullptr;
MemoryProfiling profiling;

struct StringStash {
v8::Local<v8::String> strings[V8String_MAX];
@@ -54,11 +54,7 @@ ToJsHeapNode(v8::AllocationProfile::Node* node, uint32_t parentId, StringStash*
} // namespace

NAN_METHOD(StartMemoryProfiling) {
if (!profiling) {
profiling = new MemoryProfiling();
}

if (profiling->isRunning) {
if (profiling.v8ProfilerRunning) {
return;
}

@@ -88,17 +84,13 @@ NAN_METHOD(StartMemoryProfiling) {
}
}

profiling->isRunning = profiler->StartSamplingHeapProfiler(sampleIntervalBytes, maxStackDepth);
profiling.v8ProfilerRunning = profiler->StartSamplingHeapProfiler(sampleIntervalBytes, maxStackDepth);
}

NAN_METHOD(CollectHeapProfile) {
info.GetReturnValue().SetNull();

if (!profiling) {
return;
}

if (!profiling->isRunning) {
if (!profiling.v8ProfilerRunning) {
return;
}

@@ -123,12 +115,12 @@ NAN_METHOD(CollectHeapProfile) {

v8::AllocationProfile::Node* root = profile->GetRootNode();

const std::vector<v8::AllocationProfile::Sample>& samples = profile->GetSamples();
const auto& samples = profile->GetSamples();

profiling->generation++;
uint64_t generation = profiling->generation;
profiling.generation++;
uint64_t generation = profiling.generation;

khash_t(SampleId)* tracking = profiling->tracking;
khash_t(SampleId)* tracking = profiling.tracking;

for (const auto& sample : samples) {
if (kh_get(SampleId, tracking, sample.sample_id) == kh_end(tracking)) {
@@ -165,16 +157,16 @@ NAN_METHOD(CollectHeapProfile) {
stash.strings[V8String_LineNumber] = Nan::New<v8::String>("lineNumber").ToLocalChecked();
stash.strings[V8String_ParentId] = Nan::New<v8::String>("parentId").ToLocalChecked();

std::vector<BFSNode>& stack = profiling->stack;
tinystl::vector<DFSNode>& stack = profiling.stack;
stack.clear();

// Cut off the root node
for (v8::AllocationProfile::Node* child : root->children) {
stack.emplace_back(child, root->node_id);
stack.push_back(DFSNode{child, root->node_id});
}

while (!stack.empty()) {
BFSNode graphNode = stack.back();
DFSNode graphNode = stack.back();
stack.pop_back();

v8::AllocationProfile::Node* node = graphNode.node;
@@ -183,7 +175,7 @@ NAN_METHOD(CollectHeapProfile) {
Nan::Set(jsNodeTree, Nan::New<v8::Uint32>(node->node_id), jsNode);

for (v8::AllocationProfile::Node* child : node->children) {
stack.emplace_back(child, node->node_id);
stack.push_back(DFSNode{child, node->node_id});
}
}

@@ -207,22 +199,17 @@ NAN_METHOD(CollectHeapProfile) {
}

NAN_METHOD(StopMemoryProfiling) {
if (!profiling) {
if (!profiling.v8ProfilerRunning) {
return;
}

if (profiling->isRunning) {
v8::HeapProfiler* profiler = info.GetIsolate()->GetHeapProfiler();

if (!profiler) {
return;
}
v8::HeapProfiler* profiler = info.GetIsolate()->GetHeapProfiler();

profiler->StopSamplingHeapProfiler();
if (!profiler) {
return;
}

delete profiling;
profiling = nullptr;
profiler->StopSamplingHeapProfiler();
}

} // namespace Profiling
37 changes: 28 additions & 9 deletions src/native_ext/metrics.cpp
Original file line number Diff line number Diff line change
@@ -44,9 +44,18 @@ int32_t GetGcStatsIndex(v8::GCType type) {
return -1;
}
}

enum GcType {
GcTypeAll,
GcTypeScavenge,
GcTypeMarkSweepCompact,
GcTypeIncrementalMarking,
GcTypeProcessWeakCallbacks,
};

struct GcCounters {
GcCounters(const std::string& type) : type(type) {}
std::string type;
GcCounters(GcType type) : type(type) {}
GcType type;
Counters time;
Counters amount;
};
@@ -72,11 +81,11 @@ const size_t kGcTypes = 5;
struct {
Counters eventLoop;
GcCounters gcCounters[kGcTypes] = {
{"all"},
{"scavenge"},
{"mark_sweep_compact"},
{"incremental_marking"},
{"process_weak_callbacks"}};
{GcTypeAll},
{GcTypeScavenge},
{GcTypeMarkSweepCompact},
{GcTypeIncrementalMarking},
{GcTypeProcessWeakCallbacks}};
} stats;

void EventLoopPrepareCallback(uv_prepare_t* handle) {
@@ -102,7 +111,7 @@ void EventLoopCheckCallback(uv_check_t* handle) {
#endif
}
void WriteCounters(
v8::Local<v8::Object>& parent, const std::string& key, const Counters& counters) {
v8::Local<v8::Object>& parent, const char* key, const Counters& counters) {
auto obj = Nan::New<v8::Object>();
Nan::Set(obj, Nan::New("min").ToLocalChecked(), Nan::New<v8::Number>(double(counters.min)));
Nan::Set(obj, Nan::New("max").ToLocalChecked(), Nan::New<v8::Number>(double(counters.max)));
@@ -113,6 +122,16 @@ void WriteCounters(
Nan::Set(parent, Nan::New(key).ToLocalChecked(), obj);
}

Nan::MaybeLocal<v8::String> GcTypeString(GcType type) {
switch (type) {
case GcTypeScavenge: return Nan::New("scavenge");
case GcTypeMarkSweepCompact: return Nan::New("mark_sweep_compact");
case GcTypeIncrementalMarking: return Nan::New("incremental_marking");
case GcTypeProcessWeakCallbacks: return Nan::New("process_weak_callbacks");
default: return Nan::New("all");
}
}

NAN_GC_CALLBACK(GcPrologue) {
state.gc.startTime = uv_hrtime();
v8::HeapStatistics heapStats;
@@ -151,7 +170,7 @@ NAN_METHOD(CollectCounters) {
auto typeObj = Nan::New<v8::Object>();
WriteCounters(typeObj, "collected", gcStats.amount);
WriteCounters(typeObj, "duration", gcStats.time);
Nan::Set(gcObj, Nan::New(gcStats.type).ToLocalChecked(), typeObj);
Nan::Set(gcObj, GcTypeString(gcStats.type).ToLocalChecked(), typeObj);
}

Nan::Set(obj, Nan::New("gc").ToLocalChecked(), gcObj);
50 changes: 50 additions & 0 deletions src/native_ext/tinystl/allocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*-
* Copyright 2012 Matthew Endsley
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/

#ifndef TINYSTL_ALLOCATOR_H
#define TINYSTL_ALLOCATOR_H

#include "stddef.h"

#ifndef TINYSTL_ALLOCATOR

namespace tinystl {

struct allocator {
static void* static_allocate(size_t bytes) {
return operator new(bytes);
}

static void static_deallocate(void* ptr, size_t /*bytes*/) {
operator delete(ptr);
}
};
}

# define TINYSTL_ALLOCATOR ::tinystl::allocator
#endif // TINYSTL_ALLOCATOR

#endif
287 changes: 287 additions & 0 deletions src/native_ext/tinystl/buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
/*-
* Copyright 2012-1015 Matthew Endsley
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/

#ifndef TINYSTL_BUFFER_H
#define TINYSTL_BUFFER_H

#include "new.h"
#include "traits.h"

namespace tinystl {

template<typename T, typename Alloc = TINYSTL_ALLOCATOR>
struct buffer {
T* first;
T* last;
T* capacity;
};

template<typename T>
static inline void buffer_destroy_range_traits(T* first, T* last, pod_traits<T, false>) {
for (; first < last; ++first)
first->~T();
}

template<typename T>
static inline void buffer_destroy_range_traits(T*, T*, pod_traits<T, true>) {
}

template<typename T>
static inline void buffer_destroy_range(T* first, T* last) {
buffer_destroy_range_traits(first, last, pod_traits<T>());
}

template<typename T>
static inline void buffer_fill_urange_traits(T* first, T* last, pod_traits<T, false>) {
for (; first < last; ++first)
new(placeholder(), first) T();
}

template<typename T>
static inline void buffer_fill_urange_traits(T* first, T* last, pod_traits<T, true>) {
for (; first < last; ++first)
*first = T();
}

template<typename T>
static inline void buffer_fill_urange_traits(T* first, T* last, const T& value, pod_traits<T, false>) {
for (; first < last; ++first)
new(placeholder(), first) T(value);
}

template<typename T>
static inline void buffer_fill_urange_traits(T* first, T* last, const T& value, pod_traits<T, true>) {
for (; first < last; ++first)
*first = value;
}

template<typename T>
static inline void buffer_move_urange_traits(T* dest, T* first, T* last, pod_traits<T, false>) {
for (T* it = first; it != last; ++it, ++dest)
move_construct(dest, *it);
buffer_destroy_range(first, last);
}

template<typename T>
static inline void buffer_move_urange_traits(T* dest, T* first, T* last, pod_traits<T, true>) {
for (; first != last; ++first, ++dest)
*dest = *first;
}

template<typename T>
static inline void buffer_bmove_urange_traits(T* dest, T* first, T* last, pod_traits<T, false>) {
dest += (last - first);
for (T* it = last; it != first; --it, --dest) {
move_construct(dest - 1, *(it - 1));
buffer_destroy_range(it - 1, it);
}
}

template<typename T>
static inline void buffer_bmove_urange_traits(T* dest, T* first, T* last, pod_traits<T, true>) {
dest += (last - first);
for (T* it = last; it != first; --it, --dest)
*(dest - 1) = *(it - 1);
}

template<typename T>
static inline void buffer_move_urange(T* dest, T* first, T* last) {
buffer_move_urange_traits(dest, first, last, pod_traits<T>());
}

template<typename T>
static inline void buffer_bmove_urange(T* dest, T* first, T* last) {
buffer_bmove_urange_traits(dest, first, last, pod_traits<T>());
}

template<typename T>
static inline void buffer_fill_urange(T* first, T* last) {
buffer_fill_urange_traits(first, last, pod_traits<T>());
}

template<typename T>
static inline void buffer_fill_urange(T* first, T* last, const T& value) {
buffer_fill_urange_traits(first, last, value, pod_traits<T>());
}

template<typename T, typename Alloc>
static inline void buffer_init(buffer<T, Alloc>* b) {
b->first = b->last = b->capacity = 0;
}

template<typename T, typename Alloc>
static inline void buffer_destroy(buffer<T, Alloc>* b) {
buffer_destroy_range(b->first, b->last);
Alloc::static_deallocate(b->first, (size_t)((char*)b->capacity - (char*)b->first));
}

template<typename T, typename Alloc>
static inline void buffer_reserve(buffer<T, Alloc>* b, size_t capacity) {
if (b->first + capacity <= b->capacity)
return;

typedef T* pointer;
const size_t size = (size_t)(b->last - b->first);
pointer newfirst = (pointer)Alloc::static_allocate(sizeof(T) * capacity);
buffer_move_urange(newfirst, b->first, b->last);
Alloc::static_deallocate(b->first, sizeof(T) * capacity);

b->first = newfirst;
b->last = newfirst + size;
b->capacity = newfirst + capacity;
}

template<typename T, typename Alloc>
static inline void buffer_resize(buffer<T, Alloc>* b, size_t size) {
buffer_reserve(b, size);

buffer_fill_urange(b->last, b->first + size);
buffer_destroy_range(b->first + size, b->last);
b->last = b->first + size;
}

template<typename T, typename Alloc>
static inline void buffer_resize(buffer<T, Alloc>* b, size_t size, const T& value) {
buffer_reserve(b, size);

buffer_fill_urange(b->last, b->first + size, value);
buffer_destroy_range(b->first + size, b->last);
b->last = b->first + size;
}

template<typename T, typename Alloc>
static inline void buffer_shrink_to_fit(buffer<T, Alloc>* b) {
if (b->last == b->first) {
const size_t capacity = (size_t)(b->last - b->first);
Alloc::static_deallocate(b->first, sizeof(T)*capacity);
b->capacity = b->first;
} else if (b->capacity != b->last) {
const size_t capacity = (size_t)(b->capacity - b->first);
const size_t size = (size_t)(b->last - b->first);
T* newfirst = (T*)Alloc::static_allocate(sizeof(T) * size);
buffer_move_urange(newfirst, b->first, b->last);
Alloc::static_deallocate(b->first, sizeof(T) * capacity);
b->first = newfirst;
b->last = newfirst + size;
b->capacity = b->last;
}
}

template<typename T, typename Alloc>
static inline void buffer_clear(buffer<T, Alloc>* b) {
buffer_destroy_range(b->first, b->last);
b->last = b->first;
}

template<typename T, typename Alloc>
static inline T* buffer_insert_common(buffer<T, Alloc>* b, T* where, size_t count) {
const size_t offset = (size_t)(where - b->first);
const size_t newsize = (size_t)((b->last - b->first) + count);
if (b->first + newsize > b->capacity)
buffer_reserve(b, (newsize * 3) / 2);

where = b->first + offset;

if (where != b->last)
buffer_bmove_urange(where + count, where, b->last);

b->last = b->first + newsize;

return where;
}

template<typename T, typename Alloc, typename Param>
static inline void buffer_insert(buffer<T, Alloc>* b, T* where, const Param* first, const Param* last) {
where = buffer_insert_common(b, where, last - first);
for (; first != last; ++first, ++where)
new(placeholder(), where) T(*first);
}

template<typename T, typename Alloc>
static inline void buffer_insert(buffer<T, Alloc>* b, T* where, size_t count) {
where = buffer_insert_common(b, where, count);
for (size_t i = 0; i < count; ++i)
new(placeholder(), where) T();
}

template<typename T, typename Alloc, typename Param>
static inline void buffer_append(buffer<T, Alloc>* b, const Param* param) {
if (b->capacity != b->last) {
new(placeholder(), b->last) T(*param);
++b->last;
} else {
buffer_insert(b, b->last, param, param + 1);
}
}

template<typename T, typename Alloc>
static inline void buffer_append(buffer<T, Alloc>* b) {
if (b->capacity != b->last) {
new(placeholder(), b->last) T();
++b->last;
} else {
buffer_insert(b, b->last, 1);
}
}

template<typename T, typename Alloc>
static inline T* buffer_erase(buffer<T, Alloc>* b, T* first, T* last) {
typedef T* pointer;
const size_t range = (last - first);
for (pointer it = last, end = b->last, dest = first; it != end; ++it, ++dest)
move(*dest, *it);

buffer_destroy_range(b->last - range, b->last);

b->last -= range;
return first;
}

template<typename T, typename Alloc>
static inline T* buffer_erase_unordered(buffer<T, Alloc>* b, T* first, T* last) {
typedef T* pointer;
const size_t range = (last - first);
const size_t tail = (b->last - last);
pointer it = b->last - ((range < tail) ? range : tail);
for (pointer end = b->last, dest = first; it != end; ++it, ++dest)
move(*dest, *it);

buffer_destroy_range(b->last - range, b->last);

b->last -= range;
return first;
}

template<typename T, typename Alloc>
static inline void buffer_swap(buffer<T, Alloc>* b, buffer<T, Alloc>* other) {
typedef T* pointer;
const pointer tfirst = b->first, tlast = b->last, tcapacity = b->capacity;
b->first = other->first, b->last = other->last, b->capacity = other->capacity;
other->first = tfirst, other->last = tlast, other->capacity = tcapacity;
}
}

#endif
43 changes: 43 additions & 0 deletions src/native_ext/tinystl/new.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*-
* Copyright 2012 Matthew Endsley
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/

#ifndef TINYSTL_NEW_H
#define TINYSTL_NEW_H

#include "stddef.h"

namespace tinystl {

struct placeholder {};
}

inline void* operator new(size_t, tinystl::placeholder, void* ptr) {
return ptr;
}

inline void operator delete(void*, tinystl::placeholder, void*) throw() {}

#endif
40 changes: 40 additions & 0 deletions src/native_ext/tinystl/stddef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*-
* Copyright 2012 Matthew Endsley
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/

#ifndef TINYSTL_STDDEF_H
#define TINYSTL_STDDEF_H

#if defined(_WIN64)
typedef long long unsigned int size_t;
#elif defined(_WIN32)
typedef unsigned int size_t;
#elif defined (__linux__) && defined(__SIZE_TYPE__)
typedef __SIZE_TYPE__ size_t;
#else
# include <stddef.h>
#endif

#endif
85 changes: 85 additions & 0 deletions src/native_ext/tinystl/traits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*-
* Copyright 2012 Matthew Endsley
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/

#ifndef TINYSTL_TRAITS_H
#define TINYSTL_TRAITS_H

#include "new.h"

#if defined(__GNUC__) && defined(__is_pod)
# define TINYSTL_TRY_POD_OPTIMIZATION(t) __is_pod(t)
#elif defined(_MSC_VER)
# define TINYSTL_TRY_POD_OPTIMIZATION(t) (!__is_class(t) || __is_pod(t))
#else
# define TINYSTL_TRY_POD_OPTIMIZATION(t) false
#endif

namespace tinystl {
template<typename T, bool pod = TINYSTL_TRY_POD_OPTIMIZATION(T)> struct pod_traits {};

template<typename T, T t> struct swap_holder;

template<typename T>
static inline void move_impl(T& a, T& b, ...) {
a = b;
}

template<typename T>
static inline void move_impl(T& a, T& b, T*, swap_holder<void (T::*)(T&), &T::swap>* = 0) {
a.swap(b);
}

template<typename T>
static inline void move(T& a, T&b) {
move_impl(a, b, (T*)0);
}

template<typename T>
static inline void move_construct_impl(T* a, T& b, ...) {
new(placeholder(), a) T(b);
}

template<typename T>
static inline void move_construct_impl(T* a, T& b, void*, swap_holder<void (T::*)(T&), &T::swap>* = 0) {
// If your type T does not have a default constructor, simply insert:
// struct tinystl_nomove_construct;
// in the class definition
new(placeholder(), a) T;
a->swap(b);
}

template<typename T>
static inline void move_construct_impl(T* a, T& b, T*, typename T::tinystl_nomove_construct* = 0) {
new(placeholder(), a) T(b);
}

template<typename T>
static inline void move_construct(T* a, T& b) {
move_construct_impl(a, b, (T*)0);
}
}

#endif
336 changes: 336 additions & 0 deletions src/native_ext/tinystl/vector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,336 @@
/*-
* Copyright 2012-2018 Matthew Endsley
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/

#ifndef TINYSTL_VECTOR_H
#define TINYSTL_VECTOR_H

#include "allocator.h"
#include "buffer.h"
#include "new.h"
#include "stddef.h"

namespace tinystl {
template<typename T, typename Alloc = TINYSTL_ALLOCATOR>
class vector {
public:
vector();
vector(const vector& other);
vector(vector&& other);
vector(size_t size);
vector(size_t size, const T& value);
vector(const T* first, const T* last);
~vector();

vector& operator=(const vector& other);
vector& operator=(vector&& other);

void assign(const T* first, const T* last);

const T* data() const;
T* data();
size_t size() const;
size_t capacity() const;
bool empty() const;

T& operator[](size_t idx);
const T& operator[](size_t idx) const;

const T& front() const;
T& front();
const T& back() const;
T& back();

void resize(size_t size);
void resize(size_t size, const T& value);
void clear();
void reserve(size_t capacity);

void push_back(const T& t);
void pop_back();

void emplace_back();
template<typename Param>
void emplace_back(const Param& param);

void shrink_to_fit();

void swap(vector& other);

typedef T value_type;

typedef T* iterator;
iterator begin();
iterator end();

typedef const T* const_iterator;
const_iterator begin() const;
const_iterator end() const;

void insert(iterator where);
void insert(iterator where, const T& value);
void insert(iterator where, const T* first, const T* last);

template<typename Param>
void emplace(iterator where, const Param& param);

iterator erase(iterator where);
iterator erase(iterator first, iterator last);

iterator erase_unordered(iterator where);
iterator erase_unordered(iterator first, iterator last);

private:
buffer<T, Alloc> m_buffer;
};

template<typename T, typename Alloc>
inline vector<T, Alloc>::vector() {
buffer_init(&m_buffer);
}

template<typename T, typename Alloc>
inline vector<T, Alloc>::vector(const vector& other) {
buffer_init(&m_buffer);
buffer_reserve(&m_buffer, other.size());
buffer_insert(&m_buffer, m_buffer.last, other.m_buffer.first, other.m_buffer.last);
}

template<typename T, typename Alloc>
inline vector<T, Alloc>::vector(vector&& other) {
buffer_move(&m_buffer, &other.m_buffer);
}

template<typename T, typename Alloc>
inline vector<T, Alloc>::vector(size_t size) {
buffer_init(&m_buffer);
buffer_resize(&m_buffer, size);
}

template<typename T, typename Alloc>
inline vector<T, Alloc>::vector(size_t size, const T& value) {
buffer_init(&m_buffer);
buffer_resize(&m_buffer, size, value);
}

template<typename T, typename Alloc>
inline vector<T, Alloc>::vector(const T* first, const T* last) {
buffer_init(&m_buffer);
buffer_insert(&m_buffer, m_buffer.last, first, last);
}

template<typename T, typename Alloc>
inline vector<T, Alloc>::~vector() {
buffer_destroy(&m_buffer);
}

template<typename T, typename Alloc>
inline vector<T, Alloc>& vector<T, Alloc>::operator=(const vector& other) {
vector(other).swap(*this);
return *this;
}

template<typename T, typename Alloc>
vector<T, Alloc>& vector<T, Alloc>::operator=(vector&& other) {
buffer_destroy(&m_buffer);
buffer_move(&m_buffer, &other.m_buffer);
return *this;
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::assign(const T* first, const T* last) {
buffer_clear(&m_buffer);
buffer_insert(&m_buffer, m_buffer.last, first, last);
}

template<typename T, typename Alloc>
inline const T* vector<T, Alloc>::data() const {
return m_buffer.first;
}

template<typename T, typename Alloc>
inline T* vector<T, Alloc>::data() {
return m_buffer.first;
}

template<typename T, typename Alloc>
inline size_t vector<T, Alloc>::size() const {
return (size_t)(m_buffer.last - m_buffer.first);
}

template<typename T, typename Alloc>
inline size_t vector<T, Alloc>::capacity() const {
return (size_t)(m_buffer.capacity - m_buffer.first);
}

template<typename T, typename Alloc>
inline bool vector<T, Alloc>::empty() const {
return m_buffer.last == m_buffer.first;
}

template<typename T, typename Alloc>
inline T& vector<T, Alloc>::operator[](size_t idx) {
return m_buffer.first[idx];
}

template<typename T, typename Alloc>
inline const T& vector<T, Alloc>::operator[](size_t idx) const {
return m_buffer.first[idx];
}

template<typename T, typename Alloc>
inline const T& vector<T, Alloc>::front() const {
return m_buffer.first[0];
}

template<typename T, typename Alloc>
inline T& vector<T, Alloc>::front() {
return m_buffer.first[0];
}

template<typename T, typename Alloc>
inline const T& vector<T, Alloc>::back() const {
return m_buffer.last[-1];
}

template<typename T, typename Alloc>
inline T& vector<T, Alloc>::back() {
return m_buffer.last[-1];
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::resize(size_t size) {
buffer_resize(&m_buffer, size);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::resize(size_t size, const T& value) {
buffer_resize(&m_buffer, size, value);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::clear() {
buffer_clear(&m_buffer);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::reserve(size_t capacity) {
buffer_reserve(&m_buffer, capacity);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::push_back(const T& t) {
buffer_append(&m_buffer, &t);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::emplace_back() {
buffer_append(&m_buffer);
}

template<typename T, typename Alloc>
template<typename Param>
inline void vector<T, Alloc>::emplace_back(const Param& param) {
buffer_append(&m_buffer, &param);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::pop_back() {
buffer_erase(&m_buffer, m_buffer.last - 1, m_buffer.last);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::shrink_to_fit() {
buffer_shrink_to_fit(&m_buffer);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::swap(vector& other) {
buffer_swap(&m_buffer, &other.m_buffer);
}

template<typename T, typename Alloc>
inline typename vector<T, Alloc>::iterator vector<T,Alloc>::begin() {
return m_buffer.first;
}

template<typename T, typename Alloc>
inline typename vector<T, Alloc>::iterator vector<T,Alloc>::end() {
return m_buffer.last;
}

template<typename T, typename Alloc>
inline typename vector<T, Alloc>::const_iterator vector<T,Alloc>::begin() const {
return m_buffer.first;
}

template<typename T, typename Alloc>
inline typename vector<T, Alloc>::const_iterator vector<T,Alloc>::end() const {
return m_buffer.last;
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::insert(typename vector::iterator where) {
buffer_insert(&m_buffer, where, 1);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::insert(iterator where, const T& value) {
buffer_insert(&m_buffer, where, &value, &value + 1);
}

template<typename T, typename Alloc>
inline void vector<T, Alloc>::insert(iterator where, const T* first, const T* last) {
buffer_insert(&m_buffer, where, first, last);
}

template<typename T, typename Alloc>
inline typename vector<T, Alloc>::iterator vector<T, Alloc>::erase(iterator where) {
return buffer_erase(&m_buffer, where, where + 1);
}

template<typename T, typename Alloc>
inline typename vector<T, Alloc>::iterator vector<T, Alloc>::erase(iterator first, iterator last) {
return buffer_erase(&m_buffer, first, last);
}

template<typename T, typename Alloc>
inline typename vector<T, Alloc>::iterator vector<T, Alloc>::erase_unordered(iterator where) {
return buffer_erase_unordered(&m_buffer, where, where + 1);
}

template<typename T, typename Alloc>
inline typename vector<T, Alloc>::iterator vector<T, Alloc>::erase_unordered(iterator first, iterator last) {
return buffer_erase_unordered(&m_buffer, first, last);
}

template<typename T, typename Alloc>
template<typename Param>
void vector<T, Alloc>::emplace(typename vector::iterator where, const Param& param) {
buffer_insert(&m_buffer, where, &param, &param + 1);
}
}

#endif // TINYSTL_VECTOR_H
33 changes: 22 additions & 11 deletions src/native_ext/util/platform.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "platform.h"
#include <chrono>
#include <uv.h>

#ifdef __APPLE__
@@ -8,14 +7,6 @@

namespace Splunk {

namespace {
template <typename Duration>
int64_t SinceEpoch() {
return std::chrono::duration_cast<Duration>(std::chrono::system_clock::now().time_since_epoch())
.count();
}
} // namespace

#ifdef __APPLE__
int64_t HrTime() {
static mach_timebase_info_data_t timebase;
@@ -29,8 +20,28 @@ int64_t HrTime() {
int64_t HrTime() { return uv_hrtime(); }
#endif

int64_t MicroSecondsSinceEpoch() { return SinceEpoch<std::chrono::microseconds>(); }
#ifdef _WIN32
#include <sysinfoapi.h>
int64_t MicroSecondsSinceEpoch() {
FILETIME ft;
GetSystemTimePreciseAsFileTime(&ft);

int64_t t = (int64_t) ft.dwHighDateTime << 32 | ft.dwLowDateTime;
t -= 116444736000000000LL;
return t / 10LL;
}
#else
#include <time.h>
int64_t MicroSecondsSinceEpoch() {
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
return ts.tv_sec * 1000000LL + ts.tv_nsec / 1000LL;
}

return 0;
}
#endif

int64_t MilliSecondsSinceEpoch() { return SinceEpoch<std::chrono::milliseconds>(); }
int64_t MilliSecondsSinceEpoch() { return MicroSecondsSinceEpoch() / 1000; }

} // namespace Splunk