thor moved into the main line -- tree code experiences radical changes
This commit is contained in:
+1
-1
@@ -97,7 +97,7 @@ EXCLUDE_PATTERNS = */auton/* \
|
||||
*_impl.h \
|
||||
*_impl.cc \
|
||||
*/u/* \
|
||||
*test.cc
|
||||
*_test.cc
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
|
||||
+25
-2
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "ccmem.h"
|
||||
|
||||
/*void mem::SwapBytes__Chars(long *a_lp_in, long *b_lp_in, size_t remaining) {
|
||||
void mem::SwapBytes__Chars(long *a_lp_in, long *b_lp_in, ssize_t remaining) {
|
||||
char *a_cp = reinterpret_cast<char*>(a_lp_in);
|
||||
char *b_cp = reinterpret_cast<char*>(b_lp_in);
|
||||
|
||||
@@ -19,4 +19,27 @@
|
||||
*a_cp = tb;
|
||||
a_cp++;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void mem::SwapBytes__Impl(long *a_lp, long *b_lp, ssize_t remaining) {
|
||||
//DEBUG_MSG(3.0,"Swapping %d bytes, %d left", int(elems), int(remaining));
|
||||
|
||||
// TODO: Not as good as an MMX memcpy, but still good...
|
||||
// TODO: replace 'remaining' decrement with end pointer
|
||||
for (;;) {
|
||||
remaining -= sizeof(long);
|
||||
if (unlikely(remaining < 0)) break;
|
||||
long ta = *a_lp;
|
||||
long tb = *b_lp;
|
||||
*b_lp = ta;
|
||||
b_lp++;
|
||||
*a_lp = tb;
|
||||
a_lp++;
|
||||
}
|
||||
|
||||
remaining += sizeof(long);
|
||||
|
||||
if (unlikely(remaining != 0)) {
|
||||
SwapBytes__Chars(a_lp, b_lp, remaining);
|
||||
}
|
||||
}
|
||||
|
||||
+22
-42
@@ -68,7 +68,7 @@ namespace mem {
|
||||
* @param elems number of *elements*
|
||||
*/
|
||||
template<typename T>
|
||||
void DebugPoison(T* array, size_t elems) {
|
||||
void DebugPoison(T* array, size_t elems = 1) {
|
||||
DEBUG_ONLY(DebugPoisonBytes(array, elems * sizeof(T)));
|
||||
}
|
||||
|
||||
@@ -332,55 +332,35 @@ namespace mem {
|
||||
inline T* CopyConstruct(T* dest, const T* src, size_t elems = 1) {
|
||||
for (size_t i = 0; i < elems; i++) new(dest+i)T(src[i]); return dest;
|
||||
}
|
||||
template<>
|
||||
inline char* CopyConstruct<char>(char* dest, const char* src, size_t elems) {
|
||||
::memcpy(dest, src, elems); return dest;
|
||||
}
|
||||
#define BASE_CCMEM__FAST_COPY(T) \
|
||||
template<> inline T* CopyConstruct<T>(T* dest, const T* src, size_t elems) \
|
||||
{ ::memcpy(dest, src, elems * sizeof(T)); return dest; }
|
||||
BASE_CCMEM__FAST_COPY(char)
|
||||
BASE_CCMEM__FAST_COPY(short)
|
||||
BASE_CCMEM__FAST_COPY(int)
|
||||
BASE_CCMEM__FAST_COPY(long)
|
||||
BASE_CCMEM__FAST_COPY(long long)
|
||||
BASE_CCMEM__FAST_COPY(unsigned char)
|
||||
BASE_CCMEM__FAST_COPY(unsigned short)
|
||||
BASE_CCMEM__FAST_COPY(unsigned int)
|
||||
BASE_CCMEM__FAST_COPY(unsigned long)
|
||||
BASE_CCMEM__FAST_COPY(unsigned long long)
|
||||
BASE_CCMEM__FAST_COPY(float)
|
||||
BASE_CCMEM__FAST_COPY(double)
|
||||
#undef BASE_CCMEM__FAST_COPY
|
||||
|
||||
template<typename T>
|
||||
inline T* DupConstruct(const T* src, size_t elems = 1) {
|
||||
return CopyConstruct(Alloc<T>(elems), src, elems);
|
||||
}
|
||||
|
||||
inline void SwapBytes__Chars(long *a_lp_in, long *b_lp_in, size_t remaining) {
|
||||
char *a_cp = reinterpret_cast<char*>(a_lp_in);
|
||||
char *b_cp = reinterpret_cast<char*>(b_lp_in);
|
||||
|
||||
while (remaining) {
|
||||
char ta = *a_cp;
|
||||
char tb = *b_cp;
|
||||
remaining--;
|
||||
*b_cp = ta;
|
||||
b_cp++;
|
||||
*a_cp = tb;
|
||||
a_cp++;
|
||||
}
|
||||
}
|
||||
void SwapBytes__Chars(long *a_lp_in, long *b_lp_in, ssize_t remaining);
|
||||
void SwapBytes__Impl(long *a_lp_in, long *b_lp_in, ssize_t remaining);
|
||||
|
||||
template<typename T>
|
||||
void SwapBytes(T* a, T* b, size_t bytes) {
|
||||
long *a_lp = reinterpret_cast<long*>(a);
|
||||
long *b_lp = reinterpret_cast<long*>(b);
|
||||
ssize_t remaining = bytes;
|
||||
|
||||
//DEBUG_MSG(3.0,"Swapping %d bytes, %d left", int(elems), int(remaining));
|
||||
|
||||
// TODO: Not as good as an MMX memcpy, but still good...
|
||||
// TODO: replace 'remaining' decrement with end pointer
|
||||
while (likely((remaining -= sizeof(long)) >= 0)) {
|
||||
long ta = *a_lp;
|
||||
long tb = *b_lp;
|
||||
*b_lp = ta;
|
||||
b_lp++;
|
||||
*a_lp = tb;
|
||||
a_lp++;
|
||||
|
||||
}
|
||||
|
||||
remaining += sizeof(long);
|
||||
|
||||
if (unlikely(remaining != 0)) {
|
||||
SwapBytes__Chars(a_lp, b_lp, remaining);
|
||||
}
|
||||
SwapBytes__Impl(reinterpret_cast<long*>(a), reinterpret_cast<long*>(b),
|
||||
bytes);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
+281
-184
@@ -8,21 +8,30 @@
|
||||
* traversal framework allows for the following to be available at no
|
||||
* additional work on the application programmer:
|
||||
*
|
||||
* @li Serialization (save to disk)
|
||||
* @li Deserialization (read from disk)
|
||||
* @li Serialization (save to byte stream)
|
||||
* @li Deserialization (read from byte stream)
|
||||
* @li Object freezing/thawing/refreezing
|
||||
* (storing bulk flattened objects in RAM)
|
||||
* @li Debug print, or save to s-expression or XML
|
||||
* @li Destructors and copy constructors
|
||||
*
|
||||
* We define the concept of an object-traversal (OT) compliant class:
|
||||
*
|
||||
* This has no support for (at least currently):
|
||||
* @li No polymorphism, i.e. virtual functions
|
||||
* @li No cycles in the pointer graph (actually there are a few exceptions,
|
||||
* such as trees can have parent pointers, see OT_FIX)
|
||||
* @li No inheritance, although non-polymorphic inheritance may be a
|
||||
* possibility
|
||||
* @li Blank default constructor that puts object into an "invalid" state,
|
||||
* with Init methods
|
||||
*
|
||||
* @li Cycles
|
||||
* @li Polymorphism (i.e. object-oriented inheritance)
|
||||
* These classes can be thought of as "pure data structures". If your class
|
||||
* is not OT-compliant, you probably want to put the FORBID_COPY header in
|
||||
* your class. This is not to say that non-OT-compliant classes aren't
|
||||
* useful -- it's definitely true that some objects aren't really meant to
|
||||
* be copied or sent over the network. Think for example the Thread class.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BASE_OTRAV_H
|
||||
#define BASE_OTRAV_H
|
||||
|
||||
@@ -32,8 +41,6 @@
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// TODO: Remove nullability from arrays
|
||||
|
||||
#define OT__NAME(x) v_OT->Name( #x )
|
||||
|
||||
/**
|
||||
@@ -56,27 +63,67 @@
|
||||
* Within OT_DEF, declare an array being pointed to, managed by
|
||||
* new[] and delete[].
|
||||
*/
|
||||
#define OT_ARRAY(x, i) (OT__NAME(x), v_OT->Array(this->x, i, false))
|
||||
#define OT_ARRAY(x, i) (OT__NAME(x), v_OT->Array(this->x, i))
|
||||
/**
|
||||
* Within OT_DEF, declare an array or object being pointed to managed by
|
||||
* malloc and free.
|
||||
*/
|
||||
#define OT_MALLOC_ARRAY(x, i) (OT__NAME(x), v_OT->MallocArray(this->x, i, false))
|
||||
#define OT_MALLOC_ARRAY(x, i) (OT__NAME(x), v_OT->MallocArray(this->x, i))
|
||||
/**
|
||||
* Within OT_DEF, declare a pointer to an object that might be NULL.
|
||||
* Within OT_DEF, declare a pointer to a new-delete object that might be NULL.
|
||||
*/
|
||||
#define OT_PTR_NULLABLE(x) (OT__NAME(x), v_OT->Ptr(this->x, true))
|
||||
/**
|
||||
* Within OT_DEF, declare a pointer to an array that might be NULL.
|
||||
*/
|
||||
#define OT_ARRAY_NULLABLE(x, i) (OT__NAME(x), v_OT->Array(this->x, i, true))
|
||||
/**
|
||||
* Within OT_DEF, declare a pointer to a malloced array that might be NULL.
|
||||
*/
|
||||
#define OT_MALLOC_ARRAY_NULLABLE(x, i) (OT__NAME(x), v_OT->MallocArray(this->x, i, true))
|
||||
|
||||
/**
|
||||
* Define the object traversal for this object.
|
||||
* Like OT_DEF but doesn't define any of the automatic freebies.
|
||||
*
|
||||
* @see OT_DEF
|
||||
*/
|
||||
#define OT_DEF_ONLY(AClass) \
|
||||
public: \
|
||||
template<typename Visitor> \
|
||||
friend void TraverseObject(AClass *obj_OT, Visitor *v_OT) { \
|
||||
obj_OT->TraverseObject__OT_(v_OT); \
|
||||
} \
|
||||
private: \
|
||||
template<typename Visitor> \
|
||||
void TraverseObject__OT_(Visitor *v_OT)
|
||||
|
||||
/**
|
||||
* Automatically generate a copy constructor based on the object traversal.
|
||||
*/
|
||||
#define OT_GEN_COPY_CONSTRUCTOR(AClass) \
|
||||
public: AClass(const AClass& other) { ot_private::DeepCopyImplementation(other, this); } private:
|
||||
|
||||
/**
|
||||
* Automatically create a dstructor based on object traversal.
|
||||
*/
|
||||
#define OT_GEN_DESTRUCTOR(AClass) \
|
||||
public: ~AClass() { ot_private::DestructorImplementation(this); } private:
|
||||
|
||||
/**
|
||||
* Automatically create a dstructor based on object traversal.
|
||||
*/
|
||||
#define OT_GEN_ASSIGN(AClass) \
|
||||
public: const AClass& operator = (const AClass& other) \
|
||||
{ this->~AClass(); new(this)AClass(other); return *this; } \
|
||||
private:
|
||||
|
||||
/**
|
||||
* Generate a default constructor.
|
||||
*/
|
||||
#define OT_GEN_DEFAULT_CONSTRUCTOR(AClass) \
|
||||
public: AClass() { } private:
|
||||
|
||||
/**
|
||||
* Automatically create a Copy method based on the copy constructor.
|
||||
*/
|
||||
#define OT_GEN_COPY_METHOD(AClass) \
|
||||
public: void Copy(const AClass& other) { new(this)AClass(other); } private:
|
||||
|
||||
/**
|
||||
* Define the object traversal for this object, and clearly defines its
|
||||
* lifecycle and resource allocation as FASTlib-compliant.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
@@ -87,7 +134,7 @@
|
||||
* MyTree *right;
|
||||
* int num_extra_data;
|
||||
* Data *extra_data_array;
|
||||
*
|
||||
*
|
||||
* OT_DEF(MyTree) {
|
||||
* OT_MY_OBJECT(value);
|
||||
* OT_PTR_NULLABLE(left);
|
||||
@@ -99,39 +146,73 @@
|
||||
* ... rest of class definition ...
|
||||
* @endcode
|
||||
*
|
||||
* The OT_DEF declares its own members, and its pointers. Notice that
|
||||
* <code>OT_MY_OBJECT(num_extra_data)</code> must come before the subsequent
|
||||
* line that uses num_extra_data as an array length. If deserialization is
|
||||
* occuring, each <code>OT_...</code> call is actually deserializing each
|
||||
* member, so num_extra_data is uninitialized until <code>OT_MY_OBJECT</code>
|
||||
* is called on it.
|
||||
* The OT_DEF is used to declare a class's members, and its pointers.
|
||||
* Notice that <code>OT_MY_OBJECT(num_extra_data)</code> must come before
|
||||
* the subsequent line that uses num_extra_data as an array length. If
|
||||
* deserialization is occuring, each <code>OT_...</code> call is actually
|
||||
* deserializing each member, so num_extra_data is uninitialized until
|
||||
* <code>OT_MY_OBJECT</code> is called on it.
|
||||
*
|
||||
* Fine-point: If you have an array of pointers, you are pretty much doomed
|
||||
* to declare the array of pointers and iterate over the array yourself for
|
||||
* each pointer, treating each element of the array as a separate pointer.
|
||||
* Note that all your familiar programming concepts like if-statements and
|
||||
* for-loops are valid in the OT_DEF block because it's just a function,
|
||||
* just make sure you're careful about only accessing members that have
|
||||
* already been "traversed".
|
||||
*
|
||||
* This macro will also make your class FASTlib-compliant by creating a
|
||||
* default constructor, copy constructor, assignment operator,
|
||||
* and Copy method.
|
||||
*
|
||||
* @see OT_MY_OBJECT, OT_MY_ARRAY, OT_PTR, OT_ARRAY, OT_MALLOC_ARRAY,
|
||||
* OT_PTR_NULLABLE, OT_ARRAY_NULLABLE, OT_MALLOC_ARRAY_NULLABLE.
|
||||
*/
|
||||
#define OT_DEF(AClass) \
|
||||
public: \
|
||||
template<typename Visitor> \
|
||||
friend void TraverseObject(AClass *obj_OT, Visitor *v_OT) { \
|
||||
obj_OT->TraverseObject__OT_(v_OT); \
|
||||
} \
|
||||
private: \
|
||||
template<typename Visitor> \
|
||||
void TraverseObject__OT_(Visitor *v_OT)
|
||||
OT_GEN_DEFAULT_CONSTRUCTOR(AClass) \
|
||||
OT_GEN_COPY_CONSTRUCTOR(AClass) \
|
||||
OT_GEN_DESTRUCTOR(AClass) \
|
||||
OT_GEN_COPY_METHOD(AClass) \
|
||||
OT_GEN_ASSIGN(AClass) \
|
||||
OT_DEF_ONLY(AClass)
|
||||
|
||||
/**
|
||||
* Defines object traversal for classes with no pointer members.
|
||||
*
|
||||
* This will use the compiler's default copy constructor and default
|
||||
* destructor, which are almost certainly faster than the ot-based one.
|
||||
*/
|
||||
#define OT_DEF_BASIC(AClass) \
|
||||
public: \
|
||||
OT_GEN_DEFAULT_CONSTRUCTOR(AClass) \
|
||||
OT_GEN_COPY_METHOD(AClass) \
|
||||
OT_GEN_ASSIGN(AClass) \
|
||||
OT_DEF_ONLY(AClass)
|
||||
|
||||
/**
|
||||
* Declares automatic OT features for a class for classes that have no
|
||||
* pointers.
|
||||
*
|
||||
* This ensures you have a valid,
|
||||
*/
|
||||
#define OT_DEFAULTS
|
||||
|
||||
/**
|
||||
* Declare automatic OT features for a class, but for classes that have
|
||||
* pointers.
|
||||
*/
|
||||
#define OT_DEFAULTS_PTR
|
||||
|
||||
// Re-think how this is supposed to work.
|
||||
// /**
|
||||
// * Create an automatically-generated print method for your class.
|
||||
// */
|
||||
// #define OT_GENERATE_PRINT(AClass)
|
||||
// public:
|
||||
// template<>
|
||||
// friend void Print(const AClass& obj, FILE *stream) {
|
||||
// OTPrint(obj, stream);
|
||||
// #define OT_GENERATE_PRINT(AClass)
|
||||
// public:
|
||||
// template<>
|
||||
// friend void Print(const AClass& obj, FILE *stream) {
|
||||
// OTPrint(obj, stream);
|
||||
// }
|
||||
|
||||
// TODO: Automatically generate copy constructors and the like
|
||||
@@ -229,87 +310,18 @@ inline void TraverseArray(T* x, index_t n_elems, Visitor *v) {
|
||||
namespace ot_private {
|
||||
// TODO: Space-conservatory serialization and deserialization
|
||||
// (Currently only freezing/thawing is supported)
|
||||
|
||||
// These have to be hoisted out of the class.
|
||||
// Apparently explicit specialization for templates cannot be done in class
|
||||
// scope.
|
||||
|
||||
/** Visits an object with no OT implementation. */
|
||||
/* template<typename DefaultPrinter, typename Printer, typename T>
|
||||
void OTPrinter_Primitive(
|
||||
const char *name, T& x, Printer* printer) {
|
||||
DefaultPrinter::Print(name, x, printer);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, const char* x, Printer* printer) {
|
||||
printer->Write("%s : string = %s", name, x);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, char x, Printer* printer) {
|
||||
if (isprint(x)) {
|
||||
printer->Write("%s : char = %d '%c'", name, x, x);
|
||||
} else {
|
||||
printer->Write("%s : char = %d", name, x);
|
||||
}
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, short x, Printer* printer) {
|
||||
printer->Write("%s : short = %d", name, x);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, int x, Printer* printer) {
|
||||
printer->Write("%s : int = %d", name, x);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, long x, Printer* printer) {
|
||||
printer->Write("%s : long = %ld", name, x);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, unsigned char x, Printer* printer) {
|
||||
printer->Write("%s : uchar = %u", name, x);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, unsigned short x, Printer* printer) {
|
||||
printer->Write("%s : ushort = %u", name, x);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, unsigned int x, Printer* printer) {
|
||||
printer->Write("%s : uint = %u", name, x);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, unsigned long x, Printer* printer) {
|
||||
printer->Write("%s : ulong = %lu", name, x);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, float x, Printer* printer) {
|
||||
printer->Write("%s : float = %f", name, x);
|
||||
}
|
||||
template<typename DefaultPrinter, typename Printer>
|
||||
inline void OTPrinter_Primitive(
|
||||
const char *name, double x, Printer* printer) {
|
||||
printer->Write("%s : double = %f", name, x);
|
||||
}
|
||||
*/
|
||||
|
||||
template<typename DefaultPrinter, typename Printer, typename T>
|
||||
struct OTPrinter_Primitive {
|
||||
struct OTPrinter_Dispatcher {
|
||||
static void Print(const char *name, T& x, Printer* printer) {
|
||||
DefaultPrinter::Print(name, x, printer);
|
||||
}
|
||||
};
|
||||
|
||||
/* macro for use within this file */
|
||||
#define OTPRINTER__SPECIAL(T, format_str) \
|
||||
template<typename DefaultPrinter, typename Printer> \
|
||||
struct OTPrinter_Primitive<DefaultPrinter, Printer, T> { \
|
||||
struct OTPrinter_Dispatcher<DefaultPrinter, Printer, T> { \
|
||||
static void Print(const char *name, T x, Printer *printer) { \
|
||||
printer->Write("%s : "format_str, name, x); \
|
||||
} \
|
||||
@@ -334,7 +346,7 @@ namespace ot_private {
|
||||
FILE *stream_;
|
||||
int indent_amount_;
|
||||
const char *name_;
|
||||
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
struct DefaultPrimitivePrinter {
|
||||
@@ -361,10 +373,11 @@ namespace ot_private {
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
void InitBegin(const T& x, FILE *stream_in) {
|
||||
void Doit(const T& x, FILE *stream_in) {
|
||||
stream_ = stream_in;
|
||||
indent_amount_ = 0;
|
||||
TraverseObject(const_cast<T*>(&x), this);
|
||||
name_ = "<root>";
|
||||
Object(const_cast<T*>(&x), false, "");
|
||||
}
|
||||
|
||||
/** Stores the name of the object going to come in. */
|
||||
@@ -373,7 +386,7 @@ namespace ot_private {
|
||||
}
|
||||
|
||||
template<typename T> void Primitive(T& x) {
|
||||
OTPrinter_Primitive< DefaultPrimitivePrinter<T>, OTPrinter, T >
|
||||
OTPrinter_Dispatcher< DefaultPrimitivePrinter<T>, OTPrinter, T >
|
||||
::Print(name_, x, this);
|
||||
}
|
||||
|
||||
@@ -382,29 +395,27 @@ namespace ot_private {
|
||||
if (nullable && !obj) {
|
||||
Write("%s : %s %s = NULL", name_, label, typeid(T).name());
|
||||
} else {
|
||||
OTPrinter_Primitive< DefaultObjectPrinter<T>, OTPrinter, T >
|
||||
OTPrinter_Dispatcher< DefaultObjectPrinter<T>, OTPrinter, T >
|
||||
::Print(name_, *obj, this);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> void Array(T* array, index_t len,
|
||||
bool nullable) {
|
||||
if (nullable && !array) {
|
||||
Write("%s : %s[] = NULL", name_, typeid(T).name());
|
||||
} else {
|
||||
Write("%s : %s[%"LI"d] = {", name_, typeid(T).name(), len);
|
||||
template<typename T> void Array(T* array, index_t len) {
|
||||
if (array == NULL) {
|
||||
len = 0;
|
||||
}
|
||||
Write("%s : %s[%"LI"d] = {", name_, typeid(T).name(), len);
|
||||
Indent(2);
|
||||
for (index_t i = 0; i < len; i++) {
|
||||
Write("element %"LI"d {", i);
|
||||
Indent(2);
|
||||
for (index_t i = 0; i < len; i++) {
|
||||
Write("element %"LI"d {", i);
|
||||
Indent(2);
|
||||
name_ = "(array element)";
|
||||
TraverseObject(&array[i], this);
|
||||
Indent(-2);
|
||||
Write("}");
|
||||
}
|
||||
name_ = "(array element)";
|
||||
TraverseObject(&array[i], this);
|
||||
Indent(-2);
|
||||
Write("}");
|
||||
}
|
||||
Indent(-2);
|
||||
Write("}");
|
||||
}
|
||||
|
||||
/** Visits an internal object. */
|
||||
@@ -415,7 +426,7 @@ namespace ot_private {
|
||||
/** Visits an array. */
|
||||
template<typename T> void MyArray(T* x, index_t len) {
|
||||
// Recurse in case any of these objects have pointers
|
||||
Array(x, len, false);
|
||||
Array(x, len);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,20 +440,19 @@ namespace ot_private {
|
||||
}
|
||||
|
||||
/** Visits an array pointed to, allocated with malloc */
|
||||
template<typename T> void MallocArray(T*& source_region, index_t len,
|
||||
bool nullable) {
|
||||
Array(source_region, len, nullable);
|
||||
template<typename T> void MallocArray(T*& source_region, index_t len) {
|
||||
Array(source_region, len);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
void Indent(int delta) {
|
||||
indent_amount_ += delta;
|
||||
}
|
||||
|
||||
|
||||
void Write(const char *format, ...);
|
||||
|
||||
|
||||
void ShowIndents();
|
||||
|
||||
|
||||
FILE *stream() const {
|
||||
return stream_;
|
||||
}
|
||||
@@ -476,26 +486,26 @@ namespace ot_private {
|
||||
* being considered.
|
||||
*/
|
||||
ptrdiff_t freeze_offset_;
|
||||
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
void InitBegin(const T& x, char *block_in) {
|
||||
void Doit(const T& x, char *block_in) {
|
||||
block_ = block_in;
|
||||
pos_ = sizeof(T);
|
||||
freeze_offset_ = mem::PointerDiff(block_, &x);
|
||||
|
||||
|
||||
mem::Copy(reinterpret_cast<T*>(block_), &x);
|
||||
// we must cast away const due to TraverseObject's limitations
|
||||
TraverseObject(const_cast<T*>(&x), this);
|
||||
}
|
||||
|
||||
|
||||
size_t size() const {
|
||||
return stride_align_max(pos_);
|
||||
}
|
||||
|
||||
/** Receives the nanme of the upcoming object -- we ignore this. */
|
||||
void Name(const char *s) {}
|
||||
|
||||
|
||||
/** Visits an object with no OT implementation. */
|
||||
template<typename T> void Primitive(T& x) {
|
||||
// Primitives can be bit-copied
|
||||
@@ -526,15 +536,13 @@ namespace ot_private {
|
||||
* This allocates space within the block for the array, copies the
|
||||
* data pointed to, and recurses on the array's elements.
|
||||
*/
|
||||
template<typename T> void Array(T*& source_region, index_t len,
|
||||
bool nullable);
|
||||
template<typename T> void Array(T*& source_region, index_t len);
|
||||
|
||||
/** Visits an array pointed to, allocated with malloc */
|
||||
template<typename T> void MallocArray(T*& source_region, index_t len,
|
||||
bool nullable) {
|
||||
Array(source_region, len, nullable);
|
||||
template<typename T> void MallocArray(T*& source_region, index_t len) {
|
||||
Array(source_region, len);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
/**
|
||||
@@ -603,8 +611,8 @@ namespace ot_private {
|
||||
}
|
||||
|
||||
template<typename T> void OTPointerFreezer::Array(
|
||||
T*& source_region, index_t len, bool nullable) {
|
||||
if (nullable && unlikely(source_region == NULL)) {
|
||||
T*& source_region, index_t len) {
|
||||
if (len == 0) {
|
||||
*DestinationEquivalentPointer_(&source_region) = NULL;
|
||||
} else {
|
||||
// Get the pointer we will write into, and fix our internal pointer
|
||||
@@ -632,7 +640,7 @@ namespace ot_private {
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
void InitBegin(const T& obj) {
|
||||
void Doit(const T& obj) {
|
||||
pos_ = sizeof(T);
|
||||
TraverseObject(const_cast<T*>(&obj), this);
|
||||
}
|
||||
@@ -646,7 +654,7 @@ namespace ot_private {
|
||||
|
||||
/** Receives the nanme of the upcoming object -- we ignore this. */
|
||||
void Name(const char *s) {}
|
||||
|
||||
|
||||
/** visits an object with no OT implementation */
|
||||
template<typename T> void Primitive(T& x) {}
|
||||
/** visits an internal object */
|
||||
@@ -657,7 +665,7 @@ namespace ot_private {
|
||||
template<typename T> void MyArray(T* x, index_t len) {
|
||||
TraverseArray(x, len, this);
|
||||
}
|
||||
|
||||
|
||||
/** visits an object pointed to, allocated with new */
|
||||
template<typename T> void Ptr(T*& x, bool nullable) {
|
||||
if (!nullable || x != NULL) {
|
||||
@@ -666,15 +674,15 @@ namespace ot_private {
|
||||
}
|
||||
}
|
||||
/** visits an array pointed to, allocated with new[] */
|
||||
template<typename T> void Array(T*& x, index_t len, bool nullable) {
|
||||
if (!nullable || x != NULL) {
|
||||
template<typename T> void Array(T*& x, index_t len) {
|
||||
if (len != 0) {
|
||||
PretendLayout_<T>(len);
|
||||
TraverseArray(x, len, this);
|
||||
}
|
||||
}
|
||||
/** visits an array pointed to, allocated with malloc */
|
||||
template<typename T> void MallocArray(T*& x, index_t len, bool nullable) {
|
||||
Array(x, len, nullable);
|
||||
template<typename T> void MallocArray(T*& x, index_t len) {
|
||||
Array(x, len);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -687,24 +695,24 @@ namespace ot_private {
|
||||
class OTPointerThawer {
|
||||
private:
|
||||
ptrdiff_t offset_;
|
||||
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
T* InitBegin(ptrdiff_t offset_in, char *data) {
|
||||
T* Doit(ptrdiff_t offset_in, char *data) {
|
||||
offset_ = offset_in;
|
||||
T* dest = reinterpret_cast<T*>(data);
|
||||
MyObject(*dest);
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
T* InitBegin(char *data) {
|
||||
return InitBegin<T>(data, reinterpret_cast<ptrdiff_t>(data));
|
||||
T* Doit(char *data) {
|
||||
return Doit<T>(data, reinterpret_cast<ptrdiff_t>(data));
|
||||
}
|
||||
|
||||
/** Receives the nanme of the upcoming object -- we ignore this. */
|
||||
void Name(const char *s) {}
|
||||
|
||||
|
||||
/** visits an object with no OT implementation */
|
||||
template<typename T> void Primitive(T& x) {}
|
||||
/** visits an internal object */
|
||||
@@ -726,15 +734,15 @@ namespace ot_private {
|
||||
}
|
||||
}
|
||||
/** visits an array pointed to, allocated with new[] */
|
||||
template<typename T> void Array(T*& x, index_t len, bool nullable) {
|
||||
if (!nullable || x != NULL) {
|
||||
template<typename T> void Array(T*& x, index_t len) {
|
||||
if (len != 0) {
|
||||
x = mem::PointerAdd(x, offset_);
|
||||
MyArray(x, len);
|
||||
}
|
||||
}
|
||||
/** visits an array pointed to, allocated with malloc */
|
||||
template<typename T> void MallocArray(T*& x, index_t len, bool nullable) {
|
||||
Array(x, len, nullable);
|
||||
template<typename T> void MallocArray(T*& x, index_t len) {
|
||||
Array(x, len);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -742,7 +750,7 @@ namespace ot_private {
|
||||
private:
|
||||
ptrdiff_t pre_offset_;
|
||||
ptrdiff_t post_offset_;
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* Fixes pointers.
|
||||
@@ -756,13 +764,13 @@ namespace ot_private {
|
||||
* @param dest the object to recurse on
|
||||
*/
|
||||
template<typename T>
|
||||
T* InitBegin(ptrdiff_t pre_offset_in, ptrdiff_t post_offset_in, T *dest) {
|
||||
T* Doit(ptrdiff_t pre_offset_in, ptrdiff_t post_offset_in, T *dest) {
|
||||
pre_offset_ = pre_offset_in;
|
||||
post_offset_ = post_offset_in;
|
||||
TraverseObject(dest, this);
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
/** Receives the nanme of the upcoming object -- we ignore this. */
|
||||
void Name(const char *s) {}
|
||||
|
||||
@@ -784,17 +792,98 @@ namespace ot_private {
|
||||
}
|
||||
}
|
||||
/** visits an array pointed to, allocated with new[] */
|
||||
template<typename T> void Array(T*& x, index_t len, bool nullable) {
|
||||
if (!nullable || x != NULL) {
|
||||
template<typename T> void Array(T*& x, index_t len) {
|
||||
if (len != 0) {
|
||||
TraverseArray(mem::PointerAdd(x, pre_offset_), len, this);
|
||||
x = mem::PointerAdd(x, post_offset_);
|
||||
}
|
||||
}
|
||||
/** visits an array pointed to, allocated with malloc */
|
||||
template<typename T> void MallocArray(T*& x, index_t len, bool nullable) {
|
||||
Array(x, len, nullable);
|
||||
template<typename T> void MallocArray(T*& x, index_t len) {
|
||||
Array(x, len);
|
||||
}
|
||||
};
|
||||
|
||||
struct OTDeepCopier {
|
||||
public:
|
||||
/** Receives the nanme of the upcoming object -- we ignore this. */
|
||||
void Name(const char *s) {}
|
||||
|
||||
/** visits an object with no OT implementation */
|
||||
template<typename T> void Primitive(T& x) {}
|
||||
/** visits an internal object */
|
||||
template<typename T> void MyObject(T& x) {
|
||||
TraverseObject(&x, this);
|
||||
}
|
||||
/** visits an array */
|
||||
template<typename T> void MyArray(T* x, index_t len) {
|
||||
TraverseArray(x, len, this);
|
||||
}
|
||||
/** visits an object pointed to, allocated with new */
|
||||
template<typename T> void Ptr(T*& x, bool nullable) {
|
||||
if (!nullable || x != NULL) {
|
||||
x = new T(*x);
|
||||
}
|
||||
}
|
||||
/** visits an array pointed to, allocated with new[] */
|
||||
template<typename T> void Array(T*& x, index_t len) {
|
||||
x = mem::CopyConstruct(new T[len], x, len);
|
||||
}
|
||||
/** visits an array pointed to, allocated with malloc */
|
||||
template<typename T> void MallocArray(T*& x, index_t len) {
|
||||
x = mem::CopyConstruct(mem::Alloc<T>(len), x, len);
|
||||
}
|
||||
};
|
||||
|
||||
struct OTDestructor {
|
||||
public:
|
||||
/** Receives the nanme of the upcoming object -- we ignore this. */
|
||||
void Name(const char *s) {}
|
||||
|
||||
/** visits an object with no OT implementation */
|
||||
template<typename T> void Primitive(T& x) {}
|
||||
/** visits an internal object */
|
||||
template<typename T> void MyObject(T& x) {
|
||||
// C++ will automatically chain this
|
||||
}
|
||||
/** visits an array */
|
||||
template<typename T> void MyArray(T* x, index_t len) {
|
||||
// C++ will automatically chain this
|
||||
}
|
||||
/** visits an object pointed to, allocated with new */
|
||||
template<typename T> void Ptr(T*& x, bool nullable) {
|
||||
if (!nullable || x != NULL) {
|
||||
delete x;
|
||||
}
|
||||
DEBUG_POISON_PTR(x);
|
||||
}
|
||||
/** visits an array pointed to, allocated with new[] */
|
||||
template<typename T> void Array(T*& x, index_t len, bool nullable) {
|
||||
delete[] x;
|
||||
DEBUG_POISON_PTR(x);
|
||||
}
|
||||
/** visits an array pointed to, allocated with malloc */
|
||||
template<typename T> void MallocArray(T*& x, index_t len) {
|
||||
T *tmpx = x;
|
||||
mem::DestructAll(tmpx, len);
|
||||
mem::Free(tmpx);
|
||||
DEBUG_POISON_PTR(x);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void DestructorImplementation(T *dest) {
|
||||
ot_private::OTDestructor d;
|
||||
TraverseObject(dest, &d);
|
||||
// can't poison this because of destructor chanining
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void DeepCopyImplementation(const T& src, T *dest) {
|
||||
ot_private::OTDeepCopier d;
|
||||
mem::Copy(dest, &src, 1);
|
||||
TraverseObject(dest, &d);
|
||||
}
|
||||
}; // namespace ot_private
|
||||
|
||||
namespace ot {
|
||||
@@ -807,7 +896,7 @@ namespace ot {
|
||||
template<typename T>
|
||||
void Print(const T& object, FILE *stream = stderr) {
|
||||
ot_private::OTPrinter printer;
|
||||
printer.InitBegin(object, stream);
|
||||
printer.Doit(object, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -826,7 +915,7 @@ namespace ot {
|
||||
const char *PrintMsg(const T& object, const char *message) {
|
||||
ot_private::OTPrinter printer;
|
||||
fprintf(stderr, ANSI_HRED"---- PRINTING %s ----"ANSI_CLEAR"\n", message);
|
||||
printer.InitBegin(object, stderr);
|
||||
printer.Doit(object, stderr);
|
||||
return message;
|
||||
}
|
||||
|
||||
@@ -836,7 +925,7 @@ namespace ot {
|
||||
template<typename T>
|
||||
size_t PointerFrozenSize(const T& obj) {
|
||||
ot_private::OTFrozenSizeCalculator calc;
|
||||
calc.InitBegin(obj);
|
||||
calc.Doit(obj);
|
||||
return calc.size();
|
||||
}
|
||||
|
||||
@@ -846,7 +935,7 @@ namespace ot {
|
||||
template<typename T>
|
||||
void PointerFreeze(const T& live_object, char *block) {
|
||||
ot_private::OTPointerFreezer freezer;
|
||||
freezer.InitBegin(live_object, block);
|
||||
freezer.Doit(live_object, block);
|
||||
DEBUG_SAME_INT(freezer.size(), ot::PointerFrozenSize(live_object));
|
||||
}
|
||||
|
||||
@@ -857,7 +946,7 @@ namespace ot {
|
||||
template<typename T>
|
||||
void PointerRefreeze(T* obj) {
|
||||
ot_private::OTPointerRelocator fixer;
|
||||
fixer.InitBegin<T>(
|
||||
fixer.Doit<T>(
|
||||
0, -mem::PointerAbsoluteAddress(obj),
|
||||
reinterpret_cast<T*>(obj));
|
||||
}
|
||||
@@ -875,7 +964,7 @@ namespace ot {
|
||||
template<typename T>
|
||||
void PointerRefreeze(const T* src, char* dest) {
|
||||
ot_private::OTPointerRelocator fixer;
|
||||
fixer.InitBegin<T>(
|
||||
fixer.Doit<T>(
|
||||
mem::PointerDiff(dest, src), -mem::PointerAbsoluteAddress(src),
|
||||
reinterpret_cast<T*>(dest));
|
||||
}
|
||||
@@ -890,7 +979,7 @@ namespace ot {
|
||||
template<typename T>
|
||||
T* PointerThaw(char *block) {
|
||||
ot_private::OTPointerThawer fixer;
|
||||
return fixer.InitBegin<T>(
|
||||
return fixer.Doit<T>(
|
||||
mem::PointerAbsoluteAddress(block),
|
||||
block);
|
||||
}
|
||||
@@ -903,11 +992,19 @@ namespace ot {
|
||||
template<typename T>
|
||||
void PointerRelocate(const char *old_location, char *new_location) {
|
||||
ot_private::OTPointerRelocator fixer;
|
||||
fixer.InitBegin<T>(
|
||||
fixer.Doit<T>(
|
||||
mem::PointerDiff(new_location, old_location),
|
||||
mem::PointerDiff(new_location, old_location),
|
||||
reinterpret_cast<T*>(new_location));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep-copy initializer for OT-compliant classes.
|
||||
*/
|
||||
template<typename T>
|
||||
void Copy(const T& src, T* dest) {
|
||||
new(dest)T(src);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+2
-25
@@ -66,9 +66,9 @@ class ArrayList {
|
||||
index_t size_;
|
||||
index_t cap_;
|
||||
|
||||
OT_DEF(ArrayList) {
|
||||
OT_DEF_ONLY(ArrayList) {
|
||||
OT_MY_OBJECT(size_);
|
||||
OT_MALLOC_ARRAY_NULLABLE(ptr_, size_);
|
||||
OT_MALLOC_ARRAY(ptr_, size_);
|
||||
}
|
||||
|
||||
OT_FIX(ArrayList) {
|
||||
@@ -298,29 +298,6 @@ class ArrayList {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this arraylist.
|
||||
*
|
||||
* Currently only works for things that are bit-copiable, containing no
|
||||
* pointers.
|
||||
*/
|
||||
template<typename Serializer>
|
||||
void Serialize(Serializer *s) const {
|
||||
s->Put(size_);
|
||||
s->Put(ptr_, size_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this list, deserializing from the given source.
|
||||
*/
|
||||
template<typename Deserializer>
|
||||
void Deserialize(Deserializer *s) {
|
||||
s->Get(&size_);
|
||||
cap_ = size_;
|
||||
ptr_ = mem::Alloc<Element>(cap_);
|
||||
s->Get(ptr_, size_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to shrink the ArrayList.
|
||||
*/
|
||||
|
||||
@@ -9,11 +9,11 @@ librule(
|
||||
binrule(
|
||||
name = "col_test",
|
||||
sources = ["col_test.cc"],
|
||||
linkables = [":col"])
|
||||
deplibs = [":col"])
|
||||
|
||||
|
||||
binrule(
|
||||
name = "timing_test",
|
||||
sources = ["timing_test.cc"],
|
||||
linkables = [":col", "fx:fx"])
|
||||
deplibs = [":col", "fx:fx"])
|
||||
|
||||
|
||||
+1
-42
@@ -35,22 +35,11 @@ class MinHeap {
|
||||
|
||||
ArrayList<Entry> entries_;
|
||||
|
||||
OT_DEF(MinHeap) {
|
||||
OT_DEF_BASIC(MinHeap) {
|
||||
OT_MY_OBJECT(entries_);
|
||||
}
|
||||
|
||||
public:
|
||||
MinHeap() {}
|
||||
~MinHeap() {}
|
||||
|
||||
/**
|
||||
* Copy constructor (for use in collections only!).
|
||||
*/
|
||||
MinHeap(const MinHeap& other) {
|
||||
Copy(other);
|
||||
}
|
||||
CC_ASSIGNMENT_OPERATOR(MinHeap);
|
||||
|
||||
/**
|
||||
* Initializes an empty priority queue.
|
||||
*/
|
||||
@@ -64,29 +53,6 @@ class MinHeap {
|
||||
bool is_empty() const {
|
||||
return entries_.size() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this heap.
|
||||
*
|
||||
* Currently only works for things that are bit-copiable, containing no
|
||||
* pointers.
|
||||
*
|
||||
* @deprecated Use otrav instead.
|
||||
*/
|
||||
template<typename Serializer>
|
||||
void Serialize(Serializer *s) const {
|
||||
entries_.Serialize(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this heap, deserializing from the given source.
|
||||
*
|
||||
* @deprecated Use otrav instead.
|
||||
*/
|
||||
template<typename Deserializer>
|
||||
void Deserialize(Deserializer *s) {
|
||||
entries_.Deserialize(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Places a value at the specified priority.
|
||||
@@ -160,13 +126,6 @@ class MinHeap {
|
||||
return entries_.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies another MinHeap.
|
||||
*/
|
||||
void Copy(const MinHeap& other) {
|
||||
entries_.Copy(other.entries_);
|
||||
}
|
||||
|
||||
private:
|
||||
static index_t ChildIndex_(index_t i) {
|
||||
return (i << 1) + 1;
|
||||
|
||||
+37
-10
@@ -4,10 +4,18 @@
|
||||
* Dense integer-to-value map.
|
||||
*/
|
||||
|
||||
#ifndef COL_INTMAP_H
|
||||
#define COL_INTMAP_H
|
||||
|
||||
#include "base/common.h"
|
||||
#include "base/ccmem.h"
|
||||
#include "base/otrav.h"
|
||||
|
||||
/**
|
||||
* A dense grow-as-needed array that serves as an integer-keyed map.
|
||||
*/
|
||||
template<class TValue>
|
||||
class DenseIntMap {
|
||||
FORBID_COPY(DenseIntMap);
|
||||
|
||||
public:
|
||||
typedef TValue Value;
|
||||
|
||||
@@ -16,32 +24,43 @@ class DenseIntMap {
|
||||
index_t size_;
|
||||
Value default_value_;
|
||||
|
||||
public:
|
||||
DenseIntMap() {
|
||||
DEBUG_POISON_PTR(ptr_);
|
||||
size_ = BIG_BAD_NUMBER;
|
||||
}
|
||||
~DenseIntMap() {
|
||||
DEBUG_ASSERT(size_ != BIG_BAD_NUMBER);
|
||||
mem::Free(ptr_);
|
||||
OT_DEF(DenseIntMap) {
|
||||
OT_MY_OBJECT(size_);
|
||||
OT_MY_OBJECT(default_value_);
|
||||
OT_MALLOC_ARRAY(ptr_, size_);
|
||||
}
|
||||
|
||||
public:
|
||||
/** Creates a blank mapping. */
|
||||
void Init() {
|
||||
ptr_ = NULL;
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
/** Accesses the default value. Use this to set it. */
|
||||
Value& default_value() {
|
||||
return default_value_;
|
||||
}
|
||||
/** Accesses the default value. */
|
||||
const Value& default_value() const {
|
||||
return default_value_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-inclusive upper bound on the last non-default element.
|
||||
*
|
||||
* Iterating up to size() is guaranteed to hit all elements without
|
||||
* growing the internal array.
|
||||
*/
|
||||
index_t size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses an element, expanding if necessary.
|
||||
*
|
||||
* If you are just probing, beware that this might actually grow the array!
|
||||
*/
|
||||
Value& operator [] (index_t index) {
|
||||
DEBUG_BOUNDS(index, BIG_BAD_NUMBER);
|
||||
if (unlikely(index >= size_)) {
|
||||
@@ -54,9 +73,15 @@ class DenseIntMap {
|
||||
}
|
||||
return ptr_[index];
|
||||
}
|
||||
/**
|
||||
* Accesses an element from a static context.
|
||||
*/
|
||||
const Value& operator [] (index_t index) const {
|
||||
return get(index);
|
||||
}
|
||||
/**
|
||||
* Accesses an element, never growing the internal representation.
|
||||
*/
|
||||
const Value& get(index_t index) const {
|
||||
DEBUG_BOUNDS(index, BIG_BAD_NUMBER);
|
||||
if (likely(index < size_)) {
|
||||
@@ -66,3 +91,5 @@ class DenseIntMap {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
template<typename T>
|
||||
class Queue {
|
||||
FORBID_COPY(Queue); // No copy constructor defined (yet)
|
||||
|
||||
private:
|
||||
struct Node {
|
||||
T data;
|
||||
|
||||
@@ -21,7 +21,7 @@ class RangeSet {
|
||||
Boundary begin;
|
||||
Boundary end;
|
||||
|
||||
OT_DEF(Range) {
|
||||
OT_DEF_BASIC(Range) {
|
||||
OT_MY_OBJECT(begin);
|
||||
OT_MY_OBJECT(end);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ class RangeSet {
|
||||
// replace the list
|
||||
ranges_.Swap(&new_list);
|
||||
}
|
||||
|
||||
|
||||
const ArrayList<Range>& ranges() const {
|
||||
return ranges_;
|
||||
}
|
||||
|
||||
+1
-14
@@ -30,19 +30,11 @@ class String {
|
||||
private:
|
||||
ArrayList<char> array_;
|
||||
|
||||
OT_DEF(String) {
|
||||
OT_DEF_BASIC(String) {
|
||||
OT_MY_OBJECT(array_);
|
||||
}
|
||||
|
||||
public:
|
||||
String() {}
|
||||
~String() {}
|
||||
|
||||
String(const String& other) {
|
||||
Copy(other);
|
||||
}
|
||||
CC_ASSIGNMENT_OPERATOR(String);
|
||||
|
||||
/**
|
||||
* Implicit conversion constructor.
|
||||
*/
|
||||
@@ -74,11 +66,6 @@ class String {
|
||||
COMPILER_PRINTF(2, 3)
|
||||
const String& InitSprintf(const char *format, ...);
|
||||
|
||||
/** Copies another string. */
|
||||
void Copy(const String& other) {
|
||||
array_.Copy(other.array_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes as a copy of an existing region of characters.
|
||||
* The existing array does not need to be null terminated.
|
||||
|
||||
@@ -7,5 +7,5 @@ librule(
|
||||
binrule(
|
||||
name = "dataset_test",
|
||||
sources = ["dataset_test.cc"],
|
||||
linkables = [":data", "fx:fx", "math:math"])
|
||||
deplibs = [":data", "fx:fx", "math:math"])
|
||||
|
||||
|
||||
@@ -48,9 +48,6 @@ class DatasetFeature {
|
||||
}
|
||||
|
||||
public:
|
||||
DatasetFeature() {}
|
||||
~DatasetFeature() {}
|
||||
|
||||
/**
|
||||
* Initialize to be a continuous feature.
|
||||
*
|
||||
@@ -172,8 +169,6 @@ class DatasetFeature {
|
||||
* Information describing a dataset and its features.
|
||||
*/
|
||||
class DatasetInfo {
|
||||
FORBID_COPY(DatasetInfo);
|
||||
|
||||
private:
|
||||
String name_;
|
||||
ArrayList<DatasetFeature> features_;
|
||||
@@ -184,9 +179,6 @@ class DatasetInfo {
|
||||
}
|
||||
|
||||
public:
|
||||
DatasetInfo() {}
|
||||
~DatasetInfo() {}
|
||||
|
||||
/** Gets a mutable list of all features. */
|
||||
ArrayList<DatasetFeature>& features() {
|
||||
return features_;
|
||||
@@ -315,17 +307,7 @@ class DatasetInfo {
|
||||
success_t ReadPoint(TextLineReader *reader, double *point,
|
||||
bool *is_done) const;
|
||||
|
||||
/**
|
||||
* Initializes to be a copy.
|
||||
* @param other data set feature information to copy
|
||||
*/
|
||||
void Copy(const DatasetInfo& other) {
|
||||
name_.Copy(other.name_);
|
||||
features_.Copy(other.features_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
char *SkipSpace_(char *s);
|
||||
|
||||
char *SkipNonspace_(char *s);
|
||||
@@ -347,8 +329,6 @@ class DatasetInfo {
|
||||
* may be an issue, especially if this is Boolean data.)
|
||||
*/
|
||||
class Dataset {
|
||||
FORBID_COPY(Dataset);
|
||||
|
||||
private:
|
||||
Matrix matrix_;
|
||||
DatasetInfo info_;
|
||||
@@ -359,9 +339,6 @@ class Dataset {
|
||||
}
|
||||
|
||||
public:
|
||||
Dataset() {}
|
||||
~Dataset() {}
|
||||
|
||||
/**
|
||||
* Metadata about the feature types and names for the dataset.
|
||||
*
|
||||
|
||||
@@ -21,4 +21,4 @@ librule(
|
||||
binrule(
|
||||
name = "otrav_test",
|
||||
sources = ["otrav_test.cc"],
|
||||
linkables = [":fastlib_int"])
|
||||
deplibs = [":fastlib_int"])
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "data/dataset.h"
|
||||
#include "data/crossvalidation.h"
|
||||
#include "math/math.h"
|
||||
#include "file/serialize.h"
|
||||
#include "file/textfile.h"
|
||||
#include "fx/fx.h"
|
||||
|
||||
|
||||
@@ -38,4 +38,16 @@ void TestDatasetLayout() {
|
||||
d3->WriteArff("test_dataset_layout.arff");
|
||||
}
|
||||
|
||||
TEST_SUITE_END(otrav, TestDatasetPrint, TestDatasetLayout)
|
||||
void TestCopy() {
|
||||
Dataset *d = new Dataset;
|
||||
|
||||
d->InitFromFile("fake.arff");
|
||||
|
||||
Dataset d2(*d);
|
||||
|
||||
delete d;
|
||||
|
||||
d2.WriteArff("test_dataset_copy.arff");
|
||||
}
|
||||
|
||||
TEST_SUITE_END(otrav, TestDatasetPrint, TestDatasetLayout, TestCopy)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
librule(
|
||||
sources = ["textfile.cc", "serialize.cc"],
|
||||
headers = ["textfile.h", "serialize.h"],
|
||||
sources = ["textfile.cc"],
|
||||
headers = ["textfile.h"],
|
||||
deplibs = ["base:base", "col:col"],
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ librule(
|
||||
binrule(
|
||||
name = "textfile_test",
|
||||
sources = ["textfile_test.cc"],
|
||||
linkables = [":file", "fx:fx"]
|
||||
deplibs = [":file", "fx:fx"]
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* @file serialize.cc
|
||||
*
|
||||
* Definitions for serialization methods.
|
||||
*/
|
||||
|
||||
#include "serialize.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
file::magic_t file::CreateMagic(const char *str) {
|
||||
magic_t magic = 0x31415926;
|
||||
|
||||
for (; *str != '\0'; str++) {
|
||||
magic = (magic << 9) + (magic >> 11) + *str;
|
||||
}
|
||||
|
||||
return magic;
|
||||
}
|
||||
|
||||
success_t NativeArraySerializer::WriteFile(const char *fname) {
|
||||
FILE *f = fopen(fname, "wb");
|
||||
|
||||
if (unlikely(!f)) {
|
||||
return SUCCESS_FAIL;
|
||||
}
|
||||
|
||||
if (unlikely(index_t(fwrite(ptr(), 1, size(), f)) != index_t(size()))) {
|
||||
(void) fclose(f);
|
||||
return SUCCESS_FAIL;
|
||||
}
|
||||
|
||||
return SUCCESS_FROM_INT(fclose(f));
|
||||
}
|
||||
|
||||
success_t NativeFileDeserializer::Init(const char *fname) {
|
||||
struct stat info;
|
||||
FILE *f;
|
||||
size_t file_size;
|
||||
char *data;
|
||||
|
||||
DEBUG_MSG(1.0, "Opening a native file deserializer.");
|
||||
|
||||
if (unlikely(stat(fname, &info) < 0)) {
|
||||
NONFATAL("File [%s] does not exist.", fname);
|
||||
data = NULL;
|
||||
} else {
|
||||
f = fopen(fname, "rb");
|
||||
|
||||
if (unlikely(!f)) {
|
||||
data = NULL;
|
||||
NONFATAL("Cannot read [%s], but it exists.", fname);
|
||||
} else {
|
||||
file_size = size_t(info.st_size);
|
||||
data = mem::Alloc<char>(file_size);
|
||||
|
||||
if (unlikely(fread(data, 1, file_size, f) != file_size)) {
|
||||
mem::Free(data);
|
||||
data = NULL;
|
||||
NONFATAL("Error reading contents of [%s].", fname);
|
||||
}
|
||||
|
||||
(void) fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (data == NULL) {
|
||||
// We have to initialize this into a valid state, or else the program
|
||||
// will segfault.
|
||||
file_size = 0;
|
||||
}
|
||||
|
||||
NativeArrayDeserializer::Init(data, file_size);
|
||||
|
||||
return (data != NULL) ? SUCCESS_PASS : SUCCESS_FAIL;
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
// Copyright 2007 Georgia Institute of Technology. All rights reserved.
|
||||
// ABSOLUTELY NOT FOR DISTRIBUTION
|
||||
/**
|
||||
* @file serialize.h
|
||||
*
|
||||
* Tools for serialization.
|
||||
*
|
||||
* See NativeArraySerializer and NativeArrayDeserializer for an example of
|
||||
* the Serializer and Deserializer "concepts".
|
||||
*
|
||||
* WARNING: This has been only casually tested, not thoroughly tested.
|
||||
* Use at your own risk.
|
||||
*/
|
||||
|
||||
#ifndef FILE_SERIALIZE_H
|
||||
#define FILE_SERIALIZE_H
|
||||
|
||||
#include "base/common.h"
|
||||
#include "base/ccmem.h"
|
||||
#include "col/arraylist.h"
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
namespace file {
|
||||
/**
|
||||
* Magic number type.
|
||||
*/
|
||||
typedef uint32 magic_t;
|
||||
|
||||
/**
|
||||
* Automatically creates a magic number by hashing the
|
||||
* string.
|
||||
*/
|
||||
magic_t CreateMagic(const char *str);
|
||||
};
|
||||
|
||||
/**
|
||||
* Automatically creates a magic number for a class.
|
||||
*
|
||||
* This is especially useful if you have a templated class.
|
||||
* You can add other magic numbers to it if you want the number to be
|
||||
* more specific, like MAGIC_NUMBER(a) + MAGIC_NUMBER(b).
|
||||
*
|
||||
* @param classname the name of the class
|
||||
*/
|
||||
#define MAGIC_NUMBER(classname) \
|
||||
(file::CreateMagic(typeid(classname).name()))
|
||||
|
||||
/**
|
||||
* Use this to serialize a stream of objects in an array.
|
||||
*
|
||||
* Useful before sending canonical versions over MPI, or to a file.
|
||||
*
|
||||
* The computer reading this should use the same CPU type.
|
||||
* In particular, the type sizes and byte order must remain the same.
|
||||
*
|
||||
* Only primitives or structs of primitives should be stored; in
|
||||
* particular, no pointers.
|
||||
*
|
||||
* TODO: More complicated serializers (like text serializers) later
|
||||
* might have a slight problem with serializing structs. Come back
|
||||
* later for info. Maybe we'll decide against text serializers.
|
||||
*/
|
||||
class NativeArraySerializer {
|
||||
FORBID_COPY(NativeArraySerializer);
|
||||
|
||||
private:
|
||||
ArrayList<char> data_;
|
||||
|
||||
public:
|
||||
NativeArraySerializer() {}
|
||||
~NativeArraySerializer() {}
|
||||
|
||||
void Init() {
|
||||
data_.Init();
|
||||
}
|
||||
|
||||
void PutMagic(file::magic_t magic_num) {
|
||||
Put(magic_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a struct or primitive to the end.
|
||||
*
|
||||
* This will store the object bit-by-bit, so don't store any
|
||||
* pointers.
|
||||
*/
|
||||
template<typename T>
|
||||
void Put(const T& val) {
|
||||
mem::CopyBytes(data_.AddBack(sizeof(T)), &val, sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an array of structs or primtives to the end.
|
||||
*
|
||||
* This will store the object bit-by-bit, so don't store any
|
||||
* pointers.
|
||||
*/
|
||||
template<typename T>
|
||||
void Put(const T* array, index_t count) {
|
||||
size_t bytes = count * sizeof(T);
|
||||
mem::CopyBytes(data_.AddBack(bytes), array, bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an array of non-primitives to the end.
|
||||
*/
|
||||
template<typename T>
|
||||
void Serialize(const T* array, index_t count) {
|
||||
for (index_t i = 0; i < count; i++) {
|
||||
array[i].Serialize(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data serialized, clearing the internal
|
||||
* state of this serializer.
|
||||
*
|
||||
* The pointer must eventually be freed with mem::Free.
|
||||
*
|
||||
* @return a pointer that can later be passed to deserializer
|
||||
*/
|
||||
char *ReleasePointer() {
|
||||
data_.Trim();
|
||||
return data_.ReleasePointer();
|
||||
}
|
||||
|
||||
const char *ptr() const {
|
||||
return data_.begin();
|
||||
}
|
||||
|
||||
index_t size() const {
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps to a file.
|
||||
*/
|
||||
success_t WriteFile(const char *fname);
|
||||
};
|
||||
|
||||
/**
|
||||
* Use this to deserialize a stream created by NativeArraySerializer.
|
||||
*
|
||||
* This computer should use the same architecture as was used to seralize.
|
||||
* Specifically, the type sizes and byte order must be identical.
|
||||
*/
|
||||
class NativeArrayDeserializer {
|
||||
private:
|
||||
const char *ptr_;
|
||||
index_t pos_;
|
||||
index_t size_;
|
||||
|
||||
public:
|
||||
NativeArrayDeserializer() {
|
||||
DEBUG_POISON_PTR(ptr_);
|
||||
}
|
||||
~NativeArrayDeserializer() {}
|
||||
|
||||
/**
|
||||
* Initializes given a pointer.
|
||||
*
|
||||
* The pointer will not be freed.
|
||||
*/
|
||||
void Init(const char *ptr_in, index_t size_in) {
|
||||
ptr_ = ptr_in;
|
||||
size_ = size_in;
|
||||
pos_ = 0;
|
||||
}
|
||||
|
||||
success_t CheckMagic(file::magic_t magic_num) {
|
||||
file::magic_t x;
|
||||
Get(&x);
|
||||
return likely(x == magic_num) ? SUCCESS_PASS : SUCCESS_FAIL;
|
||||
}
|
||||
|
||||
void AssertMagic(file::magic_t magic_num) {
|
||||
file::magic_t x;
|
||||
Get(&x);
|
||||
assert(x == magic_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next struct or primtiive.
|
||||
*/
|
||||
template<typename T>
|
||||
void Get(T *dest) {
|
||||
DEBUG_ASSERT(size_t(pos_ + sizeof(T)) <= size_t(size_));
|
||||
mem::CopyBytes(dest, ptr_ + pos_, sizeof(T));
|
||||
pos_ += sizeof(T);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next array of structs or primitives.
|
||||
*/
|
||||
template<typename T>
|
||||
void Get(T *dest, index_t count) {
|
||||
size_t bytes = count * sizeof(T);
|
||||
DEBUG_ASSERT(index_t(pos_ + bytes) <= index_t(size_));
|
||||
mem::CopyBytes(dest, ptr_ + pos_, bytes);
|
||||
pos_ += bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an array of Serializables.
|
||||
*/
|
||||
template<typename T>
|
||||
void Deserialize(T *dest, index_t count) {
|
||||
for (index_t i = 0; i < count; i++) {
|
||||
dest[i].Deserialize(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether finished.
|
||||
*
|
||||
* You are not recommended to use this; store counts instead.
|
||||
*
|
||||
* @return true iff there is no data remaining
|
||||
*/
|
||||
bool done() const {
|
||||
return pos_ == size_;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
size_t pos() const {
|
||||
return pos_;
|
||||
}
|
||||
|
||||
const char *ptr() const {
|
||||
return ptr_;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deserializer from a file.
|
||||
*
|
||||
* NOTE: This currently uses a NativeArrayDeserializer, but in the future
|
||||
* may use buffering.
|
||||
*/
|
||||
class NativeFileDeserializer : public NativeArrayDeserializer {
|
||||
public:
|
||||
NativeFileDeserializer() {}
|
||||
~NativeFileDeserializer() {
|
||||
mem::Free(const_cast<char*>(ptr()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes by reading the entire file into memory.
|
||||
*/
|
||||
success_t Init(const char *fname);
|
||||
};
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -50,10 +50,10 @@ librule(
|
||||
binrule(
|
||||
name = "uselapack_test",
|
||||
sources = ["uselapack_test.cc"],
|
||||
linkables = [":la"])
|
||||
deplibs = [":la"])
|
||||
|
||||
binrule(
|
||||
name = "la_test",
|
||||
sources = ["la_test.cc"],
|
||||
headers = [],
|
||||
linkables = [":la"])
|
||||
deplibs = [":la"])
|
||||
|
||||
+5
-37
@@ -51,7 +51,7 @@ class Vector {
|
||||
/** Whether this should be freed, i.e. it is not an alias. */
|
||||
bool should_free_;
|
||||
|
||||
OT_DEF(Vector) {
|
||||
OT_DEF_ONLY(Vector) {
|
||||
OT_MY_OBJECT(length_);
|
||||
OT_MALLOC_ARRAY(ptr_, length_);
|
||||
}
|
||||
@@ -201,21 +201,6 @@ class Vector {
|
||||
should_free_ = true;
|
||||
}
|
||||
|
||||
template<typename Serializer>
|
||||
void Serialize(Serializer *s) const {
|
||||
s->Put(length_);
|
||||
s->Put(ptr_, length_);
|
||||
}
|
||||
|
||||
template<typename Deserializer>
|
||||
void Deserialize(Deserializer *s) {
|
||||
DEBUG_ONLY(AssertUninitialized_());
|
||||
s->Get(&length_);
|
||||
ptr_ = mem::Alloc<double>(length_);
|
||||
s->Get(ptr_, length_);
|
||||
should_free_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an uninitialized vector as an alias to a a sub-region
|
||||
* of this vector.
|
||||
@@ -365,13 +350,13 @@ class Matrix {
|
||||
index_t n_cols_;
|
||||
/** Whether I am a strong copy (not an alias). */
|
||||
bool should_free_;
|
||||
|
||||
OT_DEF(Matrix) {
|
||||
|
||||
OT_DEF_ONLY(Matrix) {
|
||||
OT_MY_OBJECT(n_rows_);
|
||||
OT_MY_OBJECT(n_cols_);
|
||||
OT_MALLOC_ARRAY(ptr_, n_elements());
|
||||
}
|
||||
|
||||
|
||||
OT_FIX(Matrix) {
|
||||
should_free_ = true;
|
||||
}
|
||||
@@ -577,24 +562,7 @@ class Matrix {
|
||||
n_cols_ = n_cols_in;
|
||||
should_free_ = true;
|
||||
}
|
||||
|
||||
template<typename Serializer>
|
||||
void Serialize(Serializer *s) const {
|
||||
s->Put(n_rows_);
|
||||
s->Put(n_cols_);
|
||||
s->Put(ptr_, n_elements());
|
||||
}
|
||||
|
||||
template<typename Deserializer>
|
||||
void Deserialize(Deserializer *s) {
|
||||
DEBUG_ONLY(AssertUninitialized_());
|
||||
s->Get(&n_rows_);
|
||||
s->Get(&n_cols_);
|
||||
ptr_ = mem::Alloc<double>(n_elements());
|
||||
s->Get(ptr_, n_elements());
|
||||
should_free_ = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a matrix that is an alias of a particular slice of my columns.
|
||||
*
|
||||
|
||||
@@ -273,9 +273,10 @@ void TestVector() {
|
||||
TEST_ASSERT(v8[3] == 3);
|
||||
MakeConstantVector(10, 3.5, &v9);
|
||||
TEST_ASSERT(v9[0] == 3.5);
|
||||
TEST_ASSERT(v1[0] == 0.0);
|
||||
v9.SwapValues(&v1);
|
||||
TEST_DOUBLE_EXACT(v1[0], 3.5);
|
||||
TEST_ASSERT(v9[0] == 0.0);
|
||||
TEST_ASSERT(v1[0] == 3.5);
|
||||
TEST_ASSERT(v2[0] == 3.5);
|
||||
TEST_ASSERT(v3[0] == 3.5);
|
||||
TEST_ASSERT(v4[0] != 3.5);
|
||||
|
||||
@@ -8,5 +8,5 @@ librule(
|
||||
binrule(
|
||||
name = "math_test",
|
||||
sources = ["math_test.cc"],
|
||||
linkables = [":math"])
|
||||
deplibs = [":math"])
|
||||
|
||||
|
||||
+2
-18
@@ -25,7 +25,7 @@ struct GaussianKernel {
|
||||
private:
|
||||
double inv_bandwidth_2sq_;
|
||||
|
||||
OT_DEF(GaussianKernel) {
|
||||
OT_DEF_BASIC(GaussianKernel) {
|
||||
OT_MY_OBJECT(inv_bandwidth_2sq_);
|
||||
}
|
||||
|
||||
@@ -33,10 +33,6 @@ struct GaussianKernel {
|
||||
static const bool HAS_CUTOFF = false;
|
||||
|
||||
public:
|
||||
GaussianKernel() {}
|
||||
~GaussianKernel() {}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes to a specific bandwidth.
|
||||
*
|
||||
@@ -46,10 +42,6 @@ struct GaussianKernel {
|
||||
inv_bandwidth_2sq_ = 1.0 / (2.0 * bandwidth_in * bandwidth_in);
|
||||
}
|
||||
|
||||
void Copy(const GaussianKernel& other) {
|
||||
inv_bandwidth_2sq_ = other.inv_bandwidth_2sq_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates an unnormalized density, given the distance between
|
||||
* the kernel's mean and a query point.
|
||||
@@ -93,7 +85,7 @@ struct EpanKernel {
|
||||
double inv_bandwidth_sq_;
|
||||
double bandwidth_sq_;
|
||||
|
||||
OT_DEF(EpanKernel) {
|
||||
OT_DEF_BASIC(EpanKernel) {
|
||||
OT_MY_OBJECT(inv_bandwidth_sq_);
|
||||
OT_MY_OBJECT(bandwidth_sq_);
|
||||
}
|
||||
@@ -102,9 +94,6 @@ struct EpanKernel {
|
||||
static const bool HAS_CUTOFF = true;
|
||||
|
||||
public:
|
||||
EpanKernel() {}
|
||||
~EpanKernel() {}
|
||||
|
||||
/**
|
||||
* Initializes to a specific bandwidth.
|
||||
*/
|
||||
@@ -113,11 +102,6 @@ struct EpanKernel {
|
||||
inv_bandwidth_sq_ = 1.0 / bandwidth_sq_;
|
||||
}
|
||||
|
||||
void Copy(const EpanKernel& other) {
|
||||
bandwidth_sq_ = other.bandwidth_sq_;
|
||||
inv_bandwidth_sq_ = other.inv_bandwidth_sq_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates an unnormalized density, given the distance between
|
||||
* the kernel's mean and a query point.
|
||||
|
||||
@@ -209,6 +209,65 @@ namespace math {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A value which is the min or max of multiple other values.
|
||||
*
|
||||
* Comes with a highly optimized version of x = max(x, y).
|
||||
*
|
||||
* The template argument should be something like double, with greater-than,
|
||||
* less-than, and equals operators.
|
||||
*/
|
||||
template<typename TValue>
|
||||
class MinMaxVal {
|
||||
public:
|
||||
typedef TValue Value;
|
||||
|
||||
public:
|
||||
/** The underlying value. */
|
||||
Value val;
|
||||
|
||||
OT_DEF_BASIC(MinMaxVal) {
|
||||
OT_MY_OBJECT(val);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Converts implicitly to the value.
|
||||
*/
|
||||
operator Value() const { return val; }
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
*/
|
||||
const Value& operator = (Value val_in) {
|
||||
return (val = val_in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently performs this->val = min(this->val, incoming_val).
|
||||
*
|
||||
* The expectation is that it is higly unlikely for the incoming
|
||||
* value to be the new minimum.
|
||||
*/
|
||||
void MinWith(Value incoming_val) {
|
||||
if (unlikely(incoming_val < val)) {
|
||||
val = incoming_val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently performs this->val = min(this->val, incoming_val).
|
||||
*
|
||||
* The expectation is that it is higly unlikely for the incoming
|
||||
* value to be the new maximum.
|
||||
*/
|
||||
void MaxWith(Value incoming_val) {
|
||||
if (unlikely(incoming_val > val)) {
|
||||
val = incoming_val;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#include "discrete.h"
|
||||
#include "kernel.h"
|
||||
#include "geometry.h"
|
||||
|
||||
@@ -88,8 +88,8 @@ void TestPow() {
|
||||
TEST_DOUBLE_EXACT((math::Pow<2, 1>(3.0)), 9.0);
|
||||
TEST_DOUBLE_EXACT((math::Pow<1, 2>(9.0)), 3.0);
|
||||
TEST_DOUBLE_EXACT((math::Pow<3, 3>(9.0)), 9.0);
|
||||
TEST_DOUBLE_EXACT((math::Pow<1, 3>(8.0)), 2.0);
|
||||
TEST_DOUBLE_EXACT((math::PowAbs<1, 3>(-8.0)), 2.0);
|
||||
TEST_DOUBLE_APPROX((math::Pow<1, 3>(8.0)), 2.0, 1.0e-6);
|
||||
TEST_DOUBLE_APPROX((math::PowAbs<1, 3>(-8.0)), 2.0, 1.0e-6);
|
||||
TEST_DOUBLE_EXACT((math::PowAbs<1, 1>(-8.0)), 8.0);
|
||||
TEST_DOUBLE_EXACT((math::PowAbs<2, 1>(-8.0)), 64.0);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,3 @@ librule(
|
||||
sources = ["thread.cc"],
|
||||
headers = ["thread.h", "task.h", "grain.h"],
|
||||
deplibs = ["base:base", "col:col"])
|
||||
|
||||
librule(
|
||||
name = "mpi",
|
||||
sources = [],
|
||||
headers = ["mpigrain.h"],
|
||||
deplibs = [":par"])
|
||||
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
// Copyright 2007 Georgia Institute of Technology. All rights reserved.
|
||||
// ABSOLUTELY NOT FOR DISTRIBUTION
|
||||
/**
|
||||
* @file mpigrain.h
|
||||
*
|
||||
* Tool for creating simple MPI parallel programs.
|
||||
* You must build with --compiler=mpi.
|
||||
*
|
||||
* WARNING! This currently DOES NOT have ANY WAY for you to send
|
||||
* results back!
|
||||
*
|
||||
* TODO: Broken
|
||||
*/
|
||||
|
||||
#ifndef PAR_MPIGRAIN_H
|
||||
#define PAR_MPIGRAIN_H
|
||||
|
||||
#include "xrun/xrun.h"
|
||||
|
||||
#include "grain.h"
|
||||
|
||||
#include <mpi.h>
|
||||
|
||||
/**
|
||||
* Grain-based parallelism over MPI.
|
||||
*
|
||||
* Grains must be bit-copiable. In the future serialization might be a better
|
||||
* idea.
|
||||
*
|
||||
* Uses single master that maintains priority queue, and handles work out
|
||||
* to slaves.
|
||||
*
|
||||
* TODO: This does NOT have any way for you to send results back to the
|
||||
* mater computer.
|
||||
*/
|
||||
template<typename TGrain, typename TContext = int>
|
||||
class MPIGrainRunner {
|
||||
FORBID_COPY(MPIGrainRunner);
|
||||
friend class MPIDispatcher;
|
||||
|
||||
public:
|
||||
typedef TGrain Grain;
|
||||
typedef TContext Context;
|
||||
|
||||
class Dispatcher {
|
||||
FORBID_COPY(Dispatcher);
|
||||
friend class MPIGrainRunner;
|
||||
|
||||
private:
|
||||
class MPIMasterTask : public Task {
|
||||
private:
|
||||
struct MPIGrainRunner *runner_;
|
||||
|
||||
public:
|
||||
MPIMasterTask(MPIGrainRunner *runner_in) {
|
||||
runner_ = runner_in;
|
||||
}
|
||||
|
||||
void Run() {
|
||||
int rank;
|
||||
int message;
|
||||
int n_slaves_alive = 0;
|
||||
int n_slaves_busy = 0;
|
||||
|
||||
DEBUG_MSG(1.0, "DISPATCH: Firing up the cannons.");
|
||||
DEBUG_MSG(1.0, "DISPATCH: We will accomplish %u tasks.",
|
||||
unsigned(runner_->dispatcher_->queue_->size()));
|
||||
|
||||
for (;;) {
|
||||
runner_->RecvInt_(&rank, &message);
|
||||
|
||||
runner_->mutex_.Lock();
|
||||
Grain* grain = runner_->dispatcher_->queue_->Pop();
|
||||
runner_->mutex_.Unlock();
|
||||
|
||||
if (message == BIRTH) {
|
||||
DEBUG_MSG(1.0, "DISPATCH: Received birth message.");
|
||||
n_slaves_alive++;
|
||||
n_slaves_busy++;
|
||||
} else {
|
||||
DEBUG_ASSERT(message == GIVE_ME_WORK);
|
||||
DEBUG_MSG(1.0, "DISPATCH: Somebody wants more work.");
|
||||
}
|
||||
|
||||
if (grain) {
|
||||
char buf[sizeof(Grain) + 1];
|
||||
|
||||
buf[0] = 1; // data is available
|
||||
mem::CopyBytes(buf + 1, grain, sizeof(*grain));
|
||||
delete grain;
|
||||
|
||||
DEBUG_MSG(1.0, "DISPATCH: Sending work on over.");
|
||||
MPI_Send(buf, sizeof(buf), MPI_CHAR, rank,
|
||||
runner_->tag_, MPI_COMM_WORLD);
|
||||
} else if (n_slaves_alive == runner_->n_slaves_) {
|
||||
// we have to make sure all workers are born before we quit,
|
||||
// otherwise the worker will wait infinitely for work.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG(1.0, "DISPATCH: Waiting for workers to die...");
|
||||
|
||||
|
||||
/* Wait for all to die */
|
||||
while (n_slaves_alive != 0) {
|
||||
// we received a message from the last loop
|
||||
|
||||
if (message == GIVE_ME_WORK) {
|
||||
char buf[1];
|
||||
|
||||
buf[0] = 0; // tell them to die
|
||||
MPI_Send(buf, sizeof(buf), MPI_CHAR, rank,
|
||||
runner_->tag_, MPI_COMM_WORLD);
|
||||
|
||||
DEBUG_MSG(1.0, "DISPATCH: I told a worker to die.");
|
||||
n_slaves_busy--;
|
||||
} else if (message == DEATH) {
|
||||
DEBUG_MSG(1.0, "DISPATCH: A worker died.");
|
||||
n_slaves_alive--;
|
||||
} else {
|
||||
DEBUG_ASSERT_MSG(0, "DISPATCHED: Message was %d??",
|
||||
message);
|
||||
}
|
||||
|
||||
if (n_slaves_alive != 0) {
|
||||
runner_->RecvInt_(&rank, &message);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG(1.0, "DISPATCH: All workers have died.");
|
||||
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
MPIGrainRunner *runner_;
|
||||
GrainQueue<Grain> *queue_;
|
||||
|
||||
public:
|
||||
Dispatcher() {}
|
||||
~Dispatcher() {}
|
||||
|
||||
void Init(MPIGrainRunner *runner_in) {
|
||||
queue_ = NULL;
|
||||
runner_ = runner_in;
|
||||
}
|
||||
|
||||
void set_queue(GrainQueue<Grain> *queue_in) {
|
||||
queue_ = queue_in;
|
||||
}
|
||||
|
||||
private:
|
||||
void MasterLoop_() {
|
||||
if (runner_->n_slaves_ > 0) {
|
||||
MPIMasterTask *task = new MPIMasterTask(runner_);
|
||||
task->Run();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
class ConsumerTask : public Task {
|
||||
FORBID_COPY(ConsumerTask);
|
||||
|
||||
private:
|
||||
struct MPIGrainRunner *runner_;
|
||||
|
||||
public:
|
||||
ConsumerTask(MPIGrainRunner *runner_in) {
|
||||
runner_ = runner_in;
|
||||
}
|
||||
|
||||
void Run() {
|
||||
int my_grains = 0;
|
||||
for (;;) {
|
||||
Grain *grain = runner_->NextGrain_();
|
||||
if (!grain) {
|
||||
break;
|
||||
}
|
||||
grain->Run(runner_->context_);
|
||||
delete grain;
|
||||
my_grains++;
|
||||
}
|
||||
DEBUG_MSG(1.0, "A thread on rank %d is done, completed %d grains.",
|
||||
runner_->my_rank_, my_grains);
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
enum { BIRTH = 27, GIVE_ME_WORK, DEATH };
|
||||
|
||||
private:
|
||||
int tag_;
|
||||
Context context_;
|
||||
int master_rank_;
|
||||
int my_rank_;
|
||||
int n_nodes_;
|
||||
int n_slaves_;
|
||||
Dispatcher *dispatcher_;
|
||||
|
||||
WaitCondition need_work_cond_;
|
||||
volatile int need_work_;
|
||||
WaitCondition have_work_cond_;
|
||||
volatile int have_work_;
|
||||
Mutex mutex_;
|
||||
ArrayList<Grain *> slave_grains_;
|
||||
|
||||
public:
|
||||
MPIGrainRunner() {}
|
||||
~MPIGrainRunner() {}
|
||||
|
||||
/**
|
||||
* Initialize this.
|
||||
*
|
||||
* @param name name to associate information with
|
||||
* @param tag_in the tag for this to use; this will occupy both the
|
||||
* specified tag AND the one after it
|
||||
* @param context_in the context to run grains with
|
||||
* @param master_rank_in the rank of the master (defaults to first)
|
||||
*/
|
||||
void Init(const char *name, int tag_in, Context context_in, int master_rank_in = 0) {
|
||||
tag_ = tag_in;
|
||||
context_ = context_in;
|
||||
master_rank_ = master_rank_in;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank_);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &n_nodes_);
|
||||
n_slaves_ = n_nodes_ - 1;
|
||||
DEBUG_MSG(1.0, "my_rank = %d", my_rank_);
|
||||
if (master_rank_ == my_rank_) {
|
||||
dispatcher_ = new Dispatcher();
|
||||
dispatcher_->Init(this);
|
||||
} else {
|
||||
dispatcher_ = NULL;
|
||||
}
|
||||
have_work_ = 0;
|
||||
need_work_ = 0;
|
||||
slave_grains_.Init();
|
||||
xrun_subparam_set(name, "n_nodes", "%d", n_nodes_);
|
||||
}
|
||||
|
||||
Dispatcher *dispatcher() const {
|
||||
return dispatcher_;
|
||||
}
|
||||
|
||||
Thread *SpawnThread() {
|
||||
ConsumerTask *task = new ConsumerTask(this);
|
||||
Thread *thread = new Thread();
|
||||
thread->Init(task);
|
||||
thread->Start();
|
||||
return thread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the specified number of threads, and uses those to execute
|
||||
* all grains of work.
|
||||
*
|
||||
* Use this rather than the other SpawnThread methods.
|
||||
*/
|
||||
void RunThreads(int num_threads) {
|
||||
DEBUG_MSG(1.0, "Rank %d is ready to roll.", my_rank_);
|
||||
ArrayList<Thread*> threads;
|
||||
int num_worker_threads = num_threads;
|
||||
|
||||
if (num_worker_threads != 2) abort();
|
||||
threads.Init(num_worker_threads);
|
||||
|
||||
for (int i = 0; i < num_worker_threads; i++) {
|
||||
threads[i] = SpawnThread();
|
||||
}
|
||||
if (dispatcher_) {
|
||||
dispatcher_->MasterLoop_();
|
||||
DEBUG_MSG(1.0, "Master loop done, cleaning up.");
|
||||
} else {
|
||||
SlaveLoop_();
|
||||
DEBUG_MSG(1.0, "Slave %d loop done, cleaning up.", my_rank_);
|
||||
}
|
||||
for (int i = num_worker_threads; i--;) {
|
||||
threads[i]->WaitStop();
|
||||
delete threads[i];
|
||||
}
|
||||
if (!dispatcher_) {
|
||||
// Let the master know I'm done.
|
||||
SendInt_(master_rank_, DEATH);
|
||||
}
|
||||
DEBUG_MSG(1.0, "Rank %d killed all threads.", my_rank_);
|
||||
}
|
||||
|
||||
private:
|
||||
void SendInt_(int dest_rank, int num) {
|
||||
MPI_Send(&num, 1,
|
||||
MPI_INT, dest_rank,
|
||||
tag_ + 1,
|
||||
MPI_COMM_WORLD);
|
||||
}
|
||||
|
||||
void RecvInt_(int *send_rank, int *num_ptr) {
|
||||
MPI_Status status;
|
||||
MPI_Recv(num_ptr, 1,
|
||||
MPI_INT,
|
||||
MPI_ANY_SOURCE,
|
||||
tag_ + 1,
|
||||
MPI_COMM_WORLD,
|
||||
&status);
|
||||
*send_rank = status.MPI_SOURCE;
|
||||
}
|
||||
|
||||
Grain *NextGrain_() {
|
||||
Grain *grain;
|
||||
|
||||
if (dispatcher_) {
|
||||
DEBUG_ASSERT((my_rank_ == master_rank_));
|
||||
mutex_.Lock();
|
||||
grain = dispatcher_->queue_->Pop();
|
||||
mutex_.Unlock();
|
||||
} else {
|
||||
DEBUG_ASSERT((my_rank_ != master_rank_));
|
||||
|
||||
mutex_.Lock();
|
||||
need_work_++;
|
||||
mutex_.Unlock();
|
||||
|
||||
need_work_cond_.Signal();
|
||||
|
||||
mutex_.Lock();
|
||||
while (!have_work_) {
|
||||
have_work_cond_.Wait(&mutex_);
|
||||
}
|
||||
if (slave_grains_.size() > 0) {
|
||||
grain = *slave_grains_.PopBackPtr();
|
||||
have_work_--;
|
||||
} else {
|
||||
grain = NULL;
|
||||
}
|
||||
mutex_.Unlock();
|
||||
DEBUG_MSG(2.0, "Slave gave me stuff!");
|
||||
}
|
||||
|
||||
return grain;
|
||||
}
|
||||
|
||||
void SlaveLoop_() {
|
||||
bool done = false;
|
||||
|
||||
DEBUG_MSG(1.0, "%d, WORKER: Announcing birth...", my_rank_);
|
||||
SendInt_(master_rank_, BIRTH);
|
||||
|
||||
while (!done) {
|
||||
char buf[sizeof(Grain) + 1] = "q";
|
||||
MPI_Status status;
|
||||
|
||||
DEBUG_MSG(1.0, "%d, WORKER: Waiting for work...", my_rank_);
|
||||
MPI_Recv(buf, sizeof(buf),
|
||||
MPI_CHAR, MPI_ANY_SOURCE,
|
||||
tag_,
|
||||
MPI_COMM_WORLD, &status);
|
||||
|
||||
Grain *grain = NULL;
|
||||
|
||||
if (buf[0] == 1) {
|
||||
DEBUG_MSG(1.0, "%d, WORKER: Got some work. There are %d waiting.",
|
||||
my_rank_, need_work_);
|
||||
|
||||
grain = new Grain();
|
||||
mem::CopyBytes(grain, buf+1, sizeof(Grain));
|
||||
|
||||
mutex_.Lock();
|
||||
while (need_work_ == 0) {
|
||||
need_work_cond_.Wait(&mutex_);
|
||||
}
|
||||
need_work_--;
|
||||
have_work_++;
|
||||
*slave_grains_.AddBack() = grain;
|
||||
mutex_.Unlock();
|
||||
|
||||
have_work_cond_.Signal();
|
||||
|
||||
SendInt_(master_rank_, GIVE_ME_WORK);
|
||||
} else {
|
||||
DEBUG_ASSERT_MSG(buf[0] == 0, "buf[0] = %d", buf[0]);
|
||||
grain = NULL;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_MSG(1.0, "%d, WORKER: Duly dying !!!!!!!!!!!!!!!!!!!", my_rank_);
|
||||
|
||||
mutex_.Lock();
|
||||
have_work_ = -1;
|
||||
mutex_.Unlock();
|
||||
|
||||
have_work_cond_.Broadcast();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,13 @@
|
||||
#ifndef THOR_BLOCKDEV_H
|
||||
#define THOR_BLOCKDEV_H
|
||||
|
||||
#include "fastlib/fastlib_int.h"
|
||||
#include "base/common.h"
|
||||
#include "base/otrav.h"
|
||||
#include "col/intmap.h"
|
||||
#include "col/string.h"
|
||||
#include "fx/fx.h"
|
||||
#include "par/thread.h"
|
||||
|
||||
|
||||
class BlockDevice {
|
||||
FORBID_COPY(BlockDevice);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef THOR_CACHE_H
|
||||
#define THOR_CACHE_H
|
||||
|
||||
#include "blockdev.h"
|
||||
|
||||
/**
|
||||
* Handles events associated with a cache pulling blocks in and out of memory.
|
||||
*/
|
||||
class BlockHandler {
|
||||
FORBID_COPY(BlockHandler);
|
||||
public:
|
||||
BlockHandler() {}
|
||||
virtual ~BlockHandler() {}
|
||||
|
||||
/** Save state. */
|
||||
virtual void Serialize(ArrayList<char>* data) const = 0;
|
||||
/** Initialize from state. */
|
||||
virtual void Deserialize(const ArrayList<char>& data) = 0;
|
||||
/** Initialize a chunk in frozen state. */
|
||||
virtual void BlockInitFrozen(BlockDevice::blockid_t blockid,
|
||||
BlockDevice::offset_t begin,
|
||||
BlockDevice::offset_t bytes, char *block) = 0;
|
||||
/** Freeze a chunk so it can be sent over net, or stored. */
|
||||
virtual void BlockFreeze(BlockDevice::blockid_t blockid,
|
||||
BlockDevice::offset_t begin, BlockDevice::offset_t bytes,
|
||||
const char *old_location, char *block) = 0;
|
||||
/** Thaw a chunk so it can be accessed via pointers. */
|
||||
virtual void BlockThaw(BlockDevice::blockid_t blockid,
|
||||
BlockDevice::offset_t begin, BlockDevice::offset_t bytes,
|
||||
char *block) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,439 @@
|
||||
#ifndef THOR_DFS_H
|
||||
#define THOR_DFS_H
|
||||
|
||||
#include "gnp.h"
|
||||
#include "cachearray.h"
|
||||
|
||||
/**
|
||||
* Depth-first dual-tree solver.
|
||||
*/
|
||||
template<typename GNP>
|
||||
class DualTreeDepthFirst {
|
||||
FORBID_COPY(DualTreeDepthFirst);
|
||||
|
||||
private:
|
||||
struct QMutables {
|
||||
typename GNP::QSummaryResult summary_result;
|
||||
typename GNP::QPostponed postponed;
|
||||
|
||||
OT_DEF(QMutables) {
|
||||
OT_MY_OBJECT(summary_result);
|
||||
OT_MY_OBJECT(postponed);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
typename GNP::Param param_;
|
||||
typename GNP::GlobalResult global_result_;
|
||||
|
||||
CacheArray<typename GNP::QPoint> q_points_;
|
||||
CacheArray<typename GNP::QNode> q_nodes_;
|
||||
CacheArray<typename GNP::QResult> q_results_;
|
||||
SubsetArray<QMutables> q_mutables_;
|
||||
|
||||
CacheArray<typename GNP::RPoint> r_points_;
|
||||
CacheArray<typename GNP::RNode> r_nodes_;
|
||||
const typename GNP::RNode *r_root_;
|
||||
|
||||
bool do_naive_;
|
||||
//datanode *datanode_;
|
||||
uint64 n_naive_;
|
||||
uint64 n_pre_naive_;
|
||||
uint64 n_recurse_;
|
||||
|
||||
public:
|
||||
DualTreeDepthFirst() {}
|
||||
~DualTreeDepthFirst();
|
||||
|
||||
/**
|
||||
* Solves the GNP.
|
||||
*
|
||||
* Results are stored in q_results and in this->global_result.
|
||||
* The datanode contains possible parameters, and records some
|
||||
* recursion statistics when debugging is enabled.
|
||||
* All the other arguments are the GNP input, and are not modified.
|
||||
*/
|
||||
void Doit(
|
||||
const typename GNP::Param& param_in,
|
||||
index_t q_root_index,
|
||||
index_t q_node_end_index,
|
||||
DistributedCache *q_points,
|
||||
DistributedCache *q_nodes,
|
||||
DistributedCache *r_points,
|
||||
DistributedCache *r_nodes,
|
||||
DistributedCache *q_results);
|
||||
|
||||
/**
|
||||
* Gets the global result after computation.
|
||||
*/
|
||||
const typename GNP::GlobalResult& global_result() const {
|
||||
return global_result_;
|
||||
}
|
||||
|
||||
private:
|
||||
void Begin_(index_t q_root_index);
|
||||
void Pair_(
|
||||
const typename GNP::QNode *q_node,
|
||||
const typename GNP::RNode *r_node,
|
||||
const typename GNP::Delta& delta,
|
||||
const typename GNP::QSummaryResult& unvisited,
|
||||
QMutables *q_node_mut);
|
||||
void BaseCase_(
|
||||
const typename GNP::QNode *q_node,
|
||||
const typename GNP::RNode *r_node,
|
||||
const typename GNP::QSummaryResult& unvisited,
|
||||
QMutables *q_node_mut);
|
||||
void PushDown_(index_t q_node_i, QMutables *q_node_mut);
|
||||
};
|
||||
|
||||
template<typename GNP>
|
||||
DualTreeDepthFirst<GNP>::~DualTreeDepthFirst() {
|
||||
r_nodes_.StopRead(0);
|
||||
}
|
||||
|
||||
template<typename GNP>
|
||||
void DualTreeDepthFirst<GNP>::Doit(
|
||||
const typename GNP::Param& param_in,
|
||||
index_t q_root_index,
|
||||
index_t q_end_index,
|
||||
DistributedCache *q_points,
|
||||
DistributedCache *q_nodes,
|
||||
DistributedCache *r_points,
|
||||
DistributedCache *r_nodes,
|
||||
DistributedCache *q_results) {
|
||||
param_.Copy(param_in);
|
||||
|
||||
q_nodes_.Init(q_nodes, BlockDevice::M_READ);
|
||||
r_points_.Init(r_points, BlockDevice::M_READ);
|
||||
r_nodes_.Init(r_nodes, BlockDevice::M_READ);
|
||||
|
||||
const typename GNP::QNode *q_root = q_nodes_.StartRead(q_root_index);
|
||||
q_results_.Init(q_results, BlockDevice::M_OVERWRITE,
|
||||
q_root->begin(), q_root->end());
|
||||
q_points_.Init(q_points, BlockDevice::M_READ,
|
||||
q_root->begin(), q_root->end());
|
||||
q_nodes_.StopRead(q_root_index);
|
||||
|
||||
QMutables default_mutable;
|
||||
default_mutable.summary_result.Init(param_);
|
||||
default_mutable.postponed.Init(param_);
|
||||
q_mutables_.Init(default_mutable, q_root_index, q_end_index);
|
||||
|
||||
global_result_.Init(param_);
|
||||
|
||||
r_root_ = r_nodes_.StartRead(0);
|
||||
|
||||
//datanode_ = datanode_in;
|
||||
do_naive_ = false;
|
||||
|
||||
Begin_(q_root_index);
|
||||
}
|
||||
|
||||
template<typename GNP>
|
||||
void DualTreeDepthFirst<GNP>::Begin_(index_t q_root_index) {
|
||||
typename GNP::Delta delta;
|
||||
const typename GNP::QNode *q_root = q_nodes_.StartRead(q_root_index);
|
||||
QMutables *q_root_mut = &q_mutables_[q_root_index];
|
||||
|
||||
//fx_timer_start(datanode_, "execute");
|
||||
|
||||
DEBUG_ONLY(n_naive_ = 0);
|
||||
DEBUG_ONLY(n_pre_naive_ = 0);
|
||||
DEBUG_ONLY(n_recurse_ = 0);
|
||||
|
||||
bool need_explore = GNP::Algorithm::ConsiderPairIntrinsic(
|
||||
param_, *q_root, *r_root_, &delta,
|
||||
&global_result_, &q_root_mut->postponed);
|
||||
|
||||
if (need_explore) {
|
||||
typename GNP::QSummaryResult empty_summary_result;
|
||||
|
||||
empty_summary_result.Init(param_);
|
||||
|
||||
if (do_naive_) {
|
||||
BaseCase_(q_root, r_root_, empty_summary_result, q_root_mut);
|
||||
} else {
|
||||
Pair_(q_root, r_root_, delta, empty_summary_result, q_root_mut);
|
||||
}
|
||||
PushDown_(q_root_index, q_root_mut);
|
||||
}
|
||||
|
||||
q_nodes_.StopRead(q_root_index);
|
||||
|
||||
//fx_timer_stop(datanode_, "execute");
|
||||
|
||||
#warning we should collect statistics
|
||||
/*DEBUG_ONLY(fx_format_result(datanode_, "naive_ratio", "%f",
|
||||
1.0 * n_naive_ / q_root->count() / r_root_->count()));
|
||||
DEBUG_ONLY(fx_format_result(datanode_, "naive_per_query", "%f",
|
||||
1.0 * n_naive_ / q_root->count()));
|
||||
DEBUG_ONLY(fx_format_result(datanode_, "pre_naive_ratio", "%f",
|
||||
1.0 * n_pre_naive_ / q_root->count() / r_root_->count()));
|
||||
DEBUG_ONLY(fx_format_result(datanode_, "pre_naive_per_query", "%f",
|
||||
1.0 * n_pre_naive_ / q_root->count()));
|
||||
DEBUG_ONLY(fx_format_result(datanode_, "recurse_ratio", "%f",
|
||||
1.0 * n_recurse_ / q_root->count() / r_root_->count()));
|
||||
DEBUG_ONLY(fx_format_result(datanode_, "recurse_per_query", "%f",
|
||||
1.0 * n_recurse_ / q_root->count()));*/
|
||||
|
||||
/* if (fx_param_bool(datanode_, "print", 0)) {
|
||||
ot::Print(q_results_);
|
||||
}*/
|
||||
}
|
||||
|
||||
template<typename GNP>
|
||||
void DualTreeDepthFirst<GNP>::PushDown_(
|
||||
index_t q_node_i, QMutables *q_node_mut) {
|
||||
const typename GNP::QNode *q_node = q_nodes_.StartRead(q_node_i);
|
||||
|
||||
if (q_node->is_leaf()) {
|
||||
for (index_t q_i = q_node->begin(); q_i < q_node->end(); q_i++) {
|
||||
typename GNP::QResult *q_result = q_results_.StartWrite(q_i);
|
||||
const typename GNP::QPoint *q_point = q_points_.StartRead(q_i);
|
||||
|
||||
q_result->ApplyPostponed(param_, q_node_mut->postponed, *q_point, q_i);
|
||||
q_result->Postprocess(param_, *q_point, q_i, *r_root_);
|
||||
global_result_.ApplyResult(param_, *q_point, q_i, *q_result);
|
||||
q_results_.StopWrite(q_i);
|
||||
q_points_.StopRead(q_i);
|
||||
}
|
||||
} else {
|
||||
for (index_t k = 0; k < 2; k++) {
|
||||
index_t q_child_i = q_node->child(k);
|
||||
QMutables *q_child_mut = &q_mutables_[q_child_i];
|
||||
|
||||
q_child_mut->postponed.ApplyPostponed(param_, q_node_mut->postponed);
|
||||
|
||||
PushDown_(q_child_i, q_child_mut);
|
||||
}
|
||||
}
|
||||
|
||||
q_nodes_.StopRead(q_node_i);
|
||||
}
|
||||
|
||||
template<typename GNP>
|
||||
void DualTreeDepthFirst<GNP>::Pair_(
|
||||
const typename GNP::QNode *q_node,
|
||||
const typename GNP::RNode *r_node,
|
||||
const typename GNP::Delta& delta,
|
||||
const typename GNP::QSummaryResult& unvisited,
|
||||
QMutables *q_node_mut) {
|
||||
//printf("pair(%d:%d) at (%d:%d)\n", q_node->begin(), q_node->count(), r_node->begin(), r_node->count());
|
||||
DEBUG_MSG(1.0, "Checking (%d,%d) x (%d,%d)",
|
||||
q_node->begin(), q_node->end(),
|
||||
r_node->begin(), r_node->end());
|
||||
DEBUG_ONLY(n_recurse_++);
|
||||
|
||||
/* begin prune checks */
|
||||
typename GNP::QSummaryResult mu(q_node_mut->summary_result);
|
||||
mu.ApplyPostponed(param_, q_node_mut->postponed, *q_node);
|
||||
mu.ApplySummaryResult(param_, unvisited);
|
||||
mu.ApplyDelta(param_, delta);
|
||||
|
||||
if (!GNP::Algorithm::ConsiderQueryTermination(
|
||||
param_, *q_node, mu, global_result_, &q_node_mut->postponed)) {
|
||||
q_node_mut->summary_result.ApplyDelta(param_, delta);
|
||||
DEBUG_MSG(1.0, "Termination prune");
|
||||
} else if (!GNP::Algorithm::ConsiderPairExtrinsic(
|
||||
param_, *q_node, *r_node, delta, mu, global_result_,
|
||||
&q_node_mut->postponed)) {
|
||||
DEBUG_MSG(1.0, "Extrinsic prune");
|
||||
} else {
|
||||
global_result_.UndoDelta(param_, delta);
|
||||
|
||||
if (q_node->is_leaf() && r_node->is_leaf()) {
|
||||
DEBUG_MSG(1.0, "Base case");
|
||||
BaseCase_(q_node, r_node, unvisited, q_node_mut);
|
||||
} else if (r_node->is_leaf()
|
||||
|| (q_node->count() >= r_node->count() && !q_node->is_leaf())) {
|
||||
DEBUG_MSG(1.0, "Splitting Q");
|
||||
// Phase 2: Explore children, and reincorporate their results.
|
||||
q_node_mut->summary_result.StartReaccumulate(param_, *q_node);
|
||||
|
||||
for (index_t k = 0; k < 2; k++) {
|
||||
typename GNP::Delta child_delta;
|
||||
index_t q_child_i = q_node->child(k);
|
||||
const typename GNP::QNode *q_child = q_nodes_.StartRead(q_child_i);
|
||||
QMutables *q_child_mut = &q_mutables_[q_child_i];
|
||||
q_child_mut->postponed.ApplyPostponed(
|
||||
param_, q_node_mut->postponed);
|
||||
child_delta.Init(param_);
|
||||
|
||||
if (GNP::Algorithm::ConsiderPairIntrinsic(
|
||||
param_, *q_child, *r_node, &child_delta,
|
||||
&global_result_, &q_child_mut->postponed)) {
|
||||
Pair_(q_child, r_node, delta, unvisited, q_child_mut);
|
||||
}
|
||||
|
||||
// We must VERY carefully apply both the horizontal and vertical join
|
||||
// operators here for postponed results.
|
||||
typename GNP::QSummaryResult tmp_result(q_child_mut->summary_result);
|
||||
tmp_result.ApplyPostponed(param_, q_child_mut->postponed, *q_child);
|
||||
q_node_mut->summary_result.Accumulate(param_, tmp_result, q_node->count());
|
||||
|
||||
q_nodes_.StopRead(q_child_i);
|
||||
}
|
||||
|
||||
q_node_mut->summary_result.FinishReaccumulate(param_, *q_node);
|
||||
q_node_mut->postponed.Reset(param_);
|
||||
} else {
|
||||
DEBUG_MSG(1.0, "Splitting R");
|
||||
index_t r_child1_i = r_node->child(0);
|
||||
index_t r_child2_i = r_node->child(1);
|
||||
const typename GNP::RNode *r_child1 = r_nodes_.StartRead(r_child1_i);
|
||||
const typename GNP::RNode *r_child2 = r_nodes_.StartRead(r_child2_i);
|
||||
typename GNP::Delta delta1;
|
||||
typename GNP::Delta delta2;
|
||||
double heur1;
|
||||
double heur2;
|
||||
|
||||
delta1.Init(param_);
|
||||
delta2.Init(param_);
|
||||
|
||||
if (GNP::Algorithm::ConsiderPairIntrinsic(
|
||||
param_, *q_node, *r_child1, &delta1,
|
||||
&global_result_, &q_node_mut->postponed)) {
|
||||
heur1 = GNP::Algorithm::Heuristic(param_, *q_node, *r_child1, delta1);
|
||||
} else {
|
||||
r_child1 = NULL;
|
||||
heur1 = DBL_MAX;
|
||||
}
|
||||
if (GNP::Algorithm::ConsiderPairIntrinsic(
|
||||
param_, *q_node, *r_child2, &delta2,
|
||||
&global_result_, &q_node_mut->postponed)) {
|
||||
heur2 = GNP::Algorithm::Heuristic(param_, *q_node, *r_child2, delta2);
|
||||
} else {
|
||||
r_child2 = NULL;
|
||||
heur2 = DBL_MAX;
|
||||
}
|
||||
|
||||
if (likely(heur1 <= heur2)) {
|
||||
if (r_child1 != NULL) {
|
||||
typename GNP::QSummaryResult unvisited_for_r1(
|
||||
unvisited);
|
||||
if (r_child2 != NULL) {
|
||||
unvisited_for_r1.ApplyDelta(param_, delta2);
|
||||
}
|
||||
Pair_(q_node, r_child1, delta1, unvisited_for_r1, q_node_mut);
|
||||
}
|
||||
if (r_child2 != NULL) {
|
||||
Pair_(q_node, r_child2, delta2, unvisited, q_node_mut);
|
||||
}
|
||||
} else {
|
||||
if (r_child2 != NULL) {
|
||||
typename GNP::QSummaryResult unvisited_for_r1(
|
||||
unvisited);
|
||||
if (r_child1 != NULL) {
|
||||
unvisited_for_r1.ApplyDelta(param_, delta1);
|
||||
}
|
||||
Pair_(q_node, r_child2, delta2, unvisited_for_r1, q_node_mut);
|
||||
}
|
||||
if (r_child1 != NULL) {
|
||||
Pair_(q_node, r_child1, delta1, unvisited, q_node_mut);
|
||||
}
|
||||
}
|
||||
r_nodes_.StopRead(r_child1_i);
|
||||
r_nodes_.StopRead(r_child2_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename GNP>
|
||||
void DualTreeDepthFirst<GNP>::BaseCase_(
|
||||
const typename GNP::QNode *q_node,
|
||||
const typename GNP::RNode *r_node,
|
||||
const typename GNP::QSummaryResult& unvisited,
|
||||
QMutables *q_node_mut) {
|
||||
typename GNP::PairVisitor visitor;
|
||||
|
||||
DEBUG_ONLY(n_pre_naive_ += q_node->count() * r_node->count());
|
||||
|
||||
visitor.Init(param_);
|
||||
|
||||
q_node_mut->summary_result.StartReaccumulate(param_, *q_node);
|
||||
|
||||
CacheRead<typename GNP::QPoint> first_q_point(&q_points_, q_node->begin());
|
||||
CacheWrite<typename GNP::QResult> first_q_result(&q_results_, q_node->begin());
|
||||
CacheRead<typename GNP::RPoint> first_r_point(&r_points_, r_node->begin());
|
||||
size_t q_point_stride = q_points_.n_elem_bytes();
|
||||
size_t q_result_stride = q_results_.n_elem_bytes();
|
||||
const typename GNP::QPoint *q_point = first_q_point;
|
||||
typename GNP::QResult *q_result = first_q_result;
|
||||
|
||||
for (index_t q_i = q_node->begin(); q_i < q_node->end(); ++q_i) {
|
||||
q_result->ApplyPostponed(param_, q_node_mut->postponed, *q_point, q_i);
|
||||
|
||||
if (visitor.StartVisitingQueryPoint(param_, *q_point, q_i, *r_node,
|
||||
unvisited, q_result, &global_result_)) {
|
||||
const typename GNP::RPoint *r_point = first_r_point;
|
||||
size_t r_point_stride = r_points_.n_elem_bytes();
|
||||
index_t r_end = r_node->end();
|
||||
index_t r_i = r_node->begin();
|
||||
|
||||
for (;;) {
|
||||
visitor.VisitPair(param_, *q_point, q_i, *r_point, r_i);
|
||||
if (++r_i >= r_end) {
|
||||
break;
|
||||
}
|
||||
r_point = mem::PointerAdd(r_point, r_point_stride);
|
||||
}
|
||||
|
||||
visitor.FinishVisitingQueryPoint(param_, *q_point, q_i, *r_node,
|
||||
unvisited, q_result, &global_result_);
|
||||
|
||||
DEBUG_ONLY(n_naive_ += r_node->count());
|
||||
}
|
||||
|
||||
q_node_mut->summary_result.Accumulate(param_, *q_result);
|
||||
|
||||
q_point = mem::PointerAdd(q_point, q_point_stride);
|
||||
q_result = mem::PointerAdd(q_result, q_result_stride);
|
||||
}
|
||||
|
||||
q_node_mut->summary_result.FinishReaccumulate(param_, *q_node);
|
||||
q_node_mut->postponed.Reset(param_);
|
||||
}
|
||||
|
||||
// The old version -- doesn't allow delta re-use for heuristics
|
||||
//
|
||||
// double r_child1_h = GNP::Algorithm::Heuristic(
|
||||
// param_, *q_node, *r_child1);
|
||||
// double r_child2_h = GNP::Algorithm::Heuristic(
|
||||
// param_, *q_node, *r_child2);
|
||||
//
|
||||
// if (unlikely(r_child2_h < r_child1_h)) {
|
||||
// const typename GNP::RNode *r_child_t = r_child1;
|
||||
// r_child1 = r_child2;
|
||||
// r_child2 = r_child_t;
|
||||
//
|
||||
// index_t r_child_t_i = r_child1_i;
|
||||
// r_child1_i = r_child2_i;
|
||||
// r_child2_i = r_child_t_i;
|
||||
// }
|
||||
//
|
||||
// typename GNP::Delta delta1;
|
||||
// typename GNP::Delta delta2;
|
||||
//
|
||||
// delta1.Init(param_);
|
||||
// delta2.Init(param_);
|
||||
//
|
||||
// bool do_r2 = GNP::Algorithm::ConsiderPairIntrinsic(
|
||||
// param_, *q_node, *r_child2, &delta2,
|
||||
// &global_result_, &q_node_mut->postponed);
|
||||
//
|
||||
// if (GNP::Algorithm::ConsiderPairIntrinsic(
|
||||
// param_, *q_node, *r_child1, &delta1,
|
||||
// &global_result_, &q_node_mut->postponed)) {
|
||||
// typename GNP::QSummaryResult unvisited_for_r1(
|
||||
// unvisited);
|
||||
// if (do_r2) {
|
||||
// unvisited_for_r1.ApplyDelta(param_, delta2);
|
||||
// }
|
||||
// Pair_(q_node, r_child1, delta1, unvisited_for_r1, q_node_mut);
|
||||
// }
|
||||
// if (do_r2) {
|
||||
// Pair_(q_node, r_child2, delta2, unvisited, q_node_mut);
|
||||
// }
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,26 +1,13 @@
|
||||
|
||||
/*to-do
|
||||
|
||||
- Init functions
|
||||
/- the protocol
|
||||
/- nothing is initialized in my version yet
|
||||
/- alloc() ?
|
||||
- dynamic depth
|
||||
/- the replacement policy
|
||||
/- copy from old code (old-cache.c)
|
||||
- use static width with tunable depth (that might be based on external
|
||||
pressure)
|
||||
/- think if it's possible to skip the fifo
|
||||
/- no, not possible, no buffer size guarantees
|
||||
/- how do we check items out of the n-way cache?
|
||||
/- once we start using it, we can just leave a "hole" in the cache set
|
||||
which can be filled later, like a victim cache
|
||||
/- dirty marking needs to be improved
|
||||
*/
|
||||
|
||||
#include "distribcache.h"
|
||||
|
||||
#include <stdio.h>
|
||||
/*to-do
|
||||
|
||||
- dynamic depth
|
||||
- use static width with tunable depth (that might be based on external
|
||||
pressure)
|
||||
*/
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//-- THE DISTRIBUTED CACHE ------------------------------------------------
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#ifndef THOR_DISTRIBCACHE_H
|
||||
#define THOR_DISTRIBCACHE_H
|
||||
|
||||
#include "col/arraylist.h"
|
||||
#include "col/rangeset.h"
|
||||
|
||||
#include "rpc.h"
|
||||
#include "cache.h"
|
||||
#include "blockdev.h"
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
#ifndef THOR_GNP_H
|
||||
#define THOR_GNP_H
|
||||
|
||||
#include "fastlib/fastlib.h"
|
||||
#include "base/otrav.h"
|
||||
#include "fx/fx.h"
|
||||
|
||||
struct BlankDelta {
|
||||
public:
|
||||
|
||||
@@ -14,10 +14,11 @@
|
||||
#include "thortree.h"
|
||||
#include "cachearray.h"
|
||||
|
||||
#include "file/textfile.h"
|
||||
#include "data/dataset.h"
|
||||
#include "tree/bounds.h"
|
||||
#include "base/common.h"
|
||||
#include "col/arraylist.h"
|
||||
#include "file/serialize.h"
|
||||
#include "fx/fx.h"
|
||||
|
||||
/* Implementation */
|
||||
|
||||
+3
-3
@@ -8,11 +8,11 @@
|
||||
#define THOR_RPC_H
|
||||
|
||||
#include "blockdev.h"
|
||||
|
||||
#include "fastlib/fastlib_int.h"
|
||||
|
||||
#include "rpc_sock.h"
|
||||
|
||||
#include "base/common.h"
|
||||
#include "col/arraylist.h"
|
||||
|
||||
/**
|
||||
* A single remote procedure call.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
/**
|
||||
* @file rpc_sock.cc
|
||||
*
|
||||
@@ -9,7 +7,7 @@
|
||||
#include "rpc.h"
|
||||
#include "rpc_sock.h"
|
||||
|
||||
#include "fastlib/fastlib.h"
|
||||
#include "file/textfile.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#ifndef RPC_SOCK_H
|
||||
#define RPC_SOCK_H
|
||||
|
||||
#include "spbounds.h"
|
||||
|
||||
#include "fastlib/fastlib_int.h"
|
||||
#include "col/arraylist.h"
|
||||
#include "col/queue.h"
|
||||
#include "math/math.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "cachearray.h"
|
||||
|
||||
#include "fastlib/fastlib.h"
|
||||
#include "la/matrix.h"
|
||||
#include "base/otrav.h"
|
||||
|
||||
/**
|
||||
|
||||
+5
-3
@@ -10,9 +10,12 @@
|
||||
#include "rpc.h"
|
||||
#include "cache.h"
|
||||
#include "cachearray.h"
|
||||
#include "spnode.h"
|
||||
#include "thortree.h"
|
||||
|
||||
#include "fastlib/fastlib_int.h"
|
||||
#include "col/heap.h"
|
||||
#include "col/arraylist.h"
|
||||
#include "la/uselapack.h"
|
||||
#include "tree/bounds.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
@@ -172,7 +175,6 @@ void SimpleWorkQueue<Node>::AddWork_(
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include "spbounds.h"
|
||||
|
||||
template<typename Node>
|
||||
class CentroidWorkQueue
|
||||
|
||||
+418
-226
@@ -24,49 +24,107 @@
|
||||
*/
|
||||
struct DRange {
|
||||
public:
|
||||
/**
|
||||
* The lower bound.
|
||||
*/
|
||||
double lo;
|
||||
/**
|
||||
* The upper bound.
|
||||
*/
|
||||
double hi;
|
||||
|
||||
OT_DEF_BASIC(DRange) {
|
||||
OT_MY_OBJECT(lo);
|
||||
OT_MY_OBJECT(hi);
|
||||
}
|
||||
|
||||
public:
|
||||
DRange() {}
|
||||
/** Initializes to specified values. */
|
||||
DRange(double lo_in, double hi_in)
|
||||
: lo(lo_in), hi(hi_in)
|
||||
{}
|
||||
|
||||
|
||||
/** Initialize to an empty set, where lo > hi. */
|
||||
void InitEmptySet() {
|
||||
lo = DBL_MAX;
|
||||
hi = -DBL_MAX;
|
||||
}
|
||||
|
||||
|
||||
/** Initializes to -infinity to infinity. */
|
||||
void InitUniversalSet() {
|
||||
lo = DBL_MAX;
|
||||
hi = -DBL_MAX;
|
||||
lo = -DBL_MAX;
|
||||
hi = DBL_MAX;
|
||||
}
|
||||
|
||||
/** Initializes to a range of values. */
|
||||
void Init(double lo_in, double hi_in) {
|
||||
lo = lo_in;
|
||||
hi = hi_in;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resets to a range of values.
|
||||
*
|
||||
* Since there is no dynamic memory this is the same as Init, but calling
|
||||
* Reset instead of Init probably looks more similar to surrounding code.
|
||||
*/
|
||||
void Reset(double lo_in, double hi_in) {
|
||||
lo = lo_in;
|
||||
hi = hi_in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the span of the range, hi - lo.
|
||||
*/
|
||||
double width() const {
|
||||
return hi - lo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the midpoint of this range.
|
||||
*/
|
||||
double mid() const {
|
||||
return (hi + lo) / 2;
|
||||
}
|
||||
|
||||
const DRange& operator |= (const DRange& other) {
|
||||
if (unlikely(other.lo > lo)) {
|
||||
lo = other.lo;
|
||||
/**
|
||||
* Interpolates (factor) * hi + (1 - factor) * lo.
|
||||
*/
|
||||
double interpolate(double factor) const {
|
||||
return factor * width() + lo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate an union by growing the range if necessary.
|
||||
*/
|
||||
const DRange& operator |= (double d) {
|
||||
if (unlikely(d < lo)) {
|
||||
lo = d;
|
||||
}
|
||||
if (unlikely(other.hi < hi)) {
|
||||
hi = other.hi;
|
||||
if (unlikely(d > hi)) {
|
||||
hi = d;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const DRange& operator &= (const DRange& other) {
|
||||
|
||||
/**
|
||||
* Sets this range to include only the specified value, or
|
||||
* becomes an empty set if the range does not contain the number.
|
||||
*/
|
||||
const DRange& operator &= (double d) {
|
||||
if (likely(d > lo)) {
|
||||
lo = d;
|
||||
}
|
||||
if (likely(d < hi)) {
|
||||
hi = d;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands range to include the other range.
|
||||
*/
|
||||
const DRange& operator |= (const DRange& other) {
|
||||
if (unlikely(other.lo < lo)) {
|
||||
lo = other.lo;
|
||||
}
|
||||
@@ -76,34 +134,48 @@ struct DRange {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Accumulates a bound difference. */
|
||||
/**
|
||||
* Shrinks range to be the overlap with another range, becoming an empty
|
||||
* set if there is no overlap.
|
||||
*/
|
||||
const DRange& operator &= (const DRange& other) {
|
||||
if (unlikely(other.lo > lo)) {
|
||||
lo = other.lo;
|
||||
}
|
||||
if (unlikely(other.hi < hi)) {
|
||||
hi = other.hi;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Sums the upper and lower independently. */
|
||||
const DRange& operator += (const DRange& other) {
|
||||
lo += other.lo;
|
||||
hi += other.hi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Reverses a bound difference. */
|
||||
/** Subtracts from the upper and lower independently. */
|
||||
const DRange& operator -= (const DRange& other) {
|
||||
lo -= other.lo;
|
||||
hi -= other.hi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Uniformly increases both lower and upper bounds. */
|
||||
/** Adds to the upper and lower independently. */
|
||||
const DRange& operator += (double d) {
|
||||
lo += d;
|
||||
hi += d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Uniformly decreases both upper and lower bounds. */
|
||||
/** Subtracts from the upper and lower independently. */
|
||||
const DRange& operator -= (double d) {
|
||||
lo -= d;
|
||||
hi -= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
friend DRange operator + (const DRange& a, const DRange& b) {
|
||||
DRange result;
|
||||
result.lo = a.lo + b.lo;
|
||||
@@ -131,83 +203,176 @@ struct DRange {
|
||||
result.hi = a.hi - b;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the maximum of upper and lower bounds independently.
|
||||
*/
|
||||
void MaxWith(const DRange& range) {
|
||||
if (unlikely(range.lo > lo)) {
|
||||
lo = range.lo;
|
||||
}
|
||||
if (unlikely(range.hi > hi)) {
|
||||
hi = range.hi;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the minimum of upper and lower bounds independently.
|
||||
*/
|
||||
void MinWith(const DRange& range) {
|
||||
if (unlikely(range.lo < lo)) {
|
||||
lo = range.lo;
|
||||
}
|
||||
if (unlikely(range.hi < hi)) {
|
||||
hi = range.hi;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the maximum of upper and lower bounds independently.
|
||||
*/
|
||||
void MaxWith(double v) {
|
||||
if (unlikely(v > lo)) {
|
||||
lo = v;
|
||||
if (unlikely(v > hi)) {
|
||||
hi = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the minimum of upper and lower bounds independently.
|
||||
*/
|
||||
void MinWith(double v) {
|
||||
if (unlikely(v < hi)) {
|
||||
hi = v;
|
||||
if (unlikely(v < lo)) {
|
||||
lo = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares if this is STRICTLY less than another range.
|
||||
*/
|
||||
friend bool operator < (const DRange& a, const DRange& b) {
|
||||
return a.hi < b.lo;
|
||||
}
|
||||
/**
|
||||
* Compares if this is STRICTLY equal to another range.
|
||||
*/
|
||||
friend bool operator == (const DRange& a, const DRange& b) {
|
||||
return a.lo == b.lo && a.hi == b.hi;
|
||||
}
|
||||
DEFINE_ALL_COMPARATORS(DRange);
|
||||
|
||||
/**
|
||||
* Compares if this is STRICTLY less than a value.
|
||||
*/
|
||||
friend bool operator < (const DRange& a, double b) {
|
||||
return a.hi < b;
|
||||
}
|
||||
/**
|
||||
* Compares if a value is STRICTLY less than this range.
|
||||
*/
|
||||
friend bool operator < (double a, const DRange& b) {
|
||||
return a < b.lo;
|
||||
}
|
||||
DEFINE_INEQUALITY_COMPARATORS_HETERO(DRange, double);
|
||||
|
||||
/**
|
||||
* Determines if a point is contained within the range.
|
||||
*/
|
||||
bool Contains(double d) const {
|
||||
return d >= lo || d <= hi;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hyper-rectangle bound.
|
||||
* Hyper-rectangle bound for an L-metric.
|
||||
*
|
||||
* Template parameter t_pow is the metric to use; use 2 for Euclidean (L2).
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
template<int t_pow = 2>
|
||||
class DHrectBound {
|
||||
public:
|
||||
static const int PREFERRED_POWER = t_pow;
|
||||
|
||||
private:
|
||||
DRange *bounds_;
|
||||
//double diagonal_sq_;
|
||||
index_t dim_;
|
||||
|
||||
OT_DEF(DHrectBound) {
|
||||
OT_MY_OBJECT(dim_);
|
||||
OT_MALLOC_ARRAY(bounds_, dim_);
|
||||
}
|
||||
|
||||
public:
|
||||
DHrectBound() {
|
||||
DEBUG_POISON_PTR(bounds_);
|
||||
DEBUG_ONLY(dim_ = BIG_BAD_NUMBER);
|
||||
}
|
||||
|
||||
~DHrectBound() {
|
||||
mem::Free(bounds_);
|
||||
}
|
||||
|
||||
template<typename Deserializer>
|
||||
void Deserialize(Deserializer *s) {
|
||||
DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
|
||||
|
||||
s->Get(&dim_);
|
||||
bounds_ = mem::Alloc<DRange>(dim_);
|
||||
s->Get(bounds_, dim_);
|
||||
|
||||
//ComputeDiagonal_();
|
||||
}
|
||||
|
||||
template<typename Serializer>
|
||||
void Serialize(Serializer *s) const {
|
||||
s->Put(dim_);
|
||||
s->Put(bounds_, dim_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes to specified dimensionality with each dimension the empty
|
||||
* set.
|
||||
*/
|
||||
void Init(index_t dimension) {
|
||||
DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
|
||||
|
||||
//DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
|
||||
bounds_ = mem::Alloc<DRange>(dimension);
|
||||
|
||||
for (index_t i = 0; i < dimension; i++) {
|
||||
|
||||
dim_ = dimension;
|
||||
Reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all dimensions to the empty set.
|
||||
*/
|
||||
void Reset() {
|
||||
for (index_t i = 0; i < dim_; i++) {
|
||||
bounds_[i].InitEmptySet();
|
||||
}
|
||||
|
||||
dim_ = dimension;
|
||||
|
||||
//ComputeDiagonal_();
|
||||
}
|
||||
|
||||
bool Belongs(const Vector& point) const {
|
||||
|
||||
/**
|
||||
* Determines if a point is within this bound.
|
||||
*/
|
||||
bool Contains(const Vector& point) const {
|
||||
for (index_t i = 0; i < point.length(); i++) {
|
||||
const DRange *bound = &bounds_[i];
|
||||
if (point[i] > bound->hi || point[i] < bound->lo) {
|
||||
if (!bounds_[i].Contains(point[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
double MinDistanceSqToPoint(const Vector& point) const {
|
||||
DEBUG_ASSERT(point.length() == dim_);
|
||||
return MinDistanceSqToPoint(point.ptr());
|
||||
|
||||
/** Gets the dimensionality */
|
||||
index_t dim() const {
|
||||
return dim_;
|
||||
}
|
||||
|
||||
double MinDistanceSqToPoint(const double *mpoint) const {
|
||||
|
||||
/**
|
||||
* Gets the range for a particular dimension.
|
||||
*/
|
||||
const DRange& get(index_t i) const {
|
||||
DEBUG_BOUNDS(i, dim_);
|
||||
return bounds_[i];
|
||||
}
|
||||
|
||||
/** Calculates the midpoint of the range */
|
||||
void CalculateMidpoint(Vector *centroid) const {
|
||||
centroid->Init(dim_);
|
||||
for (index_t i = 0; i < dim_; i++) {
|
||||
(*centroid)[i] = bounds_[i].mid();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates minimum bound-to-point squared distance,
|
||||
* to the specified power.
|
||||
*/
|
||||
double MinDistanceSq(const Vector& point) const {
|
||||
DEBUG_ASSERT(point.length() == dim_);
|
||||
double sumsq = 0;
|
||||
//index_t mdim = dim_;
|
||||
const double *mpoint = point.ptr();
|
||||
const DRange *mbound = bounds_;
|
||||
|
||||
index_t d = dim_;
|
||||
@@ -222,64 +387,96 @@ class DHrectBound {
|
||||
mbound++;
|
||||
mpoint++;
|
||||
|
||||
sumsq += v * v;
|
||||
sumsq += math::Pow<t_pow, 1>(v);
|
||||
} while (--d);
|
||||
|
||||
return sumsq / 4;
|
||||
|
||||
return math::Pow<2, t_pow>(sumsq) / 4;
|
||||
}
|
||||
|
||||
double MaxDistanceSqToPoint(const Vector& point) const {
|
||||
|
||||
/**
|
||||
* Calculates closest-to-their-midpoint bounding box distance,
|
||||
* i.e. calculates their midpoint and finds the minimum box-to-point
|
||||
* distance.
|
||||
*
|
||||
* Equivalent to:
|
||||
* <code>
|
||||
* other.CalcMidpoint(&other_midpoint)
|
||||
* return MinDistanceSqToPoint(other_midpoint)
|
||||
* </code>
|
||||
*/
|
||||
double MinToMidSq(const DHrectBound& other) const {
|
||||
double sumsq = 0;
|
||||
const DRange *a = this->bounds_;
|
||||
const DRange *b = other.bounds_;
|
||||
|
||||
DEBUG_ASSERT(dim_ == other.dim_);
|
||||
|
||||
for (index_t d = 0; d < dim_; d++) {
|
||||
double v = b->mid();
|
||||
double v1 = a->lo - v;
|
||||
double v2 = v - a->hi;
|
||||
|
||||
v = (v1 + fabs(v1)) + (v2 + fabs(v2));
|
||||
|
||||
a++;
|
||||
b++;
|
||||
|
||||
sumsq += math::Pow<t_pow, 1>(v);
|
||||
}
|
||||
|
||||
return math::Pow<2, t_pow>(sumsq) / 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates maximum bound-to-point squared distance,
|
||||
* to the specified power.
|
||||
*/
|
||||
double MaxDistanceSq(const Vector& point) const {
|
||||
double sumsq = 0;
|
||||
|
||||
DEBUG_ASSERT(point.length() == dim_);
|
||||
|
||||
for (index_t d = 0; d < dim_; d++) {
|
||||
double v = max(point[d] - bounds_[d].lo,
|
||||
bounds_[d].hi - point[d]);
|
||||
|
||||
sumsq += v * v;
|
||||
sumsq += math::Pow<t_pow, 1>(
|
||||
max(point[d] - bounds_[d].lo, bounds_[d].hi - point[d]));
|
||||
}
|
||||
|
||||
return sumsq;
|
||||
return math::Pow<2, t_pow>(sumsq);
|
||||
}
|
||||
|
||||
double MinDistanceSqToBound(const DHrectBound& other) const {
|
||||
|
||||
/**
|
||||
* Calculates minimum bound-to-point squared distance,
|
||||
* to the specified power.
|
||||
*
|
||||
* Example: bound1.MinDistanceSq(other) for minimum squared distance.
|
||||
*/
|
||||
double MinDistanceSq(const DHrectBound& other) const {
|
||||
double sumsq = 0;
|
||||
const DRange *a = this->bounds_;
|
||||
const DRange *b = other.bounds_;
|
||||
index_t mdim = dim_;
|
||||
|
||||
DEBUG_ASSERT(dim_ == other.dim_);
|
||||
|
||||
// We invoke the following:
|
||||
// x + fabs(x) = max(x * 2, 0)
|
||||
// (x * 2)^2 / 4 = x^2
|
||||
|
||||
DEBUG_SAME_INT(dim_, other.dim_);
|
||||
|
||||
for (index_t d = 0; d < mdim; d++) {
|
||||
#if 0
|
||||
double v = b[d].lo - a[d].hi;
|
||||
|
||||
if (v < 0) {
|
||||
v = a[d].lo - b[d].hi;
|
||||
}
|
||||
|
||||
if (likely(v > 0)) {
|
||||
sumsq += v * v;
|
||||
}
|
||||
#else
|
||||
double v1 = b[d].lo - a[d].hi;
|
||||
double v2 = a[d].lo - b[d].hi;
|
||||
|
||||
// We invoke the following:
|
||||
// x + fabs(x) = max(x * 2, 0)
|
||||
// (x * 2)^2 / 4 = x^2
|
||||
double v = (v1 + fabs(v1)) + (v2 + fabs(v2));
|
||||
|
||||
sumsq += v * v;
|
||||
#endif
|
||||
sumsq += math::Pow<t_pow, 1>(v);
|
||||
}
|
||||
|
||||
return sumsq / 4;
|
||||
return math::Pow<2, t_pow>(sumsq) / 4;
|
||||
}
|
||||
|
||||
double MinDistanceSqToBoundFarEnd(const DHrectBound& other) const {
|
||||
/**
|
||||
* Computes minimax distance, where the other node is trying to avoid me,
|
||||
* to the specified power.
|
||||
*/
|
||||
double MinimaxDistanceSq(const DHrectBound& other) const {
|
||||
double sumsq = 0;
|
||||
const DRange *a = this->bounds_;
|
||||
const DRange *b = other.bounds_;
|
||||
@@ -290,17 +487,19 @@ class DHrectBound {
|
||||
for (index_t d = 0; d < mdim; d++) {
|
||||
double v1 = b[d].hi - a[d].hi;
|
||||
double v2 = a[d].lo - b[d].lo;
|
||||
|
||||
double v = max(v1, v2);
|
||||
v = (v + fabs(v)); /* truncate negative */
|
||||
|
||||
sumsq += v * v;
|
||||
v = (v + fabs(v)); /* truncate negatives to zero */
|
||||
sumsq += math::Pow<t_pow, 1>(v);
|
||||
}
|
||||
|
||||
return sumsq / 4;
|
||||
return math::Pow<2, t_pow>(sumsq) / 4;
|
||||
}
|
||||
|
||||
double MaxDistanceSqToBound(const DHrectBound& other) const {
|
||||
/**
|
||||
* Computes maximum distance,
|
||||
* to the specified power.
|
||||
*/
|
||||
double MaxDistanceSq(const DHrectBound& other) const {
|
||||
double sumsq = 0;
|
||||
const DRange *a = this->bounds_;
|
||||
const DRange *b = other.bounds_;
|
||||
@@ -308,15 +507,18 @@ class DHrectBound {
|
||||
DEBUG_ASSERT(dim_ == other.dim_);
|
||||
|
||||
for (index_t d = 0; d < dim_; d++) {
|
||||
double v = max(b[d].hi - a[d].lo, a[d].hi - b[d].lo);
|
||||
|
||||
sumsq += v * v;
|
||||
sumsq += math::Pow<t_pow, 1>(
|
||||
max(b[d].hi - a[d].lo, a[d].hi - b[d].lo));
|
||||
}
|
||||
|
||||
return sumsq;
|
||||
return math::Pow<2, t_pow>(sumsq);
|
||||
}
|
||||
|
||||
double MidDistanceSqToBound(const DHrectBound& other) const {
|
||||
/**
|
||||
* Calculates midpoint-to-midpoint bounding box distance,
|
||||
* to the specified power.
|
||||
*/
|
||||
double MidDistanceSq(const DHrectBound& other) const {
|
||||
double sumsq = 0;
|
||||
const DRange *a = this->bounds_;
|
||||
const DRange *b = other.bounds_;
|
||||
@@ -324,133 +526,123 @@ class DHrectBound {
|
||||
DEBUG_ASSERT(dim_ == other.dim_);
|
||||
|
||||
for (index_t d = 0; d < dim_; d++) {
|
||||
double v = (a[d].hi + a[d].lo - b[d].hi - b[d].lo) * 0.5;
|
||||
|
||||
sumsq += v * v;
|
||||
sumsq += math::PowAbs<t_pow, 1>(a[d].hi + a[d].lo - b[d].hi - b[d].lo);
|
||||
}
|
||||
|
||||
return sumsq;
|
||||
return math::Pow<2, t_pow>(sumsq) / 4;
|
||||
}
|
||||
|
||||
void Update(const Vector& vector) {
|
||||
DEBUG_ASSERT(vector.length() == dim_);
|
||||
/**
|
||||
* Expands this region to include a new point.
|
||||
*/
|
||||
DHrectBound& operator |= (const Vector& vector) {
|
||||
DEBUG_SAME_INT(vector.length(), dim_);
|
||||
|
||||
for (index_t i = 0; i < dim_; i++) {
|
||||
DRange* bound = &bounds_[i];
|
||||
double d = vector[i];
|
||||
|
||||
if (unlikely(d > bound->hi)) {
|
||||
bound->hi = d;
|
||||
}
|
||||
if (unlikely(d < bound->lo)) {
|
||||
bound->lo = d;
|
||||
}
|
||||
bounds_[i] |= vector[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const DRange& get(index_t i) const {
|
||||
return bounds_[i];
|
||||
}
|
||||
|
||||
//double diagonal_sq() const {
|
||||
// return diagonal_sq_;
|
||||
//}
|
||||
|
||||
FORBID_COPY(DHrectBound);
|
||||
|
||||
private:
|
||||
//void ComputeDiagonal_() {
|
||||
// diagonal_sq_ = 0;
|
||||
// for (index_t d = 0; d < dim_; d++) {
|
||||
// double v = bounds_[d].lo - bounds_[d].hi;
|
||||
// diagonal_sq_ += v*v;
|
||||
// }
|
||||
//}
|
||||
};
|
||||
|
||||
/**
|
||||
* Euclidean metric for use with ball bounds.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
class DEuclideanMetric {
|
||||
public:
|
||||
static double CalculateMetric(const Vector& a, const Vector& b) {
|
||||
return sqrt(la::DistanceSqEuclidean(a.length(), a.ptr(), b.ptr()));
|
||||
/**
|
||||
* Expands this region to encompass another bound.
|
||||
*/
|
||||
DHrectBound& operator |= (const DHrectBound& other) {
|
||||
DEBUG_SAME_INT(other.dim_, dim_);
|
||||
|
||||
for (index_t i = 0; i < dim_; i++) {
|
||||
bounds_[i] |= other.bounds_[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Bound of a ball tree.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
template<class TPoint, class TMetric>
|
||||
class BallBound {
|
||||
FORBID_COPY(BallBound);
|
||||
|
||||
public:
|
||||
typedef TMetric Metric;
|
||||
typedef TPoint Point;
|
||||
|
||||
private:
|
||||
Point center_;
|
||||
double radius_;
|
||||
|
||||
public:
|
||||
BallBound() {}
|
||||
|
||||
const Point& center() const {
|
||||
return center;
|
||||
}
|
||||
|
||||
Point& center() {
|
||||
return center;
|
||||
}
|
||||
|
||||
double radius() const {
|
||||
return radius;
|
||||
}
|
||||
|
||||
void set_radius(double d) {
|
||||
radius = d;
|
||||
}
|
||||
|
||||
double DistanceToCenter(const Point& point) {
|
||||
return Metric::CalculateMetric(point, center_);
|
||||
}
|
||||
|
||||
bool Belongs(const Point& point) {
|
||||
return DistanceToCenter(point) <= radius_;
|
||||
}
|
||||
|
||||
double MinDistanceToPoint(const Point& point) {
|
||||
return max(0.0, DistanceToCenter(point) - radius_);
|
||||
}
|
||||
|
||||
double MaxDistanceToPoint(const Point& point) {
|
||||
return DistanceToCenter(point) + radius_;
|
||||
}
|
||||
|
||||
double MinDistanceToBound(const BallBound& ball) {
|
||||
return max(0,
|
||||
DistanceToCenter(ball.center_) - (radius_ + ball.radius_));
|
||||
}
|
||||
|
||||
double MaxDistanceToBound(const BallBound& ball) {
|
||||
return DistanceToCenter(ball.center_) + (radius_ + ball.radius_);
|
||||
}
|
||||
|
||||
double MidDistanceToBound(const BallBound& other) {
|
||||
return DistanceToCenter(other.center_);
|
||||
}
|
||||
|
||||
double MidDistanceToPoint(const Point& point) {
|
||||
return DistanceToCenter(point);
|
||||
}
|
||||
};
|
||||
|
||||
typedef BallBound<Vector, DEuclideanMetric> DEuclideanBallBound;
|
||||
// Here's an idea of what ball-trees might look like.
|
||||
// /**
|
||||
// * Euclidean metric for use with ball bounds.
|
||||
// *
|
||||
// * @experimental
|
||||
// */
|
||||
// class DEuclideanMetric {
|
||||
// public:
|
||||
// static double CalculateMetric(const Vector& a, const Vector& b) {
|
||||
// return sqrt(la::DistanceSqEuclidean(a.length(), a.ptr(), b.ptr()));
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// /**
|
||||
// * Bound of a ball tree.
|
||||
// *
|
||||
// * @experimental
|
||||
// */
|
||||
// template<class TPoint, class TMetric>
|
||||
// class BallBound {
|
||||
// FORBID_COPY(BallBound);
|
||||
//
|
||||
// public:
|
||||
// typedef TMetric Metric;
|
||||
// typedef TPoint Point;
|
||||
//
|
||||
// private:
|
||||
// Point center_;
|
||||
// double radius_;
|
||||
//
|
||||
// public:
|
||||
// BallBound() {}
|
||||
//
|
||||
// const Point& center() const {
|
||||
// return center;
|
||||
// }
|
||||
//
|
||||
// Point& center() {
|
||||
// return center;
|
||||
// }
|
||||
//
|
||||
// double radius() const {
|
||||
// return radius;
|
||||
// }
|
||||
//
|
||||
// void set_radius(double d) {
|
||||
// radius = d;
|
||||
// }
|
||||
//
|
||||
// double DistanceToCenter(const Point& point) {
|
||||
// return Metric::CalculateMetric(point, center_);
|
||||
// }
|
||||
//
|
||||
// bool Belongs(const Point& point) {
|
||||
// return DistanceToCenter(point) <= radius_;
|
||||
// }
|
||||
//
|
||||
// double MinDistanceToPoint(const Point& point) {
|
||||
// return max(0.0, DistanceToCenter(point) - radius_);
|
||||
// }
|
||||
//
|
||||
// double MaxDistanceToPoint(const Point& point) {
|
||||
// return DistanceToCenter(point) + radius_;
|
||||
// }
|
||||
//
|
||||
// double MinDistanceToBound(const BallBound& ball) {
|
||||
// return max(0,
|
||||
// DistanceToCenter(ball.center_) - (radius_ + ball.radius_));
|
||||
// }
|
||||
//
|
||||
// double MaxDistanceToBound(const BallBound& ball) {
|
||||
// return DistanceToCenter(ball.center_) + (radius_ + ball.radius_);
|
||||
// }
|
||||
//
|
||||
// double MidDistanceToBound(const BallBound& other) {
|
||||
// return DistanceToCenter(other.center_);
|
||||
// }
|
||||
//
|
||||
// double MidDistanceToPoint(const Point& point) {
|
||||
// return DistanceToCenter(point);
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// typedef BallBound<Vector, DEuclideanMetric> DEuclideanBallBound;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+5
-63
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "base/common.h"
|
||||
#include "col/arraylist.h"
|
||||
#include "file/serialize.h"
|
||||
#include "fx/fx.h"
|
||||
|
||||
/* Implementation */
|
||||
@@ -80,8 +79,8 @@ namespace tree_kdtree_private {
|
||||
|
||||
left_vector.SwapValues(&right_vector);
|
||||
|
||||
left_bound->Update(left_vector);
|
||||
right_bound->Update(right_vector);
|
||||
*left_bound |= left_vector;
|
||||
*right_bound |= right_vector;
|
||||
|
||||
if (old_from_new) {
|
||||
index_t t = old_from_new[left];
|
||||
@@ -217,44 +216,6 @@ namespace tree {
|
||||
}
|
||||
|
||||
// TODO: Perhaps move this into a "util.h" file
|
||||
|
||||
/** Serializes a KD tree to a serializer. @experimental */
|
||||
template<typename TKdTree, typename Serializer>
|
||||
void SerializeKdTree(const TKdTree *tree,
|
||||
const Matrix& matrix,
|
||||
const ArrayList<index_t>& old_from_new,
|
||||
Serializer *s) {
|
||||
s->PutMagic(file::CreateMagic("kdtree"));
|
||||
tree->SerializeAll(matrix, s);
|
||||
old_from_new.Serialize(s);
|
||||
}
|
||||
|
||||
/** Deserializes a KD tree from a serializer. @experimental */
|
||||
template<typename TKdTree, typename Deserializer>
|
||||
void DeserializeKdTree(TKdTree *uninit_tree,
|
||||
Matrix* uninit_matrix,
|
||||
ArrayList<index_t>* uninit_old_from_new,
|
||||
Deserializer *s) {
|
||||
s->AssertMagic(file::CreateMagic("kdtree"));
|
||||
uninit_tree->DeserializeAll(uninit_matrix, s);
|
||||
if (uninit_old_from_new) {
|
||||
uninit_old_from_new->Deserialize(s);
|
||||
}
|
||||
}
|
||||
|
||||
/** Reads a KD tree from a file in the SERIALIZED format. @experimental */
|
||||
template<typename TKdTree>
|
||||
void LoadKdTreeFromFile(const char *fname,
|
||||
TKdTree *uninit_tree,
|
||||
Matrix* uninit_matrix,
|
||||
ArrayList<index_t>* uninit_old_from_new) {
|
||||
NativeFileDeserializer ds;
|
||||
|
||||
ASSERT_PASS(ds.Init(fname));
|
||||
DeserializeKdTree(uninit_tree, uninit_matrix, uninit_old_from_new,
|
||||
&ds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a KD tree from a command-line parameter,
|
||||
* creating a KD tree if necessary.
|
||||
@@ -283,8 +244,6 @@ namespace tree {
|
||||
* @code
|
||||
* ./main --q=foo.txt # load from csv format
|
||||
* ./main --q=foo.txt --q/leaflen=20 # leaf length
|
||||
* ./main --q=foo.kd --q/type=native # load from serialized format
|
||||
* ./main --q=foo.txt --q/save=foo.kd # serialize the tree too
|
||||
* @endcode
|
||||
*
|
||||
* @param module the module to get parameters from
|
||||
@@ -304,12 +263,7 @@ namespace tree {
|
||||
success_t success = SUCCESS_PASS;
|
||||
|
||||
fx_timer_start(module, "load");
|
||||
if (strcmp(type, "native") == 0) {
|
||||
fx_timer_start(module, "deserialize");
|
||||
*tree_pp = new TKdTree();
|
||||
tree::LoadKdTreeFromFile(fname, *tree_pp, matrix, old_from_new);
|
||||
fx_timer_stop(module, "deserialize");
|
||||
} else if (strcmp(type, "text") == 0) {
|
||||
if (strcmp(type, "text") == 0) {
|
||||
int leaflen = fx_param_int(module, "leaflen", 20);
|
||||
|
||||
fx_timer_start(module, "load_matrix");
|
||||
@@ -322,26 +276,14 @@ namespace tree {
|
||||
*tree_pp = MakeKdTreeMidpoint<TKdTree>(
|
||||
*matrix, leaflen, old_from_new);
|
||||
fx_timer_stop(module, "make_tree");
|
||||
} else {
|
||||
FATAL("Uknown file type: %s", type);
|
||||
}
|
||||
fx_timer_stop(module, "load");
|
||||
|
||||
if (fx_param_exists(module, "save")) {
|
||||
const char *save_fname = fx_param_str_req(module, "save");
|
||||
fx_timer_start(module, "save");
|
||||
NativeArraySerializer serializer;
|
||||
serializer.Init();
|
||||
SerializeKdTree(*tree_pp, *matrix, *old_from_new, &serializer);
|
||||
serializer.WriteFile(save_fname);
|
||||
fx_timer_stop(module, "save");
|
||||
}
|
||||
|
||||
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
/** Basic KD tree structure. @experimental */
|
||||
typedef BinarySpaceTree<DHrectBound, Matrix> BasicKdTree;
|
||||
typedef BinarySpaceTree<DHrectBound<2>, Matrix> BasicKdTree;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#define TREE_SPACETREE_H
|
||||
|
||||
#include "base/cc.h"
|
||||
#include "file/serialize.h"
|
||||
#include "statistic.h"
|
||||
|
||||
/**
|
||||
@@ -34,7 +33,7 @@ class BinarySpaceTree {
|
||||
typedef TBound Bound;
|
||||
typedef TDataset Dataset;
|
||||
typedef TStatistic Statistic;
|
||||
|
||||
|
||||
private:
|
||||
Bound bound_;
|
||||
BinarySpaceTree *left_;
|
||||
@@ -42,7 +41,7 @@ class BinarySpaceTree {
|
||||
index_t begin_;
|
||||
index_t count_;
|
||||
Statistic stat_;
|
||||
|
||||
|
||||
public:
|
||||
BinarySpaceTree() {
|
||||
DEBUG_ONLY(begin_ = BIG_BAD_NUMBER);
|
||||
@@ -50,7 +49,6 @@ class BinarySpaceTree {
|
||||
DEBUG_POISON_PTR(left_);
|
||||
DEBUG_POISON_PTR(right_);
|
||||
}
|
||||
|
||||
|
||||
~BinarySpaceTree() {
|
||||
if (!is_leaf()) {
|
||||
@@ -62,7 +60,7 @@ class BinarySpaceTree {
|
||||
DEBUG_POISON_PTR(left_);
|
||||
DEBUG_POISON_PTR(right_);
|
||||
}
|
||||
|
||||
|
||||
void Init(index_t begin_in, index_t count_in) {
|
||||
DEBUG_ASSERT(begin_ == BIG_BAD_NUMBER);
|
||||
DEBUG_POISON_PTR(left_);
|
||||
@@ -70,7 +68,7 @@ class BinarySpaceTree {
|
||||
begin_ = begin_in;
|
||||
count_ = count_in;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a node in this tree by its begin and count.
|
||||
*
|
||||
@@ -123,75 +121,6 @@ class BinarySpaceTree {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the tree _structure_ only.
|
||||
* Statistics are not stored (this allows you to re-load the tree
|
||||
* for problems that require different statistics).
|
||||
*/
|
||||
template<typename Serializer>
|
||||
void Serialize(Serializer *s) const {
|
||||
bound_.Serialize(s);
|
||||
s->Put(begin_);
|
||||
s->Put(count_);
|
||||
|
||||
bool children = !is_leaf();
|
||||
s->Put(children);
|
||||
|
||||
if (children) {
|
||||
left_->Serialize(s);
|
||||
right_->Serialize(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the tree from its structure, and re-calculates bottom-up
|
||||
* statistics.
|
||||
*/
|
||||
template<typename Deserializer>
|
||||
void Deserialize(const Dataset& data, Deserializer *s) {
|
||||
DEBUG_ASSERT(begin_ == BIG_BAD_NUMBER);
|
||||
|
||||
bound_.Deserialize(s);
|
||||
s->Get(&begin_);
|
||||
s->Get(&count_);
|
||||
|
||||
bool children;
|
||||
|
||||
s->Get(&children);
|
||||
|
||||
BinarySpaceTree *l = NULL;
|
||||
BinarySpaceTree *r = NULL;
|
||||
|
||||
if (children) {
|
||||
l = new BinarySpaceTree();
|
||||
l->Deserialize(data, s);
|
||||
r = new BinarySpaceTree();
|
||||
r->Deserialize(data, s);
|
||||
}
|
||||
|
||||
set_children(data, l, r);
|
||||
}
|
||||
|
||||
template<typename Serializer>
|
||||
void SerializeAll(const Dataset& data, Serializer *s) const {
|
||||
// can't use BinarySpaceTree as a magic number, because we want to be
|
||||
// able to deserialize this class with another statistic
|
||||
s->PutMagic(file::CreateMagic("spacetree")
|
||||
+ MAGIC_NUMBER(TDataset) + MAGIC_NUMBER(TBound));
|
||||
data.Serialize(s);
|
||||
Serialize(s);
|
||||
}
|
||||
|
||||
template<typename Deserializer>
|
||||
void DeserializeAll(Dataset* data, Deserializer *s) {
|
||||
// can't use BinarySpaceTree as a magic number, because we want to be
|
||||
// able to deserialize this class with another statistic
|
||||
s->AssertMagic(file::CreateMagic("spacetree")
|
||||
+ MAGIC_NUMBER(TDataset) + MAGIC_NUMBER(TBound));
|
||||
data->Deserialize(s);
|
||||
Deserialize(*data, s);
|
||||
}
|
||||
|
||||
// TODO: Not const correct
|
||||
|
||||
/**
|
||||
|
||||
@@ -101,7 +101,7 @@ struct AffinityCommon {
|
||||
void Init(datanode *module) {
|
||||
dim = -1;
|
||||
pref = fx_param_double_req(module, "pref");
|
||||
lambda = fx_param_double(module, "lambda", 0.9);
|
||||
lambda = fx_param_double(module, "lambda", 0.6);
|
||||
}
|
||||
|
||||
void InitPointExtras(int tag, Point *point) const {
|
||||
@@ -115,11 +115,7 @@ struct AffinityCommon {
|
||||
point->info().alpha.max1 = 0;
|
||||
point->info().alpha.max2 = pref;
|
||||
point->info().alpha.max1_index = index;
|
||||
if (math::RandInt(4096) == 0) {
|
||||
point->info().rho = -pref / 2;
|
||||
} else {
|
||||
point->info().rho = 0;
|
||||
}
|
||||
point->info().rho = 0;
|
||||
}
|
||||
|
||||
void Bootstrap(int tag, index_t dim_in, index_t count) {
|
||||
|
||||
@@ -378,10 +378,6 @@ class DistributedCache : public BlockDevice {
|
||||
}
|
||||
|
||||
public:
|
||||
void Copy(const Position& other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool operator < (const Position& other) const {
|
||||
if (unlikely(block == other.block)) {
|
||||
return offset < other.offset;
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* @experimental
|
||||
*/
|
||||
|
||||
#ifndef TREE_KDTREE_H
|
||||
#define TREE_KDTREE_H
|
||||
#ifndef THOR_KDTREE_H
|
||||
#define THOR_KDTREE_H
|
||||
|
||||
#include "spnode.h"
|
||||
#include "spbounds.h"
|
||||
@@ -733,7 +733,7 @@ void ThorKdTree<TParam, TPoint, TNode>::Init(Param **parampp, int param_tag,
|
||||
Config config;
|
||||
MasterLoadData_(&config, *parampp, param_tag, module);
|
||||
MasterBuildTree_(&config, *parampp, param_tag, module);
|
||||
config.param = *parampp;
|
||||
config.param = new Param(**parampp);
|
||||
config_broadcaster_.SetData(config);
|
||||
} else {
|
||||
CacheArray<Point>::InitDistributedCacheWorker(points_channel_,
|
||||
|
||||
@@ -432,15 +432,17 @@ struct DataGetterRequest {
|
||||
template<typename T>
|
||||
class DataGetterBackend
|
||||
: public RemoteObjectBackend<DataGetterRequest, T> {
|
||||
FORBID_COPY(DataGetterBackend);
|
||||
|
||||
private:
|
||||
T data_;
|
||||
|
||||
public:
|
||||
void Init(const T& data_in) {
|
||||
ot::Copy(data_in, &data);
|
||||
ot::Copy(data_in, &data_);
|
||||
}
|
||||
void Init(const T* data_in) {
|
||||
ot::Copy(*data_in, &data);
|
||||
ot::Copy(*data_in, &data_);
|
||||
}
|
||||
|
||||
virtual void HandleRequest(const DataGetterRequest& request, T *response);
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
* @experimental
|
||||
*/
|
||||
|
||||
#ifndef TREE_SPBOUNDS_H
|
||||
#define TREE_SPBOUNDS_H
|
||||
#ifndef THOR_BOUNDS_H
|
||||
#define THOR_BOUNDS_H
|
||||
|
||||
#include "la/matrix.h"
|
||||
#include "la/la.h"
|
||||
@@ -109,15 +109,12 @@ class MinMaxVal {
|
||||
public:
|
||||
/** The underlying value. */
|
||||
Value val;
|
||||
|
||||
|
||||
OT_DEF_BASIC(MinMaxVal) {
|
||||
OT_MY_OBJECT(val);
|
||||
}
|
||||
|
||||
public:
|
||||
MinMaxVal(Value val_in) : val(val_in) {}
|
||||
MinMaxVal() {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Converts implicitly to the value.
|
||||
*/
|
||||
@@ -155,282 +152,6 @@ class MinMaxVal {
|
||||
}
|
||||
};
|
||||
|
||||
class HiBound {
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple real-valued range.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
struct DRange {
|
||||
public:
|
||||
/**
|
||||
* The lower bound.
|
||||
*/
|
||||
double lo;
|
||||
/**
|
||||
* The upper bound.
|
||||
*/
|
||||
double hi;
|
||||
|
||||
OT_DEF_BASIC(DRange) {
|
||||
OT_MY_OBJECT(lo);
|
||||
OT_MY_OBJECT(hi);
|
||||
}
|
||||
|
||||
public:
|
||||
/** Doesn't initialize anything. */
|
||||
DRange() {}
|
||||
/** Initializes to specified values. */
|
||||
DRange(double lo_in, double hi_in)
|
||||
: lo(lo_in), hi(hi_in)
|
||||
{}
|
||||
|
||||
/** Initialize to an empty set, where lo > hi. */
|
||||
void InitEmptySet() {
|
||||
lo = DBL_MAX;
|
||||
hi = -DBL_MAX;
|
||||
}
|
||||
|
||||
/** Initializes to -infinity to infinity. */
|
||||
void InitUniversalSet() {
|
||||
lo = -DBL_MAX;
|
||||
hi = DBL_MAX;
|
||||
}
|
||||
|
||||
/** Initializes to a range of values. */
|
||||
void Init(double lo_in, double hi_in) {
|
||||
lo = lo_in;
|
||||
hi = hi_in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets to a range of values.
|
||||
*
|
||||
* Since there is no dynamic memory this is the same as Init, but calling
|
||||
* Reset instead of Init probably looks more similar to surrounding code.
|
||||
*/
|
||||
void Reset(double lo_in, double hi_in) {
|
||||
lo = lo_in;
|
||||
hi = hi_in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the span of the range, hi - lo.
|
||||
*/
|
||||
double width() const {
|
||||
return hi - lo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the midpoint of this range.
|
||||
*/
|
||||
double mid() const {
|
||||
return (hi + lo) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpolates (factor) * hi + (1 - factor) * lo.
|
||||
*/
|
||||
double interpolate(double factor) const {
|
||||
return factor * width() + lo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate an union by growing the range if necessary.
|
||||
*/
|
||||
const DRange& operator |= (double d) {
|
||||
if (unlikely(d < lo)) {
|
||||
lo = d;
|
||||
}
|
||||
if (unlikely(d > hi)) {
|
||||
hi = d;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this range to include only the specified value, or
|
||||
* becomes an empty set if the range does not contain the number.
|
||||
*/
|
||||
const DRange& operator &= (double d) {
|
||||
if (likely(d > lo)) {
|
||||
lo = d;
|
||||
}
|
||||
if (likely(d < hi)) {
|
||||
hi = d;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands range to include the other range.
|
||||
*/
|
||||
const DRange& operator |= (const DRange& other) {
|
||||
if (unlikely(other.lo < lo)) {
|
||||
lo = other.lo;
|
||||
}
|
||||
if (unlikely(other.hi > hi)) {
|
||||
hi = other.hi;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shrinks range to be the overlap with another range, becoming an empty
|
||||
* set if there is no overlap.
|
||||
*/
|
||||
const DRange& operator &= (const DRange& other) {
|
||||
if (unlikely(other.lo > lo)) {
|
||||
lo = other.lo;
|
||||
}
|
||||
if (unlikely(other.hi < hi)) {
|
||||
hi = other.hi;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Sums the upper and lower independently. */
|
||||
const DRange& operator += (const DRange& other) {
|
||||
lo += other.lo;
|
||||
hi += other.hi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Subtracts from the upper and lower independently. */
|
||||
const DRange& operator -= (const DRange& other) {
|
||||
lo -= other.lo;
|
||||
hi -= other.hi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Adds to the upper and lower independently. */
|
||||
const DRange& operator += (double d) {
|
||||
lo += d;
|
||||
hi += d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Subtracts from the upper and lower independently. */
|
||||
const DRange& operator -= (double d) {
|
||||
lo -= d;
|
||||
hi -= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend DRange operator + (const DRange& a, const DRange& b) {
|
||||
DRange result;
|
||||
result.lo = a.lo + b.lo;
|
||||
result.hi = a.hi + b.hi;
|
||||
return result;
|
||||
}
|
||||
|
||||
friend DRange operator - (const DRange& a, const DRange& b) {
|
||||
DRange result;
|
||||
result.lo = a.lo - b.lo;
|
||||
result.hi = a.hi - b.hi;
|
||||
return result;
|
||||
}
|
||||
|
||||
friend DRange operator + (const DRange& a, double b) {
|
||||
DRange result;
|
||||
result.lo = a.lo + b;
|
||||
result.hi = a.hi + b;
|
||||
return result;
|
||||
}
|
||||
|
||||
friend DRange operator - (const DRange& a, double b) {
|
||||
DRange result;
|
||||
result.lo = a.lo - b;
|
||||
result.hi = a.hi - b;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the maximum of upper and lower bounds independently.
|
||||
*/
|
||||
void MaxWith(const DRange& range) {
|
||||
if (unlikely(range.lo > lo)) {
|
||||
lo = range.lo;
|
||||
}
|
||||
if (unlikely(range.hi > hi)) {
|
||||
hi = range.hi;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the minimum of upper and lower bounds independently.
|
||||
*/
|
||||
void MinWith(const DRange& range) {
|
||||
if (unlikely(range.lo < lo)) {
|
||||
lo = range.lo;
|
||||
}
|
||||
if (unlikely(range.hi < hi)) {
|
||||
hi = range.hi;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the maximum of upper and lower bounds independently.
|
||||
*/
|
||||
void MaxWith(double v) {
|
||||
if (unlikely(v > lo)) {
|
||||
lo = v;
|
||||
if (unlikely(v > hi)) {
|
||||
hi = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the minimum of upper and lower bounds independently.
|
||||
*/
|
||||
void MinWith(double v) {
|
||||
if (unlikely(v < hi)) {
|
||||
hi = v;
|
||||
if (unlikely(v < lo)) {
|
||||
lo = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares if this is STRICTLY less than another range.
|
||||
*/
|
||||
friend bool operator < (const DRange& a, const DRange& b) {
|
||||
return a.hi < b.lo;
|
||||
}
|
||||
/**
|
||||
* Compares if this is STRICTLY equal to another range.
|
||||
*/
|
||||
friend bool operator == (const DRange& a, const DRange& b) {
|
||||
return a.lo == b.lo && a.hi == b.hi;
|
||||
}
|
||||
DEFINE_ALL_COMPARATORS(DRange);
|
||||
|
||||
/**
|
||||
* Compares if this is STRICTLY less than a value.
|
||||
*/
|
||||
friend bool operator < (const DRange& a, double b) {
|
||||
return a.hi < b;
|
||||
}
|
||||
/**
|
||||
* Compares if a value is STRICTLY less than this range.
|
||||
*/
|
||||
friend bool operator < (double a, const DRange& b) {
|
||||
return a < b.lo;
|
||||
}
|
||||
DEFINE_INEQUALITY_COMPARATORS_HETERO(DRange, double);
|
||||
|
||||
/**
|
||||
* Determines if a point is contained within the range.
|
||||
*/
|
||||
bool Contains(double d) const {
|
||||
return d >= lo || d <= hi;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hyper-rectangle bound for an L-metric.
|
||||
*
|
||||
@@ -458,8 +179,7 @@ class ThorHrectBound {
|
||||
* set.
|
||||
*/
|
||||
void Init(index_t dimension) {
|
||||
DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
|
||||
|
||||
//DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
|
||||
bounds_ = mem::Alloc<DRange>(dimension);
|
||||
|
||||
dim_ = dimension;
|
||||
@@ -475,15 +195,6 @@ class ThorHrectBound {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes as a copy of another.
|
||||
*/
|
||||
void Copy(const ThorHrectBound& other) {
|
||||
DEBUG_ASSERT_MSG(dim_ == BIG_BAD_NUMBER, "Already initialized");
|
||||
bounds_ = mem::Dup(other.bounds_, other.dim_);
|
||||
dim_ = other.dim_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a point is within this bound.
|
||||
*/
|
||||
|
||||
@@ -66,7 +66,6 @@ class ThorNode {
|
||||
}
|
||||
|
||||
void set_range(index_t begin_in, index_t count_in) {
|
||||
DEBUG_ASSERT(begin_ == BIG_BAD_NUMBER);
|
||||
begin_ = begin_in;
|
||||
count_ = count_in;
|
||||
}
|
||||
@@ -151,8 +150,6 @@ class ThorNode {
|
||||
*/
|
||||
template<typename TNode, typename TInfo>
|
||||
class ThorSkeletonNode {
|
||||
FORBID_COPY(ThorSkeletonNode); // TODO: otrav might provide a copy constructor
|
||||
|
||||
public:
|
||||
typedef TNode Node;
|
||||
typedef TInfo Info;
|
||||
@@ -307,12 +304,12 @@ struct TreeGrain {
|
||||
/** One past the last point. */
|
||||
index_t point_end_index;
|
||||
|
||||
TreeGrain()
|
||||
: node_index(-1)
|
||||
, node_end_index(-1)
|
||||
, point_begin_index(-1)
|
||||
, point_end_index(-1)
|
||||
{}
|
||||
void InitBlank() {
|
||||
node_index = -1;
|
||||
node_end_index = -1;
|
||||
point_begin_index = -1;
|
||||
point_end_index = -1;
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return node_index >= 0;
|
||||
@@ -338,8 +335,6 @@ struct TreeGrain {
|
||||
*/
|
||||
template<typename TNode>
|
||||
class ThorTreeDecomposition {
|
||||
FORBID_COPY(ThorTreeDecomposition);
|
||||
|
||||
public:
|
||||
typedef TNode Node;
|
||||
struct Info {
|
||||
@@ -380,7 +375,11 @@ class ThorTreeDecomposition {
|
||||
void Init(DecompNode *root_in) {
|
||||
root_ = root_in;
|
||||
DEBUG_ASSERT(root_->info().begin_rank == 0);
|
||||
grain_by_owner_.Init(root_->info().end_rank);
|
||||
int n = root_->info().end_rank;
|
||||
grain_by_owner_.Init(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
grain_by_owner_[i].InitBlank();
|
||||
}
|
||||
FillInfo_(root_);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user