Merge branch 'master' into deploy-ng

This commit is contained in:
Mitchell Stokes 2018-05-06 11:21:13 -07:00
commit ebe2588a50
12 changed files with 212 additions and 77 deletions

View File

@ -10,7 +10,7 @@ __all__ = ['indent',
'bound', 'clamp', 'lerp', 'average', 'addListsByValue',
'boolEqual', 'lineupPos', 'formatElapsedSeconds', 'solveQuadratic',
'findPythonModule', 'mostDerivedLast',
'weightedChoice', 'randFloat', 'normalDistrib',
'clampScalar', 'weightedChoice', 'randFloat', 'normalDistrib',
'weightedRand', 'randUint31', 'randInt32',
'SerialNumGen', 'serialNum', 'uniqueName', 'Enum', 'Singleton',
'SingletonError', 'printListEnum', 'safeRepr',
@ -178,27 +178,6 @@ class Queue:
def __len__(self):
return len(self.__list)
if __debug__ and __name__ == '__main__':
q = Queue()
assert q.isEmpty()
q.clear()
assert q.isEmpty()
q.push(10)
assert not q.isEmpty()
q.push(20)
assert not q.isEmpty()
assert len(q) == 2
assert q.front() == 10
assert q.back() == 20
assert q.top() == 10
assert q.top() == 10
assert q.pop() == 10
assert len(q) == 1
assert not q.isEmpty()
assert q.pop() == 20
assert len(q) == 0
assert q.isEmpty()
def indent(stream, numIndents, str):
"""
@ -1130,6 +1109,23 @@ def findPythonModule(module):
return None
def clampScalar(value, a, b):
# calling this ought to be faster than calling both min and max
if a < b:
if value < a:
return a
elif value > b:
return b
else:
return value
else:
if value < b:
return b
elif value > a:
return a
else:
return value
def weightedChoice(choiceList, rng=random.random, sum=None):
"""given a list of (weight, item) pairs, chooses an item based on the
weights. rng must return 0..1. if you happen to have the sum of the
@ -2313,36 +2309,6 @@ def flywheel(*args, **kArgs):
pass
return flywheel
if __debug__ and __name__ == '__main__':
f = flywheel(['a','b','c','d'], countList=[11,20,3,4])
obj2count = {}
for obj in f:
obj2count.setdefault(obj, 0)
obj2count[obj] += 1
assert obj2count['a'] == 11
assert obj2count['b'] == 20
assert obj2count['c'] == 3
assert obj2count['d'] == 4
f = flywheel([1,2,3,4], countFunc=lambda x: x*2)
obj2count = {}
for obj in f:
obj2count.setdefault(obj, 0)
obj2count[obj] += 1
assert obj2count[1] == 2
assert obj2count[2] == 4
assert obj2count[3] == 6
assert obj2count[4] == 8
f = flywheel([1,2,3,4], countFunc=lambda x: x, scale = 3)
obj2count = {}
for obj in f:
obj2count.setdefault(obj, 0)
obj2count[obj] += 1
assert obj2count[1] == 1 * 3
assert obj2count[2] == 2 * 3
assert obj2count[3] == 3 * 3
assert obj2count[4] == 4 * 3
if __debug__:
def quickProfile(name="unnamed"):
@ -2687,11 +2653,36 @@ def unescapeHtmlString(s):
result += char
return result
if __debug__ and __name__ == '__main__':
assert unescapeHtmlString('asdf') == 'asdf'
assert unescapeHtmlString('as+df') == 'as df'
assert unescapeHtmlString('as%32df') == 'as2df'
assert unescapeHtmlString('asdf%32') == 'asdf2'
class PriorityCallbacks:
""" manage a set of prioritized callbacks, and allow them to be invoked in order of priority """
def __init__(self):
self._callbacks = []
def clear(self):
del self._callbacks[:]
def add(self, callback, priority=None):
if priority is None:
priority = 0
callbacks = self._callbacks
lo = 0
hi = len(callbacks)
while lo < hi:
mid = (lo + hi) // 2
if priority < callbacks[mid][0]:
hi = mid
else:
lo = mid + 1
item = (priority, callback)
callbacks.insert(lo, item)
return item
def remove(self, item):
self._callbacks.remove(item)
def __call__(self):
for priority, callback in self._callbacks:
callback()
builtins.Functor = Functor
builtins.Stack = Stack

View File

@ -615,6 +615,7 @@ if (COMPILER == "MSVC"):
PkgDisable("EGL")
PkgDisable("CARBON")
PkgDisable("COCOA")
DefSymbol("FLEX", "YY_NO_UNISTD_H")
if (PkgSkip("PYTHON")==0):
IncDirectory("ALWAYS", SDK["PYTHON"] + "/include")
LibDirectory("ALWAYS", SDK["PYTHON"] + "/libs")
@ -890,7 +891,7 @@ if (COMPILER=="GCC"):
SmartPkgEnable("EIGEN", "eigen3", (), ("Eigen/Dense",), target_pkg = 'ALWAYS')
SmartPkgEnable("ARTOOLKIT", "", ("AR"), "AR/ar.h")
SmartPkgEnable("FCOLLADA", "", ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h"))
SmartPkgEnable("ASSIMP", "assimp", ("assimp"), "assimp")
SmartPkgEnable("ASSIMP", "", ("assimp"), "assimp")
SmartPkgEnable("FFMPEG", ffmpeg_libs, ffmpeg_libs, ("libavformat/avformat.h", "libavcodec/avcodec.h", "libavutil/avutil.h"))
SmartPkgEnable("SWSCALE", "libswscale", "libswscale", ("libswscale/swscale.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample/swresample.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
@ -1460,7 +1461,7 @@ def CompileBison(wobj, wsrc, opts):
CopyFile(wdsth, GetOutputDir()+"/tmp/"+ifile+".h")
# Finally, compile the generated source file.
CompileCxx(wobj,wdstc,opts)
CompileCxx(wobj, wdstc, opts + ["FLEX"])
########################################################################
##

View File

@ -1052,7 +1052,7 @@ BulletPersistentManifold *BulletWorld::
get_manifold(int idx) const {
LightMutexHolder holder(get_global_lock());
nassertr(idx < get_num_manifolds(), NULL);
nassertr(idx < _dispatcher->getNumManifolds(), NULL);
btPersistentManifold *ptr = _dispatcher->getManifoldByIndexInternal(idx);
return (ptr) ? new BulletPersistentManifold(ptr) : NULL;
@ -1186,7 +1186,12 @@ tick_callback(btDynamicsWorld *world, btScalar timestep) {
CallbackObject *obj = w->_tick_callback_obj;
if (obj) {
BulletTickCallbackData cbdata(timestep);
// Release the global lock that we are holding during the tick callback
// and allow interactions with bullet world in the user callback
get_global_lock().release();
obj->do_callback(&cbdata);
// Acquire the global lock again and protect the execution
get_global_lock().acquire();
}
}

View File

@ -426,6 +426,23 @@ get_max_updates_per_second() const {
return _max_updates_per_second;
}
/**
* Specifies the Content-Type header, useful for applications that require
* different types of content, such as JSON.
*/
INLINE void HTTPChannel::
set_content_type(string content_type) {
_content_type = content_type;
}
/**
* Returns the value of the Content-Type header.
*/
INLINE string HTTPChannel::
get_content_type() const {
return _content_type;
}
/**
* This may be called immediately after a call to get_document() or some
* related function to specify the expected size of the document we are

View File

@ -100,6 +100,7 @@ HTTPChannel(HTTPClient *client) :
_response_type = RT_none;
_http_version = _client->get_http_version();
_http_version_string = _client->get_http_version_string();
_content_type = "application/x-www-form-urlencoded";
_state = S_new;
_done_state = S_new;
_started_download = false;
@ -3624,7 +3625,7 @@ make_header() {
if (!_body.empty()) {
stream
<< "Content-Type: application/x-www-form-urlencoded\r\n"
<< "Content-Type: " << _content_type << "\r\n"
<< "Content-Length: " << _body.length() << "\r\n";
}

View File

@ -143,6 +143,9 @@ PUBLISHED:
INLINE void set_max_updates_per_second(double max_updates_per_second);
INLINE double get_max_updates_per_second() const;
INLINE void set_content_type(string content_type);
INLINE string get_content_type() const;
INLINE void set_expected_file_size(size_t file_size);
streamsize get_file_size() const;
INLINE bool is_file_size_known() const;
@ -336,6 +339,7 @@ private:
string request_path;
string _header;
string _body;
string _content_type;
bool _want_ssl;
bool _proxy_serves_document;
bool _proxy_tunnel_now;

View File

@ -477,6 +477,7 @@ do_remove(AsyncTask *task, bool upon_death) {
{
int index = find_task_on_heap(_sleeping, task);
nassertr(index != -1, false);
PT(AsyncTask) hold_task = task;
_sleeping.erase(_sleeping.begin() + index);
make_heap(_sleeping.begin(), _sleeping.end(), AsyncTaskSortWakeTime());
cleanup_task(task, upon_death, false);
@ -486,6 +487,7 @@ do_remove(AsyncTask *task, bool upon_death) {
case AsyncTask::S_active:
{
// Active, but not being serviced, easy.
PT(AsyncTask) hold_task = task;
int index = find_task_on_heap(_active, task);
if (index != -1) {
_active.erase(_active.begin() + index);
@ -769,7 +771,6 @@ cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit) {
}
nassertv(task->_chain == this);
PT(AsyncTask) hold_task = task;
task->_state = AsyncTask::S_inactive;
task->_chain = nullptr;

View File

@ -138,35 +138,45 @@ get_datagram(Datagram &data) {
return true;
}
streamsize num_bytes = (streamsize)num_bytes_32;
size_t num_bytes = (size_t)num_bytes_32;
if (num_bytes_32 == (uint32_t)-1) {
// Another special case for a value larger than 32 bits.
num_bytes = reader.get_uint64();
}
uint64_t num_bytes_64 = reader.get_uint64();
// Make sure we have a reasonable datagram size for putting into memory.
nassertr(num_bytes == (size_t)num_bytes, false);
if (_in->fail() || _in->eof()) {
_error = true;
return false;
}
num_bytes = (size_t)num_bytes_64;
// Make sure we have a reasonable datagram size for putting into memory.
if (num_bytes_64 != (uint64_t)num_bytes) {
_error = true;
return false;
}
}
// Now, read the datagram itself. We construct an empty datagram, use
// pad_bytes to make it big enough, and read *directly* into the datagram's
// internal buffer. Doing this saves us a copy operation.
data = Datagram();
streamsize bytes_read = 0;
size_t bytes_read = 0;
while (bytes_read < num_bytes) {
streamsize bytes_left = num_bytes - bytes_read;
size_t bytes_left = num_bytes - bytes_read;
// Hold up a second - datagrams >4MB are pretty large by bam/network
// standards. Let's take it 4MB at a time just in case the length is
// corrupt, so we don't allocate potentially a few GBs of RAM only to
// find a truncated file.
bytes_left = min(bytes_left, (streamsize)4*1024*1024);
bytes_left = min(bytes_left, (size_t)4*1024*1024);
PTA_uchar buffer = data.modify_array();
buffer.resize(buffer.size() + bytes_left);
unsigned char *ptr = &buffer.p()[bytes_read];
_in->read((char *)ptr, bytes_left);
_in->read((char *)ptr, (streamsize)bytes_left);
if (_in->fail() || _in->eof()) {
_error = true;
return false;

View File

@ -78,8 +78,8 @@ extract_record(FltRecordReader &reader) {
bool FltBeadID::
extract_ancillary(FltRecordReader &reader) {
if (reader.get_opcode() == FO_long_id) {
vector_uchar s = reader.get_iterator().get_remaining_bytes();
_id.assign((const char *)s.data(), strnlen((const char *)s.data(), s.size()));
DatagramIterator &di = reader.get_iterator();
_id = di.get_fixed_string(di.get_remaining_size());
return true;
}

View File

@ -621,8 +621,8 @@ extract_record(FltRecordReader &) {
bool FltRecord::
extract_ancillary(FltRecordReader &reader) {
if (reader.get_opcode() == FO_comment) {
vector_uchar s = reader.get_iterator().get_remaining_bytes();
_comment.assign((const char *)s.data(), strnlen((const char *)s.data(), s.size()));
DatagramIterator &di = reader.get_iterator();
_comment = di.get_fixed_string(di.get_remaining_size());
return true;
}

View File

@ -88,8 +88,8 @@ def test_minkowski_sum_shape():
assert type(shape) is type(shape2)
assert shape.margin == shape2.margin
assert shape.name == shape2.name
assert shape.transform_a.compare_to(shape2.transform_a, True) == 0
assert shape.transform_b.compare_to(shape2.transform_b, True) == 0
assert shape.transform_a.mat.compare_to(shape2.transform_a.mat, 0.001) == 0
assert shape.transform_b.mat.compare_to(shape2.transform_b.mat, 0.001) == 0
assert type(shape.shape_a) == type(shape2.shape_a)
assert type(shape.shape_b) == type(shape2.shape_b)

View File

@ -0,0 +1,105 @@
from direct.showbase import PythonUtil
def test_queue():
q = PythonUtil.Queue()
assert q.isEmpty()
q.clear()
assert q.isEmpty()
q.push(10)
assert not q.isEmpty()
q.push(20)
assert not q.isEmpty()
assert len(q) == 2
assert q.front() == 10
assert q.back() == 20
assert q.top() == 10
assert q.top() == 10
assert q.pop() == 10
assert len(q) == 1
assert not q.isEmpty()
assert q.pop() == 20
assert len(q) == 0
assert q.isEmpty()
def test_flywheel():
f = PythonUtil.flywheel(['a','b','c','d'], countList=[11,20,3,4])
obj2count = {}
for obj in f:
obj2count.setdefault(obj, 0)
obj2count[obj] += 1
assert obj2count['a'] == 11
assert obj2count['b'] == 20
assert obj2count['c'] == 3
assert obj2count['d'] == 4
f = PythonUtil.flywheel([1,2,3,4], countFunc=lambda x: x*2)
obj2count = {}
for obj in f:
obj2count.setdefault(obj, 0)
obj2count[obj] += 1
assert obj2count[1] == 2
assert obj2count[2] == 4
assert obj2count[3] == 6
assert obj2count[4] == 8
f = PythonUtil.flywheel([1,2,3,4], countFunc=lambda x: x, scale = 3)
obj2count = {}
for obj in f:
obj2count.setdefault(obj, 0)
obj2count[obj] += 1
assert obj2count[1] == 1 * 3
assert obj2count[2] == 2 * 3
assert obj2count[3] == 3 * 3
assert obj2count[4] == 4 * 3
def test_unescape_html_string():
assert PythonUtil.unescapeHtmlString('asdf') == 'asdf'
assert PythonUtil.unescapeHtmlString('as+df') == 'as df'
assert PythonUtil.unescapeHtmlString('as%32df') == 'as2df'
assert PythonUtil.unescapeHtmlString('asdf%32') == 'asdf2'
def test_priority_callbacks():
l = []
def a(l=l):
l.append('a')
def b(l=l):
l.append('b')
def c(l=l):
l.append('c')
pc = PythonUtil.PriorityCallbacks()
pc.add(a)
pc()
assert l == ['a']
del l[:]
bItem = pc.add(b)
pc()
assert 'a' in l
assert 'b' in l
assert len(l) == 2
del l[:]
pc.remove(bItem)
pc()
assert l == ['a']
del l[:]
pc.add(c, 2)
bItem = pc.add(b, 10)
pc()
assert l == ['a', 'c', 'b']
del l[:]
pc.remove(bItem)
pc()
assert l == ['a', 'c']
del l[:]
pc.clear()
pc()
assert len(l) == 0