Compare commits

...

892 Commits

Author SHA1 Message Date
JoelKatz
d22b25c030 Set version to 0.21.0 2014-01-23 13:38:38 -08:00
JoelKatz
d475994e02 Pairwise no ripple:
* Cannot set noRipple flag with negative balance.
* Paths with consecutive no ripple links are invalid
* Adjust pathfinding value of no ripple out paths
* Check for no ripple when adding links in pathfinding
* Remove old noRipple logic
* Update trust line delete logic
2014-01-23 13:38:33 -08:00
JoelKatz
f0bb3dfdfb Never allow a retry as a final result 2014-01-23 13:38:28 -08:00
JoelKatz
e7f0b8eca6 Add DeliveredAmount to transaction metadata 2014-01-23 13:38:25 -08:00
JoelKatz
0bab6a9fec Add directory and order book iterators
This should fix the crossed order book bug.
* Change OfferCreate::takeOffers to use new iterators
* Change NetworkOps::getBookPage to use new iterators
* If we find an offer in the book but not the ledger, deindex it
2014-01-23 13:38:11 -08:00
David Schwartz
9486fc416c Support AccountTxnID and LastLedgerSequence. 2014-01-23 13:37:46 -08:00
JoelKatz
fb63aa737a Revert d2953f602e 2014-01-23 13:36:31 -08:00
JoelKatz
58a6ca1d3d Remove extraneous logging 2014-01-23 13:24:51 -08:00
JoelKatz
505f029edb Clean up 'destination_currencies' in new pathfinding reply 2014-01-23 13:24:43 -08:00
JoelKatz
815659b898 Replace a lock with an atomic in new pathfinding 2014-01-23 13:24:33 -08:00
JoelKatz
07d16f280c Clean up the checkAccept path to use the ledger sequence 2014-01-23 13:24:28 -08:00
JoelKatz
f88ddc947c Handle non-object in 'json' RPC method 2014-01-23 13:24:22 -08:00
Vinnie Falco
65ffdff40c Insight support for ResourceManager 2014-01-21 10:28:36 -05:00
Vinnie Falco
c95dccfec6 Move PathRequests to separate files 2014-01-21 10:28:36 -05:00
Vinnie Falco
fe83f471f5 Use duration in insight::Event, add chrono_util 2014-01-21 10:28:35 -05:00
sublimator
d2953f602e Error reporting tests 2014-01-21 10:28:35 -05:00
Vinnie Falco
9d07ddeae1 Improved human readable JSON-RPC error messages 2014-01-21 10:28:34 -05:00
Vinnie Falco
ef7810bc95 Add ScopedPointer::reset 2014-01-21 10:28:34 -05:00
David Schwartz
486539b3d3 Make offerDelete and fill Items more robust. 2014-01-21 10:28:34 -05:00
David Schwartz
990fb20a2a OrderBookDB::addOrderBook cleanup 2014-01-21 10:28:33 -05:00
Vinnie Falco
9b61a83721 Refactor, tidy up:
* Fix for msvc std::function return types
* Convert macros to constants
* Add Journal to PeerSet and use in InboundLedger
* Break lines and add annotations
* Remove some warnings
2014-01-21 10:28:33 -05:00
JoelKatz
f753519976 Ledger fetch improvements. Fetch policy improvements. 2014-01-17 16:06:15 -08:00
David Schwartz
663e38dcdd Locking and dispatching performance improvements:
* Avoid taking the master lock in most peer operations
* Dispatch recvGetLedger to JobQueue
* Dispatch consensus ledger fetches.
* Release master lock earlier in RPCHandler
2014-01-17 16:05:48 -08:00
Vinnie Falco
7570b6489d Fix and tidy up NodeStore
* Use std::unique_ptr
* Move globals to Manager singleton (fixes RocksDB exit crash)
2014-01-17 15:21:51 -05:00
Vinnie Falco
c341d1a71e Tidy up for C++11, and fixes:
* Remove shared_ptr legacy support
* Add make_unique support for pre-C++14 environments
* Fix comparison bug in sqdb
* Use std::shared_ptr in a few places
2014-01-17 12:19:04 -05:00
Vinnie Falco
fa10e90c9d Use abstract_clock 2014-01-17 12:19:04 -05:00
Vinnie Falco
68501763dd Refactor KeyCache 2014-01-17 12:19:04 -05:00
Vinnie Falco
cac1d555be Add std::make_unique 2014-01-17 12:19:03 -05:00
NATTSiM
25ff77c2fd Fix Clang compile and link errors 2014-01-16 17:18:05 -05:00
Vinnie Falco
2870c7f457 Workaround for MSVC std::function bug 2014-01-15 19:10:08 -08:00
JoelKatz
ab8d7a86ae Dispatch peerHas to JobQueue 2014-01-14 11:24:41 -08:00
JoelKatz
809359e81e Correctly handle empty account tree in ledger fetch 2014-01-14 11:24:32 -08:00
JoelKatz
6e4cd5bc9c Don't send nodes twice in getNodeFat 2014-01-14 11:24:01 -08:00
NATTSiM
de018bd582 Improved PropertyStream find and print routines 2014-01-13 21:51:31 -08:00
Vinnie Falco
544642a6ea Fix io_latency_probe hang on exit 2014-01-13 18:24:22 -08:00
JoelKatz
06737bb36f SHAMapSync bugfix. Cannot avoid push in getMissingNodes 2014-01-13 09:50:54 -08:00
JoelKatz
7efbfa2d20 Limit legacy pathfinding requests 2014-01-10 23:09:26 -08:00
Vinnie Falco
4d5df92cbc Add io_latency_probe 2014-01-10 22:54:00 -08:00
David Schwartz
1fcb2872b9 Reduce log priorities. 2014-01-10 22:54:00 -08:00
David Schwartz
00c87ca2dd Add LES::dirIsEmpty function to check if a directory is empty 2014-01-10 22:53:59 -08:00
JoelKatz
d474d68566 Order book subscribe cleanups. 2014-01-10 22:53:59 -08:00
David Schwartz
93e03804d0 SHAMapSync cleanups and performance improvements 2014-01-10 22:53:58 -08:00
JoelKatz
4591658160 PathRequests object to own all path requests. 2014-01-10 22:53:57 -08:00
JoelKatz
a2109b4bda Remove files inadvertently added 2014-01-10 22:53:57 -08:00
Vinnie Falco
deafea9c88 [REMOVE] Allow gcc 4.7 and later 2014-01-10 22:53:57 -08:00
Nicholas Dudfield
93f1a05f5c Update build for gcc 4.8.x:
* Use gcc 4.8.x, boost 1.54
* Honor CC,CXX,PATH environment variables
* Prevent compilation with unsupported toolchains
* Print g++ version during Travis build
* Run built-in unit tests after Travis build
2014-01-10 16:24:17 -08:00
Vinnie Falco
95a573b755 Set version to 0.20.1 2014-01-08 17:08:27 -08:00
Nik Bougalis
2a4623814c Don't log StatsD messages to the console by default 2014-01-08 16:57:47 -08:00
Vinnie Falco
1017adf743 Set version to 0.20.0 2014-01-08 16:15:12 -08:00
Vinnie Falco
34fb12344c Fix JobQueue 2014-01-08 14:55:10 -08:00
Vinnie Falco
ce3358bdf8 Improve diagnostics for ResourceManager 2014-01-08 11:18:46 -08:00
Vinnie Falco
1159dadfdb Fix missing jtACCEPT job limit 2014-01-08 11:18:45 -08:00
Vinnie Falco
62516ef07f Refactor TaggedCache 2014-01-07 21:14:14 -08:00
Vinnie Falco
eecd305efd Add std::hash <std::pair> specialization 2014-01-07 21:14:13 -08:00
Vinnie Falco
a83fa6b2b2 Fix warning in chrono_io 2014-01-07 21:14:07 -08:00
Vinnie Falco
b2feafa94c Use abstract_clock and improved tests, in ResourceManager
Conflicts:
	Builds/VisualStudio2012/RippleD.vcxproj.filters
2014-01-07 17:23:26 -08:00
Vinnie Falco
2d234e500d Add abstract_clock, manual_clock, chrono_io
Conflicts:
	src/beast/Builds/VisualStudio2012/beast.vcxproj.filters
2014-01-07 17:17:26 -08:00
Vinnie Falco
fee0e7b20e Fix bind in call to addJob 2014-01-07 17:08:01 -08:00
JoelKatz
a0f6429652 Add LedgerHolder class, use in LedgerMaster 2014-01-07 15:57:51 -08:00
JoelKatz
8f8b2ae4a3 Handle offers in quality directory but not in ledger 2014-01-07 15:57:50 -08:00
JoelKatz
9abdd16721 Release the master lock earlier in a few cases 2014-01-07 15:57:50 -08:00
JoelKatz
1e5963aeeb Move some operations from the I/O queue to the Job queue 2014-01-07 15:57:50 -08:00
JoelKatz
e25a83bb39 Some tiny bugfixes:
* Don't let ledger idle interval get too short
* Fix CBigNum::setuint256
* Fix SqliteStatement::isError
* Remove dead code, fix incorrect comments
* Check for NULL earlier in CKey constructors
* Prevent expire times from underflowing in TaggedCache
2014-01-07 15:57:49 -08:00
David Schwartz
e3a67b13ff Reset liquidity before retrying rippleCalc 2014-01-07 15:57:48 -08:00
JoelKatz
750cbb8399 Improvements because items in SHAMaps are immutable:
* SHAMapItem::getData is not needed
* SHAMapTreeNode::getItem is not needed
* SHAMapTreeNode::getData is not needed
* No need to copy them when constructing transactions
* No need to copy them when computing map deltas
* No need to copy them in deepCompare
* No need to copy them in SHAMapTreeNode's copy constructor
2014-01-07 15:57:48 -08:00
JoelKatz
045beb5f36 Concurrent SHAMap code
Use shared lock for SHAMap itself and concurrent map for nodes
2014-01-07 15:57:47 -08:00
JoelKatz
cd8234acba Pathfinding bugfix. Missing lock. 2014-01-07 15:57:46 -08:00
JoelKatz
de85a7c2bd Pathfinding improvements:
* Make each path request track whether it needs updating.
* Improve new request handling, reverse order for processing requests.
* Break to handle new requests immediately.
* Make mPathFindThread an integer rather than a bool. Allow two threads.
* For old pathfinding, if the ledger is unspecified, use the PathRequest's RippleLineCache.
* Log new pathfinding request latencies.
* Suspend processing requests if server is backed up.
2014-01-07 15:57:46 -08:00
Vinnie Falco
087301933a General refactoring, using C++11
* Remove broken RecycledObjectPool

* Fix beast::ServiceQueue using List instead of LockFreeStack

* Add class semaphore, fixes broken Semaphore

* Move crytpo module files to new beast directory

* Use c++11 replacements for boost and beast types:
  - std::atomic instead of beast::Atomic
  - std::function instead of boost::function, beast::function
  - std::unique_ptr instead of beast::ScopedPointer
  - std::shared_ptr instead of boost::shared_ptr

* Remove modules:
  - beast_db
  - beast_crypto
  - beast_extras

* Remove unnecessary classes:
  - AbstractFifo
  - AddConst
  - AtomicCounter
  - AtomicFlag
  - AtomicPointer
  - AtomicState
  - CopyConst
  - Expression
  - ForwardList
  - IfCond
  - Interval
  - IntrusiveArray
  - KeyvaDB
  - PointerToOther
  - PointerTraits
  - RemoveConst
  - RemoveConstVolatile
  - RemoveReference
  - RemoveVolatile
  - SharedObjectArray
  - SingleThreadedSharedObject
  - SophiaDB factory
  - SortedSet
  - WeakReference
  - beast::unique_ptr
2014-01-07 15:57:45 -08:00
JoelKatz
52333b8bd4 Fix a compiler warning in Ledger::visitStateItems 2014-01-07 15:48:50 -08:00
JoelKatz
3768b3c3ca Fix a pathfinding bug 2014-01-07 15:48:50 -08:00
JoelKatz
09b39e107d Fix subscribing to "real time" transactions. 2014-01-07 15:48:49 -08:00
Vinnie Falco
4b1155bf32 Improved diagnostic for RocksDB error codes
Conflicts:
	Builds/VisualStudio2012/RippleD.vcxproj.filters
2014-01-07 15:46:38 -08:00
Vinnie Falco
3c7fc31c95 Add ripple_common module
Conflicts:
	Builds/VisualStudio2012/RippleD.vcxproj.filters
2014-01-07 15:15:44 -08:00
Nicholas Dudfield
da3881a486 Make websocket-test the first test, and give custom timeouts of 1000ms 2014-01-05 13:40:47 +07:00
Nicholas Dudfield
ff12d9adaa Run server-test and websocket-test first. Show stderr upon abnormal rippled exit 2014-01-05 13:09:42 +07:00
Vinnie Falco
528cf56f80 Reduce StatsDCollector log verbosity 2014-01-02 19:32:27 -08:00
Vinnie Falco
0ebe3f1f35 Disable NameResolver temporarily 2014-01-02 16:12:55 -08:00
Vinnie Falco
328680b6cd Fix Resolver contract check 2014-01-02 16:10:49 -08:00
Vinnie Falco
f9dca105a6 Improved async stop for Resolver
Conflicts:
	src/ripple_app/peers/NameResolver.cpp
2014-01-02 15:38:03 -08:00
Vinnie Falco
3664db61e7 Fix static storage duration issue with some Journal logs 2014-01-02 15:21:33 -08:00
Vinnie Falco
49677aa799 Fix RippleBookType and unit tests 2013-12-29 11:33:50 -08:00
NATTSiM
27b771e2ba Fix clang compile 2013-12-27 17:46:51 -08:00
Vinnie Falco
6527cdfa97 Add RippleAsset types
Conflicts:
	Builds/VisualStudio2012/RippleD.vcxproj.filters
2013-12-27 17:21:11 -08:00
JoelKatz
b2dbe8ef83 Ledger acquire fixes/cleanups/logging
* Inbound ledger and SHAMapAddNode cleanup
    * Log acquire stats
    * Fix progress logic
    * Remove ledgers we no longer need to acquire
    * Stash stale state data in our fetch pack, it can still be useful
    * Stash in fetch pack if acquire terminated while job was pending
    * Account for duplicate/invalid nodes in a few cases previously missed
    * Dispatch each InboundLedger once (not per data)
    * Trigger only the "best" peer
    * Don't call tryAdvance on failed acquires
2013-12-27 16:48:03 -08:00
NATTSiM
9bdb0774ad Make InboundLedgers, LedgerConsensus abstract 2013-12-27 16:48:03 -08:00
Vinnie Falco
8c2ec2cfbe Add AbstractObject, cyclic_iterator, Journal improvements 2013-12-27 16:47:43 -08:00
Wolfgang Spraul
00f959ab7e removed boost_random 2013-12-26 14:31:22 -08:00
Vinnie Falco
f9c4070ad3 Add FetchPack unit test 2013-12-22 12:57:44 -08:00
Vinnie Falco
074325a7ea Inject SHAMap missing node handler dependency 2013-12-22 12:38:07 -08:00
JoelKatz
2f521a6a91 Build fetch packs correctly. 2013-12-22 12:38:07 -08:00
sublimator
07959b3cc9 Allow to full network limit in Amount::isLegalNet 2013-12-20 15:44:03 -08:00
The Doctor
21faf8eaeb Improvements to initscript and default configuration.
* Added absolute paths to the [node_db] and [debug_logfile] stanzas in the config file.

* Changed some tabs into spaces for consistency.

* Added directory tree sanity checking to initscript.

Signed-off-by: The Doctor <drwho@virtadpt.net>
2013-12-20 15:38:30 -08:00
Nik Bougalis
3e2b5dcc3d Hostname resolution support for Peers 2013-12-19 14:50:03 -08:00
Nik Bougalis
88a8433d31 Add reference counting to AsyncObject 2013-12-19 14:39:26 -08:00
Vinnie Falco
81d418007a Add CollectorManager for Beast.Insight support 2013-12-16 18:08:11 -08:00
Vinnie Falco
f88fcf55a3 Add Beast.Insight stats collection module 2013-12-16 12:22:25 -08:00
Vinnie Falco
561c8dea08 Add stl module for c++11 compatibility classes 2013-12-16 11:35:21 -08:00
David Schwartz
de92ac9e0b Websocket improvements:
* Log on_close/on_fail/on_open calls.
* Ping out connections.
* Improve ping logic.
* On websocket ping out, close abnormally.
* Avoid deadlock when shutting down websocket endpoint
2013-12-16 09:40:15 -08:00
JoelKatz
deead04a6a getFetchPack fixes, spread fetch pack requests. 2013-12-15 07:20:24 -08:00
JoelKatz
d4771a9b36 Fix missing call to setPubLedger on gap in published ledger stream. 2013-12-13 11:14:34 -08:00
JoelKatz
27b8415d0c During old pathfinding, unlock earlier. 2013-12-12 21:17:25 -08:00
David Schwartz
e1e81e5d97 Call pendSaveValidated without holding the ledger master lock 2013-12-12 21:17:20 -08:00
Vinnie Falco
3705680d68 Disable RocksDB for older compilers 2013-12-10 11:23:06 -08:00
Vinnie Falco
a01f546ae3 Use ScopedPointer instead of deprecated auto_ptr 2013-12-10 14:14:15 -05:00
Bryce Lynch
eabc905bac Add Debian-style initscript
* Add validators and validation_quorum from the v0.16 release notes.
* We keep having to tell people to do this during integration, let's just make it the default.
* Add comment about the log file location that states that it has to be absolute rather than relative after an integration troubleshoot earlier today.

Signed-off-by: Bryce Lynch <bryce@ripple.com>
2013-12-09 16:21:22 -08:00
JoelKatz
37588b6808 Avoid an extraneous test. 2013-12-09 00:52:40 -08:00
JoelKatz
071db75f04 Add a 1 MB payload limit to incoming websocket requests 2013-12-09 00:52:40 -08:00
David Schwartz
1e00940a90 Move some ledger cleaner helper functions into the ledger master. 2013-12-08 23:53:57 -08:00
JoelKatz
b984566480 Suppress a warning. 2013-12-08 23:53:47 -08:00
JoelKatz
51aef120a1 Pathfinding performance improvements:
* Use a single RippleLineCache, even for 'fast' requests
* Use a ledger copy to avoid stalling other code
2013-12-08 23:52:54 -08:00
JoelKatz
636d722e8d Memory-conserving changes to SHAMapTreeNode and visitLeavesInternal. 2013-12-08 23:52:54 -08:00
Vinnie Falco
e6da61120a Make AbstractObject unit test manual 2013-12-06 09:57:03 -08:00
JoelKatz
b901e0dcf3 Fix load stats in get_info 2013-12-05 22:04:42 -08:00
Vinnie Falco
177b3c93c4 Move DecayingSample to algorithm 2013-12-05 18:35:37 -08:00
JoelKatz
9996e4a57e The new recommended fee schedule is:
* Transaction fee: 10 drops
* Base reserve: 20 XRP
* Incremental reserve: 5 XRP
2013-12-04 19:07:58 -08:00
JoelKatz
4751b6a65c Fix for issue 211, fixes to NetworkOPs getTxsAccountB 2013-12-04 17:09:22 -08:00
David Schwartz
b3c79f5c2f Change visitLeaves to visit a snapshot so the ledger stays unlocked 2013-12-04 11:10:27 -08:00
David Schwartz
0e53105ab5 Remove dead code and fix a race condition in the node back end.
Race was between a store and a fetch, as follows:
1) Fetch: Search for the node, it is not found.
2) Store: Add the node to the database, remove the node from the negative cache.
3) Fetch: Add the node to the negative cache.
This would leave a node in the DB, cache, and negative cache.
2013-12-04 11:10:22 -08:00
Vinnie Falco
0f2a657196 Add double conversion for PropertyStream map items 2013-11-30 17:56:25 -08:00
Vinnie Falco
89aa2c7a6a Refactor some Journal::Sink members 2013-11-30 17:32:50 -08:00
Vinnie Falco
4c843b6c66 IPAddress fixes and algorithm comparison functors 2013-11-30 09:21:46 -08:00
Vinnie Falco
130c7c5c58 Refactor and fix some object arithmetic comparisons 2013-11-30 06:28:29 -08:00
Vinnie Falco
76c364ec2d Add const now() 2013-11-30 01:42:38 -08:00
Vinnie Falco
a549c94a15 Fix missing assert in UnitTest runner 2013-11-30 01:42:37 -08:00
Vinnie Falco
6de8a6907f Add AbstractObject 2013-11-30 01:42:37 -08:00
Vinnie Falco
fc31562052 Tidy doc comments 2013-11-29 23:44:36 -08:00
Vinnie Falco
cdaa65c07a Remove LightningDB database and backend 2013-11-27 15:14:21 -08:00
Vinnie Falco
8a278cf9d6 Remove sophia database and backend 2013-11-27 15:09:26 -08:00
Vinnie Falco
97cecc18ce Set version to 0.19.2 2013-11-27 13:10:19 -08:00
JoelKatz
536db23e14 Fix foundResume check in account_tx 2013-11-27 12:25:45 -08:00
Vinnie Falco
39d801fb9f Merge branch 'release' into develop 2013-11-27 10:00:34 -08:00
Vinnie Falco
6d707b21b2 Set version to 0.19.1 2013-11-27 09:54:41 -08:00
JoelKatz
2316fe5bbe A better way to return an empty set if the token isn't an object. 2013-11-27 09:11:42 -08:00
JoelKatz
16ec9d2bdb Return an empty set if token is not an object 2013-11-27 08:54:49 -08:00
JoelKatz
2ce4ce4309 Begin deprecating the old account_tx interface. 2013-11-26 22:01:10 -08:00
JoelKatz
858c3a5362 Force NDEBUG in sqlite, RocksDB, and HyperLevelDB by default 2013-11-26 21:59:35 -08:00
JoelKatz
c124ad0dcd Add BEAST_SQLITE_FORCE_NDEBUG option 2013-11-26 21:56:17 -08:00
JoelKatz
ed64c8bb29 Add LedgerCleaner:
* Manually invoked to clean ledgers
* Get status with: 'print app.ledgercleaner.*'
* Invoke or control with 'ledger_cleaner' command
2013-11-26 21:50:35 -08:00
Vinnie Falco
2678360715 Set version to 0.19.0 2013-11-22 23:39:12 -08:00
JoelKatz
54e504dd5a Make --import work 2013-11-22 23:39:07 -08:00
JoelKatz
b632a6b2cf If the RocksDB base file size is changed, change the write cache and L0 size to match 2013-11-22 23:39:02 -08:00
Vinnie Falco
b9e2ac38fa Set version to 0.19.0 2013-11-22 23:36:50 -08:00
JoelKatz
4d1c2a5798 Make --import work 2013-11-22 18:01:13 -08:00
JoelKatz
c69d8a13b3 If the RocksDB base file size is changed, change the write cache and L0 size to match 2013-11-22 16:13:12 -08:00
Vinnie Falco
7c358cda17 Set version to 0.18.0 2013-11-22 15:57:59 -08:00
Vinnie Falco
1954a0eb2e Set version to 0.18.0 2013-11-22 15:57:41 -08:00
Vinnie Falco
5500701661 Fix Workers thread name 2013-11-22 15:51:20 -08:00
Vinnie Falco
21918922f4 Set background thread name 2013-11-22 15:51:20 -08:00
Vinnie Falco
fad52c5917 Comment out write to stdout 2013-11-22 15:51:20 -08:00
Vinnie Falco
306811d2a7 Add RocksDB NodeStore backend 2013-11-22 15:51:19 -08:00
Vinnie Falco
8b72f2ad79 Add rocksdb module 2013-11-21 18:31:15 -08:00
Vinnie Falco
1a1cb696f7 Make include paths relative 2013-11-21 16:59:54 -08:00
Vinnie Falco
582c17b06b Merge commit 'b156a49cff152fd52992a4823aaeafbaf70e564e' as 'src/ripple/rocksdb/rocksdb' 2013-11-21 16:24:10 -08:00
Vinnie Falco
b156a49cff Squashed 'src/ripple/rocksdb/rocksdb/' content from commit 56589ab
git-subtree-dir: src/ripple/rocksdb/rocksdb
git-subtree-split: 56589ab81f
2013-11-21 16:24:10 -08:00
Vinnie Falco
3943cfea06 Fix LevelDB Windows port 2013-11-21 15:00:57 -08:00
David Grogan
97346c6618 Upgrade LevelDB from 1.12 to 1.14:
* Fix issues 77, 87, 182, 190, 200, and 201

* Fix bug described in https://groups.google.com/d/msg/leveldb/yL6h1mAOc20/vLU64RylIdMJ

* Fix a bug where options.max_open_files was not getting clamped properly.

* Fix link to bigtable paper in docs.

* New sstables will have the file extension .ldb. .sst files will continue to be recognized.
2013-11-21 12:59:46 -08:00
JoelKatz
474b824902 Don't throw away an initial error when detecting the handshake. 2013-11-20 17:01:21 -08:00
David Schwartz
02b5572ccc Changes to support the ledger cleaner
* Rework ledger save return values to indicate errors to callers
* Add an extra function to support the ledger cleaner.
2013-11-20 12:22:45 -08:00
Vinnie Falco
4577ad60c7 Fix ResourceManager log output 2013-11-20 11:31:19 -08:00
JoelKatz
e683c380e5 Fix a defect in RangeSet. 2013-11-20 11:31:14 -08:00
Vinnie Falco
b660d82516 Make TxFormats a Meyers singleton 2013-11-20 10:16:46 -08:00
Nicholas Dudfield
c0dda06499 Parse STArray correctly in STObject::parseJson 2013-11-20 08:54:59 -08:00
Vinnie Falco
65abd6307d Update hyperleveldb module 2013-11-19 11:33:09 -08:00
Vinnie Falco
6e713dc3b8 Merge commit '596a35accad6e838e05180e79c1ea626eaf93a34' into develop 2013-11-19 11:32:55 -08:00
Vinnie Falco
596a35acca Squashed 'src/hyperleveldb/' changes from ac2ae30..25511b7
25511b7 Merge branch 'master' of github.com:rescrv/HyperLevelDB into hyperdb
ed01020 Make "source" universal
3784d92 Ignore the static file
507319b Don't package with snappy
3e2cc8b Tolerate -fno-rtti
4dcdd6e Drop revision down to 1.0.dev
2542163 Drop all but the latest kept for garbage reasons
9c270b7 Update .gitignore
5331878 Add upack script
adc2a7a Explicitly add -lpthread for Ubuntu
7b57bbd Strip NULL chars passed to LiveBackup
e3b87e7 Add write-buffer-size option to benchmark
2f11087 Followup to snappy support with -DSNAPPY
af503da Improve efficiency of ReplayIterator; fix a bug
33c1f0c Add snappy support
ce1cacf Fix a race in ReplayIterator
5c4679b Fix a bug in the replay_iterator
ca332bd Fix sort algorithm used for compaction boundaries.
d9ec544 make checK
b83a9cd Fix a deadlock in the ReplayIterator dtor
273547b Fix a double-delete in ReplayIterator
3377c7a Add "all" to set of special timestamps
387f43a Timestamp comparison and validation.
f9a6eb1 make distcheck
9a4d0b7 Add a ReplayIterator.
1d53869 Conditionally enable read-driven compaction.
f6fa561 16% end-to-end performance improvement from the skiplist
28ffd32 Merge remote-tracking branch 'upstream/master'
a58de73 Revert "Remove read-driven compactions."
e19fc0c Fix upstream issue 200
748539c LevelDB 1.13
78b7812 Add install instructions to README
e47a48e Make benchmark dir variable
820a096 Update distributed files.
486ca7f Live backup of LevelDB instances
6579884 Put a reference counter on log_/logfile_
3075253 Update internal benchmark.
2a6b0bd Make the Version a parameter of PickCompaction
5bd76dc Release leveldb 1.12

git-subtree-dir: src/hyperleveldb
git-subtree-split: 25511b7a9101b0bafb57349d2194ba80ccbf7bc3
2013-11-19 11:32:55 -08:00
Vinnie Falco
4ad84a339f Make LedgerMaster abstract 2013-11-18 15:04:17 -08:00
JoelKatz
833435f8c2 The 'ledger' RPC command should be considered high burden if 'full' is set. 2013-11-17 20:11:40 -08:00
JoelKatz
4e4942e357 Fix break logic in STObject::parseJson for arrays. 2013-11-16 18:57:08 -08:00
JoelKatz
1fc8f0a33b Missing break in STObject::parseJson for arrays. 2013-11-16 18:56:01 -08:00
Vinnie Falco
1f433dea97 Add ripple_app TODO 2013-11-15 18:39:07 -08:00
Vinnie Falco
d8707cad2c Refactor logging 2013-11-15 13:25:56 -08:00
Vinnie Falco
a399b571ac Journal API improvements 2013-11-15 12:30:01 -08:00
Vinnie Falco
d0e71225c4 Fix severity check on ~ScopedStream 2013-11-15 11:29:45 -08:00
Vinnie Falco
19d4bf0ea5 Add README and tidy up comments 2013-11-15 11:29:45 -08:00
Vinnie Falco
9e519af887 Add missing README and TODO for all new modules 2013-11-15 11:27:26 -08:00
JoelKatz
29aa462bfd Add more comments to the consensus code. 2013-11-14 22:41:34 -08:00
JoelKatz
7a91872ee5 Fix broken indentation around BOOST_FOREACH 2013-11-14 22:35:09 -08:00
JoelKatz
68307d1012 Functions like remote_endpoint().address() can throw 2013-11-14 11:20:35 -08:00
JoelKatz
48cb707bb6 Handle a missing ledger node discovered during pathfinding. 2013-11-14 11:20:16 -08:00
JoelKatz
9322233b37 Allow the SHAMap visitLeaves functions to sanely handle a missing map node. 2013-11-13 11:04:17 -08:00
JoelKatz
1daf1b9932 Use MultiSocket for websocket 2013-11-12 21:09:01 -08:00
JoelKatz
a3024352ba Pathfinding improvements. 2013-11-12 21:08:52 -08:00
David Schwartz
58f07a573f New ResourceManager for managing server load.
* Track abusive endpoints
* Gossip across cluster.
* Use resource manager's gossip support to share load reporting across a cluster
* Swtich from legacy fees to new Resource::Charge fees.
* Connect RPC to the new resource manager.
* Set load levels where needed in RPC/websocket commands.
* Disconnect abusive peer endpoints.
* Don't start conversations with abusive peer endpoints.
* Move Resource::Consumer to InfoSub and remove LoadSource
* Remove port from inbound Consumer keys
* Add details in getJson
* Fix doAccountCurrencies for the new resource manager.
2013-11-12 21:08:52 -08:00
Vinnie Falco
a05f33f6a7 Add annotation and clean up whitespace 2013-11-12 19:30:07 -08:00
Vinnie Falco
968624971f Add TestOverlay README 2013-11-12 09:18:11 -08:00
JoelKatz
57e77a5bd2 Use Ledger::visitStateItems to implement OrderBookDB::update 2013-11-11 21:31:18 -08:00
JoelKatz
74c65cfdc5 Cleanup path request logging. 2013-11-11 19:29:56 -08:00
JoelKatz
399760fda9 Assign each path finding request an ID and track its lifecycle. 2013-11-11 18:32:45 -08:00
Vinnie Falco
67b8f95b1e Add PeerFinder README doc 2013-11-10 15:51:29 -08:00
Vinnie Falco
d4d6acdf68 Add MSVC Output window Journal config setting
Conflicts:
	src/ripple/peerfinder/impl/Manager.cpp
	src/ripple/validators/impl/Manager.cpp
2013-11-10 15:06:05 -08:00
Vinnie Falco
472baa8bac Update README 2013-11-10 10:42:07 -08:00
Vinnie Falco
dd74c19858 Tidy up LoadMonitor stats API 2013-11-09 12:08:23 -08:00
Vinnie Falco
b5f8d447a0 Tidy up Resource::Manager APIs 2013-11-09 12:00:37 -08:00
JoelKatz
5f4a1917a6 Change how cluster load is computed from average-ish to median-ish. 2013-11-08 11:05:43 -08:00
JoelKatz
cf71680aee Don't return too many paths. 2013-11-08 11:05:05 -08:00
JoelKatz
f04b9131cc terNO_LINE should never be the final result of a payment transaction that can claim a fee. 2013-11-08 10:32:15 -08:00
JoelKatz
46861fac48 Don't allow a payment to take anything from an expired offer. 2013-11-08 10:17:12 -08:00
JoelKatz
4620b667e7 Fix a race condition if PathRequest::doCreate races with the path being processed. 2013-11-07 22:30:11 -08:00
Vinnie Falco
49f43ccc0a Set version to 0.17.0-rc5 2013-11-07 10:30:50 -08:00
Vinnie Falco
63aa7284c4 Disable peerfinder hooks 2013-11-07 09:59:28 -08:00
Patrick Dehne
286ade2d17 Beast improvements and vflib compatibility module work
* Add CallQueue vflib compatibility class
* Use run instead of run_one
* Merge BindableServiceQueue into CallQueue
* Take BEAST_VARIADIC_MAX into account
* Fix license headers as suggested by Vinnie
* Remove obsolete comment
* Add ManualServiceQueue
* Add ManualServiceQueue to beast_vflib include
* Move static unit test variables of header only classes to module cpp
* Remove no longer used mutex member
* _VARIADIC_MAX maxes out at 10
* Correctly apply BEAST_VARIADIC_MAX
* Merge BindableServiceQueue into CallQueue
* New GuiServiceQueue and its JUCE dependency
* Fix leftover merge errors
* Fix CallQueue unit test
* Don't use bassert for better CI support
2013-11-07 09:42:37 -08:00
Vinnie Falco
066d92ecfa Improve MultiSocket::ssl_handle 2013-11-07 09:35:04 -08:00
Vinnie Falco
c5ccabec38 Fix to use IPS from config 2013-11-06 06:19:06 -08:00
Vinnie Falco
548fedb859 Fix missing cstdlib 2013-11-06 06:19:02 -08:00
Nicholas Dudfield
8d5378a2ca Ensure no offers cancel each other out 2013-11-05 23:20:45 -08:00
David Schwartz
bf1843be9e Add "account_currencies" command. 2013-11-05 16:07:17 -08:00
David Schwartz
d50439cc4d doAccountLines cleanup. 2013-11-05 15:41:15 -08:00
Vinnie Falco
6a8f313394 Set version to 0.17.0-rc4 2013-11-05 14:41:49 -08:00
David Schwartz
c211094d3e Allow two trust lines to be created without reserve check. 2013-11-05 13:29:07 -08:00
Vinnie Falco
072b4f3b73 Set version to 0.17.0-rc3 2013-11-05 11:22:20 -08:00
Vinnie Falco
08cbcba4ee Fix warning 2013-11-05 03:23:15 -08:00
Vinnie Falco
2a9171c623 Improve hasher for IPAddress 2013-11-05 03:15:09 -08:00
Vinnie Falco
8573679fbb Fix compile error 2013-11-05 03:09:39 -08:00
Vinnie Falco
811f244fc2 Set boolalpha for Journal::ScopedStream 2013-11-05 03:09:39 -08:00
Vinnie Falco
a31b2556a3 Add ostream support for PropertyStream items 2013-11-05 03:09:39 -08:00
Vinnie Falco
a0ad5cdbfe Add to_string for asio endpoints 2013-11-05 03:09:39 -08:00
Nicholas Dudfield
59cf668348 Fix IPAddress::V4::Proxy 2013-11-05 03:02:20 -08:00
Stefan Thomas
09acc26c50 Fix marker being set for last result. 2013-11-03 22:39:55 -08:00
JoelKatz
0ae7bcff52 Fix the path filtering loop exit condition. 2013-11-03 17:20:10 -08:00
JoelKatz
2210dbac94 Don't abort the path filtering loop too early. 2013-11-03 16:37:35 -08:00
JoelKatz
6b2f654a30 Improve path filtering:
1) Ignore paths with very low liquidity
2) Allow an extra filling path to be added if needed
2013-11-03 02:20:18 -08:00
Vinnie Falco
3296ac5628 Turn off test URL in SiteFiles 2013-11-01 16:10:25 -07:00
Vinnie Falco
6d06cb29df Block until thread exits in manager dtors 2013-11-01 15:48:37 -07:00
Vinnie Falco
b08c7d15cd Stoppable, make stop() require call to start() 2013-11-01 13:31:38 -07:00
Vinnie Falco
940d620a96 Fix SiteFiles thread name 2013-11-01 10:34:35 -07:00
Vinnie Falco
a39fa8ae5f New SiteFiles for fetching and managing ripple.txt files 2013-10-31 08:10:06 -07:00
Vinnie Falco
f859bf160a Improve URL string conversions and ostream support 2013-10-31 08:10:06 -07:00
Vinnie Falco
e0512930ae Fix error parameter in HTTPClient logic 2013-10-31 08:10:06 -07:00
Vinnie Falco
7bbf6c553f Move ServiceQueueBase out of detail namespace 2013-10-31 08:10:05 -07:00
Vinnie Falco
aeb335ebdc Add hash function to URL 2013-10-31 08:10:05 -07:00
Vinnie Falco
73ab408b3c Move MurmurHash to beast 2013-10-31 08:10:04 -07:00
Vinnie Falco
f333a33f3d Make ServiceQueue::enqueue virtual 2013-10-31 08:10:04 -07:00
Nik Bougalis
42b841735e PeerFinder work 2013-10-29 20:52:57 -07:00
Vinnie Falco
e710bd2183 Use IPAddressConversion 2013-10-29 20:52:57 -07:00
Vinnie Falco
84556ba76a Add Bootstrap Strategy exposition 2013-10-29 20:52:56 -07:00
David Schwartz
4eebea91d3 DecayingSample::decay must always return with the time current. 2013-10-29 14:46:22 -07:00
JoelKatz
4ddadb8792 Correctly compute amount left on sell offer when a crossing offer pays us more than we asked for. 2013-10-28 16:48:47 -07:00
JoelKatz
8e65d6288d Fix limit calculation. 2013-10-28 07:24:01 -07:00
Justin Lynn
8e18deb74f disable e-mail notifications for travisCI 2013-10-25 17:48:20 -07:00
Justin Lynn
7ae1ad524b Merge branch 'develop' of github.com:ripple/rippled into develop 2013-10-24 19:11:17 -07:00
Justin Lynn
1ba1b3983a travis installs exuberant-ctags 2013-10-24 19:11:08 -07:00
Nicholas Dudfield
aabd6980ac Fix a bug in websocket-test.js referencing done() not declared in test() function signature, was causing failure of subsequent test suite, due to mocha's enveloped exception handling style 2013-10-24 19:03:03 -07:00
Nicholas Dudfield
3b19310252 Declarative path tests 2013-10-24 19:03:03 -07:00
Justin Lynn
8201805b28 explicitly use libboost 1.48 2013-10-24 18:53:38 -07:00
Justin Lynn
7277c8478b install dependencies when running travis ci 2013-10-24 18:47:18 -07:00
Justin Lynn
963a0dd934 initial travis yml file 2013-10-24 18:40:07 -07:00
JoelKatz
3108d58791 Fix typo. 2013-10-24 16:57:27 -07:00
Patrick Dehne
31b1a6a7e6 Add beast_vflib compatibility module and stand alone unit test app 2013-10-23 17:37:00 -07:00
JoelKatz
9ff65d0da4 Fix setting the no ripple flag when a trust line is created. 2013-10-23 17:24:34 -07:00
JoelKatz
c11abb42d1 Fix a case where 'sign' won't work in standalone mode. 2013-10-23 17:24:16 -07:00
Vinnie Falco
7b6d81d812 Measure CPU usage in Workers 2013-10-22 17:23:54 -07:00
Vinnie Falco
ca0daad11f Update notes 2013-10-22 12:59:56 -07:00
Vinnie Falco
a0c4e685c5 Add local_endpoint and remote_endpoint to MultiSocket 2013-10-22 12:33:11 -07:00
Nik Bougalis
b30f7a622c Set PEERS_MAX default value 2013-10-22 11:48:43 -07:00
Vinnie Falco
23f44f12bd Add IPAddressConversion and asio module 2013-10-22 11:45:30 -07:00
Nik Bougalis
6c17002e8a Peerfinder work 2013-10-22 10:43:17 -07:00
Vinnie Falco
5dda088335 Peerfinder work 2013-10-22 10:43:16 -07:00
Vinnie Falco
2427cce2c8 Rename to IPAddress and remove unused files 2013-10-22 10:43:16 -07:00
Nik Bougalis
1c41dae51c PeerFinder work 2013-10-22 10:43:15 -07:00
Vinnie Falco
1a6d72b14c Squelch spurious linker warning 2013-10-22 10:43:15 -07:00
Vinnie Falco
3dc646e03e Use serialized Context wrapper in Validators 2013-10-22 10:43:14 -07:00
Vinnie Falco
96328a8632 Add FixedPeers connection policy to peerfinder 2013-10-22 10:43:14 -07:00
Vinnie Falco
2cc4488d8e Fix crash in PropertyStream::find 2013-10-22 10:13:46 -07:00
wltsmrz
a6c2fe4761 Remove coffeescript compiler from mocha.opts until it is needed and added to dependencies 2013-10-21 17:54:36 -07:00
JoelKatz
ed905d3c3d Remove redundant code. 2013-10-21 15:06:05 -07:00
Vinnie Falco
81eadbd05c RelativeTime tidying 2013-10-20 15:31:50 -07:00
Patrick Dehne
ef1e2f8595 monotonicCurrentTimeInSeconds should return seconds, not milliseconds 2013-10-21 00:11:44 +02:00
Patrick Dehne
fae7082049 Wrap hiResCounterHandler in a function to prevent an order of initialization problems 2013-10-20 23:38:52 +02:00
Patrick Dehne
a63de23156 Rename millisecondsSinceStartup to monotonicCurrentTimeInSeconds 2013-10-20 23:37:24 +02:00
Patrick Dehne
8e0dda8480 #ifdef unneeded sys/prctl.h include in the mac build 2013-10-20 01:43:24 +02:00
Patrick Dehne
ad7b9ff8b5 Make fromStartup compile on mac 2013-10-20 01:38:59 +02:00
Vinnie Falco
04f2d0787a Merge commit '2ad98a025eb263d97b1942fc468937b4719becd8' into develop
Conflicts:
	src/beast/beast/utility/PropertyStream.h
	src/beast/beast/utility/impl/PropertyStream.cpp
	src/beast/modules/beast_sqlite/beast_sqlite.h
2013-10-19 15:57:15 -07:00
Vinnie Falco
2ad98a025e Squashed 'src/beast/' changes from 43e6d34..0e7bac9
0e7bac9 Fix include path
e5bb90f Fix constness of Proxy
ac0142a Use template cast
ef6e381 Add missing Url.h include
206e65c Fix constness of operator[]
695cc38 Use template instantiation for friend declaration
7b1e03a Add BaseFromMember
49bc04f Make List<>::Node not uncopyable
d5954ff Add Journal to UnitTest
58da106 Temporarily disable ServiceQueue dtor precondition asserts
fe58c1a Add missing #include
2c02580 Add PropertyStream for server state introspection
24c2315 Add ScopedWrapperContext
a3845f5 Add RelativeTime::value_type typedef
7442932 Fix missing PropertyStream members
ed5a98f More PropertyStream output for PeerFinder
fcfa10d Add PropertyStream
3cf0729 Tidy up AbstractHandler usage in HTTPClient
55171f4 Remove obsolete source files
1311ca3 Increase arity of SharedFunction
67d807d Add IPEndpoint::key_equal
ebf395e Add ErrorCode and boost library
2c3ead3 Add ServiceQueue::wrap
6c7f5d0 Move many Thread related classes
93e9d86 Measure CPU utilization in ServiceQueue
ca47d72 Move ServiceQueue, ThreadLocalValue, SpinLock
c864e4d Move WaitableEvent
ff305e6 Add CPUMeter and ScopedTimeInterval
01fd05c Add RecursiveMutex, UnlockGuard, TryLockGuard
5831a53 Remove Journal from most Stoppable overrides
b60a7f3 Add Request and Response HTTP parsers
44445ff Refactor net buffers classes
ac37c38 Beast class refactor
8b7056b Fix eof on HTTP client get
228b664 Remove obsolete beast container classes
1dfd655 Use RelativeTime from startup in DeadlineTimer
ae22d5d Add more methods to RelativeTime
c67929e Remove unhandled exception catcher
2472a90 Add 64 bit output for MurmurHash
f3d97c7 Add RelativeTime::fromStartup
b0b8660 IPEndpoint better parsing
ae551cd Add alternate form string parsing to IPEndpoint
d0a0dbf Don't break on Throw
0e46762 Add hasher functors for IPEndpoint
a1ec423 Add Thread::stopThreadAsync
4f7dca3 Add compiler, stdlib, and platform skeleton to beast/config
4394594 Tidy up some use of Error for throw
e5e0f52 Journal console output improvements
f07515e Add Stoppable prepare and start interfaces
d37dd46 Move RelativeTime to chrono, add ostream support
3f6e7aa Add console feature to Journal
ad0064a Journal option to write to Output window (MSVC)
0b7574b Add compilation test script
cc05ce1 Add ServiceQueue
e132aab Use boost for functional when the config is set
026b926 Fix is_continuation for boost version
c807a4e Fix invoked_type type reference
2ff781b Remove LockFreeStack::size
3acb474 Add SharedData::ConstAccess
7e4c834 Add LockFreeStack::empty
9c61a6d Added AbstractHandler, WrapHandler. HTTPClient Fixes.
94e40dc Fix unittest, by removing recursive call.
38bf408 Fix nonstandard C++ extension in getNullSink
1ef044d Build fixes
d5d3746 Fix missing <cmath> include for Gentoo
5f231d3 Update copyright notice and licenses
7b89bf6 Add FixedArray, IntrusiveArray, Crypto
5c5de57 Reorganize beast modules and files
9e18bb3 Merge commit '43deaaa5cf0d0178a4a6c3cb69c02a2a9a43ec7d' as 'src/beast/beast/http/impl/http-parser'
57703ac Fix BeforeBoost.h include
fbc247b Add Stoppable to beast
56496d8 IPEndpoint comparisons
9d9c822 Migrate some headers and general tidying
1a3cddc Add SharedArg and AsyncObject
373ca9c Add HTTPRequest and improvements to HTTPMessage parsing
9534516 Add some thread classes and fix SharedData with a simple mutex adapter
755ab36 Make CallQueue unit test runManual
c0ca037 Remove Beast version printing on startup
7efb6a3 Reorganize some MPL and Utility classes and files
69c26a1 Fix missing BeastConfig.h include in Net.cpp
40aa552 Disable Beast version printing in Ripple BeastConfig.h
7b1352d Add InterruptibleThread unit test
68cf759 ThreadWithCallQueue unit test adjustment
6501dea IPEndpoint parsing and tidying
72fc42b Move and add some template metaprogramming classes
2a164f0 Change filname capitalization (end)
6a14f25 Change filename capitalization
92fd417 Move integer types to beast/CStdInt.h
ebbd9ff Move TargetPlatform.h to beast/Config.h
874b524 Add IPEndpoint
14b34fc Tidy up some zlib macro undefines
34fffca Rename beast sources for consistency
4e59ab2 Add CallQueue unit test
327d7a6 Fixes for consolidated beast unity includes
d5ece4e Remove unused and broken classes
39f13be Remove unused ConcurrentObject
37624a7 Add ThreadWithCallQueue unit test
e82ec68 Remove obsolete beast_Function
90551a6 Temporarily leave sqlite3 in whatever threading mode it was already in.
43ebbb1 Fix SharedSingleton to use memoryBarrier
f343941 Tidy up SharedSingleton doc comments
001997e Fix leak on exit from Singleton dependency cycle
83b9d22 Rename to DeadlineTimer::cancel()
77874ee Use new instead of ::new for placement
2a04dcc Journal improvements
50965ca SharedFunction improvements
277e32b Add LockFreeStack iterators
d94e4c2 Fix undefined behavior in UnsignedIntegerCalc (again)
2dc25ce Fix DeadlineTimer, callback while holding lock
207ffde Fix undefined behavior in UnsignedIntegerCalc
1ad8ff9 Fix UnsignedInteger::isZero
1dd2836 Add support for multiprecision integer arithmetic and binary data encoding
a45fc47 Update .gitignore
962a95d Tidy up UnsignedInteger
ca695fa Add Time::isNull()
e96ce99 Better random number facilities in UnitTest
550b8e5 Fine tune UnsignedInteger declaration
8e7e3b7 Allow negative relative expirations in DeadlineTimer
f3dc7ce Add generic Journal class for logging
bfdda32 Make ChildProcess UnitTest manual since it malfunctions
02acf7d General refactoring of beast framework classes
84ef06e Fix ExitHook to derive from AtExitHook
f0acc9c Reduce the max threads in the Workers unit test
55447b0 New SharedSingleton, resolves destruction of objects with static storage duration.
41eb8a1 Remove deprecated SharedPtr::getObject
9eda4bc Make SharedObject members const, the counter mutable
6eda777 Remove deprecated createOnDemandOnce SingletonLifetime option
8c522aa Fix off by one in pending i/o count on HTTPClient
057344e Add HTTPMessage::toString and family
ee728e3 Add UniformResourceLocator::empty
ae324fb Move ./modules to ./src

git-subtree-dir: src/beast
git-subtree-split: 0e7bac945f
2013-10-19 15:54:21 -07:00
JoelKatz
67516766a6 Operations on the raw socket can throw exceptions if it's no longer connected. 2013-10-19 14:14:47 -07:00
Vinnie Falco
3b2ead3476 Turn off console output for msvc logic and managers 2013-10-18 16:29:13 -07:00
Vinnie Falco
fc5be2b911 Use DiscreteClock in ResourceManager 2013-10-18 16:04:37 -07:00
Vinnie Falco
466e623dd6 Add BaseFromMember 2013-10-18 16:04:37 -07:00
Vinnie Falco
a1b487c512 New Resource::Manager for controlling access to server resources 2013-10-18 16:04:31 -07:00
Vinnie Falco
0902af8eb5 Add DiscreteClock and sources 2013-10-17 17:46:23 -07:00
Vinnie Falco
a8a4caf0e4 Make List<>::Node not uncopyable 2013-10-17 17:46:18 -07:00
Vinnie Falco
33478517a6 Add Journal to UnitTest 2013-10-17 17:46:13 -07:00
Vinnie Falco
0d5a8ca300 Revert "Ported declarative path tests to mocha"
This reverts commit abe4f1ba03.
2013-10-17 11:11:06 -07:00
Vinnie Falco
da22f06d85 Revert "Make mocha use test/mocha.opts to DRY up options used by npm test and test/runall.sh and support coffee. Add coffee-script as devDependency to package.json"
This reverts commit 9dfbffa4b8.

Conflicts:

	test/mocha.opts
2013-10-17 11:10:48 -07:00
Vinnie Falco
a918924923 Temporarily disable ServiceQueue dtor precondition asserts 2013-10-16 15:59:04 -07:00
JoelKatz
5a9416fbcf Remove an assert that is not needed. 2013-10-16 13:47:54 -07:00
Vinnie Falco
582b5bb3ac Add --version command line option 2013-10-16 13:29:43 -07:00
Nicholas Dudfield
abe4f1ba03 Ported declarative path tests to mocha 2013-10-13 18:24:41 +07:00
Nicholas Dudfield
9dfbffa4b8 Make mocha use test/mocha.opts to DRY up options used by npm test and test/runall.sh and support coffee. Add coffee-script as devDependency to package.json 2013-10-13 15:38:04 +07:00
Vinnie Falco
a25ba91876 Set version to 0.17.0-rc2 2013-10-11 18:41:45 -07:00
Nik Bougalis
334f109415 Remove extraneous index from peerfinder map. 2013-10-11 18:36:34 -07:00
JoelKatz
eb9eb3aa53 Fix a crash in checkAccept 2013-10-11 16:13:16 -07:00
JoelKatz
978c196c78 Don't assert, just throw. 2013-10-08 15:48:15 -07:00
JoelKatz
20e7cac743 Reduce some logging. 2013-10-08 15:05:41 -07:00
Vinnie Falco
b5d51214ff Add missing #include 2013-10-07 14:26:26 -07:00
Vinnie Falco
485d4b4897 Fix order of includes 2013-10-07 14:24:13 -07:00
Vinnie Falco
fb6ecebbd1 Add PropertyStream for server state introspection 2013-10-07 14:00:03 -07:00
Vinnie Falco
0b69378a03 Update Json::Reader::decodeDouble 2013-10-07 02:49:03 -07:00
Vinnie Falco
256c12f150 Add ScopedWrapperContext 2013-10-06 19:46:42 -07:00
Nik Bougalis
8d0349eee0 Add RelativeTime::value_type typedef 2013-10-06 18:33:53 -07:00
Vinnie Falco
ab0548c9af Fix std::size_t integer ambiguity 2013-10-06 18:33:15 -07:00
Vinnie Falco
4868bc4df7 Validators PropertyStream support 2013-10-06 18:25:59 -07:00
Vinnie Falco
0900dfe46f Fix missing PropertyStream members 2013-10-06 18:25:53 -07:00
Vinnie Falco
8dfe53ff7a More PropertyStream output for PeerFinder 2013-10-06 17:30:45 -07:00
Vinnie Falco
1ae3328642 Add PropertyStream 2013-10-06 17:30:44 -07:00
JoelKatz
b9e0208aee Payment engine doesn't allow returning to XRP. 2013-10-06 15:52:16 -07:00
Vinnie Falco
497cc74adc Set version to 0.17.0-rc1 2013-10-06 11:35:47 -07:00
Vinnie Falco
eac3814fb5 Tidy up AbstractHandler usage in HTTPClient 2013-10-05 15:38:27 -07:00
Vinnie Falco
bb331abeba Remove obsolete source files 2013-10-05 13:08:39 -07:00
Vinnie Falco
6e20bd2dcd Increase arity of SharedFunction 2013-10-05 13:08:39 -07:00
Vinnie Falco
09961845b4 Remove obsolete AsyncService class 2013-10-05 13:08:38 -07:00
Vinnie Falco
7eacd3bf57 Add annotation for Validators 2013-10-05 12:03:51 -07:00
Vinnie Falco
72681fa7fb PeerFinder work 2013-10-05 11:59:17 -07:00
Vinnie Falco
500bddebff Allow CycledSet to grow without bounds 2013-10-05 02:46:23 -07:00
Vinnie Falco
4d3d46f41d Add IPEndpoint::key_equal 2013-10-05 02:41:29 -07:00
Vinnie Falco
82d8d9a092 PeerFinder work, Source fetch, show port in log 2013-10-04 23:22:56 -07:00
Vinnie Falco
30ff139a29 Add ErrorCode and boost library 2013-10-04 23:18:28 -07:00
Vinnie Falco
dc8420d32d LegacyEndpointCache work 2013-10-04 23:18:27 -07:00
Vinnie Falco
bb29c8ba85 Add PeerFinder::Checker for testing endpoints 2013-10-04 23:18:27 -07:00
Vinnie Falco
625780621b Add ServiceQueue::wrap 2013-10-04 23:18:26 -07:00
Vinnie Falco
ea2589dd9c PeerFinder work 2013-10-04 19:25:48 -07:00
Vinnie Falco
942336c454 Move many Thread related classes 2013-10-04 14:34:01 -07:00
Vinnie Falco
90282707ab Measure CPU utilization in ServiceQueue 2013-10-04 14:34:00 -07:00
Vinnie Falco
70f6c41ff7 Move ServiceQueue, ThreadLocalValue, SpinLock 2013-10-04 14:34:00 -07:00
Vinnie Falco
184cf74daa Move WaitableEvent 2013-10-04 14:33:59 -07:00
Vinnie Falco
a23fb06409 Add CPUMeter and ScopedTimeInterval 2013-10-04 14:33:59 -07:00
Vinnie Falco
3638485977 Add RecursiveMutex, UnlockGuard, TryLockGuard 2013-10-04 14:33:59 -07:00
Vinnie Falco
75f3c52d53 Validators work 2013-10-04 14:33:58 -07:00
Vinnie Falco
364973a523 Rename to key_equal for conformance with std containers 2013-10-04 14:33:58 -07:00
Vinnie Falco
678c241962 Validators work 2013-10-04 14:33:57 -07:00
Vinnie Falco
a2aa938e10 Remove Journal from most Stoppable overrides 2013-10-04 14:33:57 -07:00
Vinnie Falco
48eb92e366 Validators work 2013-10-04 14:33:56 -07:00
Vinnie Falco
2894059b63 Fix Peers to stop after children are stopped 2013-10-04 14:33:56 -07:00
Vinnie Falco
66a272debd Alphabet class for base58 conversions, Validators work 2013-10-04 14:33:56 -07:00
Vinnie Falco
7d089561c3 Add Request and Response HTTP parsers 2013-10-04 14:33:55 -07:00
Vinnie Falco
53f8e73b65 Refactor net buffers classes 2013-10-04 14:33:55 -07:00
JoelKatz
37bcf7899e Improve performance of some RPC ledger commands using visitors.
Adds SHAMap::visitLeaves and Ledger::visitStateItems
2013-10-04 11:50:22 -07:00
JoelKatz
86f662aa4a It is not longer necessary to invalidate the OrderBookDB 2013-10-04 02:33:33 -07:00
Vinnie Falco
a1b958eaac Validators update, add LeakChecked to Source subclasses 2013-10-03 19:03:38 -07:00
Vinnie Falco
06189b2584 Disable MSVC OutputWindow for PeerFinder 2013-10-03 19:03:10 -07:00
Vinnie Falco
0bf006cdae Beast class refactor 2013-10-03 19:03:10 -07:00
Vinnie Falco
3f51eb7b63 Fix eof on HTTP client get 2013-10-03 18:36:55 -07:00
Vinnie Falco
b76443dbde Use a simple Thread in SqliteDatabase 2013-10-03 18:36:54 -07:00
Vinnie Falco
5fc823ae08 Show Ripple version in BuildInfo unittest 2013-10-03 18:36:54 -07:00
Vinnie Falco
68aec74b47 Remove obsolete beast container classes 2013-10-03 18:36:53 -07:00
Vinnie Falco
acd23682d1 Use RelativeTime from startup in DeadlineTimer 2013-10-03 18:36:53 -07:00
Vinnie Falco
b042397b9f Add more methods to RelativeTime 2013-10-03 18:36:53 -07:00
David Schwartz
951a8208b8 Don't let OrderBookDB oscillate between two ledgers. 2013-10-03 17:49:38 -07:00
David Schwartz
9b3c74a095 Return the account checked if account_info finds no account. 2013-10-03 16:53:56 -07:00
David Schwartz
647c0e302a Do the tryLocal/addPeers operations on an InboundLedger without the collection lock. 2013-10-03 16:36:33 -07:00
David Schwartz
b3b22d7595 Nothing we do in doTx requires the master lock. 2013-10-03 10:55:42 -07:00
JoelKatz
1ba0139683 Claim saInRemaining. 2013-10-02 16:13:14 -07:00
Vinnie Falco
15ef435054 Set version to 0.16.0 2013-10-02 12:06:54 -07:00
Vinnie Falco
1a95dfb300 Refine Json unit test 2013-10-02 12:06:30 -07:00
Vinnie Falco
6962bdb325 Set version to 0.15.0 2013-10-02 12:02:01 -07:00
Vinnie Falco
bbbb8b1411 Fix buffer printing in json value to string 2013-10-02 11:59:32 -07:00
Vinnie Falco
0a5505f785 Add json parsing unit test 2013-10-02 11:53:18 -07:00
Vinnie Falco
b6d11c08d0 Set version to 0.14.0 2013-10-02 09:55:57 -07:00
Vinnie Falco
0f26fbd701 Set version to 0.14.0-rc3 2013-10-01 15:35:30 -07:00
Vinnie Falco
a236c81b5f Temporary fix on ENDPOINTS message hops=0 when no remote addr set 2013-10-01 15:35:06 -07:00
Vinnie Falco
73700a483d Set version to 0.14.0-rc2 2013-10-01 15:05:30 -07:00
Vinnie Falco
6062f6b036 Fix RippleAddress::clear 2013-10-01 15:05:03 -07:00
Vinnie Falco
e29b0b150d Set version to 0.14.0-rc1 2013-10-01 14:29:38 -07:00
Vinnie Falco
4fe63f9f0d PeerFinder work 2013-10-01 14:29:32 -07:00
Vinnie Falco
41879d8511 Remove obsolete mtANNOUNCE message support 2013-10-01 14:03:44 -07:00
Vinnie Falco
46d3ace6b7 Fix JobQueue to measure waiting and run times correctly 2013-10-01 12:25:02 -07:00
Vinnie Falco
2ac2fdfabd Remove unhandled exception catcher 2013-10-01 12:25:01 -07:00
Vinnie Falco
2aa5c74c2a Add 64 bit output for MurmurHash 2013-10-01 12:25:01 -07:00
Vinnie Falco
d624ed1151 Add RelativeTime::fromStartup 2013-10-01 12:25:00 -07:00
Vinnie Falco
9bc132778f Remove obsolete clean app exit configuration macro 2013-10-01 12:25:00 -07:00
Vinnie Falco
ac13c97f7e IPEndpoint better parsing 2013-10-01 12:25:00 -07:00
JoelKatz
26dfa9231a Clean up Sustain. 2013-10-01 11:18:41 -07:00
JoelKatz
072f2c93ef Do the initial work on new pathfinding requests without holding the master lock. 2013-10-01 11:06:32 -07:00
JoelKatz
14fb246b67 Handle mLedgersByIndex better. 2013-10-01 11:02:33 -07:00
JoelKatz
99e4335f00 Improve ledger performance by making sure we properly track the new LCL. 2013-10-01 11:02:33 -07:00
JoelKatz
ea1a5a77c5 Remove an obsolete comment. 2013-10-01 11:02:33 -07:00
JoelKatz
a815f455af Fix a possible buffer overflow. 2013-09-30 21:33:19 -07:00
JoelKatz
b2c46db006 Fix a bug that can cause servers to stick as 'syncing' for too long.
Add a sensible path to get to omFULL state when consensus is initiated by peer action.
2013-09-30 12:26:24 -07:00
Vinnie Falco
097b6f8e33 Add alternate form string parsing to IPEndpoint 2013-09-30 09:29:37 -07:00
Vinnie Falco
9aca3cb21c Don't break on Throw 2013-09-30 09:29:36 -07:00
Vinnie Falco
d1f589835c Add hasher functors for IPEndpoint 2013-09-30 09:29:36 -07:00
Vinnie Falco
27e8a71f08 Fix LoadManager stop 2013-09-30 09:29:34 -07:00
Vinnie Falco
db531d905c Add Thread::stopThreadAsync 2013-09-30 09:29:33 -07:00
Vinnie Falco
d27ad6251c Improve the display resolution of LoadMonitor samples 2013-09-30 04:07:14 -07:00
JoelKatz
217a017195 Reduce memory consumption while fetching. 2013-09-30 02:40:35 -07:00
JoelKatz
9350f3085d Better logging of ledger fetching. 2013-09-29 23:21:08 -07:00
JoelKatz
018a030d97 Clean this up and make it handle exceptions a bit more sanely. 2013-09-29 12:29:30 -07:00
JoelKatz
052fc7be22 'Throw' is for fatal throws only. Use 'throw' for non-fatal. 2013-09-29 12:19:15 -07:00
JoelKatz
9e0d7241eb Don't try to put transaction information in a fetch pack if there are no transactions in the target ledger. 2013-09-29 11:42:25 -07:00
JoelKatz
191e76a558 Fix a crash if a client requests an order book snapshot before we have a published ledger. 2013-09-29 11:34:07 -07:00
JoelKatz
511978b1eb Handle a partial ledger in fixMismatch 2013-09-29 07:08:00 -07:00
Vinnie Falco
6beb7996ff Fix LoadMonitor unit reporting for seconds from milliseconds 2013-09-29 02:48:26 -07:00
Vinnie Falco
c82b1b1853 Validators improvements 2013-09-28 19:47:40 -07:00
Vinnie Falco
a6ec4f91b0 Add compiler, stdlib, and platform skeleton to beast/config 2013-09-28 19:34:16 -07:00
Vinnie Falco
75c28f3951 Tidy up some use of Error for throw 2013-09-28 19:34:16 -07:00
Vinnie Falco
00a714d14d Implement Stoppable for LoadManager 2013-09-28 17:40:46 -07:00
Vinnie Falco
58a8a97177 Journal console output improvements 2013-09-28 16:42:16 -07:00
Vinnie Falco
97f1b41b4d Add more Validators journal reports 2013-09-28 15:30:02 -07:00
Vinnie Falco
8e58551475 Add Stoppable prepare and start interfaces 2013-09-28 15:30:01 -07:00
Vinnie Falco
e4fe965de0 Move RelativeTime to chrono, add ostream support 2013-09-28 15:09:12 -07:00
Vinnie Falco
3fefd43898 Add console feature to Journal 2013-09-28 15:09:12 -07:00
Vinnie Falco
d9f20436e8 Journal option to write to Output window (MSVC) 2013-09-28 15:09:11 -07:00
Vinnie Falco
9df86ec8fd Add compilation test script 2013-09-28 15:09:11 -07:00
Vinnie Falco
6602aff53d Update Validators for ServiceQueue 2013-09-28 15:09:10 -07:00
Vinnie Falco
3ec36929f1 Add ServiceQueue 2013-09-28 15:09:10 -07:00
Vinnie Falco
1f7d3d47a5 Use boost for functional when the config is set 2013-09-28 15:09:10 -07:00
Vinnie Falco
ab156cbcd1 Fix is_continuation for boost version 2013-09-28 15:09:09 -07:00
Vinnie Falco
4c43faec85 Fix invoked_type type reference 2013-09-28 15:09:09 -07:00
Vinnie Falco
2d2cd3aab1 Remove LockFreeStack::size 2013-09-28 15:09:08 -07:00
Vinnie Falco
c5f017739d Add SharedData::ConstAccess 2013-09-28 15:09:08 -07:00
Vinnie Falco
7437308bab Add AgedHistory.h 2013-09-28 15:09:07 -07:00
Vinnie Falco
fb6a0f10c3 Add LockFreeStack::empty 2013-09-28 15:09:07 -07:00
Vinnie Falco
d939c039f1 Added AbstractHandler, WrapHandler. HTTPClient Fixes. 2013-09-28 15:09:07 -07:00
Alex Dupre
c568988640 Add support for gcc 4.6 and ccache. 2013-09-28 20:26:16 +02:00
Alex Dupre
ca00a595c3 Fix unittest, by removing recursive call. 2013-09-28 20:25:41 +02:00
Alex Dupre
add0784ae2 Fix compile error. 2013-09-28 20:25:12 +02:00
Vinnie Falco
b2d84139a5 Merge pull request #165 from MarkusTeufelberger/develop
Add Arch Linux to SConstruct file
2013-09-28 06:32:54 -07:00
JoelKatz
13a09113ba Protect 'disconnect' from a dead weak pointer. 2013-09-27 20:00:18 -07:00
JoelKatz
9b28ad136b Remove some dead code and make sure we get full mutexes. 2013-09-27 14:40:36 -07:00
Vinnie Falco
cd9a4e6b57 Merge pull request #167 from wltsmrz/develop
Bump ripple-lib version
2013-09-27 12:49:32 -07:00
wltsmrz
f9596e1514 Bump ripple-lib version 2013-09-27 12:35:15 -07:00
Vinnie Falco
ac19affc11 Fix FreeBSD missing include 2013-09-27 07:45:48 -07:00
Vinnie Falco
0048efea8d Fixes for FreeBSD 2013-09-27 07:16:57 -07:00
Vinnie Falco
54dc7017e1 Fix Windows ProtectedCall handler to use ExitProcess 2013-09-27 05:20:32 -07:00
Vinnie Falco
beebfec3db Fix nonstandard C++ extension in getNullSink 2013-09-27 05:18:34 -07:00
Vinnie Falco
ae6e9e2790 Build fixes 2013-09-27 05:15:55 -07:00
Vinnie Falco
d1ec2eae83 Track run and wait times for load samples 2013-09-27 05:15:51 -07:00
Vinnie Falco
dd49eb4d65 Fix missing <cmath> include for Gentoo 2013-09-27 05:15:46 -07:00
MarkusTeufelberger
92d8a80b4e Add Arch Linux to SConstruct file 2013-09-27 05:15:40 -07:00
JoelKatz
48f815ff70 Handle negative saInSum earlier. 2013-09-27 03:29:15 -07:00
Vinnie Falco
948badc98b Set version to 0.13.0-rc5 2013-09-26 17:27:53 -07:00
JoelKatz
92bd8c4782 Missing return. 2013-09-26 17:14:55 -07:00
Vinnie Falco
5bebac7ecb Merge branch 'release' into develop 2013-09-26 15:58:58 -07:00
Vinnie Falco
efa05c5c58 Set version to 0.13.0-rc4 2013-09-26 15:57:48 -07:00
JoelKatz
2c7a846c3e Don't allow a transaction to spend into the greater of the fee or the reserve. 2013-09-26 15:50:46 -07:00
JoelKatz
d10dba6b2e Fix a case where the AcceptedLedger constructor throws 2013-09-26 15:19:26 -07:00
Vinnie Falco
d683b47dee Call std::exit for unhandled exceptions 2013-09-26 15:16:10 -07:00
JoelKatz
985af0e222 Fix a case where tryAdvance can throw. 2013-09-26 14:34:11 -07:00
JoelKatz
013520c9d4 Avoid acquiring the LedgerMaster lock in some hot code paths. 2013-09-26 13:44:40 -07:00
Vinnie Falco
00f5c9b34b Set version to 0.13.0-r3 2013-09-26 12:39:50 -07:00
Vinnie Falco
b4168392b7 Set version to 0.13.0-r3 2013-09-26 12:23:43 -07:00
JoelKatz
7cbe8572a3 Don't abort on a path that's dry because we entered with no funds. 2013-09-26 12:23:08 -07:00
JoelKatz
05a183e30a Make sizes more sensible 2013-09-26 12:23:04 -07:00
JoelKatz
2b37a4c7b0 Better tracking of resources associated with pathfinding. 2013-09-26 12:22:59 -07:00
JoelKatz
8cca807ea1 Don't abort on a path that's dry because we entered with no funds. 2013-09-26 11:49:18 -07:00
JoelKatz
4c3f059819 Make sizes more sensible 2013-09-26 11:05:15 -07:00
JoelKatz
18fc854bf3 Better tracking of resources associated with pathfinding. 2013-09-26 10:26:15 -07:00
MarkusTeufelberger
eff0271e7a Add Arch Linux to SConstruct file 2013-09-26 09:18:36 +02:00
Vinnie Falco
5888f55bdd Update LICENSE 2013-09-25 22:48:14 -07:00
Vinnie Falco
e62adfe4d4 Merge pull request #164 from wltsmrz/develop
Bump ripple-lib subversion
2013-09-25 18:58:33 -07:00
wltsmrz
6d19221e94 Bump ripple-lib subversion 2013-09-25 18:40:17 -07:00
Vinnie Falco
fcd689afbf Update copyright notice and licenses 2013-09-25 17:27:06 -07:00
David Schwartz
58a9a2cc07 Ripple Labs contributions are now open source. 2013-09-25 17:09:26 -07:00
David Schwartz
c226f9ecab Ripple Labs contributions are now open source. 2013-09-25 17:08:44 -07:00
Vinnie Falco
8f514c8e1b Merge branch 'release' into develop 2013-09-25 15:15:26 -07:00
Vinnie Falco
38ed0bee79 Update version number to 0.13.0-rc2 2013-09-25 14:42:53 -07:00
Vinnie Falco
a655662098 Disconnect WS connections when load exceeds threashold 2013-09-25 14:40:10 -07:00
David Schwartz
69dc722a7a Give mCompleteLedgers its own lock to avoid a deadlock. 2013-09-25 13:02:25 -07:00
Vinnie Falco
32a7f42557 Merge branch 'develop' into release
Conflicts:
	modules/ripple_app/basics/ripple_BuildInfo.cpp
	modules/ripple_app/misc/NetworkOPs.cpp
	modules/ripple_app/misc/NetworkOPs.h
	modules/ripple_core/functional/ripple_Config.h
	modules/ripple_core/functional/ripple_Job.cpp
	modules/ripple_core/functional/ripple_Job.h
	modules/ripple_core/functional/ripple_JobQueue.cpp
	modules/ripple_core/functional/ripple_JobQueue.h
2013-09-25 12:06:17 -07:00
Vinnie Falco
4a871a5726 Set version to 0.13-rc1 2013-09-25 11:46:42 -07:00
Vinnie Falco
909f4ffec9 Add BlackList.h to vs2012 project 2013-09-25 11:44:06 -07:00
Vinnie Falco
d163e80e77 More compatibility for IdentifierType 2013-09-25 11:44:06 -07:00
Vinnie Falco
9b22c810ef Validators Work
Conflicts:
	src/ripple_app/ledger/LedgerMaster.cpp
2013-09-25 11:44:05 -07:00
Vinnie Falco
426636f48d Add SimpleIdentifier traits for non-crypto identifiers 2013-09-25 11:44:04 -07:00
David Schwartz
3518a51d4a Make 'saaad' paths easier to find.
#   (use "git reset HEAD <file>..." to unstage)
2013-09-25 11:21:14 -07:00
David Schwartz
cca5c86673 Update the OrderBookDB if there's a jump in the published ledger stream. 2013-09-25 11:11:40 -07:00
David Schwartz
be828e834d Silly boost needs mutable locks. 2013-09-24 16:52:32 -07:00
David Schwartz
7e82612cd5 Improve test runner. 2013-09-24 16:52:21 -07:00
David Schwartz
8f4e722f73 Protect mRecentLedgers/mRecentTxSets with a mutex. 2013-09-24 16:46:25 -07:00
David Schwartz
ea11987609 Remove an obsolete comment. 2013-09-24 16:45:55 -07:00
David Schwartz
807b4fd659 "sxfad" path was missing from non-XRP to non-XRP (dif currency) list. 2013-09-24 16:06:33 -07:00
David Schwartz
ac90baa831 New test runner for Mocha 2013-09-24 16:01:43 -07:00
David Schwartz
794cd03b8f Don't process validations signed more than two minutes ago. 2013-09-24 15:47:56 -07:00
David Schwartz
2f77ca416a PEER_PRIVATE suppresses outbound connections to unconfigured peers. 2013-09-24 15:40:24 -07:00
David Schwartz
8b0df758f3 calcNodeAdvance fix. 2013-09-24 14:41:53 -07:00
wltsmrz
c76e2b54a9 Update system tests for mocha and new ripple-lib transaction submission 2013-09-24 14:12:18 -07:00
David Schwartz
01d7d7bed9 Fix deadlock in blacklist code. 2013-09-24 13:18:50 -07:00
David Schwartz
c3bb005324 Use whitelist. 2013-09-24 13:11:22 -07:00
JoelKatz
5d63086b69 Tie in blacklist code. 2013-09-24 13:00:11 -07:00
JoelKatz
f61caaae09 Initial import of IP blacklist code. 2013-09-23 14:07:16 -07:00
JoelKatz
d90c2c0e11 Fix erroneous 1-2 in complete ledgers. 2013-09-23 13:04:22 -07:00
Vinnie Falco
321898f71e Add CryptoIdentifierType and RippleCryptoIdentifier Traits 2013-09-23 10:13:25 -07:00
Vinnie Falco
1dd50f4422 Add FixedArray, IntrusiveArray, Crypto 2013-09-23 10:13:25 -07:00
Vinnie Falco
20b2e318eb Reorganize beast modules and files 2013-09-23 10:13:24 -07:00
Vinnie Falco
19eff08e16 Reorganize source files and modules 2013-09-23 10:13:21 -07:00
Vinnie Falco
2d65ab4021 Merge commit '43deaaa5cf0d0178a4a6c3cb69c02a2a9a43ec7d' as 'src/beast/beast/http/impl/http-parser' 2013-09-23 09:54:31 -07:00
Vinnie Falco
43deaaa5cf Squashed 'src/beast/beast/http/impl/http-parser/' content from commit 547553b
git-subtree-dir: src/beast/beast/http/impl/http-parser
git-subtree-split: 547553b0909c9ce10a3730baeff7c7d1f76c0ea6
2013-09-23 09:54:31 -07:00
JoelKatz
7c31a423e9 No ripple check takes precedence over destination check. 2013-09-22 21:22:14 -07:00
JoelKatz
dc61fadc56 If an account sets noRipple on a RippleState, it can only be used as the first link in the path. 2013-09-22 20:48:40 -07:00
JoelKatz
0d744cc253 Implement WSConnection::send to use the text version of the broadcast. 2013-09-22 15:55:36 -07:00
JoelKatz
1f372a3b08 Implement NoRipple transaction and trust line flags. 2013-09-22 15:14:47 -07:00
JoelKatz
b0c37d62fe Workaround tr1::functional bugs. 2013-09-22 15:14:31 -07:00
Vinnie Falco
e04dbdde19 Tidy up HTTPServer API and handle errors 2013-09-22 13:27:24 -07:00
Vinnie Falco
5bd6fb27e6 Split up RPCService 2013-09-22 13:27:23 -07:00
Vinnie Falco
b123b1a849 Fix using namespace beast directives 2013-09-22 13:22:07 -07:00
Vinnie Falco
d16aa7f928 Use JobQueue to process RPC-JSON asynchronously 2013-09-22 13:22:06 -07:00
Vinnie Falco
7dd41ffb5b Fix BeforeBoost.h include 2013-09-22 11:52:26 -07:00
Vinnie Falco
a2151bfa47 Split HTTP::Server to its own module 2013-09-22 11:52:26 -07:00
Vinnie Falco
0dc3cf07d0 Add HTTPServer 2013-09-22 11:52:22 -07:00
Vinnie Falco
ac1ebf403f Add Stoppable to beast 2013-09-22 11:51:46 -07:00
Vinnie Falco
5443e0f332 Lower the severity on JobQueue skip reporting 2013-09-22 11:51:46 -07:00
Vinnie Falco
5856730ec3 Fix objective-c ripple source 2013-09-22 11:51:45 -07:00
Vinnie Falco
ec6c09d995 Rename to Stoppable 2013-09-22 11:51:44 -07:00
Vinnie Falco
ec6ee6f3bd IPEndpoint comparisons 2013-09-22 11:51:44 -07:00
Vinnie Falco
dcbfa1524e Migrate some headers and general tidying 2013-09-22 11:51:44 -07:00
Vinnie Falco
51198c266f Add SharedArg and AsyncObject 2013-09-22 11:51:43 -07:00
Vinnie Falco
ed1a4b1283 Add HTTPRequest and improvements to HTTPMessage parsing 2013-09-22 11:51:43 -07:00
Vinnie Falco
0cbfc6079b Add some Validators RPC commands 2013-09-22 11:51:42 -07:00
Vinnie Falco
e59293ec92 Add RPCService, call the Manager from RPCServerHandler 2013-09-21 16:58:55 -07:00
Vinnie Falco
be1cede458 Add some thread classes and fix SharedData with a simple mutex adapter 2013-09-21 16:58:55 -07:00
Vinnie Falco
18d5021640 Make CallQueue unit test runManual 2013-09-20 01:12:21 -07:00
Vinnie Falco
85fc59b28b Refactor NodeStore, add NodeStoreSchedulerService 2013-09-20 01:12:21 -07:00
Vinnie Falco
63de1618e9 Remove Beast version printing on startup 2013-09-20 00:57:55 -07:00
Vinnie Falco
e3e72b3fc3 Split some framework classes into ripple_frame module 2013-09-19 21:52:21 -07:00
Vinnie Falco
5c84f75bd9 Reorganize some MPL and Utility classes and files 2013-09-19 21:37:47 -07:00
Vinnie Falco
b493db1d65 Split ripple_json to its own module 2013-09-19 20:54:12 -07:00
Vinnie Falco
c3b815004c Update TODO 2013-09-19 19:55:54 -07:00
Vinnie Falco
e6e090c542 Fixes for Service API hang on exit during unit tests 2013-09-19 19:41:55 -07:00
Vinnie Falco
fad8b0406e Remove MDB from timing test, increase timing test data size 2013-09-19 19:41:31 -07:00
Vinnie Falco
6d1796725b Add batch support to sophia backend 2013-09-19 19:41:31 -07:00
Vinnie Falco
a1596dd3d1 Merge branch 'feature-sophia' into develop
Conflicts:
	Builds/VisualStudio2012/RippleD.vcxproj
	Builds/VisualStudio2012/RippleD.vcxproj.filters
2013-09-19 18:32:48 -07:00
Vinnie Falco
927332dc01 Fix missing BeastConfig.h include in Net.cpp 2013-09-19 18:25:01 -07:00
Vinnie Falco
cc77e4e9d8 Disable Beast version printing in Ripple BeastConfig.h 2013-09-19 18:22:18 -07:00
Vinnie Falco
86c868874a Add Sophia backend (http://sphia.org) 2013-09-19 18:16:41 -07:00
Vinnie Falco
89b1859929 Refactor Application shutdown using new Service, AsyncService interfaces 2013-09-19 17:18:43 -07:00
Vinnie Falco
97e961a048 Add InterruptibleThread unit test 2013-09-19 14:42:55 -07:00
Vinnie Falco
cc1fd7bc6a ThreadWithCallQueue unit test adjustment 2013-09-19 14:42:55 -07:00
Vinnie Falco
05b0e896aa IPEndpoint parsing and tidying 2013-09-19 14:42:55 -07:00
Vinnie Falco
2464607a09 Move and add some template metaprogramming classes 2013-09-19 14:42:54 -07:00
Vinnie Falco
776d934d66 Change filname capitalization (end) 2013-09-19 14:42:54 -07:00
Vinnie Falco
be6bd6c9fb Change filename capitalization 2013-09-19 14:42:53 -07:00
Vinnie Falco
53f7846d2b Move integer types to beast/CStdInt.h 2013-09-19 14:42:53 -07:00
Vinnie Falco
c733eb6e43 Move TargetPlatform.h to beast/Config.h 2013-09-19 14:42:52 -07:00
Vinnie Falco
11601bcccb Add IPEndpoint
Conflicts:
	src/beast/Builds/VisualStudio2012/beast.vcxproj.filters
2013-09-19 14:42:52 -07:00
Vinnie Falco
3ff8902481 Tidy up some zlib macro undefines 2013-09-19 14:42:52 -07:00
Vinnie Falco
d105f6a2bd Rename beast sources for consistency 2013-09-19 14:42:51 -07:00
Vinnie Falco
ed3be7a187 Add CallQueue unit test 2013-09-19 14:42:50 -07:00
Vinnie Falco
c8187e92af Consolidate beast unity sources into 2 ripple sources 2013-09-19 14:42:50 -07:00
Vinnie Falco
ec9ee5cc4b Fixes for consolidated beast unity includes 2013-09-19 14:42:49 -07:00
Vinnie Falco
ff674a32e2 Remove unused and broken classes 2013-09-19 14:42:49 -07:00
Vinnie Falco
f22e91cb9e Use Thread in LoadManager 2013-09-19 14:42:48 -07:00
Vinnie Falco
3efab6732f Remove unused ConcurrentObject 2013-09-19 14:42:48 -07:00
Vinnie Falco
7c39867d56 Clean up exit memory leaks in NodeStore 2013-09-19 14:42:47 -07:00
Vinnie Falco
237093dcd3 Add ThreadWithCallQueue unit test 2013-09-19 14:42:47 -07:00
Vinnie Falco
985db3fa16 Call protobuff::Shutdown to free dynamic data 2013-09-19 14:42:47 -07:00
Vinnie Falco
e2e8f85b3c Remove obsolete beast_Function 2013-09-19 14:42:46 -07:00
JoelKatz
29ec27c377 Temporarily leave sqlite3 in whatever threading mode it was already in. 2013-09-19 10:33:22 -07:00
wltsmrz
4109e51e30 Improvements to js tests and increment of the ripple-lib version 2013-09-18 17:36:34 -07:00
Vinnie Falco
604ca590b6 Fix SharedSingleton to use memoryBarrier 2013-09-17 17:58:21 -07:00
Vinnie Falco
feacf3ef13 Update LogJournal for new Journal interface 2013-09-17 17:47:07 -07:00
Vinnie Falco
9b76638351 Tidy up SharedSingleton doc comments 2013-09-17 17:47:06 -07:00
Vinnie Falco
aa89f46ae1 Fix leak on exit from Singleton dependency cycle 2013-09-17 17:47:06 -07:00
Vinnie Falco
0f60a503f6 Rename to DeadlineTimer::cancel() 2013-09-17 17:47:05 -07:00
Vinnie Falco
57f8328b0d Use new instead of ::new for placement 2013-09-17 17:47:05 -07:00
Vinnie Falco
f36fcf635c Journal improvements 2013-09-17 17:47:04 -07:00
Vinnie Falco
607520f2e6 SharedFunction improvements 2013-09-17 17:47:04 -07:00
Vinnie Falco
02cb0f0499 Add LockFreeStack iterators 2013-09-17 17:47:04 -07:00
Vinnie Falco
ee5c600e29 Fix undefined behavior in UnsignedIntegerCalc (again) 2013-09-17 17:47:03 -07:00
Vinnie Falco
ddb8268d5f Fix DeadlineTimer, callback while holding lock 2013-09-17 14:13:27 -07:00
Vinnie Falco
06e80ec522 Sophia fixes for relative includes 2013-09-17 12:29:52 -07:00
Vinnie Falco
94c77c38f4 Fix .gitignore for db dirs 2013-09-17 12:29:40 -07:00
Vinnie Falco
1a78d63f05 Don't forbid RPC clients who provide credentials when not required 2013-09-17 12:02:30 -07:00
Vinnie Falco
a602eb3b5d Add ripple_sophia module 2013-09-17 11:35:17 -07:00
Vinnie Falco
fb9fc26e58 Merge commit 'c58450a44b3fed6ace9f5197f504e6b2f248a5e7' as 'src/sophia' 2013-09-17 10:09:27 -07:00
Vinnie Falco
c58450a44b Squashed 'src/sophia/' content from commit 9d29b94
git-subtree-dir: src/sophia
git-subtree-split: 9d29b94cd66d3bd67082642b9a1f6dea470f0730
2013-09-17 10:09:27 -07:00
Vinnie Falco
76f62bd7c5 Fix undefined behavior in UnsignedIntegerCalc 2013-09-16 18:47:35 -07:00
JoelKatz
007723236e Change the way the OrderBookDB is updated to prevent hangs. 2013-09-16 18:27:25 -07:00
JoelKatz
74b2d1f3fa Pass a bool to the describer telling it if the directory is new. 2013-09-16 18:12:21 -07:00
JoelKatz
b45b029ba7 Whitespace changes only 2013-09-16 18:05:25 -07:00
JoelKatz
fd59422a22 Fixes to tryAdvance logic. 2013-09-15 13:29:52 -07:00
Vinnie Falco
1f892029f8 Remove extraneous shell script 2013-09-13 18:55:10 -07:00
Vinnie Falco
846b8e339c Tidy and rename all Ripple source files 2013-09-13 16:58:24 -07:00
Vinnie Falco
5be3a1a34d Fix UnsignedInteger::isZero 2013-09-13 13:06:45 -07:00
Vinnie Falco
c631cc5f92 Persistence for Validators 2013-09-13 12:43:54 -07:00
Vinnie Falco
9b40bc6835 Add support for multiprecision integer arithmetic and binary data encoding 2013-09-13 12:43:43 -07:00
Vinnie Falco
b79ede018d Update .gitignore 2013-09-12 23:58:56 -07:00
Vinnie Falco
3b82c0b1a1 Tidy up UnsignedInteger 2013-09-12 23:58:56 -07:00
Vinnie Falco
0e4c865853 Add Time::isNull() 2013-09-12 23:58:55 -07:00
Vinnie Falco
d67e38fa85 Better random number facilities in UnitTest 2013-09-12 21:39:17 -07:00
Vinnie Falco
817a0256d2 Fine tune UnsignedInteger declaration 2013-09-12 19:18:31 -07:00
Vinnie Falco
36e88a25f6 Allow negative relative expirations in DeadlineTimer 2013-09-12 18:07:57 -07:00
Vinnie Falco
0d2344c9a6 Validators work 2013-09-12 16:30:45 -07:00
Vinnie Falco
b839ae0552 Refactor Log code, add LogJournal adapter 2013-09-12 15:06:28 -07:00
Vinnie Falco
5038a65acd Add generic Journal class for logging 2013-09-12 15:06:28 -07:00
Vinnie Falco
ec3c4ff77a Reduce scope of Application object lifetime 2013-09-12 10:55:25 -07:00
Vinnie Falco
6a84f73d2a Make ChildProcess UnitTest manual since it malfunctions 2013-09-12 10:55:24 -07:00
Vinnie Falco
681f98ad07 General refactoring of beast framework classes 2013-09-12 10:55:24 -07:00
Vinnie Falco
8c1c7b48bb Fix ExitHook to derive from AtExitHook 2013-09-12 10:55:17 -07:00
Vinnie Falco
7f61499d3a Reduce the max threads in the Workers unit test 2013-09-12 05:46:45 -07:00
Vinnie Falco
3550a21294 New SharedSingleton, resolves destruction of objects with static storage duration. 2013-09-12 05:38:39 -07:00
Vinnie Falco
048dcf8a3c Remove deprecated SharedPtr::getObject 2013-09-12 04:47:03 -07:00
Vinnie Falco
89bc2bbc6f Remove debug output for URL Validators Source 2013-09-12 04:47:03 -07:00
Vinnie Falco
db30bfe352 Make SharedObject members const, the counter mutable 2013-09-12 04:47:03 -07:00
Vinnie Falco
baa0b474ba Remove deprecated createOnDemandOnce SingletonLifetime option 2013-09-12 00:43:05 -07:00
Vinnie Falco
a76672c5f0 Split Log singleton code out into LogInstance 2013-09-11 22:42:40 -07:00
Vinnie Falco
0079c9070d Turn RIPPLE_APPLICATION_CLEAN_EXIT back on, to prevent file descriptor leaks 2013-09-11 22:03:59 -07:00
Vinnie Falco
e1e8744052 Fix empty Config paths for unit test 2013-09-11 21:48:43 -07:00
Vinnie Falco
f0231af0c0 Fix off by one in pending i/o count on HTTPClient 2013-09-11 21:40:17 -07:00
Vinnie Falco
9e6e7b5dd9 Add comments to the .proto file 2013-09-11 20:52:42 -07:00
Vinnie Falco
a48bcfeddb Migrate validators and testoverlay to the new style of source organization 2013-09-11 20:05:56 -07:00
Vinnie Falco
fb804bd1bd More Validators implementation 2013-09-11 20:05:55 -07:00
Vinnie Falco
43d386fa6e Add HTTPMessage::toString and family 2013-09-11 20:04:23 -07:00
Vinnie Falco
68422ed5b4 Add UniformResourceLocator::empty 2013-09-11 19:58:11 -07:00
Vinnie Falco
03b8ae742e Small refactor to Config paths 2013-09-11 19:58:10 -07:00
Vinnie Falco
99afec18c5 Update protoc.py for new src directories 2013-09-11 11:47:58 -07:00
Vinnie Falco
27f0cae812 Add PeerFinder peer discovery logic and unit test 2013-09-11 11:47:58 -07:00
Vinnie Falco
45eccf2ccf Move ./modules to ./src 2013-09-11 11:20:53 -07:00
Vinnie Falco
6d828ae476 Update README 2013-09-11 10:44:10 -07:00
Vinnie Falco
1b6761286f Merge commit '112234c8a911de4243eaab3eb6a37ce6df014880' as 'src/protobuf' 2013-09-11 10:40:46 -07:00
Vinnie Falco
112234c8a9 Squashed 'src/protobuf/' content from commit d6e20ba
git-subtree-dir: src/protobuf
git-subtree-split: d6e20baabb84501c720b6e42170684264bd2cdd2
2013-09-11 10:40:46 -07:00
Vinnie Falco
ae1daafd44 Remove old protobuf subtree in preparation for git subtree add 2013-09-11 10:40:37 -07:00
Vinnie Falco
255e5eedf6 Update README for protobuf 2013-09-11 10:31:13 -07:00
Vinnie Falco
0c6c9774a9 Update project files for new directory layout 2013-09-11 10:22:46 -07:00
Vinnie Falco
a04fa04d07 Update project files for new directory layout 2013-09-11 10:08:35 -07:00
Vinnie Falco
03174a0d6a Tidy up root of the repository 2013-09-11 10:04:32 -07:00
Vinnie Falco
10d88114e4 Remove old Subtrees directory 2013-09-11 10:01:06 -07:00
Vinnie Falco
7238e23e8a Merge commit '128e6a412506a0f152385a107aa8801e484a8c60' as 'src/websocket' 2013-09-11 09:58:50 -07:00
Vinnie Falco
128e6a4125 Squashed 'src/websocket/' content from commit b439cd1
git-subtree-dir: src/websocket
git-subtree-split: b439cd1ee99f319eb1464f7b44923ce96245735d
2013-09-11 09:58:50 -07:00
Vinnie Falco
3e4833acca Merge commit '1148b422d5e758e18e230d792bad30ff29630c7f' as 'src/mdb' 2013-09-11 09:58:41 -07:00
Vinnie Falco
1148b422d5 Squashed 'src/mdb/' content from commit 1eb7f66
git-subtree-dir: src/mdb
git-subtree-split: 1eb7f6695947efe1c05e83446479368e8d360d4b
2013-09-11 09:58:41 -07:00
Vinnie Falco
c6b5ccdd22 Merge commit '627114b1acdc785cce9caab8bac9b6ad90917be5' as 'src/leveldb' 2013-09-11 09:58:34 -07:00
Vinnie Falco
627114b1ac Squashed 'src/leveldb/' content from commit f851425
git-subtree-dir: src/leveldb
git-subtree-split: f851425b14fc9bcf47d0ca938986bcd0457ad5db
2013-09-11 09:58:34 -07:00
Vinnie Falco
e8893e9678 Squashed 'src/hyperleveldb/' content from commit ac2ae30
git-subtree-dir: src/hyperleveldb
git-subtree-split: ac2ae3029dd9c4ed6401c57eef7e1d84b2007bca
2013-09-11 09:58:13 -07:00
Vinnie Falco
809a2ce7bf Merge commit 'e8893e96780685b9e39447199d946739e565fef5' as 'src/hyperleveldb' 2013-09-11 09:58:13 -07:00
Vinnie Falco
86ba8ffca6 Squashed 'src/beast/' content from commit 43e6d34
git-subtree-dir: src/beast
git-subtree-split: 43e6d345e4
2013-09-11 09:57:14 -07:00
Vinnie Falco
fe18b54d20 Merge commit '86ba8ffca6a6399bb19861e1cd826ec792a33651' as 'src/beast' 2013-09-11 09:57:14 -07:00
Vinnie Falco
9812d69aa2 General beast update, fixes, optimizations, features:
* Clean ups, optimizations, and new File::commonDocumentsDirectory enum
* Replace sortArray with std::sort for performance
* More error tolerance in XML parser, speedups
* Refactor some byte-order mark detection code
* Add String::appendCharPointer overloads
* More XML parser optimisations and better error detection
* Misc performance tweaks
* Fixes for support of non utf8 strings
* Increased precision when storing strings in XmlElement
* Minor clean-ups
* Minor fix to XmlDocument
* Cleanups to CriticalSection and related synchronization primitives
* Fix DynamicArray unit test
2013-09-10 10:36:46 -07:00
Vinnie Falco
b5e1a600a1 Use SharedFunction in ProtectedCall 2013-09-10 08:04:54 -07:00
Vinnie Falco
8bdfa860ee Put back BEAST_CATCH_UNHANDLED_EXCEPTIONS macro, but disabled by default 2013-09-10 08:04:46 -07:00
Vinnie Falco
7f84f44a74 Update to SQLite 3.8.0.2 2013-09-10 07:45:34 -07:00
JoelKatz
6234f0040d 0.12.1-alpha.1 2013-09-09 18:36:00 -07:00
JoelKatz
1b18e16d1f Track consensus versus validated ledgers and log discrepancies. 2013-09-09 18:27:05 -07:00
Vinnie Falco
51332a91b9 Remove RIPPLE_PEER_USES_BEAST_MULTISOCKET configuration setting 2013-09-09 14:12:58 -07:00
Vinnie Falco
c063b940bb Add RIPPLE_APPLICATION_CLEAN_EXIT option to BeastConfig.h 2013-09-09 13:45:37 -07:00
Vinnie Falco
3c23699a87 Remove BEAST_CATCH_UNHANDLED_EXCEPTIONS 2013-09-09 13:34:18 -07:00
Vinnie Falco
00caefc1c3 Move ripple.pb.cc to VS2012 project so it rebuilds as needed 2013-09-09 12:56:59 -07:00
Vinnie Falco
6be6e68165 Tidy up the root of the repository a bit 2013-09-09 11:09:47 -07:00
Vinnie Falco
8866c2dc1f Pass .cfg validators entries to Validators logic 2013-09-09 10:50:36 -07:00
Vinnie Falco
adb6c39b92 Make UnsignedInteger HashFunction a unary function object 2013-09-09 10:50:35 -07:00
Vinnie Falco
955a791ab1 Improvements to BuffersType 2013-09-09 10:50:35 -07:00
Vinnie Falco
6c32b174e8 Tune HashMap parameters 2013-09-09 10:28:10 -07:00
Vinnie Falco
bbc9e886dd Add ValidatorsUtilities common code 2013-09-09 10:28:10 -07:00
Vinnie Falco
e1f80ef6a6 Rename to IsCond<> 2013-09-09 10:28:09 -07:00
JoelKatz
a4e81fb6ad Fix some performance problems with the new ledger master code. 2013-09-09 02:02:23 -07:00
JoelKatz
d3159aba88 Reject a non-positive destination amount immediately. 2013-09-09 01:30:39 -07:00
JoelKatz
afd22025d7 No need to compare a transaction set to itself. 2013-09-08 14:09:49 -07:00
JoelKatz
fd6e0e788e Don't include a non-XRP order book if we've already seen the issuer's account in the currency. 2013-09-08 13:41:55 -07:00
JoelKatz
cb8ba44f62 Mark some issues in the RPCServerHandler and add a temporary workaround. 2013-09-08 00:06:35 -07:00
Vinnie Falco
140be155f2 Defer DeadlineTimer callback until the lock is released 2013-09-07 21:20:13 -07:00
JoelKatz
68547c328e Handle a case of missing ledger nodes sanely. 2013-09-07 18:06:40 -07:00
JoelKatz
3174372081 Remove an erroneous comment. 2013-09-07 18:06:34 -07:00
Vinnie Falco
eaec90c897 Disable gcc warning for KeyvaDB 2013-09-07 11:57:53 -07:00
Vinnie Falco
1d1587c2ac Add HTTPClientType and HTTPMessage related helpers 2013-09-07 11:53:38 -07:00
Vinnie Falco
4a30b259b2 Tidy up contract checks in InterruptibleThread 2013-09-07 11:53:38 -07:00
Vinnie Falco
e927160ff5 Disable exception catching in unit tests 2013-09-07 11:53:37 -07:00
Vinnie Falco
aac657a2e6 Add ContentBodyBuffer 2013-09-07 11:53:37 -07:00
Vinnie Falco
8c2f9e7388 Fix incorrect whitespace in macro argument list 2013-09-07 11:53:36 -07:00
Vinnie Falco
c8cedfc06e Add SharedFunction to replace boost::function 2013-09-07 11:53:36 -07:00
Vinnie Falco
6be9c41064 Update programming by contract macros 2013-09-07 11:53:36 -07:00
Vinnie Falco
62ffbc97ba Add BEAST_MOVE_* macros 2013-09-07 11:53:35 -07:00
Vinnie Falco
0bbad54a36 Add Debug unit test to check bassert behavior 2013-09-07 11:53:35 -07:00
Vinnie Falco
044e3b09db Add StringPairArray::swapWith 2013-09-07 11:53:34 -07:00
Vinnie Falco
d6a12f791f Add UniformResourceLocator and ParsedURL 2013-09-07 11:53:34 -07:00
Vinnie Falco
bf2af27452 Rename boost_asio files 2013-09-07 11:53:34 -07:00
Vinnie Falco
98f1169ac3 Add http-parser to boost_asio 2013-09-07 11:53:33 -07:00
Vinnie Falco
816b3a4efb Remove unused Validator files 2013-09-07 11:53:33 -07:00
Vinnie Falco
941503c564 Use destroy() override instead of ContainerDeletePolicy for SharedObject 2013-09-07 11:53:32 -07:00
JoelKatz
e513380e08 Remove obsolete information. 2013-09-06 23:29:30 -07:00
Vinnie Falco
a050ba6fa4 Fix DeadlineTimer for InterruptibleThread::wait timeout 2013-09-06 21:45:41 -07:00
Vinnie Falco
3594c3b290 Fix DeadlineTimer for InterruptibleThread::wait timeout 2013-09-06 21:44:53 -07:00
Vinnie Falco
8d15b4059d Make bassert fatal 2013-09-06 21:29:16 -07:00
Vinnie Falco
403e2247a2 Add missing limit for jtUNL jobs 2013-09-06 21:29:15 -07:00
Vinnie Falco
ddcbb9c38c Fix SharedPtr commit bug again 2013-09-06 21:25:55 -07:00
Vinnie Falco
4b7b5a41a2 Fix reference count bug in SharedPtr container 2013-09-06 20:18:25 -07:00
JoelKatz
b921791b34 Old path finding aggressiveness check was backwards. 2013-09-06 12:49:20 -07:00
Vinnie Falco
a690c579c1 Merge commit '60d5ca452314e0131993e1adcc004394fb64eed2' as 'Subtrees/beast/modules/beast_asio/parsehttp' 2013-09-06 12:46:39 -07:00
Vinnie Falco
60d5ca4523 Squashed 'Subtrees/beast/modules/beast_asio/parsehttp/' content from commit 547553b
git-subtree-dir: Subtrees/beast/modules/beast_asio/parsehttp
git-subtree-split: 547553b0909c9ce10a3730baeff7c7d1f76c0ea6
2013-09-06 12:46:39 -07:00
Vinnie Falco
de7e3c578e Remove incorrect parsehttp subtree path 2013-09-06 12:46:23 -07:00
Vinnie Falco
f48c2c24b6 Merge commit 'ef544b108f8979e4622bd27657c9e93271b461fc' as 'Subtrees/beast/beast_asio/parsehttp' 2013-09-06 12:44:36 -07:00
Vinnie Falco
ef544b108f Squashed 'Subtrees/beast/beast_asio/parsehttp/' content from commit 547553b
git-subtree-dir: Subtrees/beast/beast_asio/parsehttp
git-subtree-split: 547553b0909c9ce10a3730baeff7c7d1f76c0ea6
2013-09-06 12:44:36 -07:00
JoelKatz
7abfd354f8 New improved Pathfinding engine 2013-09-06 12:35:13 -07:00
JoelKatz
65009c77a7 Raise default optimization level to 1. 2013-09-06 11:49:34 -07:00
JoelKatz
2d9d00c2ef Tiny bugfix. 2013-09-06 11:49:34 -07:00
JoelKatz
12495f0e65 Suppress a warning. 2013-09-06 11:49:34 -07:00
Vinnie Falco
e6e2873b4f Reformat, reorganize rippled-example.cfg and include the missing undocumented settings 2013-09-06 11:13:41 -07:00
Stefan Thomas
de210fef95 Simplify new account_tx API. 2013-09-06 06:49:27 -07:00
Stefan Thomas
89748aad37 Fix typo breaking resume functionality. 2013-09-06 06:49:22 -07:00
JoelKatz
aa64bdc41c Fix account_tx 2013-09-05 20:05:22 -07:00
Vinnie Falco
abcb1dce57 Switch back to mutex for JobQueue 2013-09-05 19:47:12 -07:00
Vinnie Falco
5db25ede25 Add LoanedObject container example unit test 2013-09-05 19:47:11 -07:00
JoelKatz
55015f2730 TxsAccount fix. 2013-09-05 19:44:33 -07:00
JoelKatz
9f87e36545 Only update order book DB every ten ledgers
The order book DB code should be change to update on creation of order books rather than rescan.
2013-09-05 13:08:51 -07:00
Vinnie Falco
f1522b8fef Fix using-statements for older gcc without c++11 2013-09-05 06:55:50 -07:00
Vinnie Falco
4819714edf Fix non c++11 gcc build errors 2013-09-05 06:04:20 -07:00
Vinnie Falco
eac898a26f Fix compile error on configs with c++11 move support 2013-09-05 05:08:41 -07:00
Vinnie Falco
e892e9bb4e Replace obsolete OncePerSecond with DeadlineTimer 2013-09-05 04:38:18 -07:00
Vinnie Falco
e26a3a1d84 New TestOverlay generic peer to peer network tests 2013-09-05 04:38:17 -07:00
Vinnie Falco
5a06121a85 New ContainerTest generic templates 2013-09-05 04:22:27 -07:00
Vinnie Falco
a29ced1feb Activate MSVC leak report on exit with a configuratble BeastConfig setting 2013-09-05 04:22:27 -07:00
Vinnie Falco
bcd6e9d676 Refactor SharedPtr and fix ContainerDeletePolicy bug 2013-09-05 04:22:26 -07:00
Vinnie Falco
6c267d6388 Add HashMap unit test 2013-09-05 04:22:25 -07:00
Vinnie Falco
02107c3023 Add new-styled Intrusive and MPL modules 2013-09-05 04:22:25 -07:00
Vinnie Falco
1277f70c47 Use MultiSocket and strand in Peer 2013-09-04 17:03:13 -07:00
Vinnie Falco
8e75064fe3 Fix bug and tidy up DeadlineTimer 2013-09-04 15:17:22 -07:00
Vinnie Falco
cca092f5d1 Add compile time option for new Validators code 2013-09-04 13:51:55 -07:00
Vinnie Falco
d71211185e Fix String from number conversions 2013-09-04 13:24:41 -07:00
David Schwartz
c95211e572 Change tx_account to an account_tx switch. 2013-09-04 12:48:47 -07:00
Vinnie Falco
57d55cebe4 Move UNL timer processing to the JobQueue 2013-09-04 11:55:38 -07:00
David Schwartz
0950ef3984 Mark something that should be fixed. 2013-09-04 10:07:16 -07:00
Vinnie Falco
91e0cc84ef Validators framework and unit test 2013-09-03 08:31:17 -07:00
Vinnie Falco
2e1167fbd9 Added DynamicArray, DynamicList, and HashMap 2013-09-03 08:31:16 -07:00
Vinnie Falco
5aa784922f Update TODO Files 2013-09-02 18:03:44 -07:00
JoelKatz
c06aa4ff55 Cleanups, extra logging, and catch a case where a disputed transaction structure may not get created. 2013-09-02 06:08:11 -07:00
Vinnie Falco
b1d029e5b7 Fix VS2012 project file 2013-09-01 12:34:04 -07:00
Vinnie Falco
649b20a5f2 Move NodeStore and backends to ripple_core 2013-09-01 12:22:08 -07:00
Vinnie Falco
81a4711e66 Add BeforeBoost.h and tidy up beast system headers 2013-09-01 12:22:08 -07:00
Vinnie Falco
37216bed4d Refactor TxQueue, move some boost includes down to .cpp 2013-09-01 12:22:08 -07:00
Vinnie Falco
4ef0f5d6a9 Refactor ProofOfWork 2013-09-01 12:22:07 -07:00
Vinnie Falco
369bd0f36c Disable warnings 4018 and 4244 for VS2012 builds 2013-09-01 12:22:07 -07:00
Vinnie Falco
0f30b55cba Move PeerDoor source material into ripple_app.cpp 2013-09-01 12:22:06 -07:00
Vinnie Falco
e09d6a0a9b Make RPCSub abstract 2013-09-01 12:22:06 -07:00
Vinnie Falco
3077892c3b Remove deprecated basio::IoService 2013-09-01 12:22:05 -07:00
Vinnie Falco
027fba44ed Refactor ripple_websocket.h out of the main header material 2013-09-01 12:22:05 -07:00
Vinnie Falco
5f1a8670dc Refactor HTTPClient 2013-09-01 12:22:05 -07:00
Vinnie Falco
65df4b9daf Merge ripple_client into ripple_net 2013-09-01 12:22:04 -07:00
Vinnie Falco
5b8d104fb1 Make some header material private 2013-09-01 12:22:04 -07:00
Vinnie Falco
75b53ab171 Refactor WSConnection to a common base 2013-09-01 12:22:03 -07:00
Vinnie Falco
0d5bd937b1 Move RPCServerHandler to ripple_app/rpc 2013-09-01 12:22:03 -07:00
Vinnie Falco
98b630d8db Consolidate ripple_app includes 2013-09-01 12:22:02 -07:00
Vinnie Falco
3526cabd7b Move Application to ripple_app.cpp 2013-09-01 12:22:02 -07:00
Vinnie Falco
a709167801 Split ripple_app.cpp contents into each part file. 2013-09-01 12:22:02 -07:00
Vinnie Falco
dda831e09e Move common parts into ripple_app.h 2013-09-01 12:22:01 -07:00
Vinnie Falco
2070b2b1bd Reshuffle includes in ripple_app 2013-09-01 12:22:01 -07:00
Vinnie Falco
7de2d49345 Move RPCDoor to ripple_net 2013-09-01 12:22:00 -07:00
Vinnie Falco
0bcaf70e4a Reorganize some RPC related files 2013-09-01 12:22:00 -07:00
Vinnie Falco
af0471fb7d Tidy up ripple_net module 2013-09-01 12:21:59 -07:00
Vinnie Falco
e7d043e4df Merge ripple_asio into ripple_net 2013-09-01 12:21:59 -07:00
Vinnie Falco
a9f6d67bba Hide RPCDoor implementation and use RippleSSLContext 2013-09-01 12:21:59 -07:00
Vinnie Falco
e256716da8 Merge ripple_json to ripple_basics 2013-09-01 12:21:58 -07:00
Vinnie Falco
825ac4aca1 Make canonicalize take a pointer for clarity 2013-09-01 12:21:58 -07:00
Vinnie Falco
b1973db1f5 Make NetworkOPs abstract 2013-09-01 12:21:57 -07:00
Vinnie Falco
35598d7933 Refactor InfoSub to remove NetworkOPs dependency 2013-09-01 12:21:57 -07:00
Vinnie Falco
01fda4c30e Refactor RPCSub to remove Application dependency 2013-09-01 12:21:56 -07:00
Vinnie Falco
1391a11e46 Move BuildInfo to ripple_data 2013-09-01 12:21:56 -07:00
Vinnie Falco
bbfbdabe76 Move iAdminGet to Config::getAdminRole 2013-09-01 12:21:56 -07:00
Vinnie Falco
e22c1c3495 Refactor LoadManager 2013-09-01 12:21:55 -07:00
Vinnie Falco
1ee8b3903c Fix warnings in backend factories 2013-09-01 12:21:55 -07:00
Vinnie Falco
f5db655c47 Add some forward declarations 2013-09-01 12:21:54 -07:00
Vinnie Falco
11a09879a9 Move LevelDB options initialization into the factory 2013-09-01 12:21:54 -07:00
Vinnie Falco
f30fe1b699 Fix AutoSocket to use wrap() instead of post() 2013-09-01 12:21:54 -07:00
Vinnie Falco
d022fa68cf Fix websocket constant truncation warning 2013-09-01 12:21:53 -07:00
Vinnie Falco
99743e0fe0 Update TODO 2013-09-01 09:38:37 -07:00
Vinnie Falco
97075405cc Merge pull request #158 from nbougalis/feature-nikb-todo
Add NIKB_TODO
2013-08-31 18:33:40 -07:00
Nik Bougalis
b36e534197 Add NIKB_TODO 2013-08-31 18:28:43 -07:00
Vinnie Falco
f52c1657bf Update TODO 2013-08-31 15:14:46 -07:00
JoelKatz
a85afbe409 Fix paging in tx_account 2013-08-31 13:05:19 -07:00
Vinnie Falco
88060183f6 Tidy up includes and header material 2013-08-30 17:33:33 -07:00
Vinnie Falco
f37cf6277d Tidy up beast project files 2013-08-30 17:24:32 -07:00
JoelKatz
b81e22939b Binary support. 2013-08-30 12:53:24 -07:00
JoelKatz
47532b12dd First, untested, implementation of the new tx_account function. 2013-08-30 12:53:21 -07:00
JoelKatz
11117c75b7 Infrastructure for the new tx_account command. 2013-08-30 12:53:16 -07:00
JoelKatz
da5929cd18 Add a framework for rejecting commands. 2013-08-29 18:10:27 -07:00
JoelKatz
835236a35c Add a 'returnMessage' function to return a received message. 2013-08-29 18:03:45 -07:00
JoelKatz
eb33ae0d71 Fix a few bugs caused by starting without --net. There may still be some minor ones. 2013-08-28 00:55:56 -07:00
JoelKatz
be44586f85 Mark a FIXME 2013-08-27 12:31:10 -07:00
JoelKatz
34ee13a404 Fix bit rot. 2013-08-27 12:27:46 -07:00
JoelKatz
b102afcd3b Don't define TRUST_NETWORK 2013-08-27 12:21:30 -07:00
JoelKatz
e005dd5921 Correctly check if a node in an acquiring TXN set is a TXN we have. 2013-08-27 03:46:46 -07:00
JoelKatz
640e9482c4 This doesn't seem to properly synchronize reads and writes. 2013-08-27 02:22:40 -07:00
JoelKatz
d7ca14b18d This is too expensive. 2013-08-27 02:22:33 -07:00
JoelKatz
2780a5768a Fix another regression. 2013-08-27 01:49:46 -07:00
JoelKatz
2cc2d982a8 Fix a broken assert. 2013-08-27 00:53:26 -07:00
Vinnie Falco
e869713990 Fix warnings 2013-08-26 18:59:57 -07:00
JoelKatz
85e8a71918 Fix the disappearing paths problem. 2013-08-26 16:56:40 -07:00
Vinnie Falco
551643ff64 Log PROXY handshake addresses 2013-08-26 13:28:11 -07:00
JoelKatz
d7086bfc5e Set version to v0.12.0 2013-08-26 12:19:40 -07:00
Vinnie Falco
174303195b Add Subtrees/boost to .gitignore 2013-08-26 12:09:48 -07:00
JoelKatz
f2d2bdafd3 Merge branch 'develop' of github.com:ripple/rippled into develop 2013-08-25 15:32:04 -07:00
Vinnie Falco
b37c537b4a Set remote IP on PROXY handshake 2013-08-25 01:57:51 -07:00
Vinnie Falco
4170bcd294 Add PROXY peer listener and consolidate SSL contexts. 2013-08-25 01:57:51 -07:00
Vinnie Falco
3602e19dcd Add peer_port_proxy to config 2013-08-25 01:57:50 -07:00
Vinnie Falco
ef7cb16dcd Add toString for IPv4Address 2013-08-25 01:57:50 -07:00
Vinnie Falco
dea3c27e95 Add SSLContext 2013-08-25 01:57:50 -07:00
JoelKatz
68c089924a Merge branch 'develop' of github.com:ripple/rippled into develop 2013-08-24 20:52:10 -07:00
Vinnie Falco
ab08478e86 Use MultiSocket in Peer 2013-08-24 20:44:02 -07:00
Vinnie Falco
99dbc447f4 Use MultiSocket in Peer 2013-08-24 20:34:18 -07:00
Vinnie Falco
7b9a5e8753 Update MultiSocket for improved Socket 2013-08-24 20:06:17 -07:00
Vinnie Falco
db4a1dfaa4 Improvements to Socket and SocketWrapper 2013-08-24 20:06:17 -07:00
Vinnie Falco
bab6ab53d5 Add SocketWrapperStrand 2013-08-24 20:06:16 -07:00
Vinnie Falco
838b5befc6 Fix PrefilledReadStream::close to use lowest_layer 2013-08-24 20:06:16 -07:00
Vinnie Falco
bea6302759 Make asio Socket unit tests run automatically 2013-08-24 20:06:16 -07:00
Vinnie Falco
1959a93f28 Update to SQLite 3.8.0 Pre-release (as of 2013-08-22 02:56 UTC) 2013-08-24 20:06:15 -07:00
Vinnie Falco
364206b4e4 Remove unused sqlite subtree 2013-08-24 18:49:48 -07:00
Vinnie Falco
451d8ed488 Update sqlite to 3.7.17 (2013-05-20) 2013-08-24 18:48:08 -07:00
Vinnie Falco
444aba567f Set version to v0.12.0-rc6 2013-08-24 12:40:05 -07:00
Vinnie Falco
8b59a7b07b Fix NetworkOPs to set timers on processing 2013-08-24 12:39:14 -07:00
Vinnie Falco
21485ec003 Use SharedData in JobQueue and set latency, limits for new job types 2013-08-24 10:18:24 -07:00
Vinnie Falco
2bea9a8739 Merge beast_basics to beast_core 2013-08-24 10:18:24 -07:00
Vinnie Falco
9ba8ea679c Fix call doClusterReport on timer 2013-08-24 08:35:21 -07:00
Vinnie Falco
8908cdbfd5 Add TracketMutex unit test 2013-08-23 17:49:29 -07:00
Vinnie Falco
942e71b0ce Fix remove beast_boost.cpp from SConstruct 2013-08-23 15:04:45 -07:00
Vinnie Falco
f14333012b Use RippleMutex instead of boost::mutex 2013-08-23 15:00:04 -07:00
Vinnie Falco
c21a53a3ea Fix NetworkOPs timer to use JobQueue (2 new JobTypes added) 2013-08-23 15:00:04 -07:00
Vinnie Falco
4ececd0204 Add function call timing for all Application::sweep operations 2013-08-23 15:00:04 -07:00
Vinnie Falco
b0533a91fe Add TrackedMutex and measureFunctionCallTime 2013-08-23 15:00:04 -07:00
Vinnie Falco
5e827ba863 Fix KeyvaDB warnings 2013-08-23 07:01:37 -07:00
Vinnie Falco
0506a15209 Fix #ifdef for pragma 2013-08-22 18:43:55 -07:00
Vinnie Falco
5dc9169f98 Add logTimedDestroy and report in ~Ledger and ~SHAMap 2013-08-22 18:10:02 -07:00
Vinnie Falco
384370b433 Add String::fromNumber<> template for disambiguation 2013-08-22 18:10:01 -07:00
David Schwartz
a75631da56 STPath::assembleAdd function. 2013-08-22 16:03:37 -07:00
David Schwartz
37bfafe3bb Add some 'reserve' operations. 2013-08-22 16:02:45 -07:00
David Schwartz
76589f5084 Inline some functions. 2013-08-22 16:02:10 -07:00
JoelKatz
9aaabaebcd Don't send full ledgers to non-admins when under load. 2013-08-22 15:49:14 -07:00
JoelKatz
64e729fba6 Don't remove pathfinding requests erroneously. 2013-08-22 15:48:37 -07:00
Vinnie Falco
ce99820467 Add debug_log.txt to .gitignore 2013-08-22 15:36:44 -07:00
Vinnie Falco
663d5c9cee Log high SHAMap destroy times in ~Ledger 2013-08-22 15:36:40 -07:00
Vinnie Falco
8b86b81fc9 Add ~InboundLedger 2013-08-22 15:25:34 -07:00
Vinnie Falco
382b358bdf Move shared_ptr releases to outside the lock in InboundLedgers::sweep 2013-08-22 15:25:33 -07:00
Vinnie Falco
35836c9896 Move shared_ptr releases to outside the lock in TaggedCache::sweep 2013-08-22 15:25:33 -07:00
Vinnie Falco
8e95ee6ed3 Update MultiSocket to use new beast asio APIs 2013-08-21 19:41:44 -07:00
Vinnie Falco
647acebdbf New beast Socket, SharedHandler, ComposedAsyncOperation APIs 2013-08-21 19:41:22 -07:00
Vinnie Falco
a39e973abe Set version to v0.12.0-rc5 2013-08-21 18:52:54 -07:00
David Schwartz
3a2e770e52 Be more tolerant of corrupt peer entries. 2013-08-21 16:36:57 -07:00
David Schwartz
c17cfe9ea6 Send a smarter list of peers. 2013-08-21 16:36:51 -07:00
David Schwartz
c5a40141fe Don't let clients get tx history arbitrarily far back. 2013-08-21 11:18:33 -07:00
David Schwartz
32aabc8999 Change peer low water count from 4 to 10. 2013-08-21 11:18:24 -07:00
David Schwartz
e8eadae116 Can't use signing hashes to suppress. 2013-08-21 10:31:54 -07:00
David Schwartz
6704a5190e Make STPath::hasSeen const. 2013-08-21 10:31:41 -07:00
David Schwartz
a2f90da10c Fix pathfinding aggressiveness logic. 2013-08-21 10:31:34 -07:00
Vinnie Falco
beb50496a4 Remove KeyvaDB from NodeStore unit tests 2013-08-20 16:32:21 -07:00
Vinnie Falco
9d897001b6 Fix DirectoryIterator when multiple wildcards are used. 2013-08-20 15:24:02 -07:00
Vinnie Falco
651c9c8be7 Turn on C++11 for QMake builds 2013-08-20 15:22:36 -07:00
Vinnie Falco
578fee5f74 Fix ProtectedCall default handler 2013-08-20 15:22:21 -07:00
Vinnie Falco
568226e1ce Add top level out.txt to .gitignore 2013-08-20 15:04:20 -07:00
Vinnie Falco
54fe17d5eb Remove obsolete Xcode project 2013-08-20 14:59:20 -07:00
Vinnie Falco
d744e23e5e Disable KeyvaDB as a NodeStore backend choice 2013-08-20 14:47:45 -07:00
JoelKatz
e7fc07869d Disable the PoW unit test. 2013-08-19 15:00:16 -07:00
Vinnie Falco
02412b2ba4 Merge branch 'release' into develop
Conflicts:
	Subtrees/beast/modules/beast_asio/protocol/beast_HandshakeDetectorType.h
	modules/ripple_app/basics/ripple_BuildInfo.cpp
	modules/ripple_app/ledger/LedgerMaster.cpp
2013-08-19 14:30:27 -07:00
JoelKatz
45b7a6cdef Don't touch a possibly-failed inbound ledger. 2013-08-19 01:59:55 -07:00
JoelKatz
96b918fb10 0.12.0-rc3b 2013-08-19 01:57:01 -07:00
JoelKatz
9d3e3058bc Don't call both a function and a parameter "progress". 2013-08-18 23:27:54 -07:00
JoelKatz
c221cfde7a Some filterNodes cleanups. 2013-08-18 21:39:46 -07:00
JoelKatz
54a6d21903 Make the progress logic that triggers timeouts smarter. 2013-08-18 21:31:09 -07:00
JoelKatz
4e19c7cda1 Some extra debug. 2013-08-18 20:42:59 -07:00
JoelKatz
55af90fb68 Slow down fetching to avoid Sorceror's Apprentice syndrome. 2013-08-18 20:42:09 -07:00
JoelKatz
dfae891018 Fix a bug that could cause us not to acquire the current ledger. 2013-08-18 20:10:32 -07:00
JoelKatz
6e0d6bdba4 Make sure checkAccept is called, unless we know we don't need to, when findCreate completed immediately 2013-08-18 19:29:55 -07:00
JoelKatz
48c4eb3ad3 Suppress a warning. 2013-08-18 19:29:45 -07:00
JoelKatz
86147a6c6b Fix one case where checkAccept didn't get called. 2013-08-18 19:10:07 -07:00
Vinnie Falco
dd3ac6a154 Make HandlerCall operator() const 2013-08-18 17:21:59 -07:00
Vinnie Falco
0df51dc9e4 Add explicit checking for OpenSSL multithreading support 2013-08-18 13:09:09 -07:00
Vinnie Falco
a110a01e0d Move destroy to the .cpp 2013-08-18 13:09:09 -07:00
Vinnie Falco
7776781560 Fix pure virtual stubs for future returns 2013-08-18 13:08:34 -07:00
Vinnie Falco
958bc5866d Disable buffered handshake API to fix variations in boost versions 2013-08-18 04:11:53 -07:00
Vinnie Falco
1eccbd5e9d Disable buffered handshake API to fix variations in boost versions 2013-08-18 04:11:23 -07:00
Vinnie Falco
48bacf189d Clean up combinations of buffered handshaking and future returns 2013-08-18 03:20:57 -07:00
Vinnie Falco
d571788172 Tidy up argument types for all wrappers and call sites 2013-08-18 03:07:12 -07:00
Vinnie Falco
2d04fc4641 Remove obsolete handler wrappers 2013-08-18 02:35:53 -07:00
Vinnie Falco
04b5c7f447 New Context object for composed operations and continuation hooks 2013-08-18 01:53:43 -07:00
Vinnie Falco
d0e4352582 Fix clang compile error 2013-08-17 22:54:43 -07:00
Vinnie Falco
f342a70fd5 [WIP] MultiSocket 2013-08-17 21:10:03 -07:00
Vinnie Falco
6a8f054b2f Refactor Handler wrapper to meet the safety assurances of the original Handler 2013-08-17 21:10:03 -07:00
Vinnie Falco
d9b1b56c98 Fatal error if a Thread is destroyed while running 2013-08-17 21:10:02 -07:00
Vinnie Falco
6616cd86ef Add ContainerDeletePolicy for ownership containers 2013-08-17 21:10:01 -07:00
Vinnie Falco
2333a38cd7 Fix thread destruction in TestPeer and better exception reporting 2013-08-17 21:10:00 -07:00
Vinnie Falco
93f983ad71 Loop through the failing unit test 2013-08-17 21:10:00 -07:00
Vinnie Falco
0a58333edc Fixes to handshake and socket wrapper 2013-08-17 21:09:59 -07:00
Vinnie Falco
191562c13c Fix incorrect future returns for pure virtuals 2013-08-17 21:09:59 -07:00
Vinnie Falco
7fe3d3dc1b Fix gcc compile 2013-08-17 21:09:59 -07:00
Vinnie Falco
15dfaeb666 Use handshake detect stream in MultiSocket 2013-08-17 21:09:58 -07:00
Vinnie Falco
4eb3504a75 Refactor handshake parsing and logic classes 2013-08-17 21:09:58 -07:00
Vinnie Falco
2ce0ada8f5 Disable buffered handshake APIs 2013-08-17 21:09:57 -07:00
Vinnie Falco
59fe53781f Add TestPeerLogicProxyClient 2013-08-17 21:09:57 -07:00
Vinnie Falco
bb941354ce Generic HandshakeDetectStream and HandshakeDetectLogic 2013-08-17 21:09:57 -07:00
Vinnie Falco
0feccfd7b0 MultiSocket with ssl handshake detection 2013-08-17 21:09:56 -07:00
Vinnie Falco
461a710738 Allow selective enabling of async future returns 2013-08-17 21:09:56 -07:00
Vinnie Falco
4c605a79b7 Rename to max_needed for clarity 2013-08-17 21:09:55 -07:00
Vinnie Falco
4952ea2707 Add class PrefilledReadStream 2013-08-17 21:09:55 -07:00
Vinnie Falco
b064f66ea2 Fix async_result returns and handler copying 2013-08-17 21:09:55 -07:00
Vinnie Falco
7cf0ce22b1 Add default construction and isNull for Call handlers 2013-08-17 21:09:54 -07:00
Vinnie Falco
d22b236d2d Add 1-arity and 2-arity binding to CompletionCall 2013-08-17 21:09:54 -07:00
Vinnie Falco
462a1394d7 Add this_layer and this_layer_type to SocketWrapper 2013-08-17 21:09:53 -07:00
Vinnie Falco
9bfd8c923d Check for macro before setting it 2013-08-17 21:09:53 -07:00
Vinnie Falco
8c65adbffe Tidy up move obsolete and deprecated files 2013-08-17 21:09:53 -07:00
JoelKatz
fe1b8d253c Don't tolerate failed ledger acquires in the publication stream. 2013-08-16 23:22:33 -07:00
JoelKatz
39caac637c Typo. 2013-08-16 18:50:33 -07:00
JoelKatz
c98b24dbe6 Missing comma. 2013-08-16 18:41:47 -07:00
JoelKatz
6eec84144a A better fix for countAccountTxs. 2013-08-16 18:12:33 -07:00
JoelKatz
eb121e9312 Revert "Fix 'NetworkOPs::countAccountTxs' taking way too long."
This reverts commit ff127d2b25.
A new fix is in development.
2013-08-16 17:50:30 -07:00
Vinnie Falco
44aa45f307 Set version to 0.12.0-rc3 2013-08-16 17:47:29 -07:00
JoelKatz
ff127d2b25 Fix 'NetworkOPs::countAccountTxs' taking way too long. 2013-08-16 17:40:28 -07:00
Vinnie Falco
9bc96bc558 Fix missing return value 2013-08-16 10:43:31 -07:00
2733 changed files with 184367 additions and 228404 deletions

View File

@@ -1,10 +0,0 @@
;; Emacs - Code style and formatting settings
;; C++
((c++-mode
(indent-tabs-mode . t)
(tab-width . 4)
(c-basic-offset . 4)))
;; Headers should open in C++ mode
((c-mode . ((mode . c++))))

9
.gitignore vendored
View File

@@ -24,16 +24,18 @@ Debug/*.*
Release/*.*
# Ignore locally installed node_modules
node_modules
/node_modules
# Ignore tmp directory.
tmp
# Ignore database directory.
db
db/*.db
db/*.db-*
# Ignore debug logs
debug_log.txt
# Ignore customized configs
rippled.cfg
validators.txt
@@ -67,3 +69,6 @@ My Amplifier XE Results - RippleD
# KeyvaDB files
*.key
*.val
# Compiler intermediate output
/out.txt

23
.travis.yml Normal file
View File

@@ -0,0 +1,23 @@
language: cpp
compiler:
- gcc
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq python-software-properties
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo add-apt-repository -y ppa:boost-latest/ppa
- sudo apt-get update -qq
- sudo apt-get install -qq libboost1.54-all-dev protobuf-compiler libprotobuf-dev libssl-dev exuberant-ctags
- sudo apt-get install -qq gcc-4.8
- sudo apt-get install -qq g++-4.8
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 40 --slave /usr/bin/g++ g++ /usr/bin/g++-4.8
- sudo update-alternatives --set gcc /usr/bin/gcc-4.8
- g++ -v
script: scons && ./build/rippled --unittest && npm install && npm test
notifications:
email:
false
irc:
channels:
- "chat.freenode.net#ripple-dev"

View File

@@ -1,7 +1,7 @@
# Ripple protocol buffers
PROTOS = ../../modules/ripple_data/protocol/ripple.proto
PROTOS = ../../src/ripple_data/protocol/ripple.proto
PROTOS_DIR = ../../build/proto
# Google Protocol Buffers support
@@ -31,7 +31,9 @@ TEMPLATE = app
CONFIG += console thread warn_off
CONFIG -= qt gui
linux-gg++:QMAKE_CXXFLAGS += \
DEFINES += _DEBUG
linux-g++:QMAKE_CXXFLAGS += \
-Wall \
-Wno-sign-compare \
-Wno-char-subscripts \
@@ -39,52 +41,62 @@ linux-gg++:QMAKE_CXXFLAGS += \
-Wno-unused-parameter \
-Wformat \
-O0 \
-std=c++11 \
-pthread
INCLUDEPATH += \
"../.." \
"../../Subtrees" \
"../../Subtrees/leveldb/" \
"../../Subtrees/leveldb/port" \
"../../Subtrees/leveldb/include" \
"../../src" \
"../../src/leveldb/" \
"../../src/leveldb/port" \
"../../src/leveldb/include" \
$${PROTOS_DIR}
OTHER_FILES += \
$$files(../../Subtrees/beast/*) \
$$files(../../Subtrees/beast/modules/beast_basics/diagnostic/*)
# $$files(../../src/*, true) \
# $$files(../../src/beast/*) \
# $$files(../../src/beast/modules/beast_basics/diagnostic/*)
# $$files(../../src/beast/modules/beast_core/, true)
# $$files(../../Subtrees/beast/modules/beast_core/, true)
# $$files(../../modules/*, true) \
UI_HEADERS_DIR += ../../modules/ripple_basics
UI_HEADERS_DIR += ../../src/ripple_basics
# ---------
# New style
#
SOURCES += \
../../Subtrees/beast/modules/beast_asio/beast_asio.cpp \
../../Subtrees/beast/modules/beast_basics/beast_basics.cpp \
../../Subtrees/beast/modules/beast_core/beast_core.cpp \
../../Subtrees/beast/modules/beast_crypto/beast_crypto.cpp \
../../Subtrees/beast/modules/beast_db/beast_db.cpp \
../../Subtrees/beast/modules/beast_sqdb/beast_sqdb.cpp \
../../Subtrees/beast/modules/beast_sqlite/beast_sqlite.c \
../../modules/ripple_app/ripple_app_pt1.cpp \
../../modules/ripple_app/ripple_app_pt2.cpp \
../../modules/ripple_app/ripple_app_pt3.cpp \
../../modules/ripple_app/ripple_app_pt4.cpp \
../../modules/ripple_app/ripple_app_pt5.cpp \
../../modules/ripple_app/ripple_app_pt6.cpp \
../../modules/ripple_app/ripple_app_pt7.cpp \
../../modules/ripple_app/ripple_app_pt8.cpp \
../../modules/ripple_asio/ripple_asio.cpp \
../../modules/ripple_basics/ripple_basics.cpp \
../../modules/ripple_core/ripple_core.cpp \
../../modules/ripple_client/ripple_client.cpp \
../../modules/ripple_data/ripple_data.cpp \
../../modules/ripple_hyperleveldb/ripple_hyperleveldb.cpp \
../../modules/ripple_json/ripple_json.cpp \
../../modules/ripple_leveldb/ripple_leveldb.cpp \
../../modules/ripple_mdb/ripple_mdb.c \
../../modules/ripple_net/ripple_net.cpp \
../../modules/ripple_websocket/ripple_websocket.cpp
../../src/ripple/beast/ripple_beast.cpp \
../../src/ripple/beast/ripple_beastc.c \
../../src/ripple/common/ripple_common.cpp \
../../src/ripple/http/ripple_http.cpp \
../../src/ripple/json/ripple_json.cpp \
../../src/ripple/peerfinder/ripple_peerfinder.cpp \
../../src/ripple/resource/ripple_resource.cpp \
../../src/ripple/rpc/ripple_rpc.cpp \
../../src/ripple/sitefiles/ripple_sitefiles.cpp \
../../src/ripple/sslutil/ripple_sslutil.cpp \
../../src/ripple/testoverlay/ripple_testoverlay.cpp \
../../src/ripple/types/ripple_types.cpp \
../../src/ripple/validators/ripple_validators.cpp
# ---------
# Old style
#
SOURCES += \
../../src/ripple_app/ripple_app.cpp \
../../src/ripple_app/ripple_app_pt1.cpp \
../../src/ripple_app/ripple_app_pt2.cpp \
../../src/ripple_app/ripple_app_pt3.cpp \
../../src/ripple_app/ripple_app_pt4.cpp \
../../src/ripple_app/ripple_app_pt5.cpp \
../../src/ripple_app/ripple_app_pt6.cpp \
../../src/ripple_app/ripple_app_pt7.cpp \
../../src/ripple_app/ripple_app_pt8.cpp \
../../src/ripple_basics/ripple_basics.cpp \
../../src/ripple_core/ripple_core.cpp \
../../src/ripple_data/ripple_data.cpp \
../../src/ripple_hyperleveldb/ripple_hyperleveldb.cpp \
../../src/ripple_leveldb/ripple_leveldb.cpp \
../../src/ripple_net/ripple_net.cpp \
../../src/ripple_websocket/ripple_websocket.cpp
LIBS += \
-lboost_date_time-mt\

View File

@@ -1,10 +1,10 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2012 for Windows Desktop
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "beast", "..\..\Subtrees\beast\Builds\VisualStudio2012\beast.vcxproj", "{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}"
EndProject
# Visual Studio 2012
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RippleD", "RippleD.vcxproj", "{B7F39ECD-473C-484D-BC34-31F8362506A5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "beast", "..\..\src\beast\Builds\VisualStudio2012\beast.vcxproj", "{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -13,14 +13,6 @@ Global
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|Win32.ActiveCfg = Debug|Win32
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|Win32.Build.0 = Debug|Win32
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|x64.ActiveCfg = Debug|x64
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|x64.Build.0 = Debug|x64
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|Win32.ActiveCfg = Release|Win32
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|Win32.Build.0 = Release|Win32
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|x64.ActiveCfg = Release|x64
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|x64.Build.0 = Release|x64
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Debug|Win32.ActiveCfg = Debug|Win32
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Debug|Win32.Build.0 = Debug|Win32
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Debug|x64.ActiveCfg = Debug|x64
@@ -29,6 +21,14 @@ Global
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Release|Win32.Build.0 = Release|Win32
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Release|x64.ActiveCfg = Release|x64
{B7F39ECD-473C-484D-BC34-31F8362506A5}.Release|x64.Build.0 = Release|x64
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|Win32.ActiveCfg = Debug|Win32
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|Win32.Build.0 = Debug|Win32
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|x64.ActiveCfg = Debug|x64
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Debug|x64.Build.0 = Debug|x64
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|Win32.ActiveCfg = Release|Win32
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|Win32.Build.0 = Release|Win32
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|x64.ActiveCfg = Release|x64
{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -14,9 +14,10 @@
<PreprocessorDefinitions>_VARIADIC_MAX=10;_WIN32_WINNT=0x0600;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WarningLevel>Level3</WarningLevel>
<AdditionalIncludeDirectories>$(RepoDir);$(RepoDir)\src\cpp\protobuf\src;$(RepoDir)\src\cpp\protobuf\vsprojects;$(RepoDir)\build\proto;$(RepoDir)\Subtrees;$(RepoDir)\Subtrees\leveldb;$(RepoDir)\Subtrees\leveldb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(RepoDir)\src\protobuf\src;$(RepoDir)\src\protobuf\vsprojects;$(RepoDir)\src;$(RepoDir)\src\leveldb;$(RepoDir)\src\leveldb\include;$(RepoDir)\build\proto;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<ExceptionHandling>Async</ExceptionHandling>
<DisableSpecificWarnings>4018;4244</DisableSpecificWarnings>
</ClCompile>
<Link>
<AdditionalDependencies>Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
LICENSE

Binary file not shown.

View File

@@ -1,28 +0,0 @@
Vinnie Falco's Change Log
2013/08/07
- Add 'print' test that shows all the tests
- Improved "package.test" match string format when choosing tests to run
2013/08/04
- Begin reworking of socket code
2013/08/01
- Add beast::SemanticVersion
- Change rippled to use SemanticVersion
- Add runStartup to UnitTest, allowing forced tests on startup
- Force rippled BuildInfo unit test to run on every startup
2013/07/31
- Add "hostname" to server_info output
- Replace "build_version" in server_info with the actual build version
- Remove "client_version" from server_info
2013/07/30
- Add FatalErrorReporter to main
- Rewrote the build and protocol version numbering code

View File

@@ -1,487 +0,0 @@
--------------------------------------------------------------------------------
RIPPLE TODO
--------------------------------------------------------------------------------
REMINDER: KEEP CHANGE LOG UP TO DATE
Vinnie's List: Changes day to day, descending priority
(Items marked '*' can be handled by others.)
- beast::Socket integration in Ripple
- Socket implementation for PROXY protocol
- Socket that supports multiple protcols
- Unit tests for boost::asio wrappers
- Review boost::asio wrappers and consolidation of network code in ripple_net
- Deeply create directories specified in config settings
- Finish unit tests and code for Validators
* Document the command line options for the beast unit test framework
David Features:
- override config items from command line
- change config via RPC, this is for debugging
--------------------------------------------------------------------------------
- Refactor Section code into ConfigFile
- Improved Mutex to track deadlocks
- Work on KeyvaDB
- Allow skipped/disabled unit tests and reporting.
- Supress useless gcc warnings
http://stackoverflow.com/questions/3378560/how-to-disable-gcc-warnings-for-a-few-lines-of-code
- Get rid of boost::filesystem
- Make some fatal_assert macro that calls FatalError
- What the heck is up with site_scons/site_tools/protoc.py?
- Figure out the right behavior of ProtectedCall
- Do something about the throw() reporting weaknesses:
* Make sure all Sconstruct and .pro builds have debug symbols in release
* Replace all throw with beast::Throw()
(Only in ripple sources, not in Subtrees/, protobuf, or websocket)
- Improved Beast exception object, provides __FILE__ and __LINE__
- Add file and line capabilities to beast::Throw()
- Allow beast::Throw to be hooked for logging
- Add stack trace capability to beast::Throw() diagnostics via the hook
(use the existing beast::SystemStats::getStackBacktrace())
- Implement getStackBacktrace for BEAST_BSD targets
- Add UnhandledExceptionCatcher to beast
- Return EXIT_FAILURE on unhandled exception
- Option to print the list of available unit tests
- Add convenience variadic functions to JobQueue that do the bind for you
- Consolidate databases
- Figure out why we need WAL sqlite mode if we no longer use sqlite for the node store
- Add "skipped" field to beginTestCase() to disable a test but still record
that it was skipped in the output. Like for mdb import.
- use beast DeadlineTimer for sweep in Application
- Make SNTP Client have its own io_service
- Get rid of 'ref' typedefs that really mean const&
- Use secp256k1 from beast
- Fix xsd/dtd line in JUnit XML output
- Get rid of the WriteLog() stuff in the ripple tests and make it report the
message directly to the UnitTest object. Then update the JUnit XML output
routines to also write the auxiliary messages.
* Take away the "I" prefix from abstract interface classes, in both the class
name and the file name. It is messing up sorting in the IDE. Use "Imp" or
suffix for implementations.
* Restyle all the macros in ripple_ConfigSection.h
- Move src/protobuf to Subtrees and deal with protobuf_core.cpp
- Replace home-made database wrappers with beast::sqdb
- Use static creation member functions instead of endless constructor
variations in base_uint, uint256, and family.
- Raise the warning level and fix everything
- Replace base_uint and uintXXX with UnsignedInteger
* Need to specialize UnsignedInteger to work efficiently with 4 and 8 byte
multiples of the size.
- Rewrite boost program_options in Beast
- Replace endian conversion calls with beast calls:
htobe32, be32toh, ntohl, etc...
Start by removing the system headers which provide these routines, if possible
- Rename RPCHandler to CallHandler
- See if UniqueNodeList is really used, and if its not used remove it. If
only some small part of it is used, then delete the rest. David says
that it is broken anyway.
- Tidy up convenience functions in RPC.h
- Maybe rename RPCServer to RPCClientServicer
- Profile/VTune the application to identify hot spots
* Determine why rippled has a slow startup on Windows
* Improve the performance when running all unit tests on Windows
- Rename "fullBelow" to something like haveAllDescendants or haveAllChildren.
- Class to represent IP and Port number, with members to print, check syntax,
etc... replace the boost calls.
- Remove dependence on JobQueue, LoadFeeTrack, and NetworkOPs from LoadManager
by providing an observer (beast::ListenerList or Listeners). This way
LoadManager does not need stopThread() function.
- Rewrite Sustain to use Beast and work on Windows as well
* Do not enable watchdog process if a debugger is attached
- Make separate LevelDB VS2012 project for source browsing, leave ony the unity
.cpp in the main RippleD project
- Add LevelDB unity .cpp to the LevelDB fork
- Make sure the leak detector output appears on Linux and FreeBSD debug builds.
- Create SharedData <LoadState>, move all load related state variables currently
protected by separated mutexes in different classes into the LoadState, and
use read/write locking semantics to update the values. Later, use Listeners
to notify dependent code to resolve the dependency inversion.
- Rename LoadMonitor to LoadMeter, change LoadEvent to LoadMeter::ScopedSample
- Rename LedgerMaster to Ledgers, create ILedgers interface.
- Restructure the ripple sources to have this directory structure:
/Source/ripple/ripple_core/ripple_core.h
/...
/Source/Subtrees/... ?
PROBLEM: Where to put BeastConfig.h ?
- Figure out where previous ledgers go after a call to LedgerMaster::pushLedger()
and see if it is possible to clean up the leaks on exit.
- Replace all NULL with nullptr
- Add ICore interface (incremental replacement for Application)
- Make TxFormats a member of ICore instead of a singleton.
PROBLEM: STObject derived classes like STInt16 make direct use of the
singleton. It might have to remain a singleton. At the very least,
it should be a SharedSingleton to resolve ordering issues.
- Rename include guards to boost style, e.g. RIPPLE_LOG_H_INCLUDED
- Replace C11X with BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
- Fix all leaks on exit (!)
Say there's a leak, a ledger that can never be accessed is locked in some
structure. If the organized teardown code frees that structure, the leak
will not be reported.
Yes, so you'll detect some small subset of leaks that way.
You'll still have to be vigilant for the leaks that won't detect.
The problem is ordering. There are lots of circular dependencies.
The biggest problem is the order of destruction of global objects. (I think)
Getting rid of global objects is a good solution to that.
Vinnie Falco: Those I can resolve with my ReferenceCountedSingleton. And
yeah thats a good approach, one that I am doing slowly anyway
Yeah, that's good for other reasons too, not just the unpredictability of
creation order that can hide bugs.
There may also just be some missing destructors.
Some of it may be things being shut down in the wrong order. Like if you shut
down the cache and then something that uses the cache, objects may get
put in the cache after it was shut down.
- Remove "ENABLE_INSECURE" when the time is right.
- lift unique_ptr / auto_ptr into ripple namespace,
or replace with ScopedPointer (preferred)
- Make LevelDB and Ripple code work with both Unicode and non-Unicode Windows APIs
- Go searching through VFALCO notes and fix everything
- Deal with function-level statics used for SqliteDatabase (like in
HSBESQLite::visitAll)
- Document in order:
SerializedType
STObject
SerializedLedgerEntry
- Replace uint160, uint256 in argument lists, template parameter lists, and
data members with tyepdefs from ripple_ProtocolTypes.h
- Consolidate SQLite database classes: DatabaseCon, Database, SqliteDatabase.
--------------------------------------------------------------------------------
LEVELDB TODO
--------------------------------------------------------------------------------
- Add VisualStudio 2012 project file to our fork
- Add LevelDB unity .cpp and .h to our fork
- Replace Beast specific platform macros with universal macros so that the
unity doesn't require Beast
- Submit LevelDB fork changes to Bitcoin upstream
--------------------------------------------------------------------------------
WEBSOCKET TODO
--------------------------------------------------------------------------------
*** Figure out how hard we want to fork websocket first **
- Think about stripping the ripple specifics out of AutoSocket, make AutoSocket
part of our websocketpp fork
- Regroup all the sources together in one directory
- Strip includes and enforce unity
- Put a new front-end on websocket to hide ALL of their classes and templates
from the host application, make this part of the websocket fork
--------------------------------------------------------------------------------
PROTOCOL BUFFERS TODO
--------------------------------------------------------------------------------
- Create/maintain the protobuf Git repo (original uses SVN)
- Update the subtree
- Make a Visual Studio 2012 Project for source browsing
--------------------------------------------------------------------------------
NOTES
--------------------------------------------------------------------------------
LoadEvent
Is referenced with both a shared pointer and an auto pointer.
Should be named LoadMeter::ScopedSample. Or possibly ScopedLoadSample
JobQueue
getLoadEvent and getLoadEventAP differ only in the style of pointer
container which is returned. Unnecessary complexity.
Naming: Some names don't make sense.
Index
Stop using Index to refer to keys in tables. Replace with "Key" ?
Index implies a small integer, or a data structure.
This is all over the place in the Ledger API, "Index" of this and
"Index" of that, the terminology is imprecise and helps neither
understanding nor recall.
Inconsistent names
We have full names like SerializedType and then acronyms like STObject
Two names for some things, e.g. SerializedLedgerEntry and SLE
Shared/Smart pointer typedefs in classes have a variety of different names
for the same thing. e.g. "pointer", "ptr", "ptr_t", "wptr"
Verbose names
The prefix "Flat" is more appealing than "Serialized" because its shorter and
easier to pronounce.
Ledger "Skip List"
Is not really a skip list data structure. This is more appropriately
called an "index" although that name is currently used to identify hashes
used as keys.
Duplicate Code
LedgerEntryFormat and TxFormat
* Resolved with a todo item, create WireFormats<> template class.
Interfaces
Serializer
Upon analysis this class does two incompatible things. Flattening, and
unflattening. The interface should be reimplemented as two distinct
abstract classes, InputStream and OutputStream with suitable implementations
such as to and from a block of memory or dynamically allocated buffer.
The name and conflation of dual roles serves to confuse code at the point
of call. Does set(Serializer& s) flatten or unflatten the data? This
would be more clear:
bool write (OutputStream& stream);
We have beast for InputStream and OutputStream, we can use those now.
boost
Unclear from the class declaration what style of shared object management
is used. Prefer to derive from a SharedObject class so that the
behavior is explicit. Furthermore the use of intrusive containers is
preferred over the alternative.
make_shared <> () is awkward.
boost::recursive_mutex
Recursive mutexes should never be necessary.
They require the "mutable" keyword for const members to acquire the lock (yuck)
Replace recursive_mutex with beast::Mutex to remove boost dependency
--------------------------------------------------------------------------------
Davidisms
--------------------------------------------------------------------------------
(Figure out a good place to record information like this permanently)
Regarding a defect where a failing transaction was being submitted over and over
again on the network (July 3, 2013)
The core problem was an interaction between two bits of logic.
1) Normally, we won't relay a transaction again if we already recently relayed
it. But this is bypassed if the transaction failed in a way that could
allow it to succeed later. This way, if one server discovers a transaction
can now work, it can get all servers to retry it.
2) Normally, we won't relay a transaction if we think it can't claim a fee.
But if we're not sure it can't claim a fee because we're in an unhealthy
state, we propagate the transaction to let other servers decide if they
think it can claim a fee.
With these two bits of logic, two unhealthy servers could infinitely propagate
a transaction back and forth between each other.
A node is "full below" if we believe we have (either in the database or
scheduled to be stored in the database) the contents of every node below that
node in a hash tree. When trying to acquire a hash tree/map, if a node is
full below, we know not to bother with anything below that node.
The fullBelowCache is a cache of hashes of nodes that are full below. Which means
there are no missing children
What we want from the unique node list:
- Some number of trusted roots (known by domain)
probably organizations whose job is to provide a list of validators
- We imagine the IRGA for example would establish some group whose job is to
maintain a list of validators. There would be a public list of criteria
that they would use to vet the validator. Things like:
* Not anonymous
* registered business
* Physical location
* Agree not to cease operations without notice / arbitrarily
* Responsive to complaints
- Identifiable jurisdiction
* Homogeneity in the jurisdiction is a business risk
* If all validators are in the same jurisdiction this is a business risk
- OpenCoin sets criteria for the organizations
- Rippled will ship with a list of trusted root "certificates"
In other words this is a list of trusted domains from which the software
can contact each trusted root and retrieve a list of "good" validators
and then do something with that information
- All the validation information would be public, including the broadcast
messages.
- The goal is to easily identify bad actors and assess network health
* Malicious intent
* Or, just hardware problems (faulty drive or memory)
--------------------------------------------------------------------------------
ChosenValidators
--------------------------------------------------------------------------------
David:
I've cut 2 of the 6 active client-facing servers to hyper. Since then, we've
had 5 spinouts on 3 servers, none of them on the 2 I've cut over. But they
are also the most recently restarted servers, so it's not a 100% fair test.
Maybe OC should have a URL that you can query to get the latest list of URI's
for OC-approved organzations that publish lists of validators. The server and
client can ship with that master trust URL and also the list of URI's at the
time it's released, in case for some reason it can't pull from OC. That would
make the default installation safe even against major changes in the
organizations that publish validator lists.
The difference is that if an organization that provides lists of validators
goes rogue, administrators don't have to act.
TODO:
Write up from end-user perspective on the deployment and administration
of this feature, on the wiki. "DRAFT" or "PROPOSE" to mark it as provisional.
Template: https://ripple.com/wiki/Federation_protocol
- What to do if you're a publisher of ValidatorList
- What to do if you're a rippled administrator
- Overview of how ChosenValidators works
Goals:
Make default configuration of rippled secure.
* Ship with TrustedUriList
* Also have a preset RankedValidators
Eliminate administrative burden of maintaining
Produce the ChosenValidators list.
Allow quantitative analysis of network health.
What determines that a validator is good?
- Are they present (i.e. sending validations)
- Are they on the consensus ledger
- What percentage of consensus rounds do they participate in
- Are they stalling consensus
* Measurements of constructive/destructive behavior is
calculated in units of percentage of ledgers for which
the behavior is measured.
Nouns
Validator
- Signs ledgers and participate in consensus
- Fields
* Public key
* Friendly name
* Jurisdiction
* Org type: profit, nonprofit, "profit/gateway"
- Metadata
* Visible on the network?
* On the consensus ledger?
* Percentage of recent participation in consensus
* Frequency of stalling the consensus process
ValidatorSource
- Abstract
- Provides a list of Validator
ValidatorList
- Essentially an array of Validator
TrustedUriValidatorSource
- ValidatorSource which uses HTTPS and a predefined URI
- Domain owner is responsible for removing bad validators
TrustedUriValidatorSource::List
- Essentially an array of TrustedUriValidatorSource
- Can be read from a file
LocalFileValidatorSource
- ValidatorSource which reads information from a local file.
TrustedUriList // A copy of this ships with the app
* has a KnownValidators
KnownValidators
* A series of KnownValidator that comes from a TrustedUri
* Persistent storage has a timestamp
RankedValidators
* Created as the union of all KnownValidators with "weight" being the
number of appearances.
ChosenValidators
* Result of the algorithm that chooses a random subset of RankedKnownValidators
* "local health" percentage is the percent of validations from this list that
you've seen recently. And have they been behaving.
Algorithm
When updating a source

View File

@@ -1,18 +1,53 @@
Ripple - P2P Payment Network
============================
#Ripple - P2P Payment Network
[![Build Status](https://ci.ripple.com/jenkins/buildStatus/icon?job=rippled)](https://ci.ripple.com/jenkins/job/rippled/)
Some portions of this source code are currently closed source.
##[![Build Status](https://ci.ripple.com/jenkins/buildStatus/icon?job=rippled)](https://ci.ripple.com/jenkins/job/rippled/)
This is the repository for Ripple's `rippled`, reference P2P network server.
Build instructions:
###Build instructions:
* https://ripple.com/wiki/Rippled_build_instructions
Setup instructions:
###Setup instructions:
* https://ripple.com/wiki/Rippled_setup_instructions
For more information:
### Repository Contents
#### ./bin
Scripts and data files for Ripple integrators.
#### ./build
Intermediate and final build outputs.
#### ./Builds
Platform or IDE-specific project files.
#### ./doc
Documentation and example configuration files.
#### ./src
Source code directory. Some of the directories contained here are
external repositories inlined via git-subtree, see the corresponding
README for more details.
#### ./test
Javascript / Mocha tests.
## License
Provided under the terms of the ISC License:
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
###For more information:
* https://ripple.com
* https://ripple.com/wiki

View File

@@ -8,11 +8,16 @@ import glob
import os
import platform
import re
import sys
OSX = bool(platform.mac_ver()[0])
FreeBSD = bool('FreeBSD' == platform.system())
Linux = bool('Linux' == platform.system())
Ubuntu = bool(Linux and 'Ubuntu' == platform.linux_distribution()[0])
Debian = bool(Linux and 'debian' == platform.linux_distribution()[0])
Archlinux = bool(Linux and ('','','') == platform.linux_distribution()) #Arch still has issues with the platform module
USING_CLANG = OSX
#
# We expect this to be set
@@ -20,7 +25,7 @@ Ubuntu = bool(Linux and 'Ubuntu' == platform.linux_distribution()[0])
BOOST_HOME = os.environ.get("RIPPLED_BOOST_HOME", None)
if OSX or Ubuntu:
if OSX or Ubuntu or Debian or Archlinux:
CTAGS = 'ctags'
elif FreeBSD:
CTAGS = 'exctags'
@@ -31,13 +36,14 @@ else:
# scons tools
#
HONOR_ENVS = ['CC', 'CXX', 'PATH']
env = Environment(
tools = ['default', 'protoc']
tools = ['default', 'protoc'],
#ENV = dict((k, os.environ[k]) for k in HONOR_ENVS)
ENV = dict((k, os.environ[k]) for k in HONOR_ENVS if k in os.environ)
)
GCC_VERSION = re.split('\.', commands.getoutput(env['CXX'] + ' -dumpversion'))
# Use a newer gcc on FreeBSD
if FreeBSD:
env.Replace(CC = 'gcc46')
@@ -50,7 +56,18 @@ if OSX:
env.Replace(CXX= 'clang++')
env.Append(CXXFLAGS = ['-std=c++11', '-stdlib=libc++'])
env.Append(LINKFLAGS='-stdlib=libc++')
env['FRAMEWORKS'] = ['AppKit']
env['FRAMEWORKS'] = ['AppKit','Foundation']
GCC_VERSION = re.split('\.', commands.getoutput(env['CXX'] + ' -dumpversion'))
# Add support for ccache. Usage: scons ccache=1
ccache = ARGUMENTS.get('ccache', 0)
if int(ccache):
env.Prepend(CC = ['ccache'])
env.Prepend(CXX = ['ccache'])
ccache_dir = os.getenv('CCACHE_DIR')
if ccache_dir:
env.Replace(CCACHE_DIR = ccache_dir)
#
# Builder for CTags
@@ -83,13 +100,13 @@ BOOST_LIBS = [
'boost_regex',
'boost_system',
'boost_thread',
'boost_random',
]
# We whitelist platforms where the non -mt version is linked with pthreads. This
# can be verified with: ldd libboost_filesystem.* If a threading library is
# included the platform can be whitelisted.
if FreeBSD or Ubuntu or OSX:
if FreeBSD or Ubuntu or Archlinux:
# if FreeBSD or Ubuntu or Archlinux or OSX:
# non-mt libs do link with pthreads.
env.Append(
LIBS = BOOST_LIBS
@@ -101,8 +118,12 @@ else:
#-------------------------------------------------------------------------------
#
# VFALCO This is my oasis of sanity. Nothing having to do with directories,
# source files, or include paths should reside outside the boundaries.
# VFALCO NOTE Clean area.
#
#-------------------------------------------------------------------------------
#
# Nothing having to do with directories, source files,
# or include paths should reside outside the boundaries.
#
# List of includes passed to the C++ compiler.
@@ -110,62 +131,82 @@ else:
#
INCLUDE_PATHS = [
'.',
'build/proto',
'Subtrees',
'Subtrees/leveldb',
'Subtrees/leveldb/port',
'Subtrees/leveldb/include',
'Subtrees/beast',
'src',
'src/leveldb',
'src/leveldb/port',
'src/leveldb/include',
'src/beast',
'build/proto'
]
# if BOOST_HOME:
# INCLUDE_PATHS.append(BOOST_HOME)
if OSX:
COMPILED_FILES = [
'Subtrees/beast/modules/beast_core/beast_core.mm'
]
else:
COMPILED_FILES = [
'Subtrees/beast/modules/beast_core/beast_core.cpp'
]
#-------------------------------------------------------------------------------
#
# Compiled sources
#
COMPILED_FILES = []
# -------------------
# Beast unity sources
#
if OSX:
# OSX: Use the Objective C++ version of beast_core
COMPILED_FILES.extend (['src/ripple/beast/ripple_beastobjc.mm'])
else:
COMPILED_FILES.extend (['src/ripple/beast/ripple_beast.cpp'])
COMPILED_FILES.extend (['src/ripple/beast/ripple_beastc.c'])
# ------------------------------
# New-style Ripple unity sources
#
COMPILED_FILES.extend([
'Subtrees/beast/modules/beast_asio/beast_asio.cpp',
'Subtrees/beast/modules/beast_basics/beast_basics.cpp',
# 'Subtrees/beast/modules/beast_core/beast_core.cpp',
'Subtrees/beast/modules/beast_crypto/beast_crypto.cpp',
'Subtrees/beast/modules/beast_db/beast_db.cpp',
'Subtrees/beast/modules/beast_sqdb/beast_sqdb.cpp',
'Subtrees/beast/modules/beast_sqlite/beast_sqlite.c',
'modules/ripple_app/ripple_app_pt1.cpp',
'modules/ripple_app/ripple_app_pt2.cpp',
'modules/ripple_app/ripple_app_pt3.cpp',
'modules/ripple_app/ripple_app_pt4.cpp',
'modules/ripple_app/ripple_app_pt5.cpp',
'modules/ripple_app/ripple_app_pt6.cpp',
'modules/ripple_app/ripple_app_pt7.cpp',
'modules/ripple_app/ripple_app_pt8.cpp',
'modules/ripple_asio/ripple_asio.cpp',
'modules/ripple_basics/ripple_basics.cpp',
'modules/ripple_core/ripple_core.cpp',
'modules/ripple_data/ripple_data.cpp',
'modules/ripple_hyperleveldb/ripple_hyperleveldb.cpp',
'modules/ripple_json/ripple_json.cpp',
'modules/ripple_leveldb/ripple_leveldb.cpp',
'modules/ripple_mdb/ripple_mdb.c',
'modules/ripple_net/ripple_net.cpp',
'modules/ripple_websocket/ripple_websocket.cpp'
'src/ripple/common/ripple_common.cpp',
'src/ripple/http/ripple_http.cpp',
'src/ripple/json/ripple_json.cpp',
'src/ripple/peerfinder/ripple_peerfinder.cpp',
'src/ripple/resource/ripple_resource.cpp',
'src/ripple/rocksdb/ripple_rocksdb.cpp',
'src/ripple/rpc/ripple_rpc.cpp',
'src/ripple/sitefiles/ripple_sitefiles.cpp',
'src/ripple/sslutil/ripple_sslutil.cpp',
'src/ripple/testoverlay/ripple_testoverlay.cpp',
'src/ripple/types/ripple_types.cpp',
'src/ripple/validators/ripple_validators.cpp'
])
# ------------------------------
# Old-style Ripple unity sources
#
COMPILED_FILES.extend([
'src/ripple_app/ripple_app.cpp',
'src/ripple_app/ripple_app_pt1.cpp',
'src/ripple_app/ripple_app_pt2.cpp',
'src/ripple_app/ripple_app_pt3.cpp',
'src/ripple_app/ripple_app_pt4.cpp',
'src/ripple_app/ripple_app_pt5.cpp',
'src/ripple_app/ripple_app_pt6.cpp',
'src/ripple_app/ripple_app_pt7.cpp',
'src/ripple_app/ripple_app_pt8.cpp',
'src/ripple_basics/ripple_basics.cpp',
'src/ripple_core/ripple_core.cpp',
'src/ripple_data/ripple_data.cpp',
'src/ripple_hyperleveldb/ripple_hyperleveldb.cpp',
'src/ripple_leveldb/ripple_leveldb.cpp',
'src/ripple_net/ripple_net.cpp',
'src/ripple_websocket/ripple_websocket.cpp'
])
#
#
#-------------------------------------------------------------------------------
# Map top level source directories to their location in the outputs
#
VariantDir('build/obj/src', 'src', duplicate=0)
VariantDir('build/obj/modules', 'modules', duplicate=0)
VariantDir('build/obj/Subtrees', 'Subtrees', duplicate=0)
#-------------------------------------------------------------------------------
@@ -207,18 +248,29 @@ if not OSX:
'-rdynamic', '-pthread',
])
DEBUGFLAGS = ['-g', '-DDEBUG']
DEBUGFLAGS = ['-g', '-DDEBUG', '-D_DEBUG']
env.Append(CCFLAGS = ['-pthread', '-Wall', '-Wno-sign-compare', '-Wno-char-subscripts']+DEBUGFLAGS)
env.Append(CXXFLAGS = ['-O0', '-pthread', '-Wno-invalid-offsetof', '-Wformat']+DEBUGFLAGS)
env.Append(CXXFLAGS = ['-O1', '-pthread', '-Wno-invalid-offsetof', '-Wformat']+DEBUGFLAGS)
# RTTI is required for Beast and CountedObject.
#
env.Append(CXXFLAGS = ['-frtti'])
if (int(GCC_VERSION[0]) > 4 or (int(GCC_VERSION[0]) == 4 and int(GCC_VERSION[1]) >= 7)):
env.Append(CXXFLAGS = ['-std=c++11'])
UBUNTU_GCC_48_INSTALL_STEPS = '''
https://ripple.com/wiki/Ubuntu_build_instructions#Ubuntu_versions_older_than_13.10_:_Install_gcc_4.8'''
if not USING_CLANG:
if (int(GCC_VERSION[0]) == 4 and int(GCC_VERSION[1]) < 7):
print "\nrippled, using c++11, requires g++ version >= 4.8 to compile"
if Ubuntu:
print UBUNTU_GCC_48_INSTALL_STEPS
sys.exit(1)
else:
env.Append(CXXFLAGS = ['-std=c++11'])
# FreeBSD doesn't support O_DSYNC
if FreeBSD:
@@ -228,7 +280,7 @@ if OSX:
env.Append(LINKFLAGS = ['-L/usr/local/opt/openssl/lib'])
env.Append(CXXFLAGS = ['-I/usr/local/opt/openssl/include'])
PROTO_SRCS = env.Protoc([], 'modules/ripple_data/protocol/ripple.proto', PROTOCOUTDIR='build/proto', PROTOCPYTHONOUTDIR=None)
PROTO_SRCS = env.Protoc([], 'src/ripple_data/protocol/ripple.proto', PROTOCOUTDIR='build/proto', PROTOCPYTHONOUTDIR=None)
env.Clean(PROTO_SRCS, 'site_scons/site_tools/protoc.pyc')
# Only tag actual Ripple files.

View File

@@ -1,72 +0,0 @@
# Subtrees
These directories come from entire outside repositories
brought in using git-subtree.
About git-subtree:
https://github.com/apenwarr/git-subtree <br>
http://blogs.atlassian.com/2013/05/alternatives-to-git-submodule-git-subtree/ <br>
## LevelDB
Ripple's fork of LevelDB is shared by the Bitcoin reference client project.
Repository <br>
```
git@github.com:ripple/LevelDB.git
```
Branch
```
ripple-fork
```
## LightningDB (a.k.a. MDB)
A supposedly fast memory-mapped key value database system
Repository <br>
```
git://gitorious.org/mdb/mdb.git
```
Branch
```
mdb.master
```
## websocket
Ripple's fork of websocketpp has some incompatible changes and Ripple specific includes.
Repository
```
git@github.com:ripple/websocketpp.git
```
Branch
```
ripple-fork
```
## protobuf
Ripple's fork of protobuf doesn't have any actual changes, but since the upstream
repository uses SVN, we have created a Git version to use with the git-subtree command.
Repository
```
git@github.com:ripple/protobuf.git
```
Branch
```
master
```
**NOTE** Linux builds use the protobuf installed in /usr/lib. This will be
fixed in a future revision.
## SQLite
Not technically a subtree but included here because it is a direct
copy of the official SQLite distributions available here:
http://sqlite.org/download.html

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -1,103 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_BUFFERTYPE_H_INCLUDED
#define BEAST_BUFFERTYPE_H_INCLUDED
/** Storage for a BufferSequence.
Meets these requirements:
BufferSequence
ConstBufferSequence (when Buffer is mutable_buffer)
MutableBufferSequence (when Buffer is const_buffer)
*/
template <class Buffer>
class BufferType
{
public:
typedef Buffer value_type;
typedef typename std::vector <Buffer>::const_iterator const_iterator;
BufferType ()
: m_size (0)
{
}
template <class OtherBuffers>
explicit BufferType (OtherBuffers const& buffers)
: m_size (0)
{
m_buffers.reserve (std::distance (buffers.begin (), buffers.end ()));
BOOST_FOREACH (typename OtherBuffers::value_type buffer, buffers)
{
m_size += boost::asio::buffer_size (buffer);
m_buffers.push_back (buffer);
}
}
/** Determine the total size of all buffers.
This is faster than calling boost::asio::buffer_size.
*/
std::size_t size () const noexcept
{
return m_size;
}
const_iterator begin () const noexcept
{
return m_buffers.begin ();
}
const_iterator end () const noexcept
{
return m_buffers.end ();
}
/** Retrieve a consumed BufferSequence. */
BufferType consumed (std::size_t bytes) const
{
BufferType result;
result.m_buffers.reserve (m_buffers.size ());
BOOST_FOREACH (Buffer buffer, m_buffers)
{
std::size_t const have = boost::asio::buffer_size (buffer);
std::size_t const reduce = std::min (bytes, have);
bytes -= reduce;
if (have > reduce)
result.m_buffers.push_back (buffer + reduce);
}
return result;
}
private:
std::size_t m_size;
std::vector <Buffer> m_buffers;
};
typedef boost::asio::const_buffer ConstBuffer;
typedef boost::asio::mutable_buffer MutableBuffer;
/** Meets the requirements of ConstBufferSequence */
typedef BufferType <ConstBuffer> ConstBuffers;
/** Meets the requirements of MutableBufferSequence */
typedef BufferType <MutableBuffer> MutableBuffers;
#endif

View File

@@ -1,75 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_COMPLETIONCALL_H_INCLUDED
#define BEAST_COMPLETIONCALL_H_INCLUDED
// Meets these requirements:
//
// CompletionHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/CompletionHandler.html
//
class CompletionCall
{
public:
typedef void result_type;
template <class Handler>
CompletionCall (BOOST_ASIO_MOVE_ARG(Handler) handler)
: m_call (new CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler)))
{
}
CompletionCall (CompletionCall const& other)
: m_call (other.m_call)
{
}
void operator() ()
{
(*m_call) ();
}
private:
struct Call : SharedObject, LeakChecked <Call>
{
virtual void operator() () = 0;
};
template <class Handler>
struct CallType : Call
{
CallType (BOOST_ASIO_MOVE_ARG(Handler) handler)
: m_handler (handler)
{
}
void operator() ()
{
m_handler ();
}
Handler m_handler;
};
private:
SharedObjectPtr <Call> m_call;
};
#endif

View File

@@ -1,84 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ERRORCALL_H_INCLUDED
#define BEAST_ERRORCALL_H_INCLUDED
// Meets these requirements:
//
// AcceptHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/AcceptHandler.html
//
// ConnectHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ConnectHandler.html
//
// ShutdownHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ShutdownHandler.html
//
// HandshakeHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/HandshakeHandler.html
//
class ErrorCall
{
public:
typedef void result_type;
template <class Handler>
ErrorCall (BOOST_ASIO_MOVE_ARG(Handler) handler)
: m_call (new CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler)))
{
}
ErrorCall (ErrorCall const& other)
: m_call (other.m_call)
{
}
void operator() (boost::system::error_code const& ec)
{
(*m_call) (ec);
}
private:
struct Call : SharedObject, LeakChecked <Call>
{
virtual void operator() (boost::system::error_code const&) = 0;
};
template <class Handler>
struct CallType : Call
{
CallType (BOOST_ASIO_MOVE_ARG(Handler) handler)
: m_handler (handler)
{
}
void operator() (boost::system::error_code const& ec)
{
m_handler (ec);
}
Handler m_handler;
};
private:
SharedObjectPtr <Call> m_call;
};
#endif

View File

@@ -1,81 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_TRANSFERCALL_H_INCLUDED
#define BEAST_TRANSFERCALL_H_INCLUDED
// Meets these requirements
//
// ReadHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ReadHandler.html
//
// WriteHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/WriteHandler.html
//
// BUfferedHandshakeHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/BufferedHandshakeHandler.html
//
class TransferCall
{
public:
typedef void result_type;
template <class Handler>
TransferCall (BOOST_ASIO_MOVE_ARG(Handler) handler)
: m_call (new CallType <Handler> (BOOST_ASIO_MOVE_CAST(Handler)(handler)))
{
}
TransferCall (TransferCall const& other)
: m_call (other.m_call)
{
}
void operator() (boost::system::error_code const& ec, std::size_t bytes_transferred)
{
(*m_call) (ec, bytes_transferred);
}
private:
struct Call : SharedObject, LeakChecked <Call>
{
virtual void operator() (boost::system::error_code const&, std::size_t) = 0;
};
template <class Handler>
struct CallType : Call
{
CallType (BOOST_ASIO_MOVE_ARG(Handler) handler)
: m_handler (handler)
{
}
void operator() (boost::system::error_code const& ec, std::size_t bytes_transferred)
{
m_handler (ec, bytes_transferred);
}
Handler m_handler;
};
private:
SharedObjectPtr <Call> m_call;
};
#endif

View File

@@ -1,85 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_H_INCLUDED
#define BEAST_ASIO_H_INCLUDED
//------------------------------------------------------------------------------
/* If you fail to make sure that all your compile units are building Beast with
the same set of option flags, then there's a risk that different compile
units will treat the classes as having different memory layouts, leading to
very nasty memory corruption errors when they all get linked together.
That's why it's best to always include the BeastConfig.h file before any
beast headers.
*/
#ifndef BEAST_BEASTCONFIG_H_INCLUDED
# ifdef _MSC_VER
# pragma message ("Have you included your BeastConfig.h file before including the Beast headers?")
# else
# warning "Have you included your BeastConfig.h file before including the Beast headers?"
# endif
#endif
// Must come before boost includes to fix the bost placeholders.
#include "../beast_core/beast_core.h"
/* This module requires boost and possibly OpenSSL */
#include "system/beast_BoostIncludes.h"
namespace beast
{
// Order matters
#include "basics/beast_PeerRole.h"
#include "basics/beast_BufferType.h"
#include "basics/beast_CompletionCall.h"
#include "basics/beast_ErrorCall.h"
#include "basics/beast_TransferCall.h"
#include "sockets/beast_SocketBase.h"
#include "sockets/beast_Socket.h"
#include "sockets/beast_SocketInterface.h"
#include "sockets/beast_SocketWrapperBasics.h"
#include "sockets/beast_SocketWrapper.h"
#include "sockets/beast_SharedSocket.h"
#include "sockets/beast_SslContext.h"
#include "protocol/beast_ProxyHandshake.h"
#include "protocol/beast_HandshakeDetectorType.h"
#include "protocol/beast_StreamHandshakeDetectorType.h"
#include "tests/beast_TestPeerBasics.h"
#include "tests/beast_TestPeer.h"
#include "tests/beast_TestPeerDetails.h"
#include "tests/beast_TestPeerLogic.h"
#include "tests/beast_TestPeerLogicSyncServer.h"
#include "tests/beast_TestPeerLogicSyncClient.h"
#include "tests/beast_TestPeerLogicProxyClient.h"
#include "tests/beast_TestPeerLogicAsyncServer.h"
#include "tests/beast_TestPeerLogicAsyncClient.h"
#include "tests/beast_TestPeerType.h"
#include "tests/beast_TestPeerDetailsTcp.h"
#include "tests/beast_PeerTest.h"
}
#endif

View File

@@ -1,344 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_HANDSHAKEDETECTORTYPE_H_INCLUDED
#define BEAST_HANDSHAKEDETECTORTYPE_H_INCLUDED
class DetectPolicy
{
public:
DetectPolicy ()
: m_finished (false)
, m_success (false)
{
}
/** Returns the minimum number of bytes we need to succeed.
*/
virtual std::size_t needed () = 0;
/** Returns true if the return value of success() is valid.
*/
bool finished () const noexcept
{
return m_finished;
}
/** Returns true if the buffers matched the Handshake
*/
bool success () const noexcept
{
bassert (m_finished);
return m_success;
}
protected:
void conclude (bool success = true)
{
m_finished = true;
m_success = success;
}
void fail ()
{
conclude (false);
}
//--------------------------------------------------------------------------
/** Represents a small, fixed size buffer.
This provides a convenient interface for doing a bytewise
verification/reject test on a handshake protocol.
*/
template <int Bytes>
struct Input
{
template <typename ConstBufferSequence>
explicit Input (ConstBufferSequence const& buffer)
: m_buffer (boost::asio::buffer (m_storage))
, m_size (boost::asio::buffer_copy (m_buffer, buffer))
, m_data (boost::asio::buffer_cast <uint8 const*> (m_buffer))
{
}
#if 0
uint8 const* data () const noexcept
{
return m_data;
}
#endif
uint8 operator[] (std::size_t index) const noexcept
{
bassert (index >= 0 && index < m_size);
return m_data [index];
}
bool peek (std::size_t bytes) const noexcept
{
if (m_size >= bytes)
return true;
return false;
}
template <typename T>
bool peek (T* t) noexcept
{
std::size_t const bytes = sizeof (T);
if (m_size >= bytes)
{
std::copy (m_data, m_data + bytes, t);
return true;
}
return false;
}
bool consume (std::size_t bytes) noexcept
{
if (m_size >= bytes)
{
m_data += bytes;
m_size -= bytes;
return true;
}
return false;
}
template <typename T>
bool read (T* t) noexcept
{
std::size_t const bytes = sizeof (T);
if (m_size >= bytes)
{
//this causes a stack corruption.
//std::copy (m_data, m_data + bytes, t);
memcpy (t, m_data, bytes);
m_data += bytes;
m_size -= bytes;
return true;
}
return false;
}
// Reads an integraltype in network byte order
template <typename IntegerType>
bool readNetworkInteger (IntegerType* value)
{
// Must be an integral type!
// not available in all versions of std:: unfortunately
//static_bassert (std::is_integral <IntegerType>::value);
IntegerType networkValue;
if (! read (&networkValue))
return false;
*value = fromNetworkByteOrder (networkValue);
return true;
}
private:
boost::array <uint8, Bytes> m_storage;
MutableBuffer m_buffer;
std::size_t m_size;
uint8 const* m_data;
};
private:
bool m_finished;
bool m_success;
};
// Handshake for SSL 2
//
// http://tools.ietf.org/html/rfc5246#appendix-E.2
//
// uint8 V2CipherSpec[3];
// struct {
// uint16 msg_length;
// uint8 msg_type;
// Version version; Should be 'ProtocolVersion'?
// uint16 cipher_spec_length;
// uint16 session_id_length;
// uint16 challenge_length;
// ...
//
class SSL2 : public DetectPolicy
{
public:
typedef int arg_type;
explicit SSL2 (arg_type const&)
{
}
enum
{
bytesNeeded = 3
};
std::size_t needed ()
{
return bytesNeeded;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
Input <bytesNeeded> in (buffer);
{
uint8 byte;
if (! in.peek (&byte))
return;
// First byte must have the high bit set
//
if((byte & 0x80) != 0x80)
return fail ();
}
// The remaining bits contain the
// length of the following data in bytes.
//
uint16 msg_length;
if (! in.readNetworkInteger(&msg_length))
return;
// sizeof (msg_type +
// Version (ProtcolVersion?) +
// cipher_spec_length +
// session_id_length +
// challenge_length)
//
// Should be 9 or greater.
//
if (msg_length < 9)
return fail ();
uint8 msg_type;
if (! in.read (&msg_type))
return;
// The msg_type must be 0x01 for a version 2 ClientHello
//
if (msg_type != 0x01)
return fail ();
conclude ();
}
};
// Handshake for SSL 3 (Also TLS 1.0 and 1.1)
//
// http://www.ietf.org/rfc/rfc2246.txt
//
// Section 7.4. Handshake protocol
//
class SSL3 : public DetectPolicy
{
public:
typedef int arg_type; // dummy
explicit SSL3 (arg_type const&)
{
}
enum
{
bytesNeeded = 6
};
std::size_t needed ()
{
return bytesNeeded;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
uint16 version;
Input <bytesNeeded> in (buffer);
uint8 msg_type;
if (! in.read (&msg_type))
return;
// msg_type must be 0x16 = "SSL Handshake"
//
if (msg_type != 0x16)
return fail ();
if (! in.read (&version))
return;
version = fromNetworkByteOrder (version);
uint16 length;
if (! in.read (&length))
return;
length = fromNetworkByteOrder (length);
conclude ();
}
};
//--------------------------------------------------------------------------
template <typename Logic>
class HandshakeDetectorType
{
public:
typedef typename Logic::arg_type arg_type;
explicit HandshakeDetectorType (arg_type const& arg = arg_type ())
: m_logic (arg)
{
}
std::size_t needed () noexcept
{
return m_logic.needed ();
}
bool finished () noexcept
{
return m_logic.finished ();
}
/** If finished is true, this tells us if the handshake was detected.
*/
bool success () noexcept
{
return m_logic.success ();
}
/** Analyze the buffer to match the Handshake.
Returns `true` if the analysis is complete.
*/
template <typename ConstBufferSequence>
bool analyze (ConstBufferSequence const& buffer)
{
bassert (! m_logic.finished ());
m_logic.analyze (buffer);
return m_logic.finished ();
}
private:
Logic m_logic;
};
#endif

View File

@@ -1,384 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
ProxyHandshake::ProxyHandshake (bool expectHandshake)
: m_status (expectHandshake ? statusHandshake : statusNone)
, m_gotCR (false)
{
m_buffer.preallocateBytes (maxVersion1Bytes);
}
ProxyHandshake::~ProxyHandshake ()
{
}
std::size_t ProxyHandshake::feed (void const* inputBuffer, size_t inputBytes)
{
std::size_t bytesConsumed = 0;
char const* p = static_cast <char const*> (inputBuffer);
if (m_status == statusHandshake)
{
if (! m_gotCR)
{
while (inputBytes > 0 && m_buffer.length () < maxVersion1Bytes - 1)
{
beast_wchar c = *p++;
++bytesConsumed;
--inputBytes;
m_buffer += c;
if (c == '\r')
{
m_gotCR = true;
break;
}
else if (c == '\n')
{
m_status = statusFailed;
}
}
if (m_buffer.length () > maxVersion1Bytes - 1)
{
m_status = statusFailed;
}
}
}
if (m_status == statusHandshake)
{
if (inputBytes > 0 && m_gotCR)
{
bassert (m_buffer.length () < maxVersion1Bytes);
char const lf ('\n');
if (*p == lf)
{
++bytesConsumed;
--inputBytes;
m_buffer += lf;
parseLine ();
}
else
{
m_status = statusFailed;
}
}
}
return bytesConsumed;
}
void ProxyHandshake::parseLine ()
{
Version1 p;
bool success = p.parse (m_buffer.getCharPointer (), m_buffer.length ());
if (success)
{
m_endpoints = p.endpoints;
m_status = statusOk;
}
else
{
m_status = statusFailed;
}
}
int ProxyHandshake::indexOfFirstNonNumber (String const& input)
{
bassert (input.length () > 0);
int i = 0;
for (; i < input.length (); ++i)
{
if (! CharacterFunctions::isDigit (input [i]))
break;
}
return i;
}
bool ProxyHandshake::chop (String const& what, String& input)
{
if (input.startsWith (what))
{
input = input.substring (what.length ());
return true;
}
return false;
}
bool ProxyHandshake::chopUInt (int* value, int limit, String& input)
{
if (input.length () <= 0)
return false;
String const s = input.substring (0, indexOfFirstNonNumber (input));
if (s.length () <= 0)
return false;
int const n = s.getIntValue ();
// Leading zeroes disallowed as per spec, to prevent confusion with octal
if (String (n) != s)
return false;
if (n < 0 || n > limit)
return false;
input = input.substring (s.length ());
*value = n;
return true;
}
//------------------------------------------------------------------------------
/*
steps:
Proxy protocol lets us filter attackers by learning the source ip and port
1. Determine if we should use the proxy on a connection
- Port just for proxy protocol connections
- Filter on source IPs
2. Read a line from the connection to get the proxy information
3. Parse the line (human or binary?)
4. Code Interface to retrieve proxy information (ip/port) on connection
*/
ProxyHandshake::Version1::Version1 ()
{
}
bool ProxyHandshake::IPv4::Addr::chop (String& input)
{
if (!ProxyHandshake::chopUInt (&a, 255, input))
return false;
if (!ProxyHandshake::chop (".", input))
return false;
if (!ProxyHandshake::chopUInt (&b, 255, input))
return false;
if (!ProxyHandshake::chop (".", input))
return false;
if (!ProxyHandshake::chopUInt (&c, 255, input))
return false;
if (!ProxyHandshake::chop (".", input))
return false;
if (!ProxyHandshake::chopUInt (&d, 255, input))
return false;
return true;
}
bool ProxyHandshake::Version1::parse (void const* headerData, size_t headerBytes)
{
String input (static_cast <CharPointer_UTF8::CharType const*> (headerData), headerBytes);
if (input.length () < 2)
return false;
if (! input.endsWith ("\r\n"))
return false;
input = input.dropLastCharacters (2);
if (! ProxyHandshake::chop ("PROXY ", input))
return false;
if (ProxyHandshake::chop ("UNKNOWN", input))
{
endpoints.proto = protoUnknown;
input = "";
}
else
{
if (ProxyHandshake::chop ("TCP4 ", input))
{
endpoints.proto = protoTcp4;
if (! endpoints.ipv4.sourceAddr.chop (input))
return false;
if (! ProxyHandshake::chop (" ", input))
return false;
if (! endpoints.ipv4.destAddr.chop (input))
return false;
if (! ProxyHandshake::chop (" ", input))
return false;
if (! ProxyHandshake::chopUInt (&endpoints.ipv4.sourcePort, 65535, input))
return false;
if (! ProxyHandshake::chop (" ", input))
return false;
if (! ProxyHandshake::chopUInt (&endpoints.ipv4.destPort, 65535, input))
return false;
}
else if (ProxyHandshake::chop ("TCP6 ", input))
{
endpoints.proto = protoTcp6;
//bassertfalse;
return false;
}
else
{
return false;
}
}
// Can't have anything extra between the last port number and the CRLF
if (input.length () > 0)
return false;
return true;
}
//------------------------------------------------------------------------------
class ProxyHandshakeTests : public UnitTest
{
public:
ProxyHandshakeTests () : UnitTest ("ProxyHandshake", "beast")
{
}
static std::string goodIpv4 ()
{
return "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; // 56 chars
}
static std::string goodIpv6 ()
{
return "PROXY TCP6 fffffffffffffffffffffffffffffffffffffff.fffffffffffffffffffffffffffffffffffffff 65535 65535\r\n";
//1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123 4 (104 chars)
}
static std::string goodUnknown ()
{
return "PROXY UNKNOWN\r\n";
}
static std::string goodUnknownBig ()
{
return "PROXY UNKNOWN fffffffffffffffffffffffffffffffffffffff.fffffffffffffffffffffffffffffffffffffff 65535 65535\r\n";
//1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456 7 (107 chars)
}
void testHandshake (std::string const& s, bool shouldSucceed)
{
if (s.size () > 1)
{
ProxyHandshake h (true);
expect (h.getStatus () == ProxyHandshake::statusHandshake);
for (std::size_t i = 0; i < s.size () && h.getStatus () == ProxyHandshake::statusHandshake ; ++i)
{
std::size_t const bytesConsumed = h.feed (& s[i], 1);
if (i != s.size () - 1)
expect (h.getStatus () == ProxyHandshake::statusHandshake);
expect (bytesConsumed == 1);
}
if (shouldSucceed)
{
expect (h.getStatus () == ProxyHandshake::statusOk);
}
else
{
expect (h.getStatus () == ProxyHandshake::statusFailed);
}
}
else
{
bassertfalse;
}
}
void testVersion1String (std::string const& s, bool shouldSucceed)
{
ProxyHandshake::Version1 p;
if (shouldSucceed)
{
expect (p.parse (s.c_str (), s.size ()));
}
else
{
unexpected (p.parse (s.c_str (), s.size ()));
}
for (std::size_t i = 1; i < s.size () - 1; ++i)
{
String const partial = String (s).dropLastCharacters (i);
std::string ss (partial.toStdString ());
expect (! p.parse (ss.c_str (), ss.size ()));
}
testHandshake (s, shouldSucceed);
}
void testVersion1 ()
{
beginTestCase ("version1");
testVersion1String (goodIpv4 (), true);
testVersion1String (goodIpv6 (), false);
testVersion1String (goodUnknown (), true);
testVersion1String (goodUnknownBig (), true);
}
void runTest ()
{
testVersion1 ();
}
};
static ProxyHandshakeTests proxyHandshakeTests;

View File

@@ -1,164 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_PROXYYHANDSHAKE_H_INCLUDED
#define BEAST_PROXYYHANDSHAKE_H_INCLUDED
/** PROXY protocol handshake state machine.
The PROXY Protocol:
http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
*/
class ProxyHandshake
{
public:
/** Status of the handshake state machine. */
enum Status
{
statusNone, // No handshake expected
statusHandshake, // Handshake in progress
statusFailed, // Handshake failed
statusOk, // Handshake succeeded
};
enum Proto
{
protoTcp4,
protoTcp6,
protoUnknown
};
/** PROXY information for IPv4 families. */
struct IPv4
{
struct Addr
{
int a;
int b;
int c;
int d;
bool chop (String& input);
};
Addr sourceAddr;
Addr destAddr;
int sourcePort;
int destPort;
};
/** PROXY information for IPv6 families. */
struct IPv6
{
struct Addr
{
int a;
int b;
int c;
int d;
};
Addr sourceAddr;
Addr destAddr;
int sourcePort;
int destPort;
};
/** Fully decoded PROXY information. */
struct Endpoints
{
Endpoints ()
: proto (protoUnknown)
{
}
Proto proto;
IPv4 ipv4; // valid if proto == protoTcp4
IPv6 ipv6; // valid if proto == protoTcp6;
};
//--------------------------------------------------------------------------
/** Parser for PROXY version 1. */
struct Version1
{
enum
{
// Maximum input buffer size needed, including a null
// terminator, as per the PROXY protocol specification.
maxBufferBytes = 108
};
Endpoints endpoints;
Version1 ();
/** Parse the header.
@param rawHeader a pointer to the header data
@return `true` If it was parsed successfully.
*/
bool parse (void const* headerData, size_t headerBytes);
};
//--------------------------------------------------------------------------
/** Create the handshake state.
If a handshake is expected, then it is required.
@param wantHandshake `false` to skip handshaking.
*/
explicit ProxyHandshake (bool expectHandshake = false);
~ProxyHandshake ();
inline Status getStatus () const noexcept
{
return m_status;
}
inline Endpoints const& getEndpoints () const noexcept
{
return m_endpoints;
};
/** Feed the handshaking state engine.
@return The number of bytes consumed in the input buffer.
*/
std::size_t feed (void const* inputBuffer, std::size_t inputBytes);
// Utility functions used by parsers
static int indexOfFirstNonNumber (String const& input);
static bool chop (String const& what, String& input);
static bool chopUInt (int* value, int limit, String& input);
private:
void parseLine ();
private:
enum
{
maxVersion1Bytes = 107 // including crlf, not including null term
};
Status m_status;
String m_buffer;
bool m_gotCR;
Endpoints m_endpoints;
};
#endif

View File

@@ -1,78 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_STREAMHANDSHAKEDETECTORTYPE_H_INCLUDED
#define BEAST_STREAMHANDSHAKEDETECTORTYPE_H_INCLUDED
/** Wraps a HandshakeDetector and does the work on the Socket for you.
*/
template <class Detector>
class StreamHandshakeDetectorType
{
protected:
typedef boost::system::error_code error_code;
typedef StreamHandshakeDetectorType <Detector> This;
public:
typedef typename Detector::arg_type arg_type;
explicit StreamHandshakeDetectorType (arg_type const& arg = arg_type ())
{
}
template <typename HandshakeHandler>
void async_handshake (Socket& socket, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler)
{
#if 0
std::size_t const bytes = m_detector.needed ();
#if 1
boost::asio::async_read (socket, m_buffer.prepare (bytes), boost::bind (
&This::on_read <typename HandshakeHandler>, this, &socket,
handler,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
#else
boost::asio::async_read (socket, m_buffer.prepare (bytes), boost::bind (
&This::on_read2, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
#endif
#endif
}
protected:
template <typename HandshakeHandler>
void on_read (Socket* socket, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler,
error_code const& ec, std::size_t bytes_transferred)
{
m_buffer.commit (bytes_transferred);
if (m_detector.analyze (m_buffer.data ()))
{
if (m_detector.success ())
{
//socket->async_handshake (Socket::server, m_buffer.data (), handler);
}
}
}
private:
Detector m_detector;
boost::asio::streambuf m_buffer;
};
#endif

View File

@@ -1,83 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SHAREDSOCKET_H_INCLUDED
#define BEAST_SHAREDSOCKET_H_INCLUDED
/** A Socket interface with reference counting.
You can keep a pointer to the base class so that you don't have
to see the template or underlying object implementation.
@see SharedSocketTYpe, SharedObjectPtr
*/
/** @{ */
class SharedSocket
: public SharedObject
, public virtual Socket
{
public:
/** Store your SharedSocket in one of these! */
typedef SharedObjectPtr <SharedSocket> Ptr;
};
//------------------------------------------------------------------------------
/** A RAII container for wrapping an object as a Socket.
To use this, construct the class with an instance of your object
created with operator new. The constructor will take ownership,
and delete it when the last reference is removed. For example:
@code
boost::asio::io_service ios;
boost::asio::ssl:context ctx;
SharedSocket::Ptr mySocket (
new (boost::asio::ssl::stream (ios, ctx)));
mySocket->handshake ();
@endcode
@see SharedSocket
*/
template <class Object>
class SharedSocketType
: public SharedSocket
, public SocketWrapper <Object>
{
public:
/** Create the shared socket.
This takes posession of the object, which will be deleted
when the last reference goes away.
*/
SharedSocketType (Object* object)
: SocketWrapper <Object> (object)
, m_object (object)
{
}
private:
ScopedPointer <Object> m_object;
};
/** @} */
#endif

View File

@@ -1,277 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
Socket::~Socket ()
{
}
//-----------------------------------------------------------------------------
//
// basic_io_object
//
boost::asio::io_service& Socket::get_io_service ()
{
pure_virtual ();
return *static_cast <boost::asio::io_service*>(nullptr);
}
//-----------------------------------------------------------------------------
//
// basic_socket
//
void* Socket::lowest_layer (char const*) const
{
pure_virtual ();
return nullptr;
}
void* Socket::native_handle (char const*) const
{
pure_virtual ();
return nullptr;
}
boost::system::error_code Socket::cancel (boost::system::error_code& ec)
{
return pure_virtual (ec);
}
boost::system::error_code Socket::shutdown (shutdown_type, boost::system::error_code& ec)
{
return pure_virtual (ec);
}
boost::system::error_code Socket::close (boost::system::error_code& ec)
{
return pure_virtual (ec);
}
//------------------------------------------------------------------------------
//
// basic_socket_acceptor
//
boost::system::error_code Socket::accept (Socket&, boost::system::error_code& ec)
{
return pure_virtual (ec);
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
Socket::async_accept (Socket&, BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
ErrorCall, void (boost::system::error_code)> init(
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
return init.result.get();
#else
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
#endif
}
//------------------------------------------------------------------------------
//
// basic_stream_socket
//
std::size_t Socket::read_some (MutableBuffers const&, boost::system::error_code& ec)
{
pure_virtual (ec);
return 0;
}
std::size_t Socket::write_some (ConstBuffers const&, boost::system::error_code& ec)
{
pure_virtual (ec);
return 0;
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
Socket::async_read_some (MutableBuffers const&, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
TransferCall, void (boost::system::error_code, std::size_t)> init(
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
return init.result.get();
#else
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
#endif
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
Socket::async_write_some (ConstBuffers const&, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
TransferCall, void (boost::system::error_code, std::size_t)> init(
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
return init.result.get();
#else
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
#endif
}
//--------------------------------------------------------------------------
//
// ssl::stream
//
bool Socket::requires_handshake ()
{
return false;
}
boost::system::error_code Socket::handshake (handshake_type, boost::system::error_code& ec)
{
return pure_virtual (ec);
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
Socket::async_handshake (handshake_type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
ErrorCall, void (boost::system::error_code)> init(
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
return init.result.get();
#else
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
#endif
}
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
boost::system::error_code Socket::handshake (handshake_type,
ConstBuffers const&, boost::system::error_code& ec)
{
return pure_virtual (ec);
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
Socket::async_handshake (handshake_type, ConstBuffers const&,
BOOST_ASIO_MOVE_ARG(TransferCall) handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
TransferCall, void (boost::system::error_code, std::size_t)> init(
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
return init.result.get();
#else
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
#endif
}
#endif
boost::system::error_code Socket::shutdown (boost::system::error_code& ec)
{
return pure_virtual (ec);
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
Socket::async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
ErrorCall, void (boost::system::error_code, std::size_t)> init(
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
return init.result.get();
#else
boost::system::error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
#endif
}
//------------------------------------------------------------------------------
/* members, and the most common base class in which they appear:
basic_io_object
io_service& get_io_service ()
basic_socket <Protocol> : basic_io_object
typedef protocol_type
typedef lowest_layer_type
lowest_layer_type& lowest_layer ()
lowest_layer_type const& lowest_layer () const
native_handle ()
cancel ()
shutdon (shutdown_type)
close ()
<various>
basic_socket_acceptor <Protocol> : basic_io_object
typedef protocol_type
native_handle ()
listen ()
accept ()
async_accept ()
cancel ()
close ()
basic_stream_socket <Protocol> : basic_socket <Protocol>
ssl::stream
handshake ()
async_handshake ()
shutdown ()
*/

View File

@@ -1,62 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SOCKETINTERFACE_H_INCLUDED
#define BEAST_SOCKETINTERFACE_H_INCLUDED
/** These define the interfaces that SocketWrapper can adapt with SFINAE. */
struct SocketInterface
{
// has close()
struct Close { };
/** Tag for some compatibility with boost::asio::basic_socket_acceptor
http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/basic_socket_acceptor.html
*/
struct Acceptor : Close { };
// Has lowest_layer() and lowest_layer_type
struct LowestLayer { };
/** Tag for parts of boost::asio::basic_socket
http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/basic_socket.html
*/
struct Socket : Close, LowestLayer { };
/** Tag for parts of boost::asio::basic_stream_socket
http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/basic_stream_socket.html
*/
struct SyncStream { };
struct AsyncStream { };
struct Stream : SyncStream, AsyncStream { };
/** Tags for parts of boost::asio::ssl::stream
http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream.html
*/
struct AnyHandshake { };
struct SyncHandshake : AnyHandshake { };
struct AsyncHandshake : AnyHandshake { };
struct BufferedSyncHandshake : AnyHandshake { };
struct BufferedAsyncHandshake : AnyHandshake { };
struct Handshake : SyncHandshake, AsyncHandshake,
BufferedSyncHandshake, BufferedAsyncHandshake,
LowestLayer { };
};
#endif

View File

@@ -1,729 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SOCKETWRAPPER_H_INCLUDED
#define BEAST_SOCKETWRAPPER_H_INCLUDED
/** Wraps a reference to any object and exports all availble interfaces.
If the object does not support an interface, calling those
member functions will behave as if a pure virtual was called.
Note that only a reference to the underlying is stored. Management
of the lifetime of the object is controlled by the caller.
Examples of the type of WrappedObject:
asio::ip::tcp::socket
arg must be an io_context
SocketWrapper will create and take ownership of the tcp::socket
WrappedObjectType will be tcp::socket
next_layer () returns a asio::ip::tcp::socket&
lowest_layer () returns a asio::ip::tcp::socket&
asio::ip::tcp::socket&
arg must be an existing socket&
The caller owns the underlying socket object
WrappedObjectType will be tcp::socket
next_layer () returns a asio::ip::tcp::socket&
lowest_layer () returns a asio::ip::tcp::socket&
asio::ssl::stream <asio::ip::tcp::socket>
arg must be an io_context
SocketWrapper creates and takes ownership of the ssl::stream
WrappedObjecType will be asio::ssl::stream <asio::ip::tcp::socket>
next_layer () returns a asio::ip::tcp::socket&
lowest_layer () returns a asio::ip::tcp::socket&
asio::ssl::stream <asio::ip::tcp::socket&>
arg must be an existing socket&
The caller owns the socket, but SocketWrapper owns the ssl::stream
WrappedObjectType will be asio::ssl::stream <asio::ip::tcp::socket&>
next_layer () returns a asio::ip::tcp::socket&
lowest_layer () returns a asio::ip::tcp::socket&
asio::ssl::stream <asio::buffered_stream <asio::ip::tcp::socket> > >
This makes my head explode
*/
//------------------------------------------------------------------------------
namespace SocketWrapperMemberChecks
{
template <bool Enable>
struct EnableIf : boost::false_type { };
template <>
struct EnableIf <true> : boost::true_type { };
BEAST_DEFINE_IS_CALL_POSSIBLE(has_get_io_service, get_io_service);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_lowest_layer, lowest_layer);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_cancel, cancel);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_shutdown, shutdown);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_close, close);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_accept, accept);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_accept, async_accept);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_read_some, read_some);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_write_some, write_some);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_read_some, async_read_some);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_write_some, async_write_some);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_handshake, handshake);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_handshake, async_handshake);
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_shutdown, async_shutdown);
// Extracts the underlying socket type from the protocol of another asio object
template <typename T, typename Enable = void>
struct native_socket
{
typedef void* socket_type;
inline native_socket (Socket&) : m_socket (nullptr) { SocketBase::pure_virtual (); }
inline socket_type& get () { SocketBase::pure_virtual (); return m_socket; }
inline socket_type& operator-> () { return get (); }
private:
socket_type m_socket;
};
// Enabled if T::protocol_type::socket exists as a type
template <typename T>
struct native_socket <T, typename boost::enable_if <boost::is_class <
typename T::protocol_type::socket> >::type>
{
typedef typename T::protocol_type::socket socket_type;
inline native_socket (Socket& peer) : m_socket_ptr (&peer.native_handle <socket_type> ()) { }
inline socket_type& get () noexcept { return *m_socket_ptr; }
inline socket_type& operator-> () noexcept { return get (); }
private:
socket_type* m_socket_ptr;
};
};
template <typename WrappedObject>
class SocketWrapper
: public virtual Socket
, public SocketWrapperBasics
, public Uncopyable
{
private:
typedef typename boost::remove_reference <WrappedObject>::type wrapped_type;
public:
typedef typename boost::remove_reference <WrappedObject>::type WrappedObjectType;
template <typename Arg>
explicit SocketWrapper (Arg& arg)
: m_object (arg)
{
}
template <typename Arg1, typename Arg2>
SocketWrapper (Arg1& arg1, Arg2& arg2)
: m_object (arg1, arg2)
{
}
//--------------------------------------------------------------------------
//
// basic_io_object
//
boost::asio::io_service& get_io_service ()
{
using namespace SocketWrapperMemberChecks;
#if 0
// This is the one that doesn't work, (void) arg lists
return get_io_service (
EnableIf <has_get_io_service <wrapped_type,
io_service ()>::value> ());
#else
return get_io_service (boost::true_type ());
#endif
}
boost::asio::io_service& get_io_service (
boost::true_type)
{
return m_object.get_io_service ();
}
boost::asio::io_service& get_io_service (
boost::false_type)
{
pure_virtual ();
return *static_cast <boost::asio::io_service*>(nullptr);
}
//--------------------------------------------------------------------------
//
// basic_socket
//
#if 0
// This is a potential work-around for the problem with
// the has_type_lowest_layer_type template, but requires
// Boost 1.54 or later.
//
// This include will be needed:
//
// #include <boost/tti/has_type.hpp>
//
//
BOOST_TTI_HAS_TYPE(lowest_layer_type)
#endif
template <class T>
struct has_type_lowest_layer_type
{
typedef char yes;
typedef struct {char dummy[2];} no;
template <class C> static yes f(typename C::lowest_layer_type*);
template <class C> static no f(...);
#ifdef _MSC_VER
static bool const value = sizeof(f<T>(0)) == 1;
#else
// This line fails to compile under Visual Studio 2012
static bool const value = sizeof(has_type_lowest_layer_type<T>::f<T>(0)) == 1;
#endif
};
void* lowest_layer (char const* type_name) const
{
using namespace SocketWrapperMemberChecks;
return lowest_layer (type_name,
EnableIf <has_type_lowest_layer_type <wrapped_type>::value> ());
}
void* lowest_layer (char const* type_name,
boost::true_type) const
{
char const* const name (typeid (typename wrapped_type::lowest_layer_type).name ());
if (strcmp (name, type_name) == 0)
return const_cast <void*> (static_cast <void const*> (&m_object.lowest_layer ()));
return nullptr;
}
void* lowest_layer (char const*,
boost::false_type) const
{
pure_virtual ();
return nullptr;
}
//--------------------------------------------------------------------------
void* native_handle (char const* type_name) const
{
char const* const name (typeid (wrapped_type).name ());
if (strcmp (name, type_name) == 0)
return const_cast <void*> (static_cast <void const*> (&m_object));
return nullptr;
}
//--------------------------------------------------------------------------
error_code cancel (error_code& ec)
{
using namespace SocketWrapperMemberChecks;
return cancel (ec,
EnableIf <has_cancel <wrapped_type,
error_code (error_code&)>::value> ());
}
error_code cancel (error_code& ec,
boost::true_type)
{
return m_object.cancel (ec);
}
error_code cancel (error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
}
//--------------------------------------------------------------------------
error_code shutdown (shutdown_type what, error_code& ec)
{
using namespace SocketWrapperMemberChecks;
return shutdown (what, ec,
EnableIf <has_shutdown <wrapped_type,
error_code (shutdown_type, error_code&)>::value> ());
}
error_code shutdown (shutdown_type what, error_code& ec,
boost::true_type)
{
return m_object.shutdown (what, ec);
}
error_code shutdown (shutdown_type, error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
}
//--------------------------------------------------------------------------
error_code close (error_code& ec)
{
using namespace SocketWrapperMemberChecks;
return close (ec,
EnableIf <has_close <wrapped_type,
error_code (error_code&)>::value> ());
}
error_code close (error_code& ec,
boost::true_type)
{
return m_object.close (ec);
}
error_code close (error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
}
//--------------------------------------------------------------------------
//
// basic_socket_acceptor
//
error_code accept (Socket& peer, error_code& ec)
{
using namespace SocketWrapperMemberChecks;
typedef typename native_socket <wrapped_type>::socket_type socket_type;
return accept (peer, ec,
EnableIf <has_accept <wrapped_type,
error_code (socket_type&, error_code&)>::value> ());
}
error_code accept (Socket& peer, error_code& ec,
boost::true_type)
{
using namespace SocketWrapperMemberChecks;
return m_object.accept (
native_socket <wrapped_type> (peer).get (), ec);
}
error_code accept (Socket&, error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
{
using namespace SocketWrapperMemberChecks;
typedef typename native_socket <wrapped_type>::socket_type socket_type;
return async_accept (peer, BOOST_ASIO_MOVE_CAST(ErrorCall)(handler),
EnableIf <has_async_accept <wrapped_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
(socket_type&, BOOST_ASIO_MOVE_ARG(TransferCall))>::value> ());
}
template <typename AcceptHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(ErrorCall, void (error_code))
async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler,
boost::true_type)
{
using namespace SocketWrapperMemberChecks;
return m_object.async_accept (
native_socket <wrapped_type> (peer).get (),
BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler));
}
template <typename AcceptHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, void (error_code))
async_accept (Socket&, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
AcceptHandler, void (error_code)> init(
BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler));
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler), ec));
return init.result.get();
#else
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler), ec));
#endif
}
//--------------------------------------------------------------------------
//
// basic_stream_socket
//
std::size_t read_some (MutableBuffers const& buffers, error_code& ec)
{
using namespace SocketWrapperMemberChecks;
return read_some (buffers, ec,
EnableIf <has_read_some <wrapped_type,
std::size_t (MutableBuffers const&, error_code&)>::value> ());
}
template <typename MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers, error_code& ec,
boost::true_type)
{
return m_object.read_some (buffers, ec);
}
template <typename MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const&, error_code& ec,
boost::false_type)
{
pure_virtual (ec);
return 0;
}
//--------------------------------------------------------------------------
std::size_t write_some (ConstBuffers const& buffers, error_code& ec)
{
using namespace SocketWrapperMemberChecks;
return write_some (buffers, ec,
EnableIf <has_write_some <wrapped_type,
std::size_t (ConstBuffers const&, error_code&)>::value> ());
}
template <typename ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers, error_code& ec,
boost::true_type)
{
return m_object.write_some (buffers, ec);
}
template <typename ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const&, error_code& ec,
boost::false_type)
{
pure_virtual (ec);
return 0;
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
async_read_some (MutableBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
{
using namespace SocketWrapperMemberChecks;
return async_read_some (buffers, BOOST_ASIO_MOVE_CAST(TransferCall)(handler),
EnableIf <has_async_read_some <wrapped_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
(MutableBuffers const&, BOOST_ASIO_MOVE_ARG(TransferCall))>::value> ());
}
template <typename MutableBufferSequence, typename ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (error_code, std::size_t))
async_read_some (MutableBufferSequence const& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
boost::true_type)
{
return m_object.async_read_some (buffers,
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
}
template <typename MutableBufferSequence, typename ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (error_code, std::size_t))
async_read_some (MutableBufferSequence const&, BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
ReadHandler, void (error_code, std::size_t)> init(
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (BOOST_ASIO_MOVE_CAST(ReadHandler)(handler), ec, 0));
return init.result.get();
#else
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (BOOST_ASIO_MOVE_CAST(ReadHandler)(handler), ec, 0));
#endif
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
async_write_some (ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
{
using namespace SocketWrapperMemberChecks;
return async_write_some (buffers, BOOST_ASIO_MOVE_CAST(TransferCall)(handler),
EnableIf <has_async_write_some <wrapped_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
(ConstBuffers const&, BOOST_ASIO_MOVE_ARG(TransferCall))>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
async_write_some (ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler,
boost::true_type)
{
return m_object.async_write_some (buffers,
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
async_write_some (ConstBuffers const&, BOOST_ASIO_MOVE_ARG(TransferCall) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
TransferCall, void (error_code, std::size_t)> init(
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
return init.result.get();
#else
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
#endif
}
//--------------------------------------------------------------------------
//
// ssl::stream
//
bool requires_handshake ()
{
using namespace SocketWrapperMemberChecks;
return
has_handshake <wrapped_type,
error_code (handshake_type, error_code&)>::value ||
has_async_handshake <wrapped_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
(handshake_type, BOOST_ASIO_MOVE_ARG(ErrorCall))>::value;
}
//--------------------------------------------------------------------------
error_code handshake (handshake_type type, error_code& ec)
{
using namespace SocketWrapperMemberChecks;
return handshake (type, ec,
EnableIf <has_handshake <wrapped_type,
error_code (handshake_type, error_code&)>::value> ());
}
error_code handshake (handshake_type type, error_code& ec,
boost::true_type)
{
return m_object.handshake (type, ec);
}
error_code handshake (handshake_type, error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
{
using namespace SocketWrapperMemberChecks;
return async_handshake (type, BOOST_ASIO_MOVE_CAST(ErrorCall)(handler),
EnableIf <has_async_handshake <wrapped_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
(handshake_type, BOOST_ASIO_MOVE_ARG(ErrorCall))>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler,
boost::true_type)
{
return m_object.async_handshake (type,
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
async_handshake (handshake_type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
ErrorCall, void (error_code)> init(
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
return init.result.get();
#else
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
#endif
}
//--------------------------------------------------------------------------
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
error_code handshake (handshake_type type, ConstBuffers const& buffers, error_code& ec)
{
using namespace SocketWrapperMemberChecks;
return handshake (type, buffers, ec,
EnableIf <has_handshake <wrapped_type,
error_code (handshake_type, ConstBuffers const&, error_code&)>::value> ());
}
error_code handshake (handshake_type type, ConstBuffers const& buffers, error_code& ec,
boost::true_type)
{
return m_object.handshake (type, buffers, ec);
}
error_code handshake (handshake_type, ConstBuffers const&, error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
async_handshake (handshake_type type, ConstBuffers const& buffers,
BOOST_ASIO_MOVE_ARG(TransferCall) handler)
{
using namespace SocketWrapperMemberChecks;
return async_handshake (type, buffers, BOOST_ASIO_MOVE_CAST(TransferCall)(handler),
EnableIf <has_async_handshake <wrapped_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
(handshake_type, ConstBuffers const&, error_code&)>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
async_handshake (handshake_type type, ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler,
boost::true_type)
{
return m_object.async_handshake (type, buffers,
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (error_code, std::size_t))
async_handshake (handshake_type, ConstBuffers const&, BOOST_ASIO_MOVE_ARG(TransferCall) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
TransferCall, void (error_code, std::size_t)> init(
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
return init.result.get();
#else
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
#endif
}
#endif
//--------------------------------------------------------------------------
error_code shutdown (error_code& ec)
{
using namespace SocketWrapperMemberChecks;
return shutdown (ec,
EnableIf <has_shutdown <wrapped_type,
error_code (error_code&)>::value> ());
}
error_code shutdown (error_code& ec,
boost::true_type)
{
return m_object.shutdown (ec);
}
error_code shutdown (error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
}
//--------------------------------------------------------------------------
void async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
{
using namespace SocketWrapperMemberChecks;
return async_shutdown (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler),
EnableIf <has_async_shutdown <wrapped_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
(BOOST_ASIO_MOVE_ARG(ErrorCall))>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler,
boost::true_type)
{
return m_object.async_shutdown (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (error_code))
async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
ErrorCall, void (error_code, std::size_t)> init(
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
return init.result.get();
#else
error_code ec;
ec = pure_virtual (ec);
get_io_service ().post (boost::bind (
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
#endif
}
private:
WrappedObject m_object;
};
#endif

View File

@@ -1,136 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SOCKETWRAPPERBASICS_H_INCLUDED
#define BEAST_SOCKETWRAPPERBASICS_H_INCLUDED
/** Some utilities for SocketWrapper and others.
*/
class SocketWrapperBasics
{
public:
#if 0
/** Template specialization to determine available interfaces. */
template <typename Object>
struct InterfacesOf
{
/** Intrusive tag support.
To use this, add a struct called SocketInterfaces to your
class and derive it from the interfaces that you support.
For example:
@code
struct MyHandshakingStream
{
struct SocketInterfaces
: SocketInterface::Stream
, SocketInterface::Handshake
{
};
}
@endcode
*/
typedef typename Object::SocketInterfaces type;
typedef type value;
};
// Specialization for boost::asio::basic_socket_acceptor
template <typename Protocol, typename SocketService>
struct InterfacesOf <boost::asio::basic_socket_acceptor <Protocol, SocketService> >
{
struct value : SocketInterface::Acceptor { };
typedef value type;
};
// Specialization for boost::asio::basic_socket
template <typename Protocol, typename SocketService>
struct InterfacesOf <boost::asio::basic_socket <Protocol, SocketService> >
{
struct value : SocketInterface::Socket { };
typedef value type;
};
// Specialization for boost::asio::basic_stream_socket
template <typename Protocol, typename SocketService>
struct InterfacesOf <boost::asio::basic_stream_socket <Protocol, SocketService> >
{
struct value : SocketInterface::Socket, SocketInterface::Stream { };
typedef value type;
};
// Specialization for boost::asio::buffered_stream
template <typename Stream>
struct InterfacesOf <boost::asio::buffered_stream <Stream> >
{
struct value : SocketInterface::Stream { };
typedef value type;
};
// Specialization for boost::asio::buffered_read_stream
template <typename Stream>
struct InterfacesOf <boost::asio::buffered_read_stream <Stream> >
{
struct value : SocketInterface::Stream { };
typedef value type;
};
// Specialization for boost::asio::buffered_write_stream
template <typename Stream>
struct InterfacesOf <boost::asio::buffered_write_stream <Stream> >
{
struct value : SocketInterface::Stream { };
typedef value type;
};
// Specialization for boost::asio::ssl::stream
template <typename Stream>
struct InterfacesOf <boost::asio::ssl::stream <Stream> >
{
struct value : SocketInterface::Stream , SocketInterface::Handshake { };
typedef value type;
};
#if 1
// Less elegant, but works.
// Determines if Object supports the specified Interface
template <typename Object, typename Interface, class Enable = void>
struct HasInterface : boost::false_type { };
template <typename Object, typename Interface>
struct HasInterface <Object, Interface,
typename boost::enable_if <boost::is_base_of <
Interface, typename InterfacesOf <Object>::type> >::type >
: boost::true_type { };
#else
// This should work, but doesn't.
// K-ballo from #boost suggested it.
//
// Determines if Object supports the specified Interface
template <typename Object, typename Interface>
struct HasInterface : boost::is_base_of <Interface, typename InterfacesOf <Object> >
{
};
#endif
#endif
};
#endif

View File

@@ -1,65 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
/** Add this to get the @ref beast_basics module.
@file beast_basics.cpp
@ingroup beast_basics
*/
#include "BeastConfig.h"
#include "beast_basics.h"
#if BEAST_MSVC && _DEBUG
#include <crtdbg.h>
#endif
#if BEAST_MSVC
#pragma warning (push)
#pragma warning (disable: 4100) // unreferenced formal parmaeter
#pragma warning (disable: 4355) // 'this' used in base member
#endif
namespace beast
{
#include "events/beast_DeadlineTimer.cpp"
#include "events/beast_OncePerSecond.cpp"
#include "threads/beast_InterruptibleThread.cpp"
#include "threads/beast_Semaphore.cpp"
#include "memory/beast_FifoFreeStoreWithTLS.cpp"
#include "memory/beast_FifoFreeStoreWithoutTLS.cpp"
#include "memory/beast_GlobalPagedFreeStore.cpp"
#include "memory/beast_PagedFreeStore.cpp"
#include "threads/beast_CallQueue.cpp"
#include "threads/beast_Listeners.cpp"
#include "threads/beast_ManualCallQueue.cpp"
#include "threads/beast_ParallelFor.cpp"
#include "threads/beast_ReadWriteMutex.cpp"
#include "threads/beast_ThreadGroup.cpp"
#include "threads/beast_ThreadWithCallQueue.cpp"
#include "threads/beast_Workers.cpp"
}
#if BEAST_MSVC
#pragma warning (pop)
#endif

View File

@@ -1,276 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
/** Include this to get the @ref beast_basics module.
@file beast_basics.h
@ingroup beast_basics
*/
#ifndef BEAST_BASICS_H_INCLUDED
#define BEAST_BASICS_H_INCLUDED
//------------------------------------------------------------------------------
/* If you fail to make sure that all your compile units are building Beast with
the same set of option flags, then there's a risk that different compile
units will treat the classes as having different memory layouts, leading to
very nasty memory corruption errors when they all get linked together.
That's why it's best to always include the BeastConfig.h file before any
beast headers.
*/
#ifndef BEAST_BEASTCONFIG_H_INCLUDED
# ifdef _MSC_VER
# pragma message ("Have you included your BeastConfig.h file before including the Beast headers?")
# else
# warning "Have you included your BeastConfig.h file before including the Beast headers?"
# endif
#endif
//------------------------------------------------------------------------------
/**
@mainpage Beast: A C++ library for server development.
### Version 1.0
Copyright 2008, 2013 by Vinnie Falco \<vinnie.falco@gmail.com\> ([e-mail][0])
Beast is a source code collection of individual modules containing
functionality for a variety of applications, with an emphasis on building
concurrent systems. Beast incorporates parts of [JUCE][3] (Jules' Utility
Class Extensions), available from [Raw Material Software][4]. Beast has no
external dependencies
Beast is hosted on Github at [https://github.com/vinniefalco/Beast][1]
The online documentation is at [http://vinniefalco.github.com/Beast][2]
## Platforms
All platforms supported by JUCE are also supported by Beast. Currently these
platforms include:
- **Windows**: Applications and VST/RTAS/NPAPI/ActiveX plugins can be built
using MS Visual Studio. The results are all fully compatible with Windows
XP, Vista or Windows 7.
- **Mac OS X**: Applications and VST/AudioUnit/RTAS/NPAPI plugins with Xcode.
- **GNU/Linux**: Applications and plugins can be built for any kernel 2.6 or
later.
- **FreeBSD**: Kernel version 8.4 or higher required.
- **iOS**: Native iPhone and iPad apps.
- **Android**: Supported.
## Prerequisites
This documentation assumes that the reader has a working knowledge of JUCE.
Some modules built on external libraries assume that the reader understands
the operation of those external libraries. Certain modules assume that the
reader understands additional domain-specific information. Modules with
additional prerequisites are marked in the documentation.
## External Modules
Some modules bring in functionality provided by external libraries. For
example, the @ref beast_bzip2 module provides the compression and decompression
algorithms in [bZip2][7]. Usage of these external library modules is optional.
They come with complete source code, as well as options for using either
system or user provided variants of the external libraries: it is not
necessary to download additional source code packages to use these modules.
External code incorporated into Beast is covered by separate licenses. See
the licensing information and notes in the corresponding source files for
copyright information and terms of use.
## Integration
Beast requires recent versions of JUCE. It won't work with versions 1.53 or
earlier. To use the library it is necessary to first download JUCE to a
location where your development environment can find it. Or, you can use your
existing installation of JUCE.
This library uses the same modularized organizational structure as JUCE. To
use a module, first add a path to the list of includes searched by your
development environment or project, which points to the Beast directory. Then,
add the single corresponding .c or .cpp file to your existing project which
already uses JUCE. For example, to use the @ref beast_core module, add the file
beast_core.cpp to your project. Some modules depend on other modules.
To use a module, include the appropriate header from within your source code.
For example, to access classes in the @ref beast_concurrent module, use this:
@code
#include "modules/beast_concurrent/beast_concurrent.h"
@endcode
Then add the corresponding file beast_concurrent.cpp to your build.
## AppConfig
Some Beast features can be controlled at compilation time through
preprocessor directives. The available choices of compilation options are
described in AppConfig.h, located in the AppConfigTemplate directory. Copy
the provided settings into your existing AppConfig.h (a file used by JUCE
convention).
## License
This library contains portions of other open source products covered by
separate licenses. Please see the corresponding source files for specific
terms.
Beast is provided under the terms of The ISC License:
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Some files contain portions of these external projects, licensed separately:
- [bZip2][7] is Copyright (C) 1996-2010 Julian R Seward. All rights
reserved. See the corresponding file LICENSE for licensing terms.
- [Soci][13] is Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton, and
various others noted in the corresponding source files. Soci is distributed
under the [Boost Software License, Version 1.0][14].
- [SQLite][15], placed in the public domain.
[0]: mailto:vinnie.falco@gmail.com "Vinnie Falco (Email)"
[1]: https://github.com/vinniefalco/Beast "Beast Project"
[2]: http://vinniefalco.github.com/Beast/ "Beast Documentation"
[3]: http://rawmaterialsoftware.com/juce.php "JUCE"
[4]: http://rawmaterialsoftware.com/ "Raw Material Software"
[5]: http://www.gnu.org/licenses/gpl-2.0.html "GNU General Public License, version 2"
[6]: http://rawmaterialsoftware.com/jucelicense.php "JUCE Licenses"
[7]: http://www.bzip.org/ "bZip2: Home"
[8]: http://freetype.org/ "The FreeType Project"
[9]: http://www.freetype.org/FTL.TXT "The FreeType Project License"
[10]: http://www.lua.org/ "The Programming Language Lua"
[11]: http://opensource.org/licenses/ISC "The ISC License"
[12]: https://github.com/vinniefalco/LuaBridge
[13]: http://soci.sourceforge.net/ "SOCI"
[14]: http://www.boost.org/LICENSE_1_0.txt "Boost Software License, Version 1.0"
[15]: http://sqlite.org/ "SQLite Home Page"
[16]: http://developer.kde.org/~wheeler/taglib.html "TagLib"
[17]: http://www.gnu.org/licenses/lgpl-2.1.html "Gnu Lesser General Public License, version 2.1"
[18]: http://www.mozilla.org/MPL/1.1/ "Mozilla Public License"
@copyright Copyright 2008-2013 by Vinnie Falco \<vinnie.falco@gmail.com\> ([e-mail][0])
@copyright Provided under the [ISC LIcense][11]
*/
//------------------------------------------------------------------------------
/** Implementation classes.
Thase classes are used internally.
@defgroup internal internal
@internal
*/
//------------------------------------------------------------------------------
/** External modules.
These modules bring in functionality from third party or system libraries.
@defgroup external external
*/
//------------------------------------------------------------------------------
/** Core classes.
This module provides core required functionality, and classes useful for
general development. All other modules require this module.
@todo Discuss the treatment of exceptions versus Error objects in the
library.
@todo Discuss the additions to BeastConfig.h
@defgroup beast_core beast_core
*/
/* Get this early so we can use it. */
#include "../beast_core/system/beast_TargetPlatform.h"
//------------------------------------------------------------------------------
#if BEAST_BOOST_IS_AVAILABLE
#include <boost/thread/tss.hpp>
#endif
#include "../beast_core/beast_core.h"
/** The Beast namespace.
This namespace contains all Beast symbols.
*/
namespace beast
{
// Order matters
#include "functor/beast_Function.h"
#include "events/beast_DeadlineTimer.h"
#include "events/beast_OncePerSecond.h"
#include "math/beast_Math.h"
#include "memory/beast_AllocatedBy.h"
#include "memory/beast_PagedFreeStore.h"
#include "memory/beast_GlobalPagedFreeStore.h"
#include "memory/beast_FifoFreeStoreWithTLS.h"
#include "memory/beast_FifoFreeStoreWithoutTLS.h"
#include "memory/beast_FifoFreeStore.h"
#include "memory/beast_GlobalFifoFreeStore.h"
#include "threads/beast_Semaphore.h"
#include "threads/beast_SerialFor.h"
#include "threads/beast_InterruptibleThread.h"
#include "threads/beast_ReadWriteMutex.h"
#include "threads/beast_ThreadGroup.h"
#include "threads/beast_CallQueue.h"
#include "threads/beast_SharedData.h"
#include "threads/beast_GlobalThreadGroup.h"
#include "threads/beast_Listeners.h"
#include "threads/beast_ManualCallQueue.h"
#include "threads/beast_ParallelFor.h"
#include "threads/beast_ThreadWithCallQueue.h"
#include "threads/beast_Workers.h"
}
#endif

View File

@@ -1,259 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
class DeadlineTimer::Manager
: public SharedSingleton <DeadlineTimer::Manager>
, public InterruptibleThread::EntryPoint
{
private:
typedef CriticalSection LockType;
typedef List <DeadlineTimer> Items;
public:
Manager ()
: SharedSingleton <Manager> (SingletonLifetime::persistAfterCreation)
, m_shouldStop (false)
, m_thread ("DeadlineTimer::Manager")
{
m_thread.start (this);
}
~Manager ()
{
m_shouldStop = true;
m_thread.interrupt ();
bassert (m_items.empty ());
}
// Okay to call on an active timer.
// However, an extra notification may still happen due to concurrency.
//
void activate (DeadlineTimer* timer, double secondsRecurring, Time const& when)
{
bassert (secondsRecurring >= 0);
LockType::ScopedLockType lock (m_mutex);
if (timer->m_isActive)
{
m_items.erase (m_items.iterator_to (*timer));
timer->m_isActive = false;
}
timer->m_secondsRecurring = secondsRecurring;
timer->m_notificationTime = when;
insertSorted (*timer);
timer->m_isActive = true;
m_thread.interrupt ();
}
// Okay to call this on an inactive timer.
// This can happen naturally based on concurrency.
//
void deactivate (DeadlineTimer* timer)
{
LockType::ScopedLockType lock (m_mutex);
if (timer->m_isActive)
{
m_items.erase (m_items.iterator_to (*timer));
timer->m_isActive = false;
}
m_thread.interrupt ();
}
void threadRun ()
{
while (! m_shouldStop)
{
Time const currentTime = Time::getCurrentTime ();
double seconds = 0;
{
LockType::ScopedLockType lock (m_mutex);
// Notify everyone whose timer has expired
//
if (! m_items.empty ())
{
for (;;)
{
Items::iterator const iter = m_items.begin ();
// Has this timer expired?
if (iter->m_notificationTime <= currentTime)
{
// Yes, so call the listener.
//
// Note that this happens while the lock is held.
//
iter->m_listener->onDeadlineTimer (*iter);
// Remove it from the list.
m_items.erase (iter);
// Is the timer recurring?
if (iter->m_secondsRecurring > 0)
{
// Yes so set the timer again.
iter->m_notificationTime =
currentTime + RelativeTime (iter->m_secondsRecurring);
// Keep it active.
insertSorted (*iter);
}
else
{
// Not a recurring timer, deactivate it.
iter->m_isActive = false;
}
}
else
{
break;
}
}
}
// Figure out how long we need to wait.
// This has to be done while holding the lock.
//
if (! m_items.empty ())
{
seconds = (m_items.front ().m_notificationTime - currentTime).inSeconds ();
}
else
{
seconds = 0;
}
}
// Note that we have released the lock here.
//
if (seconds > 0)
{
// Wait until interrupt or next timer.
//
m_thread.wait (static_cast <int> (seconds * 1000 + 0.5));
}
else if (seconds == 0)
{
// Wait until interrupt
//
m_thread.wait ();
}
else
{
// Do not wait. This can happen if the recurring timer duration
// is extremely short, or if a listener wastes too much time in
// their callback.
}
}
}
// Caller is responsible for locking
void insertSorted (DeadlineTimer& item)
{
if (! m_items.empty ())
{
Items::iterator before = m_items.begin ();
for (;;)
{
if (before->m_notificationTime >= item.m_notificationTime)
{
m_items.insert (before, item);
break;
}
++before;
if (before == m_items.end ())
{
m_items.push_back (item);
break;
}
}
}
else
{
m_items.push_back (item);
}
}
static Manager* createInstance ()
{
return new Manager;
}
private:
CriticalSection m_mutex;
bool volatile m_shouldStop;
InterruptibleThread m_thread;
Items m_items;
};
//------------------------------------------------------------------------------
DeadlineTimer::DeadlineTimer (Listener* listener)
: m_listener (listener)
, m_manager (Manager::getInstance ())
, m_isActive (false)
{
}
DeadlineTimer::~DeadlineTimer ()
{
m_manager->deactivate (this);
}
void DeadlineTimer::setExpiration (double secondsUntilDeadline)
{
bassert (secondsUntilDeadline > 0);
Time const when = Time::getCurrentTime () + RelativeTime (secondsUntilDeadline);
m_manager->activate (this, 0, when);
}
void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
{
bassert (secondsUntilDeadline > 0);
Time const when = Time::getCurrentTime () + RelativeTime (secondsUntilDeadline);
m_manager->activate (this, secondsUntilDeadline, when);
}
void DeadlineTimer::setExpirationTime (Time const& when)
{
m_manager->activate (this, 0, when);
}
void DeadlineTimer::reset ()
{
m_manager->deactivate (this);
}

View File

@@ -1,111 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
class OncePerSecond::TimerSingleton
: public SharedSingleton <OncePerSecond::TimerSingleton>
, private InterruptibleThread::EntryPoint
{
private:
TimerSingleton ()
: SharedSingleton <OncePerSecond::TimerSingleton> (
SingletonLifetime::persistAfterCreation)
, m_thread ("Once Per Second")
{
m_thread.start (this);
}
~TimerSingleton ()
{
m_thread.join ();
bassert (m_list.empty ());
}
void threadRun ()
{
for (;;)
{
bool const interrupted = m_thread.wait (1000);
if (interrupted)
break;
notify ();
}
}
void notify ()
{
CriticalSection::ScopedLockType lock (m_mutex);
for (List <Elem>::iterator iter = m_list.begin (); iter != m_list.end ();)
{
OncePerSecond* object = iter->object;
++iter;
object->doOncePerSecond ();
}
}
public:
void insert (Elem* elem)
{
CriticalSection::ScopedLockType lock (m_mutex);
m_list.push_back (*elem);
}
void remove (Elem* elem)
{
CriticalSection::ScopedLockType lock (m_mutex);
m_list.erase (m_list.iterator_to (*elem));
}
static TimerSingleton* createInstance ()
{
return new TimerSingleton;
}
private:
InterruptibleThread m_thread;
CriticalSection m_mutex;
List <Elem> m_list;
};
//------------------------------------------------------------------------------
OncePerSecond::OncePerSecond ()
{
m_elem.instance = TimerSingleton::getInstance ();
m_elem.object = this;
}
OncePerSecond::~OncePerSecond ()
{
}
void OncePerSecond::startOncePerSecond ()
{
m_elem.instance->insert (&m_elem);
}
void OncePerSecond::endOncePerSecond ()
{
m_elem.instance->remove (&m_elem);
}

View File

@@ -1,62 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ONCEPERSECOND_BEASTHEADER
#define BEAST_ONCEPERSECOND_BEASTHEADER
/*============================================================================*/
/**
Provides a once per second notification.
Derive your class from OncePerSecond and override doOncePerSecond(). Then,
call startOncePerSecond() to begin receiving the notifications. No clean-up
or other actions are required.
@ingroup beast_core
*/
class BEAST_API OncePerSecond : public Uncopyable
{
public:
OncePerSecond ();
virtual ~OncePerSecond ();
/** Begin receiving notifications. */
void startOncePerSecond ();
/** Stop receiving notifications. */
void endOncePerSecond ();
protected:
/** Called once per second. */
virtual void doOncePerSecond () = 0;
private:
class TimerSingleton;
typedef SharedObjectPtr <TimerSingleton> TimerPtr;
struct Elem : List <Elem>::Node
{
TimerPtr instance;
OncePerSecond* object;
};
Elem m_elem;
};
#endif

View File

@@ -1,266 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FUNCTION_BEASTHEADER
#define BEAST_FUNCTION_BEASTHEADER
//
// Strong replacement for boost::function:
//
// #1 Bounded memory requirement, avoids the free store.
//
// #2 Always refers to a functor (i.e. is never invalid)
//
// #3 Default value (None) is a function that
// returns a default object (the result type
// constructed with a default constructor).
//
template <typename Signature, int Bytes = 128>
class Function;
//
// nullary function
//
template <typename R, int Bytes>
class Function <R (void), Bytes>
{
public:
typedef R result_type;
typedef Function self_type;
struct None
{
typedef R result_type;
result_type operator () () const
{
return result_type ();
}
};
Function ()
{
constructCopyOf (None ());
}
Function (Function const& f)
{
f.getCall ().constructCopyInto (m_storage);
}
template <class Functor>
Function (Functor const& f)
{
constructCopyOf (f);
}
~Function ()
{
getCall ().~Call ();
}
Function& operator= (Function const& f)
{
getCall ().~Call ();
f.getCall ().constructCopyInto (m_storage);
return *this;
}
template <class Functor>
Function& operator= (Functor const& f)
{
getCall ().~Call ();
constructCopyOf (f);
return *this;
}
result_type operator () ()
{
return getCall ().operator () ();
}
private:
template <class Functor>
void constructCopyOf (Functor const& f)
{
// If this generates a compile error it means that
// the functor is too large for the static buffer.
// Increase the storage template parameter until
// the error message goes away. This might cause
// changes throughout the application with other
// template classes that depend on the size.
static_bassert (sizeof (StoredCall <Functor>) <= Bytes);
new (m_storage) StoredCall <Functor> (f);
}
private:
struct Call
{
virtual ~Call () {}
virtual void constructCopyInto (void* p) const = 0;
virtual result_type operator () () = 0;
};
template <class Functor>
struct StoredCall : Call
{
explicit StoredCall (Functor const& f) : m_f (f) { }
StoredCall (const StoredCall& c) : m_f (c.m_f) { }
void constructCopyInto (void* p) const
{
new (p) StoredCall (m_f);
}
result_type operator () ()
{
return m_f ();
}
private:
Functor m_f;
};
Call& getCall ()
{
return *reinterpret_cast <Call*> (&m_storage[0]);
}
Call const& getCall () const
{
return *reinterpret_cast <Call const*> (&m_storage[0]);
}
char m_storage [Bytes]; // should be enough
};
//------------------------------------------------------------------------------
//
// unary function
//
template <typename R, typename T1, int Bytes>
class Function <R (T1 t1), Bytes>
{
public:
typedef R result_type;
typedef Function self_type;
struct None
{
typedef R result_type;
result_type operator () (T1) const
{
return result_type ();
}
};
Function ()
{
constructCopyOf (None ());
}
Function (const Function& f)
{
f.getCall ().constructCopyInto (m_storage);
}
template <class Functor>
Function (Functor const& f)
{
constructCopyOf (f);
}
~Function ()
{
getCall ().~Call ();
}
Function& operator= (const Function& f)
{
getCall ().~Call ();
f.getCall ().constructCopyInto (m_storage);
return *this;
}
template <class Functor>
Function& operator= (Functor const& f)
{
getCall ().~Call ();
constructCopyOf (f);
return *this;
}
result_type operator () (T1 t1)
{
return getCall ().operator () (t1);
}
private:
template <class Functor>
void constructCopyOf (Functor const& f)
{
// If this generates a compile error it means that
// the functor is too large for the static buffer.
// Increase the storage template parameter until
// the error message goes away. This might cause
// changes throughout the application with other
// template classes that depend on the size.
static_bassert (sizeof (StoredCall <Functor>) <= Bytes);
new (m_storage) StoredCall <Functor> (f);
}
private:
struct Call
{
virtual ~Call () {}
virtual void constructCopyInto (void* p) const = 0;
virtual result_type operator () (T1 t1) = 0;
};
template <class Functor>
struct StoredCall : Call
{
explicit StoredCall (Functor const& f) : m_f (f) { }
StoredCall (const StoredCall& c) : m_f (c.m_f) { }
void constructCopyInto (void* p) const
{
new (p) StoredCall (m_f);
}
result_type operator () (T1 t1)
{
return m_f (t1);
}
private:
Functor m_f;
};
Call& getCall ()
{
return *reinterpret_cast <Call*> (&m_storage[0]);
}
Call const& getCall () const
{
return *reinterpret_cast <Call const*> (&m_storage[0]);
}
char m_storage [Bytes]; // should be enough
};
#endif

View File

@@ -1,63 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ALLOCATEDBY_BEASTHEADER
#define BEAST_ALLOCATEDBY_BEASTHEADER
/*============================================================================*/
/**
Customized allocation for heap objects.
Derived classes will use the specified allocator for new and delete.
@param AllocatorType The type of allocator to use.
@ingroup beast_concurrent
*/
template <class AllocatorType>
class AllocatedBy
{
public:
static inline void* operator new (size_t bytes, AllocatorType& allocator) noexcept
{
return allocator.allocate (bytes);
}
static inline void* operator new (size_t bytes, AllocatorType* allocator) noexcept
{
return allocator->allocate (bytes);
}
static inline void operator delete (void* p, AllocatorType&) noexcept
{
AllocatorType::deallocate (p);
}
static inline void operator delete (void* p, AllocatorType*) noexcept
{
AllocatorType::deallocate (p);
}
static inline void operator delete (void* p) noexcept
{
AllocatorType::deallocate (p);
}
};
#endif

View File

@@ -1,198 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// Implementation notes
//
// - A Page is a large allocation from a global PageAllocator.
//
// - Each thread maintains an 'active' page from which it makes allocations.
//
// - When the active page is full, a new one takes it's place.
//
// - Page memory is deallocated when it is not active and no longer referenced.
//
// - Each instance of FifoFreeStoreWithTLS maintains its own set of per-thread active pages,
// but uses a global PageAllocator. This reduces memory consumption without
// affecting performance.
//
#if BEAST_BOOST_IS_AVAILABLE
// This precedes every allocation
//
struct FifoFreeStoreWithTLS::Header
{
FifoFreeStoreWithTLS::Page* page;
};
//------------------------------------------------------------------------------
class FifoFreeStoreWithTLS::Page : LeakChecked <Page>, public Uncopyable
{
public:
explicit Page (const size_t bytes) : m_refs (1)
{
m_end = reinterpret_cast <char*> (this) + bytes;
m_free = reinterpret_cast <char*> (
Memory::pointerAdjustedForAlignment (this + 1));
}
~Page ()
{
bassert (! m_refs.isSignaled ());
}
inline bool release ()
{
bassert (! m_refs.isSignaled ());
return m_refs.release ();
}
void* allocate (size_t bytes)
{
bassert (bytes > 0);
char* p = Memory::pointerAdjustedForAlignment (m_free);
char* free = p + bytes;
if (free <= m_end)
{
m_free = free;
m_refs.addref ();
}
else
{
p = 0;
}
return p;
}
private:
AtomicCounter m_refs; // reference count
char* m_free; // next free byte
char* m_end; // last free byte + 1
};
//------------------------------------------------------------------------------
class FifoFreeStoreWithTLS::PerThreadData : LeakChecked <PerThreadData>, public Uncopyable
{
public:
explicit PerThreadData (FifoFreeStoreWithTLS* allocator)
: m_allocator (*allocator)
, m_active (m_allocator.newPage ())
{
}
~PerThreadData ()
{
if (m_active->release ())
m_allocator.deletePage (m_active);
}
inline void* allocate (const size_t bytes)
{
const size_t headerBytes = Memory::sizeAdjustedForAlignment (sizeof (Header));
const size_t bytesNeeded = headerBytes + bytes;
if (bytesNeeded > m_allocator.m_pages->getPageBytes ())
Throw (Error ().fail (__FILE__, __LINE__, TRANS ("the memory request was too large")));
Header* header;
header = reinterpret_cast <Header*> (m_active->allocate (bytesNeeded));
if (!header)
{
if (m_active->release ())
deletePage (m_active);
m_active = m_allocator.newPage ();
header = reinterpret_cast <Header*> (m_active->allocate (bytesNeeded));
}
header->page = m_active;
return reinterpret_cast <char*> (header) + headerBytes;
}
private:
FifoFreeStoreWithTLS& m_allocator;
Page* m_active;
};
//------------------------------------------------------------------------------
inline FifoFreeStoreWithTLS::Page* FifoFreeStoreWithTLS::newPage ()
{
return new (m_pages->allocate ()) Page (m_pages->getPageBytes ());
}
inline void FifoFreeStoreWithTLS::deletePage (Page* page)
{
// Safe, because each thread maintains its own active page.
page->~Page ();
PagedFreeStoreType::deallocate (page);
}
FifoFreeStoreWithTLS::FifoFreeStoreWithTLS ()
: m_pages (PagedFreeStoreType::getInstance ())
{
//bassert (m_pages->getPageBytes () >= sizeof (Page) + Memory::allocAlignBytes);
}
FifoFreeStoreWithTLS::~FifoFreeStoreWithTLS ()
{
// Clean up this thread's data before we release
// the reference to the global page allocator.
m_tsp.reset (0);
}
//------------------------------------------------------------------------------
void* FifoFreeStoreWithTLS::allocate (const size_t bytes)
{
PerThreadData* data = m_tsp.get ();
if (!data)
{
data = new PerThreadData (this);
m_tsp.reset (data);
}
return data->allocate (bytes);
}
//------------------------------------------------------------------------------
void FifoFreeStoreWithTLS::deallocate (void* p)
{
const size_t headerBytes = Memory::sizeAdjustedForAlignment (sizeof (Header));
Header* const header = reinterpret_cast <Header*> (reinterpret_cast <char*> (p) - headerBytes);
Page* const page = header->page;
if (page->release ())
deletePage (page);
}
#endif

View File

@@ -1,69 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FIFOFREESTOREWITHTLS_BEASTHEADER
#define BEAST_FIFOFREESTOREWITHTLS_BEASTHEADER
#if BEAST_BOOST_IS_AVAILABLE
/*============================================================================*/
/**
Lock-free and mostly wait-free FIFO memory allocator.
This allocator is suitable for use with CallQueue and Listeners. It is
expected that over time, deallocations will occur in roughly the same order
as allocations.
@note This implementation uses Thread Local Storage to further improve
performance. However, it requires boost style thread_specific_ptr.
@invariant allocate() and deallocate() are fully concurrent.
@invariant The ABA problem is handled automatically.
@ingroup beast_concurrent
*/
class BEAST_API FifoFreeStoreWithTLS
{
public:
FifoFreeStoreWithTLS ();
~FifoFreeStoreWithTLS ();
void* allocate (const size_t bytes);
static void deallocate (void* const p);
private:
typedef GlobalPagedFreeStore PagedFreeStoreType;
struct Header;
class Page;
inline Page* newPage ();
static inline void deletePage (Page* page);
private:
class PerThreadData;
boost::thread_specific_ptr <PerThreadData> m_tsp;
PagedFreeStoreType::Ptr m_pages;
};
#endif
#endif

View File

@@ -1,241 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// This precedes every allocation
struct FifoFreeStoreWithoutTLS::Header
{
union
{
FifoFreeStoreWithoutTLS::Block* block; // backpointer to the page
char pad [Memory::allocAlignBytes];
};
};
//------------------------------------------------------------------------------
class FifoFreeStoreWithoutTLS::Block : public Uncopyable
{
public:
explicit Block (const size_t bytes) : m_refs (1)
{
m_end = reinterpret_cast <char*> (this) + bytes;
m_free = reinterpret_cast <char*> (
Memory::pointerAdjustedForAlignment (this + 1));
}
~Block ()
{
bassert (!m_refs.isSignaled ());
}
inline void addref ()
{
m_refs.addref ();
}
inline bool release ()
{
return m_refs.release ();
}
enum Result
{
success, // successful allocation
ignore, // disregard the block
consumed // block is consumed (1 thread sees this)
};
Result allocate (size_t bytes, void* pBlock)
{
bassert (bytes > 0);
Result result;
for (;;)
{
char* base = m_free.get ();
if (base)
{
char* p = Memory::pointerAdjustedForAlignment (base);
char* free = p + bytes;
if (free <= m_end)
{
// Try to commit the allocation
if (m_free.compareAndSet (free, base))
{
* (reinterpret_cast <void**> (pBlock)) = p;
result = success;
break;
}
else
{
// Someone changed m_free, retry.
}
}
else
{
// Mark the block consumed.
if (m_free.compareAndSet (0, base))
{
// Only one caller sees this, the rest get 'ignore'
result = consumed;
break;
}
else
{
// Happens with another concurrent allocate(), retry.
}
}
}
else
{
// Block is consumed, ignore it.
result = ignore;
break;
}
}
return result;
}
private:
AtomicCounter m_refs; // reference count
AtomicPointer <char> m_free; // next free byte or 0 if inactive.
char* m_end; // last free byte + 1
};
//------------------------------------------------------------------------------
inline FifoFreeStoreWithoutTLS::Block* FifoFreeStoreWithoutTLS::newBlock ()
{
return new (m_pages->allocate ()) Block (m_pages->getPageBytes ());
}
inline void FifoFreeStoreWithoutTLS::deleteBlock (Block* b)
{
// It is critical that we do not call the destructor,
// because due to the lock-free implementation, a Block
// can be accessed for a short time after it is deleted.
/* b->~Block (); */ // DO NOT CALL!!!
PagedFreeStoreType::deallocate (b);
}
FifoFreeStoreWithoutTLS::FifoFreeStoreWithoutTLS ()
: m_pages (GlobalPagedFreeStore::getInstance ())
{
if (m_pages->getPageBytes () < sizeof (Block) + 256)
Throw (Error ().fail (__FILE__, __LINE__, TRANS ("the block size is too small")));
m_active = newBlock ();
}
FifoFreeStoreWithoutTLS::~FifoFreeStoreWithoutTLS ()
{
deleteBlock (m_active);
}
//------------------------------------------------------------------------------
void* FifoFreeStoreWithoutTLS::allocate (const size_t bytes)
{
const size_t actual = sizeof (Header) + bytes;
if (actual > m_pages->getPageBytes ())
Throw (Error ().fail (__FILE__, __LINE__, TRANS ("the memory request was too large")));
Header* h;
for (;;)
{
// Get an active block.
Block* b = m_active;
while (!b)
{
Thread::yield ();
b = m_active;
}
// (*) It is possible for the block to get a final release here
// In this case it will have been put in the garbage, and
// m_active will not match.
// Acquire a reference.
b->addref ();
// Is it still active?
if (m_active == b)
{
// Yes so try to allocate from it.
const Block::Result result = b->allocate (actual, &h);
if (result == Block::success)
{
// Keep the reference and return the allocation.
h->block = b;
break;
}
else if (result == Block::consumed)
{
// Remove block from active.
m_active = 0;
// Take away the reference we added
b->release ();
// Take away the original active reference.
if (b->release ())
deleteBlock (b);
// Install a fresh empty active block.
m_active = newBlock ();
}
else
{
if (b->release ())
deleteBlock (b);
}
// Try again.
}
else
{
// Block became inactive, so release our reference.
b->release ();
// (*) It is possible for this to be a duplicate final release.
}
}
return h + 1;
}
//------------------------------------------------------------------------------
void FifoFreeStoreWithoutTLS::deallocate (void* p)
{
Block* const b = (reinterpret_cast <Header*> (p) - 1)->block;
if (b->release ())
deleteBlock (b);
}

View File

@@ -1,65 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FIFOFREESTOREWITHOUTTLS_BEASTHEADER
#define BEAST_FIFOFREESTOREWITHOUTTLS_BEASTHEADER
/*============================================================================*/
/**
Lock-free FIFO memory allocator.
This allocator is suitable for use with CallQueue and Listeners. It is
expected that over time, deallocations will occur in roughly the same order
as allocations.
@note This version of the fifo free store uses less memory and doesn't require
thread specific storage. However, it runs slower. The performance
differences are negligible for desktop class applications.
@invariant allocate() and deallocate() are fully concurrent.
@invariant The ABA problem is handled automatically.
@ingroup beast_concurrent
*/
class BEAST_API FifoFreeStoreWithoutTLS
{
public:
explicit FifoFreeStoreWithoutTLS ();
~FifoFreeStoreWithoutTLS ();
void* allocate (const size_t bytes);
static void deallocate (void* const p);
private:
typedef GlobalPagedFreeStore PagedFreeStoreType;
struct Header;
class Block;
inline Block* newBlock ();
static inline void deleteBlock (Block* b);
private:
Block* volatile m_active;
PagedFreeStoreType::Ptr m_pages;
};
#endif

View File

@@ -1,226 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#define LOG_GC 0
namespace
{
// This is the upper limit on the amount of physical memory an instance of the
// allocator will allow. Going over this limit means that consumers cannot keep
// up with producers, and application logic should be re-examined.
//
// TODO: ENFORCE THIS GLOBALLY? MEASURE IN KILOBYTES AND FORCE KILOBYTE PAGE SIZES
#define HARD_LIMIT 1
const size_t hardLimitMegaBytes = 256;
}
/*
Implementation notes
- There are two pools, the 'hot' pool and the 'cold' pool.
- When a new page is needed we pop from the 'fresh' stack of the hot pool.
- When a page is deallocated it is pushed to the 'garbage' stack of the hot pool.
- Every so often, a garbage collection is performed on a separate thread.
During collection, fresh and garbage are swapped in the cold pool.
Then, the hot and cold pools are atomically swapped.
*/
//------------------------------------------------------------------------------
struct PagedFreeStore::Page : Pages::Node, LeakChecked <Page>
{
explicit Page (PagedFreeStore* const allocator)
: m_allocator (*allocator)
{
}
PagedFreeStore& getAllocator () const
{
return m_allocator;
}
private:
PagedFreeStore& m_allocator;
};
inline void* PagedFreeStore::fromPage (Page* const p)
{
return reinterpret_cast <char*> (p) +
Memory::sizeAdjustedForAlignment (sizeof (Page));
}
inline PagedFreeStore::Page* PagedFreeStore::toPage (void* const p)
{
return reinterpret_cast <Page*> (
(reinterpret_cast <char*> (p) -
Memory::sizeAdjustedForAlignment (sizeof (Page))));
}
//------------------------------------------------------------------------------
PagedFreeStore::PagedFreeStore (const size_t pageBytes)
: m_pageBytes (pageBytes)
, m_pageBytesAvailable (pageBytes - Memory::sizeAdjustedForAlignment (sizeof (Page)))
, m_newPagesLeft (int ((hardLimitMegaBytes * 1024 * 1024) / m_pageBytes))
#if LOG_GC
, m_swaps (0)
#endif
{
m_hot = m_pool1;
m_cold = m_pool2;
startOncePerSecond ();
}
PagedFreeStore::~PagedFreeStore ()
{
endOncePerSecond ();
#if LOG_GC
bassert (!m_used.isSignaled ());
#endif
dispose (m_pool1);
dispose (m_pool2);
#if LOG_GC
bassert (!m_total.isSignaled ());
#endif
}
//------------------------------------------------------------------------------
void* PagedFreeStore::allocate ()
{
Page* page = m_hot->fresh->pop_front ();
if (!page)
{
#if HARD_LIMIT
const bool exhausted = m_newPagesLeft.release ();
if (exhausted)
Throw (Error ().fail (__FILE__, __LINE__,
TRANS ("the limit of memory allocations was reached")));
#endif
void* storage = ::malloc (m_pageBytes);
if (!storage)
Throw (Error ().fail (__FILE__, __LINE__,
TRANS ("a memory allocation failed")));
page = new (storage) Page (this);
#if LOG_GC
m_total.addref ();
#endif
}
#if LOG_GC
m_used.addref ();
#endif
return fromPage (page);
}
void PagedFreeStore::deallocate (void* const p)
{
Page* const page = toPage (p);
PagedFreeStore& allocator = page->getAllocator ();
allocator.m_hot->garbage->push_front (page);
#if LOG_GC
allocator.m_used.release ();
#endif
}
//
// Perform garbage collection.
//
void PagedFreeStore::doOncePerSecond ()
{
// Physically free one page.
// This will reduce the working set over time after a spike.
{
Page* page = m_cold->garbage->pop_front ();
if (page)
{
page->~Page ();
::free (page);
m_newPagesLeft.addref ();
#ifdef LOG_GC
m_total.release ();
#endif
}
}
m_cold->fresh->swap (m_cold->garbage);
// Swap atomically with respect to m_hot
Pool* temp = m_hot;
m_hot = m_cold; // atomic
m_cold = temp;
#if LOG_GC
String s;
s << "swap " << String (++m_swaps);
s << " (" << String (m_used.get ()) << "/"
<< String (m_total.get ()) << " of "
<< String (m_newPagesLeft.get ()) << ")";
Logger::outputDebugString (s);
#endif
}
void PagedFreeStore::dispose (Pages& pages)
{
for (;;)
{
Page* const page = pages.pop_front ();
if (page)
{
page->~Page ();
::free (page);
#if LOG_GC
m_total.release ();
#endif
}
else
{
break;
}
}
}
void PagedFreeStore::dispose (Pool& pool)
{
dispose (pool.fresh);
dispose (pool.garbage);
}

View File

@@ -1,93 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_PAGEDFREESTORE_BEASTHEADER
#define BEAST_PAGEDFREESTORE_BEASTHEADER
/*============================================================================*/
/**
Lock-free memory allocator for fixed size pages.
The ABA problem (http://en.wikipedia.org/wiki/ABA_problem) is avoided by
treating freed pages as garbage, and performing a collection every second.
@ingroup beast_concurrent
*/
class BEAST_API PagedFreeStore : private OncePerSecond
{
public:
explicit PagedFreeStore (const size_t pageBytes);
~PagedFreeStore ();
// The available bytes per page is a little bit less
// than requested in the constructor, due to overhead.
//
inline size_t getPageBytes () const
{
return m_pageBytesAvailable;
}
inline void* allocate (const size_t bytes)
{
if (bytes > m_pageBytes)
Throw (Error ().fail (__FILE__, __LINE__, "the size is too large"));
return allocate ();
}
void* allocate ();
static void deallocate (void* const p);
private:
void* newPage ();
void doOncePerSecond ();
private:
struct Page;
typedef LockFreeStack <Page> Pages;
struct Pool
{
CacheLine::Padded <Pages> fresh;
CacheLine::Padded <Pages> garbage;
};
static inline void* fromPage (Page* const p);
static inline Page* toPage (void* const p);
void dispose (Pages& pages);
void dispose (Pool& pool);
private:
const size_t m_pageBytes;
const size_t m_pageBytesAvailable;
CacheLine::Aligned <Pool> m_pool1; // pair of pools
CacheLine::Aligned <Pool> m_pool2;
Pool* volatile m_cold; // pool which is cooling down
Pool* volatile m_hot; // pool we are currently using
AtomicCounter m_newPagesLeft; // limit of system allocations
#if 1
int m_swaps;
AtomicCounter m_total;
AtomicCounter m_used;
#endif
};
#endif

View File

@@ -1,153 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
CallQueue::CallQueue (String name)
: m_name (name)
{
}
CallQueue::~CallQueue ()
{
// Someone forget to close the queue.
bassert (m_closed.isSignaled ());
// Can't destroy queue with unprocessed calls.
bassert (m_queue.empty ());
}
bool CallQueue::isAssociatedWithCurrentThread () const
{
return Thread::getCurrentThreadId () == m_id;
}
// Adds a call to the queue of execution.
void CallQueue::queuep (Work* c)
{
// If this goes off it means calls are being made after the
// queue is closed, and probably there is no one around to
// process it.
bassert (!m_closed.isSignaled ());
if (m_queue.push_back (c))
signal ();
}
// Append the Work to the queue. If this call is made from the same
// thread as the last thread that called synchronize(), then the call
// will execute synchronously.
//
void CallQueue::callp (Work* c)
{
queuep (c);
// If we are called on the process thread and we are not
// recursed into doSynchronize, then process the queue. This
// makes calls from the process thread synchronous.
//
// NOTE: The value of isBeingSynchronized is invalid/volatile unless
// this thread is the last process thread.
//
// NOTE: There is a small window of opportunity where we
// might get an undesired synchronization if new thread
// calls synchronize() concurrently.
//
if (isAssociatedWithCurrentThread () &&
m_isBeingSynchronized.trySignal ())
{
doSynchronize ();
m_isBeingSynchronized.reset ();
}
}
bool CallQueue::synchronize ()
{
bool did_something;
// Detect recursion into doSynchronize(), and
// break ties for concurrent calls atomically.
//
if (m_isBeingSynchronized.trySignal ())
{
// Remember this thread.
m_id = Thread::getCurrentThreadId ();
did_something = doSynchronize ();
m_isBeingSynchronized.reset ();
}
else
{
did_something = false;
}
return did_something;
}
// Can still have pending calls, just can't put new ones in.
void CallQueue::close ()
{
m_closed.signal ();
synchronize ();
}
// Process everything in the queue. The list of pending calls is
// acquired atomically. New calls may enter the queue while we are
// processing.
//
// Returns true if any functors were called.
//
bool CallQueue::doSynchronize ()
{
bool did_something;
// Reset since we are emptying the queue. Since we loop
// until the queue is empty, it is possible for us to exit
// this function with an empty queue and signaled state.
//
reset ();
Work* call = m_queue.pop_front ();
if (call)
{
did_something = true;
// This method of processing one at a time has the desired
// side effect of synchronizing nested calls to us from a functor.
//
for (;;)
{
call->operator () ();
delete call;
call = m_queue.pop_front ();
if (call == 0)
break;
}
}
else
{
did_something = false;
}
return did_something;
}

View File

@@ -1,506 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CALLQUEUE_BEASTHEADER
#define BEAST_CALLQUEUE_BEASTHEADER
/*============================================================================*/
/**
A FIFO for calling functors asynchronously.
This object is an alternative to traditional locking techniques used to
implement concurrent systems. Instead of acquiring a mutex to change shared
data, a functor is queued for later execution (usually on another thread). The
execution of the functor applies the transformation to the shared state that
was formerly performed within a lock (i.e. CriticalSection).
For read operations on shared data, instead of acquiring a mutex and
accessing the data directly, copies are made (one for each thread), and the
thread accesses its copy without acquiring a lock. One thread owns the master
copy of the shared state. Requests for changing shared state are made by other
threads by posting functors to the master thread's CallQueue. The master
thread notifies other threads of changes by posting functors to their
respective associated CallQueue, using the Listeners interface.
The purpose of the functor is to encapsulate one mutation of shared state to
guarantee progress towards a consensus of the concurrent data among
participating threads. Functors should execute quickly, ideally in constant
time. Dynamically allocated objects of class type passed as functor parameters
should, in general, be reference counted. The ConcurrentObject class is ideal
for meeting this requirement, and has the additional benefit that the workload
of deletion is performed on a separate, provided thread. This queue is not a
replacement for a thread pool or job queue type system.
A CallQueue is considered signaled when one or more functors are present.
Functors are executed during a call to synchronize(). The operation of
executing functors via the call to synchronize() is called synchronizing
the queue. It can more generally be thought of as synchronizing multiple
copies of shared data between threads.
Although there is some extra work required to set up and maintain this
system, the benefits are significant. Since shared data is only synchronized
at well defined times, the programmer can reason and make strong statements
about the correctness of the concurrent system. For example, if an
AudioIODeviceCallback synchronizes the CallQueue only at the beginning of its
execution, it is guaranteed that shared data will remain the same throughout
the remainder of the function.
Because shared data is accessed for reading without a lock, upper bounds
on the run time performance can easily be calculated and assured. Compare
this with the use of a mutex - the run time performance experiences a
combinatorial explosion of possibilities depending on the complex interaction
of multiple threads.
Since a CallQueue is almost always used to invoke parameterized member
functions of objects, the call() function comes in a variety of convenient
forms to make usage easy:
@code
void func1 (int);
struct Object
{
void func2 (void);
void func3 (String name);
static void func4 ();
};
CallQueue fifo ("Example");
void example ()
{
fifo.call (func1, 42); // same as: func1 (42)
Object* object = new Object;
fifo.call (&Object::func2, object); // same as: object->func2 ()
fifo.call (&Object::func3, // same as: object->funcf ("Label")
object,
"Label");
fifo.call (&Object::func4); // even static members can be called.
fifo.callf (functional::bind (&Object::func2, // same as: object->func2 ()
object));
}
@endcode
@invariant Functors can be added from any thread at any time, to any queue
which is not closed.
@invariant When synchronize() is called, functors are called and deleted.
@invariant The thread from which synchronize() is called is considered the
thread associated with the CallQueue.
@invariant Functors queued by the same thread always execute in the same
order they were queued.
@invariant Functors are guaranteed to execute. It is an error if the
CallQueue is deleted while there are functors in it.
Normally, you will not use CallQueue directly, but one of its subclasses
instead. The CallQueue is one of a handful of objects that work together to
implement this system of concurrent data access.
For performance considerations, this implementation is wait-free for
producers and mostly wait-free for consumers. It also uses a lock-free
and wait-free (in the fast path) custom memory allocator.
@see GuiCallQueue, ManualCallQueue, MessageThread, ThreadWithCallQueue
@ingroup beast_concurrent
*/
class BEAST_API CallQueue
{
public:
//============================================================================
/** Type of allocator to use.
@internal
*/
typedef FifoFreeStoreType AllocatorType;
/** Abstract nullary functor in a @ref CallQueue.
Custom implementations may derive from this object for efficiency instead
of using the automatic binding functions.
*/
class Work : public LockFreeQueue <Work>::Node,
public AllocatedBy <AllocatorType>
{
public:
virtual ~Work () { }
/** Calls the functor.
This executes during the queue's call to synchronize().
*/
virtual void operator () () = 0;
};
//============================================================================
/** Create the CallQueue.
The queue starts out open and empty.
@param name A string to identify the queue during debugging.
*/
explicit CallQueue (String name);
/** Destroy the CallQueue.
@invariant Destroying a queue that contains functors results in undefined
behavior.
@note It is customary to call close() on the CallQueue early in the
shutdown process to catch functors going into the queue late.
*/
virtual ~CallQueue ();
//============================================================================
/** Add a functor and possibly synchronize.
Use this when you want to perform the bind yourself.
@param f The functor to add, typically the return value of a call
to bind().
@see call
*/
template <class Functor>
void callf (Functor f)
{
callp (new (m_allocator) CallType <Functor> (f));
}
/** Add a function call and possibly synchronize.
Parameters are evaluated immediately and added to the queue as a packaged
functor. If the current thread of execution is the same as the thread
associated with the CallQueue, synchronize() is called automatically. This
behavior can be avoided by using queue() instead.
@param f The function to call followed by up to eight parameters,
evaluated immediately. The parameter list must match the function
signature. For class member functions, the first argument must be a
pointer to the class object.
@see queue
@todo Provide an example of when synchronize() is needed in call().
*/
/** @{ */
#if BEAST_VARIADIC_MAX >= 1
template <class Fn>
void call (Fn f)
{ callf (functional::bind (f)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Fn, class T1>
void call (Fn f, T1 t1)
{ callf (functional::bind (f, t1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Fn, class T1, class T2>
void call (Fn f, T1 t1, T2 t2)
{ callf (functional::bind (f, t1, t2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Fn, class T1, class T2, class T3>
void call (Fn f, T1 t1, T2 t2, T3 t3)
{ callf (functional::bind (f, t1, t2, t3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Fn, class T1, class T2, class T3, class T4>
void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4)
{ callf (functional::bind (f, t1, t2, t3, t4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Fn, class T1, class T2, class T3, class T4, class T5>
void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ callf (functional::bind (f, t1, t2, t3, t4, t5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6>
void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ callf (functional::bind (f, t1, t2, t3, t4, t5, t6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ callf (functional::bind (f, t1, t2, t3, t4, t5, t6, t7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ callf (functional::bind (f, t1, t2, t3, t4, t5, t6, t7, t8)); }
#endif
/** @} */
/** Add a functor without synchronizing.
Use this when you want to perform the bind yourself.
@param f The functor to add, typically the return value of a call
to bind().
@see queue
*/
template <class Functor>
void queuef (Functor f)
{
queuep (new (m_allocator) CallType <Functor> (f));
}
/** Add a function call without synchronizing.
Parameters are evaluated immediately, then the resulting functor is added
to the queue. This is used to postpone the call to synchronize() when
there would be adverse side effects to executing the function immediately.
In this example, we use queue() instead of call() to avoid a deadlock:
@code
struct SharedState; // contains data shared between threads
SharedData <SharedState> sharedState;
void stateChanged ()
{
SharedData <SharedState>::ReadAccess state (sharedState);
// (read state)
}
CallQueue fifo;
void changeState ()
{
SharedData <State>::WriteAccess state (sharedState);
// (read and write state)
fifo.call (&stateChanged); // BUG: DEADLOCK because of the implicit synchronize().
fifo.queue (&stateChanged); // Okay, synchronize() will be called later,
// after the write lock is released.
}
@endcode
@param f The function to call followed by up to eight parameters,
evaluated immediately. The parameter list must match the
function signature. For non-static class member functions,
the first argument must be a pointer an instance of the class.
@see call
*/
/** @{ */
#if BEAST_VARIADIC_MAX >= 1
template <class Fn>
void queue (Fn f)
{ queuef (functional::bind (f)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Fn, class T1>
void queue (Fn f, T1 t1)
{ queuef (functional::bind (f, t1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Fn, class T1, class T2>
void queue (Fn f, T1 t1, T2 t2)
{ queuef (functional::bind (f, t1, t2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Fn, class T1, class T2, class T3>
void queue (Fn f, T1 t1, T2 t2, T3 t3)
{ queuef (functional::bind (f, t1, t2, t3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Fn, class T1, class T2, class T3, class T4>
void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4)
{ queuef (functional::bind (f, t1, t2, t3, t4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Fn, class T1, class T2, class T3, class T4, class T5>
void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ queuef (functional::bind (f, t1, t2, t3, t4, t5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6>
void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ queuef (functional::bind (f, t1, t2, t3, t4, t5, t6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ queuef (functional::bind (f, t1, t2, t3, t4, t5, t6, t7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ queuef (functional::bind (f, t1, t2, t3, t4, t5, t6, t7, t8)); }
#endif
/** @} */
protected:
//============================================================================
/** Synchronize the queue.
A synchronize operation calls all functors in the queue. If a functor
causes additional functors to be added, they are eventually executed
before synchronize() returns. Derived class call this when the queue is
signaled, and optionally at any other time. Calling this function from
more than one thread simultaneously is undefined.
@return true if any functors were executed.
*/
bool synchronize ();
/** Close the queue.
Functors may not be added after this routine is called. This is used for
diagnostics, to track down spurious calls during application shutdown
or exit. Derived classes may call this if the appropriate time is known.
The queue is synchronized after it is closed.
*/
void close ();
/** Called when the queue becomes signaled.
A queue is signaled on the transition from empty to non-empty. Derived
classes implement this function to perform a notification so that
synchronize() will be called. For example, by triggering a WaitableEvent.
@note Due to the implementation the queue can remain signaled for one
extra cycle. This does not happen under load and is not an issue
in practice.
*/
virtual void signal () = 0;
/** Called when the queue is reset.
A queue is reset when it was previously signaled and then becomes empty
as a result of a call to synchronize.
*/
virtual void reset () = 0;
public:
//============================================================================
/** Add a raw call.
@internal
Custom implementations use this to control the allocation.
@param c The call to add. The memory must come from the allocator.
*/
void callp (Work* c);
/** Queue a raw call.
Custom implementations use this to control the allocation.
@param c The call to add. The memory must come from the allocator.
*/
void queuep (Work* c);
/** Retrieve the allocator.
@return The allocator to use when allocating a raw Work object.
*/
inline AllocatorType& getAllocator ()
{
return m_allocator;
}
/** See if the caller is on the association thread.
@return `true` if the calling thread of execution is associated with the
queue.
*/
bool isAssociatedWithCurrentThread () const;
/** See if the queue is being synchronized.
This is used for diagnostics.
@note This must be called from the associated thread or else the return
value is undefined.
@return `true` if the call stack contains synchronize() for this queue.
*/
bool isBeingSynchronized () const
{
return m_isBeingSynchronized.isSignaled ();
}
private:
template <class Functor>
class CallType : public Work
{
public:
explicit CallType (Functor f) : m_f (f) { }
void operator () ()
{
m_f ();
}
private:
Functor m_f;
};
bool doSynchronize ();
private:
String const m_name;
Thread::ThreadID m_id;
LockFreeQueue <Work> m_queue;
AtomicFlag m_closed;
AtomicFlag m_isBeingSynchronized;
AllocatorType m_allocator;
};
#endif

View File

@@ -1,79 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CONCURRENTOBJECT_BEASTHEADER
#define BEAST_CONCURRENTOBJECT_BEASTHEADER
/*============================================================================*/
/**
A reference counted object with overridable destroy behavior.
This is a reference counted object compatible with
ReferenceCountedObjectPtr. When the last reference is removed, the
object is queued for deletion on a separate, provided thread. On
program exit the thread will clean itself up - no other action is
required.
This class is useful for offloading the deletion work of "deep" objects
shared by multiple threads: objects containing complex members, or a
hierarchy of allocated structures. For example, a ValueTree. The problem
of performing heavyweight memory or cleanup operations from either an
AudioIODeviceCallback or the message thread is avoided.
The deletion behavior can be overriden by providing a replacement
for destroyConcurrentObject().
@ingroup beast_concurrent
*/
class BEAST_API ConcurrentObject : Uncopyable
{
public:
inline void incReferenceCount () noexcept
{
m_refs.addref ();
}
inline void decReferenceCount () noexcept
{
if (m_refs.release ())
destroyConcurrentObject ();
}
protected:
ConcurrentObject ();
virtual ~ConcurrentObject ();
/** Delete the object.
This function is called when the reference count drops to zero. The
default implementation performs the delete on a separate, provided thread
that cleans up after itself on exit.
*/
virtual void destroyConcurrentObject ();
protected:
class Deleter;
private:
AtomicCounter m_refs;
};
#endif

View File

@@ -1,224 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
InterruptibleThread::ThreadHelper::ThreadHelper (String name,
InterruptibleThread* owner)
: Thread (name)
, m_owner (owner)
{
}
InterruptibleThread* InterruptibleThread::ThreadHelper::getOwner () const
{
return m_owner;
}
void InterruptibleThread::ThreadHelper::run ()
{
m_owner->run ();
}
//------------------------------------------------------------------------------
InterruptibleThread::InterruptibleThread (String name)
: m_thread (name, this)
, m_entryPoint (nullptr)
, m_state (stateRun)
{
}
InterruptibleThread::~InterruptibleThread ()
{
m_runEvent.signal ();
join ();
}
void InterruptibleThread::start (EntryPoint* const entryPoint)
{
m_entryPoint = entryPoint;
m_thread.startThread ();
// Prevent data race with member variables
//
m_runEvent.signal ();
}
void InterruptibleThread::join ()
{
m_thread.stopThread (-1);
}
bool InterruptibleThread::wait (int milliSeconds)
{
// Can only be called from the corresponding thread of execution.
//
bassert (isTheCurrentThread ());
bool interrupted = false;
for (;;)
{
bassert (m_state != stateWait);
// See if we are interrupted
//
if (m_state.tryChangeState (stateInterrupt, stateRun))
{
// We were interrupted, state is changed to Run. Caller must run now.
//
interrupted = true;
break;
}
else if (m_state.tryChangeState (stateRun, stateWait) ||
m_state.tryChangeState (stateReturn, stateWait))
{
// Transitioned to wait. Caller must wait now.
//
interrupted = false;
break;
}
}
if (!interrupted)
{
interrupted = m_thread.wait (milliSeconds);
if (!interrupted)
{
if (m_state.tryChangeState (stateWait, stateRun))
{
interrupted = false;
}
else
{
bassert (m_state == stateInterrupt);
interrupted = true;
}
}
}
return interrupted;
}
void InterruptibleThread::interrupt ()
{
for (;;)
{
int const state = m_state;
if (state == stateInterrupt ||
state == stateReturn ||
m_state.tryChangeState (stateRun, stateInterrupt))
{
// Thread will see this at next interruption point.
//
break;
}
else if (m_state.tryChangeState (stateWait, stateRun))
{
m_thread.notify ();
break;
}
}
}
bool InterruptibleThread::interruptionPoint ()
{
// Can only be called from the thread of execution.
//
bassert (isTheCurrentThread ());
if (m_state == stateWait)
{
// It is impossible for this function to be called while in the wait state.
//
Throw (Error ().fail (__FILE__, __LINE__));
}
else if (m_state == stateReturn)
{
// If this goes off it means the thread called the
// interruption a second time after already getting interrupted.
//
Throw (Error ().fail (__FILE__, __LINE__));
}
bool const interrupted = m_state.tryChangeState (stateInterrupt, stateRun);
return interrupted;
}
InterruptibleThread::id InterruptibleThread::getId () const
{
return m_threadId;
}
bool InterruptibleThread::isTheCurrentThread () const
{
return m_thread.getCurrentThreadId () == m_threadId;
}
void InterruptibleThread::setPriority (int priority)
{
m_thread.setPriority (priority);
}
InterruptibleThread* InterruptibleThread::getCurrentThread ()
{
InterruptibleThread* result = nullptr;
Thread* const thread = Thread::getCurrentThread ();
if (thread != nullptr)
{
ThreadHelper* const helper = dynamic_cast <ThreadHelper*> (thread);
bassert (helper != nullptr);
result = helper->getOwner ();
}
return result;
}
void InterruptibleThread::run ()
{
m_threadId = m_thread.getThreadId ();
m_runEvent.wait ();
m_entryPoint->threadRun ();
}
//------------------------------------------------------------------------------
bool CurrentInterruptibleThread::interruptionPoint ()
{
bool interrupted = false;
InterruptibleThread* const interruptibleThread (InterruptibleThread::getCurrentThread ());
bassert (interruptibleThread != nullptr);
interrupted = interruptibleThread->interruptionPoint ();
return interrupted;
}

View File

@@ -1,184 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_INTERRUPTIBLETHREAD_BEASTHEADER
#define BEAST_INTERRUPTIBLETHREAD_BEASTHEADER
//==============================================================================
/**
A thread with soft interruption support.
The thread must periodically call interruptionPoint(), which returns `true`
the first time an interruption has occurred since the last call to
interruptionPoint().
To create a thread, derive your class from InterruptibleThread::EntryPoint
and implement the threadRun() function. Then, call run() with your object.
@ingroup beast_core
*/
class BEAST_API InterruptibleThread
{
public:
/** InterruptibleThread entry point.
*/
class EntryPoint
{
public:
virtual ~EntryPoint () { }
virtual void threadRun () = 0;
};
public:
typedef Thread::ThreadID id;
/** Construct an interruptible thread.
The name is used for debugger diagnostics.
@param name The name of the thread.
*/
explicit InterruptibleThread (String name);
/** Destroy the interruptible thread.
This will signal an interrupt and wait until the thread exits.
*/
~InterruptibleThread ();
/** Start the thread.
*/
void start (EntryPoint* const entryPoint);
/** Wait for the thread to exit.
*/
void join ();
/** Wait for interrupt or timeout.
This call blocks until the thread is interrupted, or until the timeout
expires if milliSeconds is non-negative.
May only be called by the thread of execution.
@param milliSeconds The amount of time to wait. Negative values mean
no timeout.
@return `true` if the interrupt occurred, or `false` if the
timeout expired.
*/
bool wait (int milliSeconds = -1);
/** Interrupt the thread of execution.
This can be called from any thread.
*/
void interrupt ();
/** Determine if an interruption is requested.
After the function returns `true`, the interrupt status is cleared.
Subsequent calls will return `false` until another interrupt is requested.
May only be called by the thread of execution.
@see CurrentInterruptibleThread::interruptionPoint
@return `true` if an interrupt was requested.
*/
bool interruptionPoint ();
/** Get the ID of the associated thread.
@return The ID of the thread.
*/
id getId () const;
/** Determine if this is the thread of execution.
@note The return value is undefined if the thread is not running.
@return `true` if the caller is this thread of execution.
*/
bool isTheCurrentThread () const;
/** Adjust the thread priority.
@note This only affects some platforms.
@param priority A number from 0..10
*/
void setPriority (int priority);
/** Get the InterruptibleThread for the thread of execution.
This will return `nullptr` when called from the message thread, or from
a thread of execution that is not an InterruptibleThread.
*/
static InterruptibleThread* getCurrentThread ();
private:
class ThreadHelper : public Thread
{
public:
ThreadHelper (String name, InterruptibleThread* owner);
InterruptibleThread* getOwner () const;
void run ();
private:
InterruptibleThread* const m_owner;
};
void run ();
ThreadHelper m_thread;
EntryPoint* m_entryPoint;
WaitableEvent m_runEvent;
id m_threadId;
enum
{
stateRun,
stateInterrupt,
stateReturn,
stateWait
};
AtomicState m_state;
};
//------------------------------------------------------------------------------
/** Global operations on the current InterruptibleThread.
Calling members of the class from a thread of execution which is not an
InterruptibleThread results in undefined behavior.
*/
class CurrentInterruptibleThread
{
public:
/** Call the current thread's interrupt point function.
*/
static bool interruptionPoint ();
};
#endif

View File

@@ -1,763 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// CallQueue item to process a Call for a particular listener.
// This is used to avoid bind overhead.
//
class ListenersBase::CallWork : public CallQueue::Work
{
public:
inline CallWork (ListenersBase::Call* const c, void* const listener)
: m_call (c), m_listener (listener)
{
}
void operator () ()
{
m_call->operator () (m_listener);
}
private:
ListenersBase::Call::Ptr m_call;
void* const m_listener;
};
//------------------------------------------------------------------------------
// CallQueue item to process a Call for a group.
// This is used to avoid bind overhead.
//
class ListenersBase::GroupWork : public CallQueue::Work
{
public:
inline GroupWork (Group* group,
ListenersBase::Call* c,
const timestamp_t timestamp)
: m_group (group)
, m_call (c)
, m_timestamp (timestamp)
{
}
void operator () ()
{
m_group->do_call (m_call, m_timestamp);
}
private:
Group::Ptr m_group;
ListenersBase::Call::Ptr m_call;
const timestamp_t m_timestamp;
};
//------------------------------------------------------------------------------
// CallQueue item to process a call for a particular listener.
// This is used to avoid bind overhead.
//
class ListenersBase::GroupWork1 : public CallQueue::Work
{
public:
inline GroupWork1 (Group* group,
ListenersBase::Call* c,
const timestamp_t timestamp,
void* const listener)
: m_group (group)
, m_call (c)
, m_timestamp (timestamp)
, m_listener (listener)
{
}
void operator () ()
{
m_group->do_call1 (m_call, m_timestamp, m_listener);
}
private:
Group::Ptr m_group;
ListenersBase::Call::Ptr m_call;
const timestamp_t m_timestamp;
void* const m_listener;
};
//------------------------------------------------------------------------------
// A Proxy maintains a list of Entry.
// Each Entry holds a group and the current Call (which can be updated).
//
struct ListenersBase::Proxy::Entry : Entries::Node,
SharedObject,
AllocatedBy <AllocatorType>
{
typedef SharedObjectPtr <Entry> Ptr;
explicit Entry (Group* g)
: group (g)
{
}
~Entry ()
{
bassert (call.get () == 0);
}
Group::Ptr group;
AtomicPointer <Call> call;
};
//------------------------------------------------------------------------------
// A Group maintains a list of Entry.
//
struct ListenersBase::Group::Entry : List <Entry>::Node,
AllocatedBy <AllocatorType>
{
Entry (void* const l, const timestamp_t t)
: listener (l)
, timestamp (t)
{
}
void* const listener;
const timestamp_t timestamp;
};
//------------------------------------------------------------------------------
//
// Group
//
//------------------------------------------------------------------------------
// - A list of listeners associated with the same CallQueue.
//
// - The list is only iterated on the CallQueue's thread.
//
// - It is safe to add or remove listeners from the group
// at any time.
//
ListenersBase::Group::Group (CallQueue& callQueue)
: m_fifo (callQueue)
, m_listener (0)
{
}
ListenersBase::Group::~Group ()
{
// If this goes off it means a Listener forgot to remove itself.
bassert (m_list.empty ());
// shouldn't be deleting group during a call
bassert (m_listener == 0);
}
// Add the listener with the given timestamp.
// The listener will only get calls with higher timestamps.
// The caller must prevent duplicates.
//
void ListenersBase::Group::add (void* listener,
const timestamp_t timestamp,
AllocatorType& allocator)
{
ReadWriteMutex::ScopedWriteLockType lock (m_mutex);
bassert (!contains (listener));
// Should never be able to get here while in call()
bassert (m_listener == 0);
// Add the listener and remember the time stamp so we don't
// send it calls that were queued earlier than the add().
m_list.push_back (*new (allocator) Entry (listener, timestamp));
}
// Removes the listener from the group if it exists.
// Returns true if the listener was removed.
//
bool ListenersBase::Group::remove (void* listener)
{
bool found = false;
ReadWriteMutex::ScopedWriteLockType lock (m_mutex);
// Should never be able to get here while in call()
bassert (m_listener == 0);
for (List <Entry>::iterator iter = m_list.begin (); iter != m_list.end (); ++iter)
{
Entry* entry = & (*iter);
if (entry->listener == listener)
{
m_list.erase (m_list.iterator_to (*entry));
delete entry;
found = true;
break;
}
}
return found;
}
// Used for assertions.
// The caller must synchronize.
//
bool ListenersBase::Group::contains (void* const listener) /*const*/
{
for (List <Entry>::iterator iter = m_list.begin (); iter != m_list.end (); iter++)
if (iter->listener == listener)
return true;
return false;
}
void ListenersBase::Group::call (Call* const c, const timestamp_t timestamp)
{
bassert (!empty ());
m_fifo.callp (new (m_fifo.getAllocator ()) GroupWork (this, c, timestamp));
}
void ListenersBase::Group::queue (Call* const c, const timestamp_t timestamp)
{
bassert (!empty ());
m_fifo.queuep (new (m_fifo.getAllocator ()) GroupWork (this, c, timestamp));
}
void ListenersBase::Group::call1 (Call* const c,
const timestamp_t timestamp,
void* const listener)
{
m_fifo.callp (new (m_fifo.getAllocator ()) GroupWork1 (
this, c, timestamp, listener));
}
void ListenersBase::Group::queue1 (Call* const c,
const timestamp_t timestamp,
void* const listener)
{
m_fifo.queuep (new (m_fifo.getAllocator ()) GroupWork1 (
this, c, timestamp, listener));
}
// Queues a reference to the Call on the thread queue of each listener
// that is currently in our list. The thread queue must be in the
// stack's call chain, either directly from CallQueue::synchronize(),
// or from Proxy::do_call() called from CallQueue::synchronize().
//
void ListenersBase::Group::do_call (Call* const c, const timestamp_t timestamp)
{
if (!empty ())
{
ReadWriteMutex::ScopedReadLockType lock (m_mutex);
// Recursion not allowed.
bassert (m_listener == 0);
// The body of the loop MUST NOT cause listeners to get called.
// Therefore, we don't have to worry about listeners removing
// themselves while iterating the list.
//
for (List <Entry>::iterator iter = m_list.begin (); iter != m_list.end ();)
{
Entry* entry = & (*iter++);
// Since it is possible for a listener to be added after a
// Call gets queued but before it executes, this prevents listeners
// from seeing Calls created before they were added.
//
if (timestamp > entry->timestamp)
{
m_listener = entry->listener;
// The thread queue's synchronize() function MUST be in our call
// stack to guarantee that these calls will not execute immediately.
// They will be handled by the tail recusion unrolling in the
// thread queue.
bassert (m_fifo.isBeingSynchronized ());
m_fifo.callp (new (m_fifo.getAllocator ()) CallWork (c, m_listener));
m_listener = 0;
}
}
}
else
{
// last listener was removed before we got here,
// and the parent listener list may have been deleted.
}
}
void ListenersBase::Group::do_call1 (Call* const c, const timestamp_t timestamp,
void* const listener)
{
if (!empty ())
{
ReadWriteMutex::ScopedReadLockType lock (m_mutex);
// Recursion not allowed.
bassert (m_listener == 0);
for (List <Entry>::iterator iter = m_list.begin (); iter != m_list.end ();)
{
Entry* entry = & (*iter++);
if (entry->listener == listener)
{
if (timestamp > entry->timestamp)
{
m_listener = entry->listener;
bassert (m_fifo.isBeingSynchronized ());
m_fifo.callp (new (m_fifo.getAllocator ()) CallWork (c, m_listener));
m_listener = 0;
}
}
}
}
else
{
// Listener was removed
}
}
//------------------------------------------------------------------------------
//
// Proxy
//
//------------------------------------------------------------------------------
// CallQueue item for processing a an Entry for a Proxy.
// This is used to avoid bind overhead.
//
class ListenersBase::Proxy::Work : public CallQueue::Work
{
public:
inline Work (Proxy* proxy,
Entry* const entry,
const timestamp_t timestamp)
: m_entry (entry)
, m_timestamp (timestamp)
{
}
void operator () ()
{
ListenersBase::Call* c = m_entry->call.exchange (0);
Group* group = m_entry->group;
if (!group->empty ())
group->do_call (c, m_timestamp);
c->decReferenceCount ();
}
private:
Entry::Ptr m_entry;
const timestamp_t m_timestamp;
};
// Holds a Call, and gets put in the CallQueue in place of the Call.
// The Call may be replaced if it hasn't been processed yet.
// A Proxy exists for the lifetime of the Listeners.
//
ListenersBase::Proxy::Proxy (void const* const member, const size_t bytes)
: m_bytes (bytes)
{
if (bytes > maxMemberBytes)
Throw (Error ().fail (__FILE__, __LINE__, "the Proxy member is too large"));
memcpy (m_member, member, bytes);
}
ListenersBase::Proxy::~Proxy ()
{
// If the proxy is getting destroyed it means:
// - the listeners object is getting destroyed
// - all listeners must have removed themselves
// - all thread queues have been fully processed
// Therefore, our entries should be gone.
// NO it is possible for an empty Group, for which
// the parent listeners object has been destroyed,
// to still exist in a thread queue!!!
// But all listeners should have removed themselves
// so our list of groups should still be empty.
bassert (m_entries.empty ());
}
// Adds the group to the Proxy.
// Caller must have the proxies mutex.
// Caller is responsible for preventing duplicates.
//
void ListenersBase::Proxy::add (Group* group, AllocatorType& allocator)
{
Entry* entry (new (allocator) Entry (group));
// Manual addref and put raw pointer in list
entry->incReferenceCount ();
m_entries.push_back (*entry);
}
// Removes the group from the Proxy.
// Caller must have the proxies mutex.
// Caller is responsible for making sure the group exists.
void ListenersBase::Proxy::remove (Group* group)
{
for (Entries::iterator iter = m_entries.begin (); iter != m_entries.end ();)
{
Entry* entry = & (*iter++);
if (entry->group == group)
{
// remove from list and manual release
m_entries.erase (m_entries.iterator_to (*entry));
entry->decReferenceCount ();
// Entry might still be in the empty group's thread queue
break;
}
}
}
// For each group, updates the call.
// Queues each group that isn't already queued.
// Caller must acquire the group read lock.
//
void ListenersBase::Proxy::update (Call* const c, const timestamp_t timestamp)
{
// why would we even want to be called?
bassert (!m_entries.empty ());
// With the read lock, this list can't change on us unless someone
// adds a listener to a new thread queue in response to a call.
for (Entries::iterator iter = m_entries.begin (); iter != m_entries.end ();)
{
Entry* entry = & (*iter++);
// Manually add a reference since we use a raw pointer
c->incReferenceCount ();
// Atomically exchange the new call for the old one
Call* old = entry->call.exchange (c);
// If no old call then they need to be queued
if (!old)
{
CallQueue& callQueue = entry->group->getCallQueue ();
callQueue.callp (new (callQueue.getAllocator ()) Work (this, entry, timestamp));
}
else
{
old->decReferenceCount ();
}
}
}
bool ListenersBase::Proxy::match (void const* const member, const size_t bytes) const
{
return m_bytes == bytes && memcmp (member, m_member, bytes) == 0;
}
//------------------------------------------------------------------------------
//
// ListenersBase
//
//------------------------------------------------------------------------------
ListenersBase::ListenersBase ()
: m_timestamp (0)
, m_allocator (AllocatorType::getInstance ())
, m_callAllocator (CallAllocatorType::getInstance ())
{
}
ListenersBase::~ListenersBase ()
{
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
{
Group* group = & (*iter++);
// If this goes off it means a Listener forgot to remove.
bassert (group->empty ());
group->decReferenceCount ();
}
// Proxies are never deleted until here.
for (Proxies::iterator iter = m_proxies.begin (); iter != m_proxies.end ();)
delete & (*iter++);
}
void ListenersBase::add_void (void* const listener, CallQueue& callQueue)
{
ReadWriteMutex::ScopedWriteLockType lock (m_groups_mutex);
#if BEAST_DEBUG
// Make sure the listener has not already been added
// SHOULD USE const_iterator!
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
{
Group* group = & (*iter++);
// We can be in do_call() on another thread now, but it
// doesn't modify the list, and we have the write lock.
bassert (!group->contains (listener));
}
#endif
// See if we already have a Group for this thread queue.
Group::Ptr group;
// SHOULD USE const_iterator
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
{
Group::Ptr cur = & (*iter++);
if (&cur->getCallQueue () == &callQueue)
{
group = cur;
break;
}
}
if (!group)
{
group = new (m_allocator) Group (callQueue);
// Add it to the list, and give it a manual ref
// since the list currently uses raw pointers.
group->incReferenceCount ();
m_groups.push_back (*group);
// Tell existing proxies to add the group
ReadWriteMutex::ScopedReadLockType lock (m_proxies_mutex);
for (Proxies::iterator iter = m_proxies.begin (); iter != m_proxies.end ();)
(iter++)->add (group, *m_allocator);
}
// Add the listener to the group with the current timestamp
group->add (listener, m_timestamp, *m_allocator);
// Increment the timestamp within the mutex so
// future calls will be newer than this listener.
++m_timestamp;
}
void ListenersBase::remove_void (void* const listener)
{
ReadWriteMutex::ScopedWriteLockType lock (m_groups_mutex);
// Make sure the listener exists
#if BEAST_DEBUG
{
bool exists = false;
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
{
Group* group = & (*iter++);
// this should never happen while we hold the mutex
bassert (!group->empty ());
if (group->contains (listener))
{
bassert (!exists); // added twice?
exists = true;
// keep going to make sure there are no empty groups
}
}
bassert (exists);
}
#endif
// Find the group and remove
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
{
Group::Ptr group = & (*iter++);
// If the listener is in there, take it out.
if (group->remove (listener))
{
// Are we the last listener?
if (group->empty ())
{
// Tell proxies to remove the group
{
ReadWriteMutex::ScopedWriteLockType lock (m_proxies_mutex);
for (Proxies::iterator iter = m_proxies.begin (); iter != m_proxies.end ();)
{
Proxy* proxy = & (*iter++);
proxy->remove (group);
}
}
// Remove it from the list and manually release
// the reference since the list uses raw pointers.
m_groups.erase (m_groups.iterator_to (*group.getObject ()));
group->decReferenceCount ();
// It is still possible for the group to exist at this
// point in a thread queue but it will get processed,
// do nothing, and release its own final reference.
}
break;
}
}
}
void ListenersBase::callp (Call::Ptr cp)
{
Call* c = cp;
ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex);
// can't be const iterator because queue() might cause called functors
// to modify the list.
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
(iter++)->call (c, m_timestamp);
}
void ListenersBase::queuep (Call::Ptr cp)
{
Call* c = cp;
ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex);
// can't be const iterator because queue() might cause called functors
// to modify the list.
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
(iter++)->queue (c, m_timestamp);
}
void ListenersBase::call1p_void (void* const listener, Call* c)
{
ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex);
// can't be const iterator because queue() might cause called functors
// to modify the list.
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
{
Group* group = & (*iter++);
if (group->contains (listener))
{
group->call1 (c, m_timestamp, listener);
break;
}
}
}
void ListenersBase::queue1p_void (void* const listener, Call* c)
{
ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex);
// can't be const iterator because queue() might cause called functors
// to modify the list.
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
{
Group* group = & (*iter++);
if (group->contains (listener))
{
group->queue1 (c, m_timestamp, listener);
break;
}
}
}
// Search for an existing Proxy that matches the pointer to
// member and replace it's Call, or create a new Proxy for it.
//
void ListenersBase::updatep (void const* const member,
const size_t bytes, Call::Ptr cp)
{
Call* c = cp;
ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex);
if (!m_groups.empty ())
{
Proxy* proxy;
{
ReadWriteMutex::ScopedReadLockType lock (m_proxies_mutex);
// See if there's already a proxy
proxy = find_proxy (member, bytes);
}
// Possibly create one
if (!proxy)
{
ReadWriteMutex::ScopedWriteLockType lock (m_proxies_mutex);
// Have to search for it again in case someone else added it
proxy = find_proxy (member, bytes);
if (!proxy)
{
// Create a new empty proxy
proxy = new (m_allocator) Proxy (member, bytes);
// Add all current groups to the Proxy.
// We need the group read lock for this (caller provided).
for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();)
{
Group* group = & (*iter++);
proxy->add (group, *m_allocator);
}
// Add it to the list.
m_proxies.push_front (*proxy);
}
}
// Requires the group read lock
proxy->update (c, m_timestamp);
}
}
// Searches for a proxy that matches the pointer to member.
// Caller synchronizes.
//
ListenersBase::Proxy* ListenersBase::find_proxy (const void* member, size_t bytes)
{
for (Proxies::iterator iter = m_proxies.begin (); iter != m_proxies.end ();)
{
Proxy* proxy = & (*iter++);
if (proxy->match (member, bytes))
return proxy;
}
return 0;
}

View File

@@ -1,797 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_LISTENERS_BEASTHEADER
#define BEAST_LISTENERS_BEASTHEADER
/*============================================================================*/
/**
A group of concurrent Listeners.
A Listener is an object of class type which inherits from a defined
interface, and registers on a provided instance of Listeners to receive
asynchronous notifications of changes to concurrent states. Another way of
defining Listeners, is that it is similar to a Juce ListenerList but with
the provision that the Listener registers with the CallQueue upon which the
notification should be made.
Listeners makes extensive use of CallQueue for providing the notifications,
and provides a higher level facility for implementing the concurrent
synchronization strategy outlined in CallQueue. Therefore, the same notes
which apply to functors in CallQueue also apply to Listener member
invocations. Their execution time should be brief, limited in scope to
updating the recipient's view of a shared state, and use reference counting
for parameters of class type.
To use this system, first declare your Listener interface:
@code
struct Listener
{
// Sent on every output block
virtual void onOutputLevelChanged (const float outputLevel) { }
};
@endcode
Now set up the place where you want to send the notifications. In this
example, we will set up the AudioIODeviceCallback to notify anyone who is
interested about changes in the current audio output level. We will use
this to implement a VU meter:
@code
Listeners <Listener> listeners;
// (Process audio data)
// Calculate output level
float outputLevel = calcOutputLevel ();
// Notify listeners
listeners.call (&Listener::onOutputLevelChanged, outputLevel);
@endcode
To receive notifications, derive from Listener and then add yourself to the
Listeners object using the desired CallQueue.
@code
// We want notifications on the message thread
GuiCallQueue fifo;
struct VUMeter : public Listener, public Component
{
VUMeter () : m_outputLevel (0)
{
listeners.add (this, fifo);
}
~VUMeter ()
{
listeners.remove (this);
}
void onOutputLevelChanged (float outputLevel)
{
// Update our copy of the output level shared state.
m_outputLevel = outputLevel;
// Now trigger a redraw of the control.
repaint ();
}
float m_outputLevel;
};
@endcode
In this example, the VUMeter constructs with the output level set to zero,
and must wait for a notification before it shows up to date data. For a
simple VU meter, this is likely not a problem. But if the shared state
contains complex information, such as dynamically allocated objects with
rich data, then we need a more solid system.
We will add some classes to create a complete robust example of the use of
Listeners to synchronize shared state:
@code
// Handles audio device output.
class AudioDeviceOutput : public AudioIODeviceCallback
{
public:
struct Listener
{
// Sent on every output block.
virtual void onOutputLevelChanged (float outputLevel) { }
};
AudioDeviceOutput () : AudioDeviceOutput ("Audio CallQueue")
{
}
~AudioDeviceOutput ()
{
m_fifo.close ();
}
void addListener (Listener* listener, CallQueue& callQueue)
{
// Acquire read access to the shared state.
SharedData <State>::ReadAccess state (m_state);
// Add the listener.
m_listeners.add (listener, callQueue);
// Queue an update for the listener to receive the initial state.
m_listeners.queue1 (listener,
&Listener::onOutputLevelChanged,
state->outputLevel);
}
void removeListener (Listener* listener)
{
m_listeners.remove (listener);
}
protected:
void audioDeviceIOCallback (const float** inputChannelData,
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples)
{
// Synchronize our call queue. Not needed for this example but
// included here as a best-practice for audio device I/O callbacks.
m_fifo.synchronize ();
// (Process audio data)
// Calculate output level.
float newOutputLevel = calcOutputLevel ();
// Update shared state.
{
SharedData <State>::WriteAccess state (m_state);
m_state->outputLevel = newOutputLevel;
}
// Notify listeners.
listeners.call (&Listener::onOutputLevelChanged, newOutputLevel);
}
private:
struct State
{
State () : outputLevel (0) { }
float outputLevel;
};
SharedData <State> m_state;
ManualCallQueue m_fifo;
};
@endcode
Although the rigor demonstrated in the example above is not strictly
required when the shared state consists only of a single float, it
becomes necessary when there are dynamically allocated objects with complex
interactions in the shared state.
@see CallQueue
@class Listeners
@ingroup beast_concurrent
*/
class BEAST_API ListenersBase
{
public:
struct ListenersStructureTag { };
typedef GlobalFifoFreeStore <ListenersStructureTag> AllocatorType;
typedef GlobalFifoFreeStore <ListenersBase> CallAllocatorType;
class Call : public SharedObject,
public AllocatedBy <CallAllocatorType>
{
public:
typedef SharedObjectPtr <Call> Ptr;
virtual void operator () (void* const listener) = 0;
};
private:
typedef unsigned long timestamp_t;
class Group;
typedef List <Group> Groups;
class Proxy;
typedef List <Proxy> Proxies;
class CallWork;
class GroupWork;
class GroupWork1;
// Maintains a list of listeners registered on the same CallQueue
//
class Group : public Groups::Node,
public SharedObject,
public AllocatedBy <AllocatorType>
{
public:
typedef SharedObjectPtr <Group> Ptr;
explicit Group (CallQueue& callQueue);
~Group ();
void add (void* listener, const timestamp_t timestamp,
AllocatorType& allocator);
bool remove (void* listener);
bool contains (void* const listener);
void call (Call* const c, const timestamp_t timestamp);
void queue (Call* const c, const timestamp_t timestamp);
void call1 (Call* const c, const timestamp_t timestamp,
void* const listener);
void queue1 (Call* const c, const timestamp_t timestamp,
void* const listener);
void do_call (Call* const c, const timestamp_t timestamp);
void do_call1 (Call* const c, const timestamp_t timestamp,
void* const listener);
bool empty () const
{
return m_list.empty ();
}
CallQueue& getCallQueue () const
{
return m_fifo;
}
private:
struct Entry;
CallQueue& m_fifo;
List <Entry> m_list;
void* m_listener;
CacheLine::Aligned <ReadWriteMutex> m_mutex;
};
// A Proxy is keyed to a unique pointer-to-member of a
// ListenerClass and is used to consolidate multiple unprocessed
// Calls into a single call to prevent excess messaging. It is up
// to the user of the class to decide when this behavior is appropriate.
//
class Proxy : public Proxies::Node,
public AllocatedBy <AllocatorType>
{
public:
enum
{
maxMemberBytes = 16
};
Proxy (void const* const member, const size_t bytes);
~Proxy ();
void add (Group* group, AllocatorType& allocator);
void remove (Group* group);
void update (Call* const c, const timestamp_t timestamp);
bool match (void const* const member, const size_t bytes) const;
private:
class Work;
struct Entry;
typedef List <Entry> Entries;
char m_member [maxMemberBytes];
const size_t m_bytes;
Entries m_entries;
};
protected:
ListenersBase ();
~ListenersBase ();
inline CallAllocatorType& getCallAllocator ()
{
return *m_callAllocator;
}
void add_void (void* const listener, CallQueue& callQueue);
void remove_void (void* const listener);
void callp (Call::Ptr c);
void queuep (Call::Ptr c);
void call1p_void (void* const listener, Call* c);
void queue1p_void (void* const listener, Call* c);
void updatep (void const* const member,
const size_t bytes, Call::Ptr cp);
private:
Proxy* find_proxy (const void* member, size_t bytes);
private:
Groups m_groups;
Proxies m_proxies;
timestamp_t m_timestamp;
CacheLine::Aligned <ReadWriteMutex> m_groups_mutex;
CacheLine::Aligned <ReadWriteMutex> m_proxies_mutex;
AllocatorType::Ptr m_allocator;
CallAllocatorType::Ptr m_callAllocator;
};
/*============================================================================*/
template <class ListenerClass>
class Listeners : public ListenersBase
{
private:
template <class Functor>
class CallType : public Call
{
public:
CallType (Functor f) : m_f (f)
{
}
void operator () (void* const listener)
{
ListenerClass* object = static_cast <ListenerClass*> (listener);
m_f.operator () (object);
}
private:
Functor m_f;
};
template <class Functor>
inline void callf (Functor f)
{
callp (new (getCallAllocator ()) CallType <Functor> (f));
}
template <class Functor>
inline void queuef (Functor f)
{
queuep (new (getCallAllocator ()) CallType <Functor> (f));
}
inline void call1p (ListenerClass* const listener, Call::Ptr c)
{
call1p_void (listener, c);
}
inline void queue1p (ListenerClass* const listener, Call::Ptr c)
{
queue1p_void (listener, c);
}
template <class Functor>
inline void call1f (ListenerClass* const listener, Functor f)
{
call1p (listener, new (getCallAllocator ()) CallType <Functor> (f));
}
template <class Functor>
inline void queue1f (ListenerClass* const listener, Functor f)
{
queue1p (listener, new (getCallAllocator ()) CallType <Functor> (f));
}
template <class Member, class Functor>
inline void updatef (Member member, Functor f)
{
updatep (reinterpret_cast <void*> (&member), sizeof (Member),
new (getCallAllocator ()) CallType <Functor> (f));
}
public:
/** Add a listener.
The specified listener is associated with the specified CallQueue and
added to the list.
Invariants:
- All other members of Listeners are blocked during add().
- The listener is guaranteed to receive every subsequent call.
- The listener must not already exist in the list.
- Safe to call from any thread.
@param listener The listener to add.
@param callQueue The CallQueue to associate with the listener.
*/
void add (ListenerClass* const listener, CallQueue& callQueue)
{
add_void (listener, callQueue);
}
/** Remove a listener.
The specified listener, which must have been previously added, is removed
from the list. A listener always needs to remove itself before the
associated CallQueue is closed.
Invariants:
- All other members of Listeners are blocked during remove().
- The listener is guaranteed not to receive calls after remove() returns.
- Safe to call from any thread.
@param listener The listener to remove.
*/
void remove (ListenerClass* const listener)
{
remove_void (listener);
}
/** Call a member function on every added listener, on its associated
CallQueue.
A listener's CallQueue will be synchronized if this function is called
from it's associated thread.
Invariants:
- A listener that later removes itself afterwards may not get called.
- Calls from the same thread always execute in order.
- A listener can remove itself even if it has a pending call.
@param mf The member function to call. This may be followed by up to 8
arguments.
*/
/** @{ */
#if BEAST_VARIADIC_MAX >= 1
template <class Mf>
inline void call (Mf mf)
{ callf (functional::bind (mf, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Mf, class T1>
void call (Mf mf, T1 t1)
{ callf (functional::bind (mf, placeholders::_1, t1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Mf, class T1, class T2>
void call (Mf mf, T1 t1, T2 t2)
{ callf (functional::bind (mf, placeholders::_1, t1, t2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Mf, class T1, class T2, class T3>
void call (Mf mf, T1 t1, T2 t2, T3 t3)
{ callf (functional::bind (mf, placeholders::_1, t1, t2, t3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Mf, class T1, class T2, class T3, class T4>
void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4)
{ callf (functional::bind (mf, placeholders::_1, t1, t2, t3, t4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Mf, class T1, class T2, class T3, class T4, class T5>
void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ callf (functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ callf (functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ callf (functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ callf (functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7, t8)); }
#endif
/** @} */
/** Queue a member function on every added listener, without synchronizing.
Operates like call(), but no CallQueue synchronization takes place. This
can be necessary when the call to queue() is made inside a held lock.
@param mf The member function to call. This may be followed by up to 8
arguments.
*/
/** @{ */
#if BEAST_VARIADIC_MAX >= 1
template <class Mf>
inline void queue (Mf mf)
{ queuef (functional::bind (mf, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Mf, class T1>
void queue (Mf mf, T1 t1)
{ queuef (functional::bind (mf, placeholders::_1, t1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Mf, class T1, class T2>
void queue (Mf mf, T1 t1, T2 t2)
{ queuef (functional::bind (mf, placeholders::_1, t1, t2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Mf, class T1, class T2, class T3>
void queue (Mf mf, T1 t1, T2 t2, T3 t3)
{ queuef (functional::bind (mf, placeholders::_1, t1, t2, t3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Mf, class T1, class T2, class T3, class T4>
void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4)
{ queuef (functional::bind (mf, placeholders::_1, t1, t2, t3, t4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Mf, class T1, class T2, class T3, class T4, class T5>
void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ queuef (functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ queuef (functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ queuef (functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ queuef (functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7, t8)); }
#endif
/** @} */
/** Call a member function on every added listener, replacing pending
calls to the same member.
This operates like call(), except that if there are pending unprocessed
calls to the same member function,they will be replaced, with the previous
parameters destroyed normally. This functionality is useful for
high frequency notifications of non critical data, where the recipient
may not catch up often enough. For example, the output level of the
AudioIODeviceCallback in the example is a candidate for the use of
update().
@param mf The member function to call. This may be followed by up to 8
arguments.
*/
/** @{ */
#if BEAST_VARIADIC_MAX >= 1
template <class Mf>
inline void update (Mf mf)
{ updatef (mf, functional::bind (mf, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Mf, class T1>
void update (Mf mf, T1 t1)
{ updatef (mf, functional::bind (mf, placeholders::_1, t1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Mf, class T1, class T2>
void update (Mf mf, T1 t1, T2 t2)
{ updatef (mf, functional::bind (mf, placeholders::_1, t1, t2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Mf, class T1, class T2, class T3>
void update (Mf mf, T1 t1, T2 t2, T3 t3)
{ updatef (mf, functional::bind (mf, placeholders::_1, t1, t2, t3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Mf, class T1, class T2, class T3, class T4>
void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4)
{ updatef (mf, functional::bind (mf, placeholders::_1, t1, t2, t3, t4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Mf, class T1, class T2, class T3, class T4, class T5>
void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ updatef (mf, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ updatef (mf, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ updatef (mf, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ updatef (mf, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7, t8)); }
#endif
/** @} */
/** Call a member function on a specific listener.
Like call(), except that one listener is targeted only. This is useful when
builing complex behaviors during the addition of a listener, such as
providing an initial state.
@param listener The listener to call.
@param mf The member function to call. This may be followed by up
to 8 arguments.
*/
/** @{ */
#if BEAST_VARIADIC_MAX >= 1
template <class Mf>
inline void call1 (ListenerClass* const listener, Mf mf)
{ call1f (listener, functional::bind (mf, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Mf, class T1>
void call1 (ListenerClass* const listener, Mf mf, T1 t1)
{ call1f (listener, functional::bind (mf, placeholders::_1, t1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Mf, class T1, class T2>
void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2)
{ call1f (listener, functional::bind (mf, placeholders::_1, t1, t2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Mf, class T1, class T2, class T3>
void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3)
{ call1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Mf, class T1, class T2, class T3, class T4>
void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4)
{ call1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Mf, class T1, class T2, class T3, class T4, class T5>
void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ call1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ call1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ call1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ call1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7, t8)); }
#endif
/** @} */
/** Queue a member function on a specific listener.
Like call1(), except that no CallQueue synchronization takes place.
@param listener The listener to call.
@param mf The member function to call. This may be followed by up
to 8 arguments.
*/
/** @{ */
#if BEAST_VARIADIC_MAX >= 1
template <class Mf>
inline void queue1 (ListenerClass* const listener, Mf mf)
{ queue1f (listener, functional::bind (mf, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Mf, class T1>
void queue1 (ListenerClass* const listener, Mf mf, T1 t1)
{ queue1f (listener, functional::bind (mf, placeholders::_1, t1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Mf, class T1, class T2>
void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2)
{ queue1f (listener, functional::bind (mf, placeholders::_1, t1, t2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Mf, class T1, class T2, class T3>
void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3)
{ queue1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Mf, class T1, class T2, class T3, class T4>
void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4)
{ queue1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Mf, class T1, class T2, class T3, class T4, class T5>
void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ queue1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ queue1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ queue1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ queue1f (listener, functional::bind (mf, placeholders::_1, t1, t2, t3, t4, t5, t6, t7, t8)); }
#endif
/** @} */
};
/** @} */
#endif

View File

@@ -1,54 +0,0 @@
/*============================================================================*/
/*
VFLib: https://github.com/vinniefalco/VFLib
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
This library contains portions of other open source products covered by
separate licenses. Please see the corresponding source files for specific
terms.
VFLib is provided under the terms of The MIT License (MIT):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
/*============================================================================*/
ManualCallQueue::ManualCallQueue (String name)
: CallQueue (name)
{
}
void ManualCallQueue::close ()
{
CallQueue::close ();
}
bool ManualCallQueue::synchronize ()
{
return CallQueue::synchronize ();
}
void ManualCallQueue::signal ()
{
}
void ManualCallQueue::reset ()
{
}

View File

@@ -1,108 +0,0 @@
/*============================================================================*/
/*
VFLib: https://github.com/vinniefalco/VFLib
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
This library contains portions of other open source products covered by
separate licenses. Please see the corresponding source files for specific
terms.
VFLib is provided under the terms of The MIT License (MIT):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
/*============================================================================*/
#ifndef VF_MANUALCALLQUEUE_VFHEADER
#define VF_MANUALCALLQUEUE_VFHEADER
/*============================================================================*/
/**
A CallQueue that requires periodic manual synchronization.
To use this, declare an instance and then place calls into it as usual.
Every so often, you must call synchronize() from the thread you want to
associate with the queue. Typically this is done within an
AudioIODeviceCallback:
@code
class AudioIODeviceCallbackWithCallQueue
: public AudioIODeviceCallback
, public CallQueue
{
public:
AudioIODeviceCallbackWithCallQueue () : m_fifo ("Audio CallQueue")
{
}
void audioDeviceIOCallback (const float** inputChannelData,
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples)
{
CallQueue::synchronize ();
// do audio i/o
}
void signal () { } // No action required
void reset () { } // No action required
};
@endcode
The close() function is provided for diagnostics. Call it as early as
possible based on the exit or shutdown logic of your application. If calls
are put into the queue after it is closed, it will generate an exception so
you can track it down.
@see CallQueue
@ingroup vf_concurrent
*/
class ManualCallQueue : public CallQueue
{
public:
/** Create a ManualCallQueue.
@param name A string used to help identify the associated
thread for debugging.
*/
explicit ManualCallQueue (String name);
/** Close the queue. If calls are placed into a closed queue, an exception
is thrown.
*/
void close ();
/** Synchronize the queue by calling all pending functors.
@return `true` if any functors were called.
*/
bool synchronize ();
private:
void signal ();
void reset ();
};
#endif

View File

@@ -1,63 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
ParallelFor::ParallelFor (ThreadGroup& pool)
: m_pool (pool)
, m_finishedEvent (false) // auto-reset
{
}
int ParallelFor::getNumberOfThreads () const
{
return m_pool.getNumberOfThreads ();
}
void ParallelFor::doLoop (int numberOfIterations, Iteration& iteration)
{
if (numberOfIterations > 1)
{
int const numberOfThreads = m_pool.getNumberOfThreads ();
// The largest number of pool threads we need is one less than the number
// of iterations, because we also run the loop body on the caller's thread.
//
int const maxThreads = numberOfIterations - 1;
// Calculate the number of parallel instances as the smaller of the number
// of threads available (including the caller's) and the number of iterations.
//
int const numberOfParallelInstances = std::min (
numberOfThreads + 1, numberOfIterations);
LoopState* loopState (new (m_pool.getAllocator ()) LoopState (
iteration, m_finishedEvent, numberOfIterations, numberOfParallelInstances));
m_pool.call (maxThreads, &LoopState::forLoopBody, loopState);
// Also use the caller's thread to run the loop body.
loopState->forLoopBody ();
m_finishedEvent.wait ();
}
else if (numberOfIterations == 1)
{
// Just one iteration, so do it.
iteration (0);
}
}

View File

@@ -1,251 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_PARALLELFOR_BEASTHEADER
#define BEAST_PARALLELFOR_BEASTHEADER
/*============================================================================*/
/**
Parallel for loop.
This uses a ThreadGroup to iterate through a for loop in parallel. The
following two pieces of code perform identical operations:
@code
extern void function (int loopIndex);
// Serial computation
//
for (int i = 0; i < numberOfIterations; ++i)
function (i);
// Parallel computation
//
ParallelFor().loop (numberOfIterations, &function);
@endcode
`function` is a caller provided functor. Convenience functions are provided
for automatic binding to member or non member functions with up to 8
arguments (not including the loop index).
@note The last argument to function () is always the loop index.
@see ThreadGroup
@ingroup beast_concurrent
*/
class BEAST_API ParallelFor : public Uncopyable
{
public:
/** Create a parallel for loop.
It is best to keep this object around instead of creating and destroying
it every time you need to run a loop.
@param pool The ThreadGroup to use. If this is omitted then a singleton
ThreadGroup is used which contains one thread per CPU.
*/
explicit ParallelFor (ThreadGroup& pool = *GlobalThreadGroup::getInstance ());
/** Determine the number of threads in the group.
@return The number of threads in the group.
*/
int getNumberOfThreads () const;
/** Execute parallel for loop.
Functor is called once for each value in the range
[0, numberOfIterations), using the ThreadGroup.
@param numberOfIterations The number of times to loop.
@param f The functor to call for each loop index.
*/
/** @{ */
template <class Functor>
void loopf (int numberOfIterations, Functor const& f)
{
IterationType <Functor> iteration (f);
doLoop (numberOfIterations, iteration);
}
#if BEAST_VARIADIC_MAX >= 1
template <class Fn>
void loop (int n, Fn f)
{ loopf (n, functional::bind (f, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Fn, class T1>
void loop (int n, Fn f, T1 t1)
{ loopf (n, functional::bind (f, t1, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Fn, class T1, class T2>
void loop (int n, Fn f, T1 t1, T2 t2)
{ loopf (n, functional::bind (f, t1, t2, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Fn, class T1, class T2, class T3>
void loop (int n, Fn f, T1 t1, T2 t2, T3 t3)
{ loopf (n, functional::bind (f, t1, t2, t3, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Fn, class T1, class T2, class T3, class T4>
void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4)
{ loopf (n, functional::bind (f, t1, t2, t3, t4, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Fn, class T1, class T2, class T3, class T4, class T5>
void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ loopf (n, functional::bind (f, t1, t2, t3, t4, t5, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6>
void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ loopf (n, functional::bind (f, t1, t2, t3, t4, t5, t6, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ loopf (n, functional::bind (f, t1, t2, t3, t4, t5, t6, t7, placeholders::_1)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ loopf (n, functional::bind (f, t1, t2, t3, t4, t5, t6, t7, t8, placeholders::_1)); }
#endif
/** @} */
private:
class Iteration
{
public:
virtual ~Iteration () { }
virtual void operator () (int loopIndex) = 0;
};
template <class Functor>
class IterationType : public Iteration, public Uncopyable
{
public:
explicit IterationType (Functor const& f) : m_f (f)
{
}
void operator () (int loopIndex)
{
m_f (loopIndex);
}
private:
Functor m_f;
};
private:
class LoopState
: public AllocatedBy <ThreadGroup::AllocatorType>
, public Uncopyable
{
private:
Iteration& m_iteration;
WaitableEvent& m_finishedEvent;
int const m_numberOfIterations;
Atomic <int> m_loopIndex;
Atomic <int> m_iterationsRemaining;
Atomic <int> m_numberOfParallelInstances;
public:
LoopState (Iteration& iteration,
WaitableEvent& finishedEvent,
int numberOfIterations,
int numberOfParallelInstances)
: m_iteration (iteration)
, m_finishedEvent (finishedEvent)
, m_numberOfIterations (numberOfIterations)
, m_loopIndex (-1)
, m_iterationsRemaining (numberOfIterations)
, m_numberOfParallelInstances (numberOfParallelInstances)
{
}
~LoopState ()
{
}
void forLoopBody ()
{
for (;;)
{
// Request a loop index to process.
int const loopIndex = ++m_loopIndex;
// Is it in range?
if (loopIndex < m_numberOfIterations)
{
// Yes, so process it.
m_iteration (loopIndex);
// Was this the last work item to complete?
if (--m_iterationsRemaining == 0)
{
// Yes, signal.
m_finishedEvent.signal ();
break;
}
}
else
{
// Out of range, all work is complete or assigned.
break;
}
}
release ();
}
void release ()
{
if (--m_numberOfParallelInstances == 0)
delete this;
}
};
private:
void doLoop (int numberOfIterations, Iteration& iteration);
private:
ThreadGroup& m_pool;
WaitableEvent m_finishedEvent;
Atomic <int> m_currentIndex;
Atomic <int> m_numberOfInstances;
};
#endif

View File

@@ -1,98 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
ReadWriteMutex::ReadWriteMutex () noexcept
{
}
ReadWriteMutex::~ReadWriteMutex () noexcept
{
}
void ReadWriteMutex::enterRead () const noexcept
{
for (;;)
{
// attempt the lock optimistically
// THIS IS NOT CACHE-FRIENDLY!
m_readers->addref ();
// is there a writer?
// THIS IS NOT CACHE-FRIENDLY!
if (m_writes->isSignaled ())
{
// a writer exists, give up the read lock
m_readers->release ();
// block until the writer is done
{
CriticalSection::ScopedLockType lock (m_mutex);
}
// now try the loop again
}
else
{
break;
}
}
}
void ReadWriteMutex::exitRead () const noexcept
{
m_readers->release ();
}
void ReadWriteMutex::enterWrite () const noexcept
{
// Optimistically acquire the write lock.
m_writes->addref ();
// Go for the mutex.
// Another writer might block us here.
m_mutex.enter ();
// Only one competing writer will get here,
// but we don't know who, so we have to drain
// readers no matter what. New readers will be
// blocked by the mutex.
//
if (m_readers->isSignaled ())
{
SpinDelay delay;
do
{
delay.pause ();
}
while (m_readers->isSignaled ());
}
}
void ReadWriteMutex::exitWrite () const noexcept
{
// Releasing the mutex first and then decrementing the
// writer count allows another waiting writer to atomically
// acquire the lock, thus starving readers. This fulfills
// the write-preferencing requirement.
m_mutex.exit ();
m_writes->release ();
}

View File

@@ -1,150 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_READWRITEMUTEX_BEASTHEADER
#define BEAST_READWRITEMUTEX_BEASTHEADER
/*============================================================================*/
/**
Multiple consumer, single producer (MCSP) synchronization.
This is an optimized lock for the multiple reader, single writer
scenario. It provides only a subset of features of the more general
traditional read/write lock. Specifically, these rules apply:
- A caller cannot hold a read lock while acquiring a write lock.
- Write locks are only recursive with respect to write locks.
- Read locks are only recursive with respect to read locks.
- A write lock cannot be downgraded.
- Writes are preferenced over reads.
For real-time applications, these restrictions are often not an issue.
The implementation is wait-free in the fast path: acquiring read access
for a lock without contention - just one interlocked increment!
@class ReadWriteMutex
@ingroup beast_concurrent
*/
//------------------------------------------------------------------------------
/**
Scoped read lock for ReadWriteMutex.
@ingroup beast_concurrent
*/
template <class LockType>
struct GenericScopedReadLock : public Uncopyable
{
inline explicit GenericScopedReadLock (LockType const& lock) noexcept
:
m_lock (lock)
{
m_lock.enterRead ();
}
inline ~GenericScopedReadLock () noexcept
{
m_lock.exitRead ();
}
private:
LockType const& m_lock;
};
//------------------------------------------------------------------------------
/**
Scoped write lock for ReadWriteMutex.
@ingroup beast_concurrent
*/
template <class LockType>
struct GenericScopedWriteLock : public Uncopyable
{
inline explicit GenericScopedWriteLock (LockType const& lock) noexcept
:
m_lock (lock)
{
m_lock.enterWrite ();
}
inline ~GenericScopedWriteLock () noexcept
{
m_lock.exitWrite ();
}
private:
LockType const& m_lock;
};
//------------------------------------------------------------------------------
class BEAST_API ReadWriteMutex
{
public:
/** Provides the type of scoped read lock to use with a ReadWriteMutex. */
typedef GenericScopedReadLock <ReadWriteMutex> ScopedReadLockType;
/** Provides the type of scoped write lock to use with a ReadWriteMutex. */
typedef GenericScopedWriteLock <ReadWriteMutex> ScopedWriteLockType;
/** Create a ReadWriteMutex */
ReadWriteMutex () noexcept;
/** Destroy a ReadWriteMutex
If the object is destroyed while a lock is held, the result is
undefined behavior.
*/
~ReadWriteMutex () noexcept;
/** Acquire a read lock.
This is recursive with respect to other read locks. Calling this while
holding a write lock is undefined.
*/
void enterRead () const noexcept;
/** Release a previously acquired read lock */
void exitRead () const noexcept;
/** Acquire a write lock.
This is recursive with respect to other write locks. Calling this while
holding a read lock is undefined.
*/
void enterWrite () const noexcept;
/** Release a previously acquired write lock */
void exitWrite () const noexcept;
private:
CriticalSection m_mutex;
mutable CacheLine::Padded <AtomicCounter> m_writes;
mutable CacheLine::Padded <AtomicCounter> m_readers;
};
#endif

View File

@@ -1,125 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
Semaphore::Semaphore (int initialCount)
: m_counter (initialCount)
{
}
Semaphore::~Semaphore ()
{
// Can't delete the semaphore while threads are waiting on it!!
bassert (m_waitingThreads.pop_front () == nullptr);
for (;;)
{
WaitingThread* waitingThread = m_deleteList.pop_front ();
if (waitingThread != nullptr)
delete waitingThread;
else
break;
}
}
void Semaphore::signal (int amount)
{
bassert (amount > 0);
while (amount--)
{
// Make counter and list operations atomic.
LockType::ScopedLockType lock (m_mutex);
if (++m_counter <= 0)
{
WaitingThread* waitingThread = m_waitingThreads.pop_front ();
bassert (waitingThread != nullptr);
waitingThread->signal ();
}
}
}
bool Semaphore::wait (int timeOutMilliseconds)
{
bool signaled = true;
// Always prepare the WaitingThread object first, either
// from the delete list or through a new allocation.
//
WaitingThread* waitingThread = m_deleteList.pop_front ();
if (waitingThread == nullptr)
waitingThread = new WaitingThread;
{
// Make counter and list operations atomic.
LockType::ScopedLockType lock (m_mutex);
if (--m_counter >= 0)
{
// Acquired the resource so put waitingThread back.
m_deleteList.push_front (waitingThread);
waitingThread = nullptr;
}
else
{
// Out of resources, go on to the waiting list.
m_waitingThreads.push_front (waitingThread);
}
}
// Do we need to wait?
if (waitingThread != nullptr)
{
// Yes so do it.
signaled = waitingThread->wait (timeOutMilliseconds);
// If the wait is satisfied, then we've been taken off the
// waiting list so put waitingThread back in the delete list.
//
m_deleteList.push_front (waitingThread);
}
return signaled;
}
//------------------------------------------------------------------------------
Semaphore::WaitingThread::WaitingThread ()
: m_event (false) // auto-reset
{
}
bool Semaphore::WaitingThread::wait (int timeOutMilliseconds)
{
return m_event.wait (timeOutMilliseconds);
}
void Semaphore::WaitingThread::signal ()
{
m_event.signal ();
}
//------------------------------------------------------------------------------
// VFALCO TODO Unit Tests!

View File

@@ -1,82 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SEMAPHORE_BEASTHEADER
#define BEAST_SEMAPHORE_BEASTHEADER
/*============================================================================*/
/**
A semaphore.
This provides a traditional semaphore synchronization primitive. There is no
upper limit on the number of signals.
@note There is no tryWait() or timeout facility for acquiring a resource.
@ingroup beast_core
*/
class BEAST_API Semaphore
{
public:
/** Create a semaphore with the specified number of resources.
@param initialCount The starting number of resources.
*/
explicit Semaphore (int initialCount = 0);
~Semaphore ();
/** Increase the number of available resources.
@param amount The number of new resources available.
*/
void signal (int amount = 1);
/** Wait for a resource.
A negative time-out value means that the method will wait indefinitely.
@returns true if the event has been signalled, false if the timeout expires.
*/
bool wait (int timeOutMilliseconds = -1);
private:
class WaitingThread
: public LockFreeStack <WaitingThread>::Node
, LeakChecked <WaitingThread>
{
public:
WaitingThread ();
bool wait (int timeOutMilliseconds);
void signal ();
private:
WaitableEvent m_event;
};
typedef SpinLock LockType;
LockType m_mutex;
Atomic <int> m_counter;
LockFreeStack <WaitingThread> m_waitingThreads;
LockFreeStack <WaitingThread> m_deleteList;
};
#endif

View File

@@ -1,295 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SHAREDDATA_H_INCLUDED
#define BEAST_SHAREDDATA_H_INCLUDED
/** Structured access to a shared state.
This template wraps an object containing members representing state
information shared between multiple threads of execution, where any thread
may need to read or write as needed. Synchronized access to the concurrent
state is enforced at compile time through strongly typed accessor classes.
This interface design facilitates source code pattern matching to find all
areas where a concurrent state is accessed.
There are three types of access:
- ReadAccess
Allows read access to the underlying object as `const`. ReadAccess may
be granted to one or more threads simultaneously. If one or more
threads have ReadAccess, requests to obtain WriteAccess are blocked.
- WriteAccess
Allows exclusive read/write access the underlying object. A WriteAccess
request blocks until all existing ReadAccess and WriteAccess requests
are released. While a WriteAccess exists, requests for ReadAccess
will block.
- UnlockedAccess
Allows read access to the underlying object without using the lock.
This can be helpful when designing concurrent structures through
composition. It also makes it easier to search for places in code
which use unlocked access.
This code example demonstrates various forms of access to a SharedData:
@code
struct SharedData
{
int value1;
String value2;
};
typedef SharedData <SharedData> SharedState;
SharedState sharedState;
void readExample ()
{
SharedState::ReadAccess state (sharedState);
print (state->value1); // read access
print (state->value2); // read access
state->value1 = 42; // write disallowed: compile error
}
void writeExample ()
{
SharedState::WriteAccess state (sharedState);
state->value2 = "Label"; // write access
}
@endcode
Forwarding constructors with up to eight parameters are provided. This lets
you write constructors into the underlying data object. For example:
@code
struct SharedData
{
explicit SharedData (int numSlots)
{
m_array.reserve (numSlots);
}
std::vector <AudioSampleBuffer*> m_array;
};
// Construct SharedData with one parameter
SharedData <SharedData> sharedState (16);
@endcode
@param Object The type of object to encapsulate.
@warning Recursive calls are not supported. It is generally not possible for
a thread of execution to acquire write access while it already has
read access. Such an attempt will result in undefined behavior.
Calling into unknown code while holding a lock can cause deadlock.
See @ref CallQueue::queue().
*/
template <class Object>
class SharedData : public Uncopyable
{
public:
class ReadAccess;
class WriteAccess;
class UnlockedAccess;
/** Create a concurrent state.
Up to 8 parameters can be specified in the constructor. These parameters
are forwarded to the corresponding constructor in Object. If no
constructor in Object matches the parameter list, a compile error is
generated.
*/
/** @{ */
SharedData () { }
template <class T1>
explicit SharedData (T1 t1)
: m_obj (t1) { }
template <class T1, class T2>
SharedData (T1 t1, T2 t2)
: m_obj (t1, t2) { }
template <class T1, class T2, class T3>
SharedData (T1 t1, T2 t2, T3 t3)
: m_obj (t1, t2, t3) { }
template <class T1, class T2, class T3, class T4>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4)
: m_obj (t1, t2, t3, t4) { }
template <class T1, class T2, class T3, class T4, class T5>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
: m_obj (t1, t2, t3, t4, t5) { }
template <class T1, class T2, class T3, class T4, class T5, class T6>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
: m_obj (t1, t2, t3, t4, t5, t6) { }
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) : m_obj (t1, t2, t3, t4, t5, t6, t7) { }
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
: m_obj (t1, t2, t3, t4, t5, t6, t7, t8) { }
/** @} */
private:
typedef ReadWriteMutex ReadWriteMutexType;
Object m_obj;
ReadWriteMutexType m_mutex;
};
//------------------------------------------------------------------------------
/** Unlocked access to a SharedData.
Use sparingly.
*/
template <class Object>
class SharedData <Object>::UnlockedAccess : public Uncopyable
{
public:
explicit UnlockedAccess (SharedData const& state)
: m_state (state)
{
}
Object const& getObject () const
{
return m_state.m_obj;
}
Object const& operator* () const
{
return getObject ();
}
Object const* operator-> () const
{
return &getObject ();
}
private:
SharedData const& m_state;
};
//------------------------------------------------------------------------------
/** Read only access to a SharedData */
template <class Object>
class SharedData <Object>::ReadAccess : public Uncopyable
{
public:
/** Create a ReadAccess from the specified SharedData */
explicit ReadAccess (SharedData const volatile& state)
: m_state (const_cast <SharedData const&> (state))
, m_lock (m_state.m_mutex)
{
}
/** Obtain a read only reference to Object */
Object const& getObject () const
{
return m_state.m_obj;
}
/** Obtain a read only reference to Object */
Object const& operator* () const
{
return getObject ();
}
/** Obtain a read only smart pointer to Object */
Object const* operator-> () const
{
return &getObject ();
}
private:
SharedData const& m_state;
ReadWriteMutexType::ScopedReadLockType m_lock;
};
//------------------------------------------------------------------------------
/** Read/write access to a SharedData */
template <class Object>
class SharedData <Object>::WriteAccess : public Uncopyable
{
public:
explicit WriteAccess (SharedData& state)
: m_state (state)
, m_lock (m_state.m_mutex)
{
}
/** Obtain a read only reference to Object */
Object const* getObject () const
{
return m_state.m_obj;
}
/** Obtain a read only reference to Object */
Object const& operator* () const
{
return getObject ();
}
/** Obtain a read only smart pointer to Object */
Object const* operator-> () const
{
return &getObject ();
}
/** Obtain a read/write pointer to Object */
Object& getObject ()
{
return m_state.m_obj;
}
/** Obtain a read/write reference to Object */
Object& operator* ()
{
return getObject ();
}
/** Obtain a read/write smart pointer to Object */
Object* operator-> ()
{
return &getObject ();
}
private:
SharedData& m_state;
ReadWriteMutexType::ScopedWriteLockType m_lock;
};
#endif

View File

@@ -1,105 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
void ThreadGroup::QuitType::operator () (Worker* worker)
{
worker->setShouldExit ();
}
//==============================================================================
ThreadGroup::Worker::Worker (String name, ThreadGroup& group)
: Thread (name)
, m_group (group)
, m_shouldExit (false)
{
startThread ();
}
ThreadGroup::Worker::~Worker ()
{
// Make sure the thread is stopped.
stopThread (-1);
}
void ThreadGroup::Worker::setShouldExit ()
{
m_shouldExit = true;
}
void ThreadGroup::Worker::run ()
{
do
{
m_group.m_semaphore.wait ();
Work* work = m_group.m_queue.pop_front ();
bassert (work != nullptr);
work->operator () (this);
delete work;
}
while (!m_shouldExit);
}
//==============================================================================
ThreadGroup::ThreadGroup (int numberOfThreads)
: m_numberOfThreads (numberOfThreads)
, m_semaphore (0)
{
for (int i = 0; i++ < numberOfThreads; )
{
String s;
s << "ThreadGroup (" << i << ")";
m_threads.push_front (new Worker (s, *this));
}
}
ThreadGroup::~ThreadGroup ()
{
// Put one quit item in the queue for each worker to stop.
for (int i = 0; i < m_numberOfThreads; ++i)
{
m_queue.push_front (new (getAllocator ()) QuitType);
m_semaphore.signal ();
}
for (;;)
{
Worker* worker = m_threads.pop_front ();
if (worker != nullptr)
delete worker;
else
break;
}
// There must not be pending work!
bassert (m_queue.pop_front () == nullptr);
}
int ThreadGroup::getNumberOfThreads () const
{
return m_numberOfThreads;
}

View File

@@ -1,215 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_THREADGROUP_BEASTHEADER
#define BEAST_THREADGROUP_BEASTHEADER
/*============================================================================*/
/**
@ingroup beast_concurrent
@brief A group of threads for parallelizing tasks.
@see ParallelFor
*/
class BEAST_API ThreadGroup
{
public:
typedef FifoFreeStoreType AllocatorType;
/** Creates the specified number of threads.
@param numberOfThreads The number of threads in the group. This must be
greater than zero. If this parameter is omitted,
one thread is created per available CPU.
*/
explicit ThreadGroup (int numberOfThreads = SystemStats::getNumCpus ());
~ThreadGroup ();
/** Allocator access.
*/
inline AllocatorType& getAllocator ()
{
return m_allocator;
}
/** Determine the number of threads in the group.
@return The number of threads in the group.
*/
int getNumberOfThreads () const;
/** Calls a functor on multiple threads.
The specified functor is executed on some or all available threads at once.
A call is always guaranteed to execute.
@param maxThreads The maximum number of threads to use, or -1 for all.
@param f The functor to call for each thread.
*/
/** @{ */
template <class Functor>
void callf (int maxThreads, Functor f)
{
bassert (maxThreads > 0 || maxThreads == -1);
int numberOfThreads = getNumberOfThreads ();
if (maxThreads != -1 && maxThreads < numberOfThreads)
numberOfThreads = maxThreads;
while (numberOfThreads--)
{
m_queue.push_front (new (getAllocator ()) WorkType <Functor> (f));
m_semaphore.signal ();
}
}
#if BEAST_VARIADIC_MAX >= 1
template <class Fn>
void call (int maxThreads, Fn f)
{ callf (maxThreads, functional::bind (f)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Fn, class T1>
void call (int maxThreads, Fn f, T1 t1)
{ callf (maxThreads, functional::bind (f, t1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Fn, class T1, class T2>
void call (int maxThreads, Fn f, T1 t1, T2 t2)
{ callf (maxThreads, functional::bind (f, t1, t2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Fn, class T1, class T2, class T3>
void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3)
{ callf (maxThreads, functional::bind (f, t1, t2, t3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Fn, class T1, class T2, class T3, class T4>
void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4)
{ callf (maxThreads, functional::bind (f, t1, t2, t3, t4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Fn, class T1, class T2, class T3, class T4, class T5>
void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ callf (maxThreads, functional::bind (f, t1, t2, t3, t4, t5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6>
void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ callf (maxThreads, functional::bind (f, t1, t2, t3, t4, t5, t6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ callf (maxThreads, functional::bind (f, t1, t2, t3, t4, t5, t6, t7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ callf (maxThreads, functional::bind (f, t1, t2, t3, t4, t5, t6, t7, t8)); }
#endif
/** @} */
private:
void stopThreads (int numberOfThreadsToStop);
//============================================================================
private:
/** A thread in the group.
*/
class Worker
: public LockFreeStack <Worker>::Node
, public Thread
, LeakChecked <Worker>
{
public:
Worker (String name, ThreadGroup& group);
~Worker ();
void setShouldExit ();
private:
void run ();
private:
ThreadGroup& m_group;
bool m_shouldExit;
};
//============================================================================
private:
/** Abstract work item.
*/
class Work : public LockFreeStack <Work>::Node
, public AllocatedBy <AllocatorType>
{
public:
virtual ~Work () { }
/* The worker is passed in so we can make it quit later.
*/
virtual void operator () (Worker* worker) = 0;
};
template <class Functor>
class WorkType : public Work, LeakChecked <WorkType <Functor> >
{
public:
explicit WorkType (Functor const& f) : m_f (f) { }
~WorkType () { }
void operator () (Worker*)
{
m_f ();
}
private:
Functor m_f;
};
/** Used to make a Worker stop
*/
class QuitType
: public Work
, LeakChecked <QuitType>
{
public:
void operator () (Worker* worker);
};
private:
int const m_numberOfThreads;
Semaphore m_semaphore;
AllocatorType m_allocator;
LockFreeStack <Work> m_queue;
LockFreeStack <Worker> m_threads;
};
#endif

View File

@@ -1,152 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
ThreadWithCallQueue::ThreadWithCallQueue (String name)
: CallQueue (name)
, m_thread (name)
, m_entryPoints (nullptr)
, m_calledStart (false)
, m_calledStop (false)
, m_shouldStop (false)
{
}
ThreadWithCallQueue::~ThreadWithCallQueue ()
{
stop (true);
}
ThreadWithCallQueue::EntryPoints* ThreadWithCallQueue::getDefaultEntryPoints () noexcept
{
static EntryPoints entryPoints;
return &entryPoints;
}
void ThreadWithCallQueue::start (EntryPoints* const entryPoints)
{
{
// This is mostly for diagnostics
// TODO: Atomic flag for this whole thing
CriticalSection::ScopedLockType lock (m_mutex);
// start() MUST be called.
bassert (!m_calledStart);
m_calledStart = true;
}
m_entryPoints = entryPoints;
m_thread.start (this);
}
void ThreadWithCallQueue::stop (bool const wait)
{
// can't call stop(true) from within a thread function
bassert (!wait || !m_thread.isTheCurrentThread ());
{
CriticalSection::ScopedLockType lock (m_mutex);
// start() MUST be called.
bassert (m_calledStart);
// TODO: Atomic for this
if (!m_calledStop)
{
m_calledStop = true;
{
CriticalSection::ScopedUnlockType unlock (m_mutex); // getting fancy
call (&ThreadWithCallQueue::doStop, this);
// in theory something could slip in here
close ();
}
}
}
if (wait)
m_thread.join ();
}
// Should be called periodically by the idle function.
// There are three possible results:
//
// #1 Returns false. The idle function may continue or return.
// #2 Returns true. The idle function should return as soon as possible.
// #3 Throws a Thread::Interruption exception.
//
// If interruptionPoint returns true or throws, it must
// not be called again before the thread has the opportunity to reset.
//
bool ThreadWithCallQueue::interruptionPoint ()
{
return m_thread.interruptionPoint ();
}
// Interrupts the idle function by queueing a call that does nothing.
void ThreadWithCallQueue::interrupt ()
{
call (&ThreadWithCallQueue::doNothing);
}
void ThreadWithCallQueue::doNothing ()
{
// Intentionally empty
}
void ThreadWithCallQueue::signal ()
{
m_thread.interrupt ();
}
void ThreadWithCallQueue::reset ()
{
}
void ThreadWithCallQueue::doStop ()
{
m_shouldStop = true;
}
void ThreadWithCallQueue::threadRun ()
{
m_entryPoints->threadInit ();
for (;;)
{
CallQueue::synchronize ();
if (m_shouldStop)
break;
bool interrupted = m_entryPoints->threadIdle ();
if (!interrupted)
interrupted = interruptionPoint ();
if (!interrupted)
m_thread.wait ();
}
m_entryPoints->threadExit ();
}

View File

@@ -1,155 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_THREADWITHCALLQUEUE_BEASTHEADER
#define BEAST_THREADWITHCALLQUEUE_BEASTHEADER
/** An InterruptibleThread with a CallQueue.
This combines an InterruptibleThread with a CallQueue, allowing functors to
be queued for asynchronous execution on the thread.
The thread runs an optional user-defined idle function, which must regularly
check for an interruption using the InterruptibleThread interface. When an
interruption is signaled, the idle function returns and the CallQueue is
synchronized. Then, the idle function is resumed.
When the ThreadWithCallQueue first starts up, an optional user-defined
initialization function is executed on the thread. When the thread exits,
a user-defined exit function may be executed on the thread.
@see CallQueue
@ingroup beast_concurrent
*/
class BEAST_API ThreadWithCallQueue
: public CallQueue
, private InterruptibleThread::EntryPoint
, LeakChecked <ThreadWithCallQueue>
{
public:
/** Entry points for a ThreadWithCallQueue.
*/
class EntryPoints
{
public:
virtual ~EntryPoints () { }
virtual void threadInit () { }
virtual void threadExit () { }
virtual bool threadIdle ()
{
bool interrupted = false;
return interrupted;
}
};
/** Create a thread.
@param name The name of the InterruptibleThread and CallQueue, used
for diagnostics when debugging.
*/
explicit ThreadWithCallQueue (String name);
/** Retrieve the default entry points.
The default entry points do nothing.
*/
static EntryPoints* getDefaultEntryPoints () noexcept;
/** Destroy a ThreadWithCallQueue.
If the thread is still running it is stopped. The destructor blocks
until the thread exits cleanly.
*/
~ThreadWithCallQueue ();
/** Start the thread, with optional entry points.
If `entryPoints` is specified then the thread runs using those
entry points. If ommitted, the default entry simply do nothing.
This is useful for creating a thread whose sole activities are
performed through the call queue.
@param entryPoints An optional pointer to @ref EntryPoints.
*/
void start (EntryPoints* const entryPoints = getDefaultEntryPoints ());
/* Stop the thread.
Stops the thread and optionally wait until it exits. It is safe to call
this function at any time and as many times as desired.
After a call to stop () the CallQueue is closed, and attempts to queue new
functors will throw a runtime exception. Existing functors will still
execute.
Any listeners registered on the CallQueue need to be removed
before stop is called
@invariant The caller is not on the associated thread.
@param wait `true` if the function should wait until the thread exits
before returning.
*/
void stop (bool const wait);
/** Determine if the thread needs interruption.
Should be called periodically by the idle function. If interruptionPoint
returns true or throws, it must not be called again until the idle function
returns and is re-entered.
@invariant No previous calls to interruptionPoint() made after the idle
function entry point returned `true`.
@return `false` if the idle function may continue, or `true` if the
idle function must return as soon as possible.
*/
bool interruptionPoint ();
/* Interrupts the idle function.
*/
void interrupt ();
private:
static void doNothing ();
void signal ();
void reset ();
void doStop ();
void threadRun ();
private:
InterruptibleThread m_thread;
EntryPoints* m_entryPoints;
bool m_calledStart;
bool m_calledStop;
bool m_shouldStop;
CriticalSection m_mutex;
};
#endif

View File

@@ -1,317 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#if defined (BEAST_CORE_BEASTHEADER) && ! BEAST_AMALGAMATED_INCLUDE
/* When you add this cpp file to your project, you mustn't include it in a file where you've
already included any other headers - just put it inside a file on its own, possibly with your config
flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
header files that the compiler may be using.
*/
#error "Incorrect use of BEAST cpp file"
#endif
// Your project must contain a BeastConfig.h file with your project-specific settings in it,
// and your header search path must make it accessible to the module's files.
#include "BeastConfig.h"
//==============================================================================
#include "native/beast_BasicNativeHeaders.h"
#include "beast_core.h"
#include <locale>
#include <cctype>
#if ! BEAST_BSD
#include <sys/timeb.h>
#endif
#if ! BEAST_ANDROID
#include <cwctype>
#endif
#if BEAST_WINDOWS
#include <ctime>
#include <winsock2.h>
#include <ws2tcpip.h>
#if ! BEAST_MINGW
#include <Dbghelp.h>
#if ! BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#pragma comment (lib, "DbgHelp.lib")
#endif
#endif
#if BEAST_MINGW
#include <ws2spi.h>
#endif
#else
#if BEAST_LINUX || BEAST_ANDROID
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <unistd.h>
#include <netinet/in.h>
#endif
#if BEAST_LINUX
#include <langinfo.h>
#endif
#include <pwd.h>
#include <fcntl.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <net/if.h>
#include <sys/ioctl.h>
#if ! BEAST_ANDROID && ! BEAST_BSD
#include <execinfo.h>
#endif
#endif
#if BEAST_MAC || BEAST_IOS
#include <xlocale.h>
#include <mach/mach.h>
#endif
#if BEAST_ANDROID
#include <android/log.h>
#endif
//------------------------------------------------------------------------------
// If the MSVC debug heap headers were included, disable
// the macros during the juce include since they conflict.
#ifdef _CRTDBG_MAP_ALLOC
#pragma push_macro("calloc")
#pragma push_macro("free")
#pragma push_macro("malloc")
#pragma push_macro("realloc")
#pragma push_macro("_recalloc")
#pragma push_macro("_aligned_free")
#pragma push_macro("_aligned_malloc")
#pragma push_macro("_aligned_offset_malloc")
#pragma push_macro("_aligned_realloc")
#pragma push_macro("_aligned_recalloc")
#pragma push_macro("_aligned_offset_realloc")
#pragma push_macro("_aligned_offset_recalloc")
#pragma push_macro("_aligned_msize")
#undef calloc
#undef free
#undef malloc
#undef realloc
#undef _recalloc
#undef _aligned_free
#undef _aligned_malloc
#undef _aligned_offset_malloc
#undef _aligned_realloc
#undef _aligned_recalloc
#undef _aligned_offset_realloc
#undef _aligned_offset_recalloc
#undef _aligned_msize
#endif
namespace beast
{
#include "containers/beast_AbstractFifo.cpp"
#include "containers/beast_DynamicObject.cpp"
#include "containers/beast_NamedValueSet.cpp"
#include "containers/beast_PropertySet.cpp"
#include "containers/beast_Variant.cpp"
#include "diagnostic/beast_Debug.cpp"
#include "diagnostic/beast_Error.cpp"
#include "diagnostic/beast_FatalError.cpp"
#include "diagnostic/beast_FPUFlags.cpp"
#include "diagnostic/beast_LeakChecked.cpp"
#include "diagnostic/beast_ProtectedCall.cpp"
#include "diagnostic/beast_SemanticVersion.cpp"
#include "diagnostic/beast_UnitTest.cpp"
#include "diagnostic/beast_UnitTestUtilities.cpp"
#include "files/beast_DirectoryIterator.cpp"
#include "files/beast_File.cpp"
#include "files/beast_FileInputStream.cpp"
#include "files/beast_FileOutputStream.cpp"
#include "files/beast_FileSearchPath.cpp"
#include "files/beast_RandomAccessFile.cpp"
#include "files/beast_TemporaryFile.cpp"
#include "json/beast_JSON.cpp"
#include "logging/beast_FileLogger.cpp"
#include "logging/beast_Logger.cpp"
#include "maths/beast_BigInteger.cpp"
#include "maths/beast_Expression.cpp"
#include "maths/beast_MurmurHash.cpp"
#include "maths/beast_Random.cpp"
#include "memory/beast_MemoryBlock.cpp"
#include "misc/beast_Main.cpp"
#include "misc/beast_Result.cpp"
#include "misc/beast_Uuid.cpp"
#include "network/beast_MACAddress.cpp"
#include "network/beast_NamedPipe.cpp"
#include "network/beast_Socket.cpp"
#include "network/beast_URL.cpp"
#include "network/beast_IPAddress.cpp"
#include "streams/beast_BufferedInputStream.cpp"
#include "streams/beast_FileInputSource.cpp"
#include "streams/beast_InputStream.cpp"
#include "streams/beast_MemoryInputStream.cpp"
#include "streams/beast_MemoryOutputStream.cpp"
#include "streams/beast_OutputStream.cpp"
#include "streams/beast_SubregionStream.cpp"
#include "system/beast_SystemStats.cpp"
#include "text/beast_CharacterFunctions.cpp"
#include "text/beast_LexicalCast.cpp"
#include "text/beast_Identifier.cpp"
#include "text/beast_LocalisedStrings.cpp"
#include "text/beast_String.cpp"
#include "text/beast_StringArray.cpp"
#include "text/beast_StringPairArray.cpp"
#include "text/beast_StringPool.cpp"
#include "text/beast_TextDiff.cpp"
#include "threads/beast_ChildProcess.cpp"
#include "threads/beast_ReadWriteLock.cpp"
#include "threads/beast_SpinDelay.cpp"
#include "threads/beast_Thread.cpp"
#include "threads/beast_ThreadPool.cpp"
#include "threads/beast_TimeSliceThread.cpp"
#include "time/beast_PerformanceCounter.cpp"
#include "time/beast_PerformedAtExit.cpp"
#include "time/beast_RelativeTime.cpp"
#include "time/beast_Time.cpp"
#include "xml/beast_XmlDocument.cpp"
#include "xml/beast_XmlElement.cpp"
#include "zip/beast_GZIPDecompressorInputStream.cpp"
#include "zip/beast_GZIPCompressorOutputStream.cpp"
#include "zip/beast_ZipFile.cpp"
#if BEAST_MAC || BEAST_IOS
#include "native/beast_osx_ObjCHelpers.h"
#endif
#if BEAST_WINDOWS
#include "native/beast_win32_FPUFlags.cpp"
#else
#include "native/beast_posix_FPUFlags.cpp"
#endif
#if BEAST_ANDROID
#include "native/beast_android_JNIHelpers.h"
#endif
#if ! BEAST_WINDOWS
#include "native/beast_posix_SharedCode.h"
#include "native/beast_posix_NamedPipe.cpp"
#endif
#if BEAST_MAC || BEAST_IOS
#include "native/beast_mac_Files.mm"
#include "native/beast_mac_Network.mm"
#include "native/beast_mac_Strings.mm"
#include "native/beast_mac_SystemStats.mm"
#include "native/beast_mac_Threads.mm"
#elif BEAST_WINDOWS
#include "native/beast_win32_ComSmartPtr.h"
#include "native/beast_win32_Files.cpp"
#include "native/beast_win32_Network.cpp"
#include "native/beast_win32_Registry.cpp"
#include "native/beast_win32_SystemStats.cpp"
#include "native/beast_win32_Threads.cpp"
#elif BEAST_LINUX
#include "native/beast_linux_Files.cpp"
#include "native/beast_linux_Network.cpp"
#include "native/beast_linux_SystemStats.cpp"
#include "native/beast_linux_Threads.cpp"
#elif BEAST_BSD
#include "native/beast_bsd_Files.cpp"
#include "native/beast_bsd_Network.cpp"
#include "native/beast_bsd_SystemStats.cpp"
#include "native/beast_bsd_Threads.cpp"
#elif BEAST_ANDROID
#include "native/beast_android_Files.cpp"
#include "native/beast_android_Misc.cpp"
#include "native/beast_android_Network.cpp"
#include "native/beast_android_SystemStats.cpp"
#include "native/beast_android_Threads.cpp"
#endif
#include "threads/beast_HighResolutionTimer.cpp"
}
#ifdef _CRTDBG_MAP_ALLOC
#pragma pop_macro("calloc")
#pragma pop_macro("free")
#pragma pop_macro("malloc")
#pragma pop_macro("realloc")
#pragma pop_macro("_recalloc")
#pragma pop_macro("_aligned_free")
#pragma pop_macro("_aligned_malloc")
#pragma pop_macro("_aligned_offset_malloc")
#pragma pop_macro("_aligned_realloc")
#pragma pop_macro("_aligned_recalloc")
#pragma pop_macro("_aligned_offset_realloc")
#pragma pop_macro("_aligned_offset_recalloc")
#pragma pop_macro("_aligned_msize")
#endif
//------------------------------------------------------------------------------
#if BEAST_BOOST_IS_AVAILABLE
namespace boost {
namespace placeholders {
boost::arg<1> _1;
boost::arg<2> _2;
boost::arg<3> _3;
boost::arg<4> _4;
boost::arg<5> _5;
boost::arg<6> _6;
boost::arg<7> _7;
boost::arg<8> _8;
boost::arg<9> _9;
}
}
#endif

View File

@@ -1,364 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_H_INCLUDED
#define BEAST_CORE_H_INCLUDED
//------------------------------------------------------------------------------
/* If you fail to make sure that all your compile units are building Beast with
the same set of option flags, then there's a risk that different compile
units will treat the classes as having different memory layouts, leading to
very nasty memory corruption errors when they all get linked together.
That's why it's best to always include the BeastConfig.h file before any
beast headers.
*/
#ifndef BEAST_BEASTCONFIG_H_INCLUDED
# ifdef _MSC_VER
# pragma message ("Have you included your BeastConfig.h file before including the Beast headers?")
# else
# warning "Have you included your BeastConfig.h file before including the Beast headers?"
# endif
#endif
//------------------------------------------------------------------------------
#include "system/beast_TargetPlatform.h"
//
// Apply sensible defaults for the configuration settings
//
#ifndef BEAST_LOG_ASSERTIONS
# if BEAST_ANDROID
# define BEAST_LOG_ASSERTIONS 1
# else
# define BEAST_LOG_ASSERTIONS 0
# endif
#endif
#if BEAST_DEBUG && ! defined (BEAST_CHECK_MEMORY_LEAKS)
#define BEAST_CHECK_MEMORY_LEAKS 1
#endif
#ifndef BEAST_INCLUDE_ZLIB_CODE
#define BEAST_INCLUDE_ZLIB_CODE 1
#endif
#ifndef BEAST_ZLIB_INCLUDE_PATH
#define BEAST_ZLIB_INCLUDE_PATH <zlib.h>
#endif
/* Config: BEAST_CATCH_UNHANDLED_EXCEPTIONS
If enabled, this will add some exception-catching code to forward unhandled exceptions
to your BEASTApplication::unhandledException() callback.
*/
#ifndef BEAST_CATCH_UNHANDLED_EXCEPTIONS
//#define BEAST_CATCH_UNHANDLED_EXCEPTIONS 1
#endif
#ifndef BEAST_BOOST_IS_AVAILABLE
#define BEAST_BOOST_IS_AVAILABLE 0
#endif
//------------------------------------------------------------------------------
//
// This is a hack to fix boost's goofy placeholders
//
#if BEAST_BOOST_IS_AVAILABLE
#ifdef BOOST_BIND_PLACEHOLDERS_HPP_INCLUDED
#error <boost/bind.hpp> must not be included before this file
#endif
// Prevent <boost/bind/placeholders.hpp> from being included
#define BOOST_BIND_PLACEHOLDERS_HPP_INCLUDED
#include <boost/bind/arg.hpp>
#include <boost/config.hpp>
// This based on <boost/bind/placeholders.cpp>
namespace boost {
namespace placeholders {
extern boost::arg<1> _1;
extern boost::arg<2> _2;
extern boost::arg<3> _3;
extern boost::arg<4> _4;
extern boost::arg<5> _5;
extern boost::arg<6> _6;
extern boost::arg<7> _7;
extern boost::arg<8> _8;
extern boost::arg<9> _9;
}
using namespace placeholders;
}
#endif
//------------------------------------------------------------------------------
//
// Choose a source of bind, placeholders, and function
//
#if !BEAST_BIND_USES_STD && !BEAST_BIND_USES_TR1 && !BEAST_BIND_USES_BOOST
# if BEAST_MSVC
# define BEAST_BIND_USES_STD 1
# elif BEAST_IOS || BEAST_MAC
# include <ciso646> // detect version of std::lib
# if BEAST_IOS && BEAST_BOOST_IS_AVAILABLE // Work-around for iOS bugs with bind.
# define BEAST_BIND_USES_BOOST 1
# elif _LIBCPP_VERSION // libc++
# define BEAST_BIND_USES_STD 1
# else // libstdc++ (GNU)
# define BEAST_BIND_USES_TR1 1
# endif
# elif BEAST_LINUX || BEAST_BSD
# define BEAST_BIND_USES_TR1 1
# else
# define BEAST_BIND_USES_STD 1
# endif
#endif
#if BEAST_BIND_USES_STD
# include <functional>
#elif BEAST_BIND_USES_TR1
# include <tr1/functional>
#elif BEAST_BIND_USES_BOOST
# include <boost/bind.hpp>
# include <boost/function.hpp>
#endif
//------------------------------------------------------------------------------
#include "system/beast_StandardHeader.h"
#if BEAST_MSVC
# pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state)
# pragma warning (push)
# pragma warning (disable: 4786) // (long class name warning)
# ifdef __INTEL_COMPILER
# pragma warning (disable: 1125)
# endif
#endif
// If the MSVC debug heap headers were included, disable
// the macros during the juce include since they conflict.
#ifdef _CRTDBG_MAP_ALLOC
#pragma push_macro("calloc")
#pragma push_macro("free")
#pragma push_macro("malloc")
#pragma push_macro("realloc")
#pragma push_macro("_recalloc")
#pragma push_macro("_aligned_free")
#pragma push_macro("_aligned_malloc")
#pragma push_macro("_aligned_offset_malloc")
#pragma push_macro("_aligned_realloc")
#pragma push_macro("_aligned_recalloc")
#pragma push_macro("_aligned_offset_realloc")
#pragma push_macro("_aligned_offset_recalloc")
#pragma push_macro("_aligned_msize")
#undef calloc
#undef free
#undef malloc
#undef realloc
#undef _recalloc
#undef _aligned_free
#undef _aligned_malloc
#undef _aligned_offset_malloc
#undef _aligned_realloc
#undef _aligned_recalloc
#undef _aligned_offset_realloc
#undef _aligned_offset_recalloc
#undef _aligned_msize
#endif
namespace beast
{
// Order matters, since headers don't have their own #include lines.
// Add new includes to the bottom.
#include "memory/beast_Uncopyable.h"
#include "system/beast_PlatformDefs.h"
#include "system/beast_TargetPlatform.h"
#include "system/beast_Functional.h"
#include "maths/beast_MathsFunctions.h"
#include "memory/beast_Atomic.h"
#include "memory/beast_AtomicCounter.h"
#include "memory/beast_AtomicFlag.h"
#include "memory/beast_AtomicPointer.h"
#include "memory/beast_AtomicState.h"
#include "containers/beast_LockFreeStack.h"
#include "threads/beast_SpinDelay.h"
#include "memory/beast_StaticObject.h"
#include "memory/beast_Memory.h"
#include "text/beast_String.h"
#include "threads/beast_CriticalSection.h"
#include "diagnostic/beast_FatalError.h"
#include "diagnostic/beast_SafeBool.h"
#include "diagnostic/beast_Error.h"
#include "diagnostic/beast_Debug.h"
#include "diagnostic/beast_Throw.h"
#include "text/beast_CharacterFunctions.h"
#include "text/beast_CharPointer_ASCII.h"
#include "text/beast_CharPointer_UTF16.h"
#include "text/beast_CharPointer_UTF32.h"
#include "text/beast_CharPointer_UTF8.h"
#include "text/beast_LexicalCast.h"
#include "time/beast_PerformedAtExit.h"
#include "diagnostic/beast_LeakChecked.h"
#include "memory/beast_ByteOrder.h"
#include "memory/beast_ByteSwap.h"
#include "maths/beast_uint24.h"
#include "logging/beast_Logger.h"
#include "threads/beast_Thread.h"
#include "diagnostic/beast_FPUFlags.h"
#include "diagnostic/beast_ProtectedCall.h"
#include "containers/beast_AbstractFifo.h"
#include "containers/beast_Array.h"
#include "containers/beast_ArrayAllocationBase.h"
#include "containers/beast_DynamicObject.h"
#include "containers/beast_ElementComparator.h"
#include "maths/beast_Random.h"
#include "containers/beast_HashMap.h"
#include "containers/beast_List.h"
#include "containers/beast_LinkedListPointer.h"
#include "containers/beast_LockFreeQueue.h"
#include "containers/beast_NamedValueSet.h"
#include "containers/beast_OwnedArray.h"
#include "containers/beast_PropertySet.h"
#include "containers/beast_SharedObjectArray.h"
#include "containers/beast_ScopedValueSetter.h"
#include "containers/beast_SharedTable.h"
#include "containers/beast_SortedLookupTable.h"
#include "containers/beast_SortedSet.h"
#include "containers/beast_SparseSet.h"
#include "containers/beast_Variant.h"
#include "files/beast_DirectoryIterator.h"
#include "files/beast_File.h"
#include "files/beast_FileInputStream.h"
#include "files/beast_FileOutputStream.h"
#include "files/beast_FileSearchPath.h"
#include "files/beast_MemoryMappedFile.h"
#include "files/beast_RandomAccessFile.h"
#include "files/beast_TemporaryFile.h"
#include "json/beast_JSON.h"
#include "logging/beast_FileLogger.h"
#include "logging/beast_Logger.h"
#include "maths/beast_BigInteger.h"
#include "maths/beast_Expression.h"
#include "maths/beast_Interval.h"
#include "maths/beast_MathsFunctions.h"
#include "maths/beast_MurmurHash.h"
#include "maths/beast_Range.h"
#include "memory/beast_ByteOrder.h"
#include "memory/beast_HeapBlock.h"
#include "memory/beast_Memory.h"
#include "memory/beast_MemoryBlock.h"
#include "memory/beast_OptionalScopedPointer.h"
#include "memory/beast_SharedObject.h"
#include "memory/beast_ScopedPointer.h"
#include "threads/beast_SpinLock.h"
#include "memory/beast_SharedSingleton.h"
#include "memory/beast_WeakReference.h"
#include "memory/beast_MemoryAlignment.h"
#include "memory/beast_CacheLine.h"
#include "memory/beast_RecycledObjectPool.h"
#include "misc/beast_Main.h"
#include "misc/beast_Result.h"
#include "misc/beast_Uuid.h"
#include "misc/beast_WindowsRegistry.h"
#include "network/beast_IPAddress.h"
#include "network/beast_MACAddress.h"
#include "network/beast_NamedPipe.h"
#include "network/beast_Socket.h"
#include "network/beast_URL.h"
#include "streams/beast_BufferedInputStream.h"
#include "streams/beast_FileInputSource.h"
#include "streams/beast_InputSource.h"
#include "streams/beast_InputStream.h"
#include "streams/beast_MemoryInputStream.h"
#include "streams/beast_MemoryOutputStream.h"
#include "streams/beast_OutputStream.h"
#include "streams/beast_SubregionStream.h"
#include "system/beast_SystemStats.h"
#include "text/beast_Identifier.h"
#include "text/beast_LocalisedStrings.h"
#include "text/beast_NewLine.h"
#include "text/beast_StringArray.h"
#include "diagnostic/beast_SemanticVersion.h"
#include "text/beast_StringPairArray.h"
#include "text/beast_StringPool.h"
#include "text/beast_TextDiff.h"
#include "threads/beast_ChildProcess.h"
#include "threads/beast_DynamicLibrary.h"
#include "threads/beast_HighResolutionTimer.h"
#include "threads/beast_InterProcessLock.h"
#include "threads/beast_Process.h"
#include "threads/beast_ReadWriteLock.h"
#include "threads/beast_ScopedLock.h"
#include "threads/beast_ScopedReadLock.h"
#include "threads/beast_ScopedWriteLock.h"
#include "threads/beast_ThreadLocalValue.h"
#include "threads/beast_ThreadPool.h"
#include "threads/beast_TimeSliceThread.h"
#include "threads/beast_WaitableEvent.h"
#include "time/beast_PerformanceCounter.h"
#include "time/beast_RelativeTime.h"
#include "time/beast_Time.h"
#include "diagnostic/beast_UnitTest.h"
#include "xml/beast_XmlDocument.h"
#include "xml/beast_XmlElement.h"
#include "diagnostic/beast_UnitTestUtilities.h"
#include "zip/beast_GZIPCompressorOutputStream.h"
#include "zip/beast_GZIPDecompressorInputStream.h"
#include "zip/beast_ZipFile.h"
}
#ifdef _CRTDBG_MAP_ALLOC
#pragma pop_macro("_aligned_msize")
#pragma pop_macro("_aligned_offset_recalloc")
#pragma pop_macro("_aligned_offset_realloc")
#pragma pop_macro("_aligned_recalloc")
#pragma pop_macro("_aligned_realloc")
#pragma pop_macro("_aligned_offset_malloc")
#pragma pop_macro("_aligned_malloc")
#pragma pop_macro("_aligned_free")
#pragma pop_macro("_recalloc")
#pragma pop_macro("realloc")
#pragma pop_macro("malloc")
#pragma pop_macro("free")
#pragma pop_macro("calloc")
#endif
#if BEAST_MSVC
#pragma warning (pop)
#endif
//------------------------------------------------------------------------------
#endif

View File

@@ -1,228 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
AbstractFifo::AbstractFifo (const int capacity) noexcept
: bufferSize (capacity)
{
bassert (bufferSize > 0);
}
AbstractFifo::~AbstractFifo() {}
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady(); }
int AbstractFifo::getNumReady() const noexcept
{
const int vs = validStart.get();
const int ve = validEnd.get();
return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
}
void AbstractFifo::reset() noexcept
{
validEnd = 0;
validStart = 0;
}
void AbstractFifo::setTotalSize (int newSize) noexcept
{
bassert (newSize > 0);
reset();
bufferSize = newSize;
}
//==============================================================================
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
{
const int vs = validStart.get();
const int ve = validEnd.value;
const int freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
numToWrite = bmin (numToWrite, freeSpace - 1);
if (numToWrite <= 0)
{
startIndex1 = 0;
startIndex2 = 0;
blockSize1 = 0;
blockSize2 = 0;
}
else
{
startIndex1 = ve;
startIndex2 = 0;
blockSize1 = bmin (bufferSize - ve, numToWrite);
numToWrite -= blockSize1;
blockSize2 = numToWrite <= 0 ? 0 : bmin (numToWrite, vs);
}
}
void AbstractFifo::finishedWrite (int numWritten) noexcept
{
bassert (numWritten >= 0 && numWritten < bufferSize);
int newEnd = validEnd.value + numWritten;
if (newEnd >= bufferSize)
newEnd -= bufferSize;
validEnd = newEnd;
}
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
{
const int vs = validStart.value;
const int ve = validEnd.get();
const int numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
numWanted = bmin (numWanted, numReady);
if (numWanted <= 0)
{
startIndex1 = 0;
startIndex2 = 0;
blockSize1 = 0;
blockSize2 = 0;
}
else
{
startIndex1 = vs;
startIndex2 = 0;
blockSize1 = bmin (bufferSize - vs, numWanted);
numWanted -= blockSize1;
blockSize2 = numWanted <= 0 ? 0 : bmin (numWanted, ve);
}
}
void AbstractFifo::finishedRead (int numRead) noexcept
{
bassert (numRead >= 0 && numRead <= bufferSize);
int newStart = validStart.value + numRead;
if (newStart >= bufferSize)
newStart -= bufferSize;
validStart = newStart;
}
//==============================================================================
class AbstractFifoTests : public UnitTest
{
public:
AbstractFifoTests() : UnitTest ("Abstract Fifo", "beast")
{
}
class WriteThread : public Thread
{
public:
WriteThread (AbstractFifo& fifo_, int* buffer_)
: Thread ("fifo writer"), fifo (fifo_), buffer (buffer_)
{
startThread();
}
~WriteThread()
{
stopThread (5000);
}
void run()
{
int n = 0;
Random r;
while (! threadShouldExit())
{
int num = r.nextInt (2000) + 1;
int start1, size1, start2, size2;
fifo.prepareToWrite (num, start1, size1, start2, size2);
bassert (size1 >= 0 && size2 >= 0);
bassert (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()));
bassert (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize()));
for (int i = 0; i < size1; ++i)
buffer [start1 + i] = n++;
for (int i = 0; i < size2; ++i)
buffer [start2 + i] = n++;
fifo.finishedWrite (size1 + size2);
}
}
private:
AbstractFifo& fifo;
int* buffer;
};
void runTest()
{
beginTestCase ("AbstractFifo");
int buffer [5000];
AbstractFifo fifo (numElementsInArray (buffer));
WriteThread writer (fifo, buffer);
int n = 0;
Random r;
bool failed = false;
for (int count = 100000; --count >= 0;)
{
int num = r.nextInt (6000) + 1;
int start1, size1, start2, size2;
fifo.prepareToRead (num, start1, size1, start2, size2);
if (! (size1 >= 0 && size2 >= 0)
&& (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()))
&& (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize())))
{
expect (false, "prepareToRead returned negative values");
break;
}
for (int i = 0; i < size1; ++i)
failed = (buffer [start1 + i] != n++) || failed;
for (int i = 0; i < size2; ++i)
failed = (buffer [start2 + i] != n++) || failed;
if (failed)
{
break;
}
fifo.finishedRead (size1 + size2);
}
expect (! failed, "read values were incorrect");
}
};
static AbstractFifoTests abstractFifoTests;

View File

@@ -1,212 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ABSTRACTFIFO_BEASTHEADER
#define BEAST_ABSTRACTFIFO_BEASTHEADER
//==============================================================================
/**
Encapsulates the logic required to implement a lock-free FIFO.
This class handles the logic needed when building a single-reader,
single-writer FIFO.
It doesn't actually hold any data itself, but your FIFO class can use one of
these to manage its position and status when reading or writing to it.
To use it, you can call prepareToWrite() to determine the position within
your own buffer that an incoming block of data should be stored, and
prepareToRead() to find out when the next outgoing block should be read from.
e.g.
@code
class MyFifo
{
public:
MyFifo() : abstractFifo (1024)
{
}
void addToFifo (const int* someData, int numItems)
{
int start1, size1, start2, size2;
abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2);
if (size1 > 0)
copySomeData (myBuffer + start1, someData, size1);
if (size2 > 0)
copySomeData (myBuffer + start2, someData + size1, size2);
abstractFifo.finishedWrite (size1 + size2);
}
void readFromFifo (int* someData, int numItems)
{
int start1, size1, start2, size2;
abstractFifo.prepareToRead (numSamples, start1, size1, start2, size2);
if (size1 > 0)
copySomeData (someData, myBuffer + start1, size1);
if (size2 > 0)
copySomeData (someData + size1, myBuffer + start2, size2);
abstractFifo.finishedRead (size1 + size2);
}
private:
AbstractFifo abstractFifo;
int myBuffer [1024];
};
@endcode
*/
class BEAST_API AbstractFifo : LeakChecked <AbstractFifo>, public Uncopyable
{
public:
//==============================================================================
/** Creates a FIFO to manage a buffer with the specified capacity. */
AbstractFifo (int capacity) noexcept;
/** Destructor */
~AbstractFifo();
//==============================================================================
/** Returns the total size of the buffer being managed. */
int getTotalSize() const noexcept;
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
int getFreeSpace() const noexcept;
/** Returns the number of items that can currently be read from the buffer. */
int getNumReady() const noexcept;
/** Clears the buffer positions, so that it appears empty. */
void reset() noexcept;
/** Changes the buffer's total size.
Note that this isn't thread-safe, so don't call it if there's any danger that it
might overlap with a call to any other method in this class!
*/
void setTotalSize (int newSize) noexcept;
//==============================================================================
/** Returns the location within the buffer at which an incoming block of data should be written.
Because the section of data that you want to add to the buffer may overlap the end
and wrap around to the start, two blocks within your buffer are returned, and you
should copy your data into the first one, with any remaining data spilling over into
the second.
If the number of items you ask for is too large to fit within the buffer's free space, then
blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
may decide to keep waiting and re-trying the method until there's enough space available.
After calling this method, if you choose to write your data into the blocks returned, you
must call finishedWrite() to tell the FIFO how much data you actually added.
e.g.
@code
void addToFifo (const int* someData, int numItems)
{
int start1, size1, start2, size2;
prepareToWrite (numItems, start1, size1, start2, size2);
if (size1 > 0)
copySomeData (myBuffer + start1, someData, size1);
if (size2 > 0)
copySomeData (myBuffer + start2, someData + size1, size2);
finishedWrite (size1 + size2);
}
@endcode
@param numToWrite indicates how many items you'd like to add to the buffer
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
the first block should be written
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
@see finishedWrite
*/
void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
/** Called after writing from the FIFO, to indicate that this many items have been added.
@see prepareToWrite
*/
void finishedWrite (int numWritten) noexcept;
/** Returns the location within the buffer from which the next block of data should be read.
Because the section of data that you want to read from the buffer may overlap the end
and wrap around to the start, two blocks within your buffer are returned, and you
should read from both of them.
If the number of items you ask for is greater than the amount of data available, then
blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
may decide to keep waiting and re-trying the method until there's enough data available.
After calling this method, if you choose to read the data, you must call finishedRead() to
tell the FIFO how much data you have consumed.
e.g.
@code
void readFromFifo (int* someData, int numItems)
{
int start1, size1, start2, size2;
prepareToRead (numSamples, start1, size1, start2, size2);
if (size1 > 0)
copySomeData (someData, myBuffer + start1, size1);
if (size2 > 0)
copySomeData (someData + size1, myBuffer + start2, size2);
finishedRead (size1 + size2);
}
@endcode
@param numWanted indicates how many items you'd like to add to the buffer
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
the first block should be written
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
@see finishedRead
*/
void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
@see prepareToRead
*/
void finishedRead (int numRead) noexcept;
private:
//==============================================================================
int bufferSize;
Atomic <int> validStart, validEnd;
};
#endif

View File

@@ -1,487 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_HASHMAP_BEASTHEADER
#define BEAST_HASHMAP_BEASTHEADER
#include "beast_OwnedArray.h"
#include "beast_LinkedListPointer.h"
#include "../memory/beast_ScopedPointer.h"
/** Simple hash functions for use with HashMap.
@see HashMap
*/
// VFALCO TODO Rewrite the hash functions to return a uint32, and not
// take the upperLimit parameter. Just do the mod in the
// calling function for simplicity.
class DefaultHashFunctions
{
public:
/** Generates a simple hash from an integer. */
int generateHash (const int key, const int upperLimit) const noexcept { return std::abs (key) % upperLimit; }
/** Generates a simple hash from an int64. */
int generateHash (const int64 key, const int upperLimit) const noexcept { return std::abs ((int) key) % upperLimit; }
/** Generates a simple hash from a string. */
int generateHash (const String& key, const int upperLimit) const noexcept { return (int) (((uint32) key.hashCode()) % (uint32) upperLimit); }
/** Generates a simple hash from a variant. */
int generateHash (const var& key, const int upperLimit) const noexcept { return generateHash (key.toString(), upperLimit); }
};
#if 0
/** Hardened hash functions for use with HashMap.
The seed is used to make the hash unpredictable. This prevents
attackers from exploiting crafted inputs to produce degenerate
containers.
*/
class HardenedHashFunctions
{
public:
/** Construct a hash function.
If a seed is specified it will be used, else a random seed
will be generated from the system.
@param seedToUse An optional seed to use.
*/
explicit HardenedHashFunctions (int seedToUse = Random::getSystemRandom ().nextInt ())
: m_seed (seedToUse)
{
}
// VFALCO TODO Need hardened versions of these functions which use the seed!
private:
int m_seed;
};
#endif
//==============================================================================
/**
Holds a set of mappings between some key/value pairs.
The types of the key and value objects are set as template parameters.
You can also specify a class to supply a hash function that converts a key value
into an hashed integer. This class must have the form:
@code
struct MyHashGenerator
{
int generateHash (MyKeyType key, int upperLimit)
{
// The function must return a value 0 <= x < upperLimit
return someFunctionOfMyKeyType (key) % upperLimit;
}
};
@endcode
Like the Array class, the key and value types are expected to be copy-by-value
types, so if you define them to be pointer types, this class won't delete the
objects that they point to.
If you don't supply a class for the HashFunctionToUse template parameter, the
default one provides some simple mappings for strings and ints.
@code
HashMap<int, String> hash;
hash.set (1, "item1");
hash.set (2, "item2");
DBG (hash [1]); // prints "item1"
DBG (hash [2]); // prints "item2"
// This iterates the map, printing all of its key -> value pairs..
for (HashMap<int, String>::Iterator i (hash); i.next();)
DBG (i.getKey() << " -> " << i.getValue());
@endcode
@tparam HashFunctionToUse The type of hash functions, which must be copy
constructible.
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
*/
template <typename KeyType,
typename ValueType,
class HashFunctionToUse = DefaultHashFunctions,
class TypeOfCriticalSectionToUse = DummyCriticalSection>
class HashMap
: public Uncopyable
, LeakChecked <HashMap <KeyType,
ValueType,
HashFunctionToUse,
TypeOfCriticalSectionToUse> >
{
private:
typedef PARAMETER_TYPE (KeyType) KeyTypeParameter;
typedef PARAMETER_TYPE (ValueType) ValueTypeParameter;
public:
//==============================================================================
/** Creates an empty hash-map.
The numberOfSlots parameter specifies the number of hash entries the map will
use. This will be the "upperLimit" parameter that is passed to your generateHash()
function. The number of hash slots will grow automatically if necessary, or
it can be remapped manually using remapTable().
@param hashFunctionToUse An instance of HashFunctionToUse, which will be
copied and stored to use with the HashMap. This
can be left out if HashFunctionToUse has a default
constructor.
*/
explicit HashMap (const int numberOfSlots = defaultHashTableSize,
HashFunctionToUse hashFunctionToUse_ = HashFunctionToUse ())
: hashFunctionToUse (hashFunctionToUse_)
, totalNumItems (0)
{
slots.insertMultiple (0, nullptr, numberOfSlots);
}
/** Destructor. */
~HashMap()
{
clear();
}
//==============================================================================
/** Removes all values from the map.
Note that this will clear the content, but won't affect the number of slots (see
remapTable and getNumSlots).
*/
void clear()
{
const ScopedLockType sl (getLock());
for (int i = slots.size(); --i >= 0;)
{
HashEntry* h = slots.getUnchecked(i);
while (h != nullptr)
{
const ScopedPointer<HashEntry> deleter (h);
h = h->nextEntry;
}
slots.set (i, nullptr);
}
totalNumItems = 0;
}
//==============================================================================
/** Returns the current number of items in the map. */
inline int size() const noexcept
{
return totalNumItems;
}
/** Returns the value corresponding to a given key.
If the map doesn't contain the key, a default instance of the value type is returned.
@param keyToLookFor the key of the item being requested
*/
inline ValueType operator[] (KeyTypeParameter keyToLookFor) const
{
const ScopedLockType sl (getLock());
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
if (entry->key == keyToLookFor)
return entry->value;
return ValueType();
}
//==============================================================================
/** Returns true if the map contains an item with the specied key. */
bool contains (KeyTypeParameter keyToLookFor) const
{
const ScopedLockType sl (getLock());
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
if (entry->key == keyToLookFor)
return true;
return false;
}
/** Returns true if the hash contains at least one occurrence of a given value. */
bool containsValue (ValueTypeParameter valueToLookFor) const
{
const ScopedLockType sl (getLock());
for (int i = getNumSlots(); --i >= 0;)
for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
if (entry->value == valueToLookFor)
return true;
return false;
}
//==============================================================================
/** Adds or replaces an element in the hash-map.
If there's already an item with the given key, this will replace its value. Otherwise, a new item
will be added to the map.
*/
void set (KeyTypeParameter newKey, ValueTypeParameter newValue)
{
const ScopedLockType sl (getLock());
const int hashIndex = generateHashFor (newKey);
HashEntry* const firstEntry = slots.getUnchecked (hashIndex);
for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
{
if (entry->key == newKey)
{
entry->value = newValue;
return;
}
}
slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
++totalNumItems;
if (totalNumItems > (getNumSlots() * 3) / 2)
remapTable (getNumSlots() * 2);
}
/** Removes an item with the given key. */
void remove (KeyTypeParameter keyToRemove)
{
const ScopedLockType sl (getLock());
const int hashIndex = generateHashFor (keyToRemove);
HashEntry* entry = slots.getUnchecked (hashIndex);
HashEntry* previous = nullptr;
while (entry != nullptr)
{
if (entry->key == keyToRemove)
{
const ScopedPointer<HashEntry> deleter (entry);
entry = entry->nextEntry;
if (previous != nullptr)
previous->nextEntry = entry;
else
slots.set (hashIndex, entry);
--totalNumItems;
}
else
{
previous = entry;
entry = entry->nextEntry;
}
}
}
/** Removes all items with the given value. */
void removeValue (ValueTypeParameter valueToRemove)
{
const ScopedLockType sl (getLock());
for (int i = getNumSlots(); --i >= 0;)
{
HashEntry* entry = slots.getUnchecked(i);
HashEntry* previous = nullptr;
while (entry != nullptr)
{
if (entry->value == valueToRemove)
{
const ScopedPointer<HashEntry> deleter (entry);
entry = entry->nextEntry;
if (previous != nullptr)
previous->nextEntry = entry;
else
slots.set (i, entry);
--totalNumItems;
}
else
{
previous = entry;
entry = entry->nextEntry;
}
}
}
}
/** Remaps the hash-map to use a different number of slots for its hash function.
Each slot corresponds to a single hash-code, and each one can contain multiple items.
@see getNumSlots()
*/
void remapTable (int newNumberOfSlots)
{
HashMap newTable (newNumberOfSlots);
for (int i = getNumSlots(); --i >= 0;)
for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
newTable.set (entry->key, entry->value);
swapWith (newTable);
}
/** Returns the number of slots which are available for hashing.
Each slot corresponds to a single hash-code, and each one can contain multiple items.
@see getNumSlots()
*/
inline int getNumSlots() const noexcept
{
return slots.size();
}
//==============================================================================
/** Efficiently swaps the contents of two hash-maps. */
template <class OtherHashMapType>
void swapWith (OtherHashMapType& otherHashMap) noexcept
{
const ScopedLockType lock1 (getLock());
const typename OtherHashMapType::ScopedLockType lock2 (otherHashMap.getLock());
slots.swapWith (otherHashMap.slots);
std::swap (totalNumItems, otherHashMap.totalNumItems);
}
//==============================================================================
/** Returns the CriticalSection that locks this structure.
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
an object of ScopedLockType as an RAII lock for it.
*/
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return lock; }
/** Returns the type of scoped lock to use for locking this array */
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
private:
//==============================================================================
class HashEntry : public Uncopyable
{
public:
HashEntry (KeyTypeParameter k, ValueTypeParameter val, HashEntry* const next)
: key (k), value (val), nextEntry (next)
{}
const KeyType key;
ValueType value;
HashEntry* nextEntry;
};
public:
//==============================================================================
/** Iterates over the items in a HashMap.
To use it, repeatedly call next() until it returns false, e.g.
@code
HashMap <String, String> myMap;
HashMap<String, String>::Iterator i (myMap);
while (i.next())
{
DBG (i.getKey() << " -> " << i.getValue());
}
@endcode
The order in which items are iterated bears no resemblence to the order in which
they were originally added!
Obviously as soon as you call any non-const methods on the original hash-map, any
iterators that were created beforehand will cease to be valid, and should not be used.
@see HashMap
*/
class Iterator : LeakChecked <Iterator>, public Uncopyable
{
public:
//==============================================================================
Iterator (const HashMap& hashMapToIterate)
: hashMap (hashMapToIterate), entry (nullptr), index (0)
{}
/** Moves to the next item, if one is available.
When this returns true, you can get the item's key and value using getKey() and
getValue(). If it returns false, the iteration has finished and you should stop.
*/
bool next()
{
if (entry != nullptr)
entry = entry->nextEntry;
while (entry == nullptr)
{
if (index >= hashMap.getNumSlots())
return false;
entry = hashMap.slots.getUnchecked (index++);
}
return true;
}
/** Returns the current item's key.
This should only be called when a call to next() has just returned true.
*/
KeyType getKey() const
{
return entry != nullptr ? entry->key : KeyType();
}
/** Returns the current item's value.
This should only be called when a call to next() has just returned true.
*/
ValueType getValue() const
{
return entry != nullptr ? entry->value : ValueType();
}
private:
//==============================================================================
const HashMap& hashMap;
HashEntry* entry;
int index;
};
private:
//==============================================================================
enum { defaultHashTableSize = 101 };
friend class Iterator;
HashFunctionToUse const hashFunctionToUse;
Array <HashEntry*> slots;
int totalNumItems;
TypeOfCriticalSectionToUse lock;
int generateHashFor (KeyTypeParameter key) const
{
const int hash = hashFunctionToUse.generateHash (key, getNumSlots());
bassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers!
return hash;
}
};
#endif // BEAST_HASHMAP_BEASTHEADER

View File

@@ -1,799 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_LIST_H_INCLUDED
#define BEAST_LIST_H_INCLUDED
/** Intrusive Containers
# Introduction
Intrusive containers are special containers that offer better performance
and exception safety guarantees than non-intrusive containers (like the
STL containers). They are useful building blocks for high performance
concurrent systems or other purposes where allocations are restricted
(such as the AudioIODeviceCallback object), because intrusive list
operations do not allocate or free memory.
While intrusive containers were and are widely used in C, they became more
and more forgotten in C++ due to the presence of the standard containers
which don't support intrusive techniques. VFLib not only reintroduces this
technique to C++ for lists, it also encapsulates the implementation in a
mostly compliant STL interface. Hence anyone familiar with standard
containers can easily use them.
# Interface
The interface for intrusive elements in this library is unified for all
containers. Unlike STL containers, objects placed into intrusive containers
are not copied. Instead, a pointer to the object is stored. All
responsibility for object lifetime is the responsibility of the caller;
the intrusive container just keeps track of what is in it.
Summary of intrusive container differences:
- Holds pointers to existing objects instead of copies.
- Does not allocate or free any objects.
- Requires a element's class declaration to be modified.
- Methods never throw exceptions when called with valid arguments.
# Usage
Like STL containers, intrusive containers are all template based, where the
template argument specifies the type of object that the container will hold.
These declarations specify a doubly linked list where each element points
to a user defined class:
@code
struct Object; // Forward declaration
List <Object> list; // Doubly-linked list of Object
@endcode
Because intrusive containers allocate no memory, allowing objects to be
placed inside requires a modification to their class declaration. Each
intrusive container declares a nested class `Node` which elements must be
derived from, using the Curiously Recurring Template Pattern (CRTP). We
will continue to fully declare the Object type from the previous example
to support emplacement into an intrusive container:
@code
struct Object : public List <Object>::Node // Required for List
{
void performAction ();
};
@endcode
Usage of a typedef eliminates redundant specification of the template
arguments but requires a forward declaration. The following code is
equivalent.
@code
struct Object; // Forward declaration
// Specify template parameters just once
typedef List <Object> ListType;
struct Object : public ListType::Node
{
void performAction ();
};
ListType::Node list;
@endcode
With these declarations we may proceed to create our objects, add them to
the list, and perform operations:
@code
// Create a few objects and put them in the list
for (i = 0; i < 5; ++i)
list.push_back (*new Object);
// Call a method on each list
for (ListType::iterator iter = list.begin(); iter != list.end (); ++iter)
iter->performAction ();
@endcode
Unlike regular STL containers, an object derived from an intrusive container
node cannot exist in more than one instance of that list at a time. This is
because the bookkeeping information for maintaining the list is kept in
the object rather than the list.
To support objects existing in multiple containers, templates variations
are instantiated by distinguishing them with an empty structure, called a
tag. The object is derived from multiple instances of Node, where each
instance specifies a unique tag. The tag is passed as the second template
argument. When the second argument is unspecified, the default tag is used.
This declaration example shows the usage of tags to allow an object to exist
simultaneously in two separate lists:
@code
struct GlobalListTag { }; // list of all objects
struct ActiveListTag { }; // subset of all objects that are active
class Object : public List <Object, GlobalListTag>
, public List <Object, ActiveListTag>
{
public:
Object () : m_isActive (false)
{
// Add ourselves to the global list
s_globalList.push_front (*this);
}
~Object ()
{
deactivate ();
}
void becomeActive ()
{
// Add ourselves to the active list
if (!m_isActive)
{
s_activeList.push_front (*this);
m_isActive = true;
}
}
void deactivate ()
{
if (m_isActive)
{
// Doesn't delete the object
s_activeList.erase (s_activeList.iterator_to (this));
m_isActive = false;
}
}
private:
bool m_isActive;
static List <Object, GlobalListTag> s_globalList;
static List <Object, ActiveListTag> s_activeList;
}
@endcode
@defgroup intrusive intrusive
@ingroup beast_core
*/
//------------------------------------------------------------------------------
/** Default tag for List.
@ingroup beast_core intrusive
*/
struct ListDefaultTag;
/**
Intrusive doubly linked list.
This intrusive List is a container similar in operation to std::list in the
Standard Template Library (STL). Like all @ref intrusive containers, List
requires you to first derive your class from List<>::Node:
@code
struct Object : List <Object>::Node
{
explicit Object (int value) : m_value (value)
{
}
int m_value;
};
@endcode
Now we define the list, and add a couple of items.
@code
List <Object> list;
list.push_back (* (new Object (1)));
list.push_back (* (new Object (2)));
@endcode
For compatibility with the standard containers, push_back() expects a
reference to the object. Unlike the standard container, however, push_back()
places the actual object in the list and not a copy-constructed duplicate.
Iterating over the list follows the same idiom as the STL:
@code
for (List <Object>::iterator iter = list.begin(); iter != list.end; ++iter)
std::cout << iter->m_value;
@endcode
You can even use BOOST_FOREACH, or range based for loops:
@code
BOOST_FOREACH (Object& object, list) // boost only
std::cout << object.m_value;
for (Object& object : list) // C++11 only
std::cout << object.m_value;
@endcode
Because List is mostly STL compliant, it can be passed into STL algorithms:
e.g. `std::for_each()` or `std::find_first_of()`.
In general, objects placed into a List should be dynamically allocated
although this cannot be enforced at compile time. Since the caller provides
the storage for the object, the caller is also responsible for deleting the
object. An object still exists after being removed from a List, until the
caller deletes it. This means an element can be moved from one List to
another with practically no overhead.
Unlike the standard containers, an object may only exist in one list at a
time, unless special preparations are made. The Tag template parameter is
used to distinguish between different list types for the same object,
allowing the object to exist in more than one list simultaneously.
For example, consider an actor system where a global list of actors is
maintained, so that they can each be periodically receive processing
time. We wish to also maintain a list of the subset of actors that require
a domain-dependent update. To achieve this, we declare two tags, the
associated list types, and the list element thusly:
@code
struct Actor; // Forward declaration required
struct ProcessTag { };
struct UpdateTag { };
typedef List <Actor, ProcessTag> ProcessList;
typedef List <Actor, UpdateTag> UpdateList;
// Derive from both node types so we can be in each list at once.
//
struct Actor : ProcessList::Node, UpdateList::Node
{
bool process (); // returns true if we need an update
void update ();
};
@endcode
@tparam Element The base type of element which the list will store
pointers to.
@tparam Tag An optional unique type name used to distinguish lists and nodes,
when the object can exist in multiple lists simultaneously.
@ingroup beast_core intrusive
*/
template <class Element, class Tag = ListDefaultTag>
class List : public Uncopyable
{
public:
typedef int size_type;
typedef Element value_type;
typedef Element& reference;
typedef Element const& const_reference;
typedef Element* pointer;
typedef Element const* const_pointer;
/** Thrown when some members are called with an empty list. */
struct empty_list_error : std::logic_error
{
empty_list_error () : std::logic_error ("empty list")
{
}
};
class Node : public Uncopyable
{
public:
Node () { }
private:
friend class List;
Node* m_next;
Node* m_prev;
};
private:
template <class ElemType, class NodeType>
class iterator_base : public std::iterator <
std::bidirectional_iterator_tag, int >
{
public:
typedef ElemType value_type;
typedef ElemType* pointer;
typedef ElemType& reference;
iterator_base (NodeType* node = nullptr) : m_node (node)
{
}
template <class OtherElemType, class OtherNodeType>
iterator_base (iterator_base <OtherElemType, OtherNodeType> const& other)
: m_node (other.m_node)
{
}
template <class OtherElemType, class OtherNodeType>
iterator_base& operator= (iterator_base <OtherElemType, OtherNodeType> const& other)
{
m_node = other.m_node;
return *this;
}
template <class OtherElemType, class OtherNodeType>
bool operator == (iterator_base <OtherElemType, OtherNodeType> const& other) const
{
return m_node == other.m_node;
}
template <class OtherElemType, class OtherNodeType>
bool operator != (iterator_base <OtherElemType, OtherNodeType> const& other) const
{
return ! this->operator== (other);
}
reference operator* () const
{
return dereference ();
}
pointer operator-> () const
{
return &dereference ();
}
iterator_base& operator++ ()
{
increment ();
return *this;
}
iterator_base operator++ (int)
{
iterator_base result (*this);
increment ();
return result;
}
iterator_base& operator-- ()
{
decrement ();
return *this;
}
iterator_base operator-- (int)
{
iterator_base result (*this);
decrement ();
return result;
}
private:
friend class List;
NodeType* get_node ()
{
return m_node;
}
NodeType const* get_node () const
{
return m_node;
}
reference dereference () const
{
return *static_cast <ElemType*> (m_node);
}
bool equal (NodeType* const* node) const
{
return m_node == node;
}
void increment ()
{
bassert (m_node->m_next);
m_node = m_node->m_next;
}
void decrement ()
{
bassert (m_node->m_prev && m_node->m_prev->m_prev != 0);
m_node = m_node->m_prev;
}
private:
NodeType* m_node;
};
public:
/** A read/write List iterator. */
typedef iterator_base <Element, Node> iterator;
/** A read-only List iterator. */
typedef iterator_base <Element const, Node const> const_iterator;
public:
/** Create an empty list. */
List () : m_size (0)
{
m_head.m_prev = nullptr; // identifies the head
m_tail.m_next = nullptr; // identifies the tail
clear ();
}
/** Returns the number of elements in the list
@return The number of elements in the list.
*/
size_type size () const
{
return m_size;
}
/** Obtain a reference to the first element.
@invariant The list may not be empty.
@return A reference to the first element.
*/
reference front ()
{
if (empty ())
Throw (empty_list_error (), __FILE__, __LINE__);
return element_from (m_head.m_next);
}
/** Obtain a const reference to the first element.
@invariant The list may not be empty.
@return A const reference to the first element.
*/
const_reference front () const
{
if (empty ())
Throw (empty_list_error (), __FILE__, __LINE__);
return element_from (m_head.m_next);
}
/** Obtain a reference to the last element.
@invariant The list may not be empty.
@return A reference to the last element.
*/
reference back ()
{
if (empty ())
Throw (empty_list_error (), __FILE__, __LINE__);
return element_from (m_tail.m_prev);
}
/** Obtain a const reference to the last element.
@invariant The list may not be empty.
@return A const reference to the last element.
*/
const_reference back () const
{
if (empty ())
Throw (empty_list_error (), __FILE__, __LINE__);
return element_from (m_tail.m_prev);
}
/** Obtain an iterator to the beginning of the list.
@return An iterator pointing to the beginning of the list.
*/
iterator begin ()
{
return iterator (m_head.m_next);
}
/** Obtain a const iterator to the beginning of the list.
@return A const iterator pointing to the beginning of the list.
*/
const_iterator begin () const
{
return const_iterator (m_head.m_next);
}
/** Obtain a const iterator to the beginning of the list.
@return A const iterator pointing to the beginning of the list.
*/
const_iterator cbegin () const
{
return const_iterator (m_head.m_next);
}
/** Obtain a iterator to the end of the list.
@return An iterator pointing to the end of the list.
*/
iterator end ()
{
return iterator (&m_tail);
}
/** Obtain a const iterator to the end of the list.
@return A constiterator pointing to the end of the list.
*/
const_iterator end () const
{
return const_iterator (&m_tail);
}
/** Obtain a const iterator to the end of the list.
@return A constiterator pointing to the end of the list.
*/
const_iterator cend () const
{
return const_iterator (&m_tail);
}
/** Determine if the list is empty.
@return `true` if the list is empty.
*/
bool empty () const
{
return m_head.m_next == &m_tail;
}
/** Clear the list.
@note This does not free the elements.
*/
void clear ()
{
m_head.m_next = &m_tail;
m_tail.m_prev = &m_head;
m_size = 0;
}
/** Insert an element.
@invariant The element must not already be in the list.
@param pos The location to insert after.
@param elem The element to insert.
@return An iterator pointing to the newly inserted element.
*/
iterator insert (iterator pos, Element& elem)
{
Node* node = node_from (elem);
node->m_next = pos.get_node ();
node->m_prev = node->m_next->m_prev;
node->m_next->m_prev = node;
node->m_prev->m_next = node;
++m_size;
return iterator (node);
}
/** Insert another list into this one.
The other list is cleared.
@param pos The location to insert after.
@param other The list to insert.
*/
void insert (iterator pos, List& other)
{
if (!other.empty ())
{
Node* before = pos.get_node ();
other.m_head.m_next->m_prev = before->m_prev;
before->m_prev->m_next = other.m_head.m_next;
other.m_tail.m_prev->m_next = before;
before->m_prev = other.m_tail.m_prev;
m_size += other.m_size;
other.clear ();
}
}
/** Remove an element.
@invariant The element must exist in the list.
@param pos An iterator pointing to the element to remove.
@return An iterator pointing to the next element after the one removed.
*/
iterator erase (iterator pos)
{
Node* node = pos.get_node ();
++pos;
node->m_next->m_prev = node->m_prev;
node->m_prev->m_next = node->m_next;
--m_size;
return pos;
}
/** Insert an element at the beginning of the list.
@invariant The element must not exist in the list.
@param elem The element to insert.
*/
void push_front (Element& elem)
{
insert (begin (), elem);
}
/** Remove the element at the beginning of the list.
@invariant The list must not be empty.
@return A reference to the popped element.
*/
Element& pop_front ()
{
Element& elem (front ());
erase (begin ());
return elem;
}
/** Append an element at the end of the list.
@invariant The element must not exist in the list.
@param elem The element to append.
*/
void push_back (Element& elem)
{
insert (end (), elem);
}
/** Remove the element at the end of the list.
@invariant The list must not be empty.
@return A reference to the popped element.
*/
Element& pop_back ()
{
Element& elem (back ());
erase (--end ());
return elem;
}
/** Swap contents with another list.
*/
void swap (List& other)
{
List temp;
temp.append (other);
other.append (*this);
append (temp);
}
/** Insert another list at the beginning of this list.
The other list is cleared.
@param list The other list to insert.
*/
void prepend (List& list)
{
insert (begin (), list);
}
/** Append another list at the end of this list.
The other list is cleared.
@param list the other list to append.
*/
void append (List& list)
{
insert (end (), list);
}
/** Obtain an iterator from an element.
@invariant The element must exist in the list.
@param elem The element to obtain an iterator for.
@return An iterator to the element.
*/
iterator iterator_to (Element& elem) const
{
return iterator (static_cast <Node*> (&elem));
}
/** Obtain a const iterator from an element.
@invariant The element must exist in the list.
@param elem The element to obtain an iterator for.
@return A const iterator to the element.
*/
const_iterator const_iterator_to (Element const& elem) const
{
return const_iterator (static_cast <Node const*> (&elem));
}
private:
inline reference element_from (Node* node)
{
return * (static_cast <pointer> (node));
}
inline const_reference element_from (Node const* node) const
{
return * (static_cast <const_pointer> (node));
}
inline Node* node_from (Element& elem)
{
return static_cast <Node*> (&elem);
}
inline Node const* node_from (Element const& elem) const
{
return static_cast <Node const*> (&elem);
}
private:
size_type m_size;
Node m_head;
Node m_tail;
};
#endif

View File

@@ -1,165 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_LOCKFREESTACK_BEASTHEADER
#define BEAST_LOCKFREESTACK_BEASTHEADER
struct LockFreeStackDefaultTag;
/*============================================================================*/
/**
Multiple Producer, Multiple Consumer (MPMC) intrusive stack.
This stack is implemented using the same intrusive interface as List. All
operations are lock-free.
The caller is responsible for preventing the "ABA" problem
(http://en.wikipedia.org/wiki/ABA_problem)
@param Tag A type name used to distinguish lists and nodes, for
putting objects in multiple lists. If this parameter is
omitted, the default tag is used.
@ingroup beast_core intrusive
*/
template <class Element, class Tag = LockFreeStackDefaultTag>
class LockFreeStack : public Uncopyable
{
public:
class Node : public Uncopyable
{
public:
Node ()
{
}
explicit Node (Node* next) : m_next (next)
{
}
private:
friend class LockFreeStack;
// VFALCO TODO Use regular Atomic<>
AtomicPointer <Node> m_next;
};
public:
LockFreeStack () : m_head (0)
{
}
/** Create a LockFreeStack from another stack.
The contents of the other stack are atomically acquired.
The other stack is cleared.
@param other The other stack to acquire.
*/
explicit LockFreeStack (LockFreeStack& other)
{
Node* head;
do
{
head = other.m_head.get ();
}
while (!other.m_head.compareAndSet (0, head));
m_head = head;
}
/** Push a node onto the stack.
The caller is responsible for preventing the ABA problem. This operation
is lock-free.
@param node The node to push.
@return True if the stack was previously empty. If multiple threads
are attempting to push, only one will receive true.
*/
bool push_front (Node* node)
{
bool first;
Node* head;
do
{
head = m_head.get ();
first = head == 0;
node->m_next = head;
}
while (!m_head.compareAndSet (node, head));
return first;
}
/** Pop an element off the stack.
The caller is responsible for preventing the ABA problem. This operation
is lock-free.
@return The element that was popped, or nullptr if the stack was empty.
*/
Element* pop_front ()
{
Node* node;
Node* head;
do
{
node = m_head.get ();
if (node == 0)
break;
head = node->m_next.get ();
}
while (!m_head.compareAndSet (head, node));
return node ? static_cast <Element*> (node) : nullptr;
}
/** Swap the contents of this stack with another stack.
This call is not thread safe or atomic. The caller is responsible for
synchronizing access.
@param other The other stack to swap contents with.
*/
void swap (LockFreeStack& other)
{
Node* temp = other.m_head.get ();
other.m_head.set (m_head.get ());
m_head.set (temp);
}
private:
AtomicPointer <Node> m_head;
};
/*============================================================================*/
/** Default tag for LockFreeStack
@ingroup beast_core intrusive
*/
struct LockFreeStackDefaultTag { };
#endif

View File

@@ -1,862 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SHAREDOBJECTARRAY_H_INCLUDED
#define BEAST_SHAREDOBJECTARRAY_H_INCLUDED
#include "../memory/beast_SharedObject.h"
#include "beast_ArrayAllocationBase.h"
#include "beast_ElementComparator.h"
#include "../threads/beast_CriticalSection.h"
//==============================================================================
/**
Holds a list of objects derived from SharedObject.
A SharedObjectArray holds objects derived from SharedObject,
and takes care of incrementing and decrementing their ref counts when they
are added and removed from the array.
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
@see Array, OwnedArray, StringArray
*/
template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection>
class SharedObjectArray
{
public:
typedef SharedObjectPtr<ObjectClass> ObjectClassPtr;
//==============================================================================
/** Creates an empty array.
@see SharedObject, Array, OwnedArray
*/
SharedObjectArray() noexcept
: numUsed (0)
{
}
/** Creates a copy of another array */
SharedObjectArray (const SharedObjectArray& other) noexcept
{
const ScopedLockType lock (other.getLock());
numUsed = other.size();
data.setAllocatedSize (numUsed);
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
for (int i = numUsed; --i >= 0;)
if (ObjectClass* o = data.elements[i])
o->incReferenceCount();
}
/** Creates a copy of another array */
template <class OtherObjectClass, class OtherCriticalSection>
SharedObjectArray (const SharedObjectArray<OtherObjectClass, OtherCriticalSection>& other) noexcept
{
const typename SharedObjectArray<OtherObjectClass, OtherCriticalSection>::ScopedLockType lock (other.getLock());
numUsed = other.size();
data.setAllocatedSize (numUsed);
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
for (int i = numUsed; --i >= 0;)
if (ObjectClass* o = data.elements[i])
o->incReferenceCount();
}
/** Copies another array into this one.
Any existing objects in this array will first be released.
*/
SharedObjectArray& operator= (const SharedObjectArray& other) noexcept
{
SharedObjectArray otherCopy (other);
swapWith (otherCopy);
return *this;
}
/** Copies another array into this one.
Any existing objects in this array will first be released.
*/
template <class OtherObjectClass>
SharedObjectArray<ObjectClass, TypeOfCriticalSectionToUse>& operator= (const SharedObjectArray<OtherObjectClass, TypeOfCriticalSectionToUse>& other) noexcept
{
SharedObjectArray<ObjectClass, TypeOfCriticalSectionToUse> otherCopy (other);
swapWith (otherCopy);
return *this;
}
/** Destructor.
Any objects in the array will be released, and may be deleted if not referenced from elsewhere.
*/
~SharedObjectArray()
{
clear();
}
//==============================================================================
/** Removes all objects from the array.
Any objects in the array that are not referenced from elsewhere will be deleted.
*/
void clear()
{
const ScopedLockType lock (getLock());
while (numUsed > 0)
if (ObjectClass* o = data.elements [--numUsed])
o->decReferenceCount();
bassert (numUsed == 0);
data.setAllocatedSize (0);
}
/** Returns the current number of objects in the array. */
inline int size() const noexcept
{
return numUsed;
}
/** Returns a pointer to the object at this index in the array.
If the index is out-of-range, this will return a null pointer, (and
it could be null anyway, because it's ok for the array to hold null
pointers as well as objects).
@see getUnchecked
*/
inline ObjectClassPtr operator[] (const int index) const noexcept
{
return getObjectPointer (index);
}
/** Returns a pointer to the object at this index in the array, without checking
whether the index is in-range.
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
it can be used when you're sure the index is always going to be legal.
*/
inline ObjectClassPtr getUnchecked (const int index) const noexcept
{
return getObjectPointerUnchecked (index);
}
/** Returns a raw pointer to the object at this index in the array.
If the index is out-of-range, this will return a null pointer, (and
it could be null anyway, because it's ok for the array to hold null
pointers as well as objects).
@see getUnchecked
*/
inline ObjectClass* getObjectPointer (const int index) const noexcept
{
const ScopedLockType lock (getLock());
return isPositiveAndBelow (index, numUsed) ? data.elements [index]
: nullptr;
}
/** Returns a raw pointer to the object at this index in the array, without checking
whether the index is in-range.
*/
inline ObjectClass* getObjectPointerUnchecked (const int index) const noexcept
{
const ScopedLockType lock (getLock());
bassert (isPositiveAndBelow (index, numUsed));
return data.elements [index];
}
/** Returns a pointer to the first object in the array.
This will return a null pointer if the array's empty.
@see getLast
*/
inline ObjectClassPtr getFirst() const noexcept
{
const ScopedLockType lock (getLock());
return numUsed > 0 ? data.elements [0]
: static_cast <ObjectClass*> (nullptr);
}
/** Returns a pointer to the last object in the array.
This will return a null pointer if the array's empty.
@see getFirst
*/
inline ObjectClassPtr getLast() const noexcept
{
const ScopedLockType lock (getLock());
return numUsed > 0 ? data.elements [numUsed - 1]
: static_cast <ObjectClass*> (nullptr);
}
/** Returns a pointer to the actual array data.
This pointer will only be valid until the next time a non-const method
is called on the array.
*/
inline ObjectClass** getRawDataPointer() const noexcept
{
return data.elements;
}
//==============================================================================
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass** begin() const noexcept
{
return data.elements;
}
/** Returns a pointer to the element which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ObjectClass** end() const noexcept
{
return data.elements + numUsed;
}
//==============================================================================
/** Finds the index of the first occurrence of an object in the array.
@param objectToLookFor the object to look for
@returns the index at which the object was found, or -1 if it's not found
*/
int indexOf (const ObjectClass* const objectToLookFor) const noexcept
{
const ScopedLockType lock (getLock());
ObjectClass** e = data.elements.getData();
ObjectClass** const endPointer = e + numUsed;
while (e != endPointer)
{
if (objectToLookFor == *e)
return static_cast <int> (e - data.elements.getData());
++e;
}
return -1;
}
/** Returns true if the array contains a specified object.
@param objectToLookFor the object to look for
@returns true if the object is in the array
*/
bool contains (const ObjectClass* const objectToLookFor) const noexcept
{
const ScopedLockType lock (getLock());
ObjectClass** e = data.elements.getData();
ObjectClass** const endPointer = e + numUsed;
while (e != endPointer)
{
if (objectToLookFor == *e)
return true;
++e;
}
return false;
}
/** Appends a new object to the end of the array.
This will increase the new object's reference count.
@param newObject the new object to add to the array
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
*/
ObjectClass* add (ObjectClass* const newObject) noexcept
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1);
bassert (data.elements != nullptr);
data.elements [numUsed++] = newObject;
if (newObject != nullptr)
newObject->incReferenceCount();
return newObject;
}
/** Inserts a new object into the array at the given index.
If the index is less than 0 or greater than the size of the array, the
element will be added to the end of the array.
Otherwise, it will be inserted into the array, moving all the later elements
along to make room.
This will increase the new object's reference count.
@param indexToInsertAt the index at which the new element should be inserted
@param newObject the new object to add to the array
@see add, addSorted, addIfNotAlreadyThere, set
*/
ObjectClass* insert (int indexToInsertAt,
ObjectClass* const newObject) noexcept
{
if (indexToInsertAt >= 0)
{
const ScopedLockType lock (getLock());
if (indexToInsertAt > numUsed)
indexToInsertAt = numUsed;
data.ensureAllocatedSize (numUsed + 1);
bassert (data.elements != nullptr);
ObjectClass** const e = data.elements + indexToInsertAt;
const int numToMove = numUsed - indexToInsertAt;
if (numToMove > 0)
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
*e = newObject;
if (newObject != nullptr)
newObject->incReferenceCount();
++numUsed;
return newObject;
}
else
{
return add (newObject);
}
}
/** Appends a new object at the end of the array as long as the array doesn't
already contain it.
If the array already contains a matching object, nothing will be done.
@param newObject the new object to add to the array
*/
void addIfNotAlreadyThere (ObjectClass* const newObject) noexcept
{
const ScopedLockType lock (getLock());
if (! contains (newObject))
add (newObject);
}
/** Replaces an object in the array with a different one.
If the index is less than zero, this method does nothing.
If the index is beyond the end of the array, the new object is added to the end of the array.
The object being added has its reference count increased, and if it's replacing
another object, then that one has its reference count decreased, and may be deleted.
@param indexToChange the index whose value you want to change
@param newObject the new value to set for this index.
@see add, insert, remove
*/
void set (const int indexToChange,
ObjectClass* const newObject)
{
if (indexToChange >= 0)
{
const ScopedLockType lock (getLock());
if (newObject != nullptr)
newObject->incReferenceCount();
if (indexToChange < numUsed)
{
if (ObjectClass* o = data.elements [indexToChange])
o->decReferenceCount();
data.elements [indexToChange] = newObject;
}
else
{
data.ensureAllocatedSize (numUsed + 1);
bassert (data.elements != nullptr);
data.elements [numUsed++] = newObject;
}
}
}
/** Adds elements from another array to the end of this array.
@param arrayToAddFrom the array from which to copy the elements
@param startIndex the first element of the other array to start copying from
@param numElementsToAdd how many elements to add from the other array. If this
value is negative or greater than the number of available elements,
all available elements will be copied.
@see add
*/
void addArray (const SharedObjectArray<ObjectClass, TypeOfCriticalSectionToUse>& arrayToAddFrom,
int startIndex = 0,
int numElementsToAdd = -1) noexcept
{
const ScopedLockType lock1 (arrayToAddFrom.getLock());
{
const ScopedLockType lock2 (getLock());
if (startIndex < 0)
{
bassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
numElementsToAdd = arrayToAddFrom.size() - startIndex;
if (numElementsToAdd > 0)
{
data.ensureAllocatedSize (numUsed + numElementsToAdd);
while (--numElementsToAdd >= 0)
add (arrayToAddFrom.getUnchecked (startIndex++));
}
}
}
/** Inserts a new object into the array assuming that the array is sorted.
This will use a comparator to find the position at which the new object
should go. If the array isn't sorted, the behaviour of this
method will be unpredictable.
@param comparator the comparator object to use to compare the elements - see the
sort() method for details about this object's form
@param newObject the new object to insert to the array
@returns the index at which the new object was added
@see add, sort
*/
template <class ElementComparator>
int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
{
const ScopedLockType lock (getLock());
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
insert (index, newObject);
return index;
}
/** Inserts or replaces an object in the array, assuming it is sorted.
This is similar to addSorted, but if a matching element already exists, then it will be
replaced by the new one, rather than the new one being added as well.
*/
template <class ElementComparator>
void addOrReplaceSorted (ElementComparator& comparator,
ObjectClass* newObject) noexcept
{
const ScopedLockType lock (getLock());
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
if (index > 0 && comparator.compareElements (newObject, data.elements [index - 1]) == 0)
set (index - 1, newObject); // replace an existing object that matches
else
insert (index, newObject); // no match, so insert the new one
}
/** Finds the index of an object in the array, assuming that the array is sorted.
This will use a comparator to do a binary-chop to find the index of the given
element, if it exists. If the array isn't sorted, the behaviour of this
method will be unpredictable.
@param comparator the comparator to use to compare the elements - see the sort()
method for details about the form this object should take
@param objectToLookFor the object to search for
@returns the index of the element, or -1 if it's not found
@see addSorted, sort
*/
template <class ElementComparator>
int indexOfSorted (ElementComparator& comparator,
const ObjectClass* const objectToLookFor) const noexcept
{
(void) comparator;
const ScopedLockType lock (getLock());
int s = 0, e = numUsed;
while (s < e)
{
if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
return s;
const int halfway = (s + e) / 2;
if (halfway == s)
break;
if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
s = halfway;
else
e = halfway;
}
return -1;
}
//==============================================================================
/** Removes an object from the array.
This will remove the object at a given index and move back all the
subsequent objects to close the gap.
If the index passed in is out-of-range, nothing will happen.
The object that is removed will have its reference count decreased,
and may be deleted if not referenced from elsewhere.
@param indexToRemove the index of the element to remove
@see removeObject, removeRange
*/
void remove (const int indexToRemove)
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (indexToRemove, numUsed))
{
ObjectClass** const e = data.elements + indexToRemove;
if (ObjectClass* o = *e)
o->decReferenceCount();
--numUsed;
const int numberToShift = numUsed - indexToRemove;
if (numberToShift > 0)
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
if ((numUsed << 1) < data.numAllocated)
minimiseStorageOverheads();
}
}
/** Removes and returns an object from the array.
This will remove the object at a given index and return it, moving back all
the subsequent objects to close the gap. If the index passed in is out-of-range,
nothing will happen and a null pointer will be returned.
@param indexToRemove the index of the element to remove
@see remove, removeObject, removeRange
*/
ObjectClassPtr removeAndReturn (const int indexToRemove)
{
ObjectClassPtr removedItem;
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (indexToRemove, numUsed))
{
ObjectClass** const e = data.elements + indexToRemove;
if (ObjectClass* o = *e)
{
removedItem = o;
o->decReferenceCount();
}
--numUsed;
const int numberToShift = numUsed - indexToRemove;
if (numberToShift > 0)
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
if ((numUsed << 1) < data.numAllocated)
minimiseStorageOverheads();
}
return removedItem;
}
/** Removes the first occurrence of a specified object from the array.
If the item isn't found, no action is taken. If it is found, it is
removed and has its reference count decreased.
@param objectToRemove the object to try to remove
@see remove, removeRange
*/
void removeObject (ObjectClass* const objectToRemove)
{
const ScopedLockType lock (getLock());
remove (indexOf (objectToRemove));
}
/** Removes a range of objects from the array.
This will remove a set of objects, starting from the given index,
and move any subsequent elements down to close the gap.
If the range extends beyond the bounds of the array, it will
be safely clipped to the size of the array.
The objects that are removed will have their reference counts decreased,
and may be deleted if not referenced from elsewhere.
@param startIndex the index of the first object to remove
@param numberToRemove how many objects should be removed
@see remove, removeObject
*/
void removeRange (const int startIndex,
const int numberToRemove)
{
const ScopedLockType lock (getLock());
const int start = blimit (0, numUsed, startIndex);
const int endIndex = blimit (0, numUsed, startIndex + numberToRemove);
if (endIndex > start)
{
int i;
for (i = start; i < endIndex; ++i)
{
if (ObjectClass* o = data.elements[i])
{
o->decReferenceCount();
data.elements[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
}
}
const int rangeSize = endIndex - start;
ObjectClass** e = data.elements + start;
i = numUsed - endIndex;
numUsed -= rangeSize;
while (--i >= 0)
{
*e = e [rangeSize];
++e;
}
if ((numUsed << 1) < data.numAllocated)
minimiseStorageOverheads();
}
}
/** Removes the last n objects from the array.
The objects that are removed will have their reference counts decreased,
and may be deleted if not referenced from elsewhere.
@param howManyToRemove how many objects to remove from the end of the array
@see remove, removeObject, removeRange
*/
void removeLast (int howManyToRemove = 1)
{
const ScopedLockType lock (getLock());
if (howManyToRemove > numUsed)
howManyToRemove = numUsed;
while (--howManyToRemove >= 0)
remove (numUsed - 1);
}
/** Swaps a pair of objects in the array.
If either of the indexes passed in is out-of-range, nothing will happen,
otherwise the two objects at these positions will be exchanged.
*/
void swap (const int index1,
const int index2) noexcept
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (index1, numUsed)
&& isPositiveAndBelow (index2, numUsed))
{
std::swap (data.elements [index1],
data.elements [index2]);
}
}
/** Moves one of the objects to a different position.
This will move the object to a specified index, shuffling along
any intervening elements as required.
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
@param currentIndex the index of the object to be moved. If this isn't a
valid index, then nothing will be done
@param newIndex the index at which you'd like this object to end up. If this
is less than zero, it will be moved to the end of the array
*/
void move (const int currentIndex,
int newIndex) noexcept
{
if (currentIndex != newIndex)
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (currentIndex, numUsed))
{
if (! isPositiveAndBelow (newIndex, numUsed))
newIndex = numUsed - 1;
ObjectClass* const value = data.elements [currentIndex];
if (newIndex > currentIndex)
{
memmove (data.elements + currentIndex,
data.elements + currentIndex + 1,
sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
}
else
{
memmove (data.elements + newIndex + 1,
data.elements + newIndex,
sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
}
data.elements [newIndex] = value;
}
}
}
//==============================================================================
/** This swaps the contents of this array with those of another array.
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
because it just swaps their internal pointers.
*/
template <class OtherArrayType>
void swapWith (OtherArrayType& otherArray) noexcept
{
const ScopedLockType lock1 (getLock());
const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
data.swapWith (otherArray.data);
std::swap (numUsed, otherArray.numUsed);
}
//==============================================================================
/** Compares this array to another one.
@returns true only if the other array contains the same objects in the same order
*/
bool operator== (const SharedObjectArray& other) const noexcept
{
const ScopedLockType lock2 (other.getLock());
const ScopedLockType lock1 (getLock());
if (numUsed != other.numUsed)
return false;
for (int i = numUsed; --i >= 0;)
if (data.elements [i] != other.data.elements [i])
return false;
return true;
}
/** Compares this array to another one.
@see operator==
*/
bool operator!= (const SharedObjectArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const noexcept
{
return ! operator== (other);
}
//==============================================================================
/** Sorts the elements in the array.
This will use a comparator object to sort the elements into order. The object
passed must have a method of the form:
@code
int compareElements (ElementType first, ElementType second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator the comparator to use for comparing elements.
@param retainOrderOfEquivalentItems if this is true, then items
which the comparator says are equivalent will be
kept in the order in which they currently appear
in the array. This is slower to perform, but may
be important in some cases. If it's false, a faster
algorithm is used, but equivalent elements may be
rearranged.
@see sortArray
*/
template <class ElementComparator>
void sort (ElementComparator& comparator,
const bool retainOrderOfEquivalentItems = false) const noexcept
{
(void) comparator; // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
const ScopedLockType lock (getLock());
sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
}
//==============================================================================
/** Reduces the amount of storage being used by the array.
Arrays typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads() noexcept
{
const ScopedLockType lock (getLock());
data.shrinkToNoMoreThan (numUsed);
}
/** Increases the array's internal storage to hold a minimum number of elements.
Calling this before adding a large known number of elements means that
the array won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
*/
void ensureStorageAllocated (const int minNumElements)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (minNumElements);
}
//==============================================================================
/** Returns the CriticalSection that locks this array.
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
an object of ScopedLockType as an RAII lock for it.
*/
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data; }
/** Returns the type of scoped lock to use for locking this array */
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
private:
//==============================================================================
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
int numUsed;
};
#endif

View File

@@ -1,212 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SHAREDTABLE_BEASTHEADER
#define BEAST_SHAREDTABLE_BEASTHEADER
/** Handle to a reference counted fixed size table.
@note Currently, ElementType must be an aggregate of POD.
@tparam ElementType The type of element.
@ingroup beast_basics
*/
template <class ElementType>
class SharedTable
{
public:
typedef ElementType Entry;
static SharedTable <ElementType> const null;
/** Creates a null table.
*/
SharedTable ()
{
}
/** Creates a table with the specified number of entries.
The entries are uninitialized.
@param numEntries The number of entries in the table.
@todo Initialize the data if ElementType is not POD.
*/
explicit SharedTable (int numEntries)
: m_data (new Data (numEntries))
{
}
/** Creates a shared reference to another table.
*/
SharedTable (SharedTable const& other)
: m_data (other.m_data)
{
}
/** Makes this table refer to another table.
*/
SharedTable& operator= (SharedTable const& other)
{
m_data = other.m_data;
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
SharedTable (SharedTable&& other) noexcept
: m_data (static_cast < typename Data::Ptr&& > (other.m_data))
{
}
SharedTable& operator= (SharedTable && other) noexcept
{
m_data = static_cast < typename Data::Ptr && > (other.m_data);
return *this;
}
#endif
/** Destructor.
*/
~SharedTable ()
{
}
/** Returns true if the two tables share the same set of entries.
*/
bool operator== (SharedTable const& other) const noexcept
{
return m_data == other.m_data;
}
/** Returns true if the two tables do not share the same set of entries.
*/
bool operator!= (SharedTable const& other) const noexcept
{
return m_data != other.m_data;
}
/** Returns true if the table is not null.
*/
inline bool isValid () const noexcept
{
return m_data != nullptr;
}
/** Returns true if the table is null.
*/
inline bool isNull () const noexcept
{
return m_data == nullptr;
}
/** Returns the number of tables referring to the same shared entries.
*/
int getReferenceCount () const noexcept
{
return m_data == nullptr ? 0 : m_data->getReferenceCount ();
}
/** Create a physical duplicate of the table.
*/
SharedTable createCopy () const
{
return SharedTable (m_data != nullptr ? m_data->clone () : nullptr);
}
/** Makes sure no other tables share the same entries as this table.
*/
void duplicateIfShared ()
{
if (m_data != nullptr && m_data->getReferenceCount () > 1)
m_data = m_data->clone ();
}
/** Return the number of entries in this table.
*/
inline int getNumEntries () const noexcept
{
return m_data->getNumEntries ();
}
/** Retrieve a table entry.
@param index The index of the entry, from 0 to getNumEntries ().
*/
inline ElementType& operator [] (int index) const noexcept
{
return m_data->getReference (index);
}
private:
class Data : public SharedObject
{
public:
typedef SharedObjectPtr <Data> Ptr;
explicit Data (int numEntries)
: m_numEntries (numEntries)
, m_table (numEntries)
{
}
inline Data* clone () const
{
Data* data = new Data (m_numEntries);
memcpy (
data->m_table.getData (),
m_table.getData (),
m_numEntries * sizeof (ElementType));
return data;
}
inline int getNumEntries () const
{
return m_numEntries;
}
inline ElementType& getReference (int index) const
{
bassert (index >= 0 && index < m_numEntries);
return m_table [index];
}
private:
int const m_numEntries;
HeapBlock <ElementType> const m_table;
};
explicit SharedTable (Data* data)
: m_data (data)
{
}
SharedObjectPtr <Data> m_data;
};
template <class ElementType>
SharedTable <ElementType> const SharedTable <ElementType>::null;
#endif
//------------------------------------------------------------------------------

View File

@@ -1,154 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SORTEDLOOKUPTABLE_BEASTHEADER
#define BEAST_SORTEDLOOKUPTABLE_BEASTHEADER
/** Sorted map for fast lookups.
This container is optimized for a data set with fixed elements.
SchemaType obeys this concept:
@code
struct SchemaType
{
typename KeyType;
typename ValueType;
// Retrieve the key for a specified value.
KeyType getKey (Value const& value);
};
@endcode
To use the table, reserve space with reserveSpaceForValues() if the number
of elements is known ahead of time. Then, call insert() for all the your
elements. Call prepareForLookups() once then call lookupValueByKey ()
*/
template <class SchemaType>
class SortedLookupTable
{
private:
typedef typename SchemaType::KeyType KeyType;
typedef typename SchemaType::ValueType ValueType;
typedef std::vector <ValueType> values_t;
private:
struct SortCompare
{
bool operator () (ValueType const& lhs, ValueType const& rhs) const
{
return SchemaType ().getKey (lhs) < SchemaType ().getKey (rhs);
}
};
struct FindCompare
{
bool operator () (ValueType const& lhs, ValueType const& rhs)
{
return SchemaType ().getKey (lhs) < SchemaType ().getKey (rhs);
}
bool operator () (KeyType const& key, ValueType const& rhs)
{
return key < SchemaType ().getKey (rhs);
}
bool operator () (ValueType const& lhs, KeyType const& key)
{
return SchemaType ().getKey (lhs) < key;
}
};
public:
typedef typename values_t::size_type size_type;
/** Reserve space for values.
Although not necessary, this can help with memory usage if the
number of values is known ahead of time.
@param numberOfValues The amount of space to reserve.
*/
void reserveSpaceForValues (size_type numberOfValues)
{
m_values.reserve (numberOfValues);
}
/** Insert a value into the index.
@invariant The value must not already exist in the index.
@param valueToInsert The value to insert.
*/
void insert (ValueType const& valueToInsert)
{
m_values.push_back (valueToInsert);
}
/** Prepare the index for lookups.
This must be called at least once after calling insert()
and before calling find().
*/
void prepareForLookups ()
{
std::sort (m_values.begin (), m_values.end (), SortCompare ());
}
/** Find the value for a key.
Quickly locates a value matching the key, or returns false
indicating no value was found.
@invariant You must call prepareForLookups() once, after all
insertions, before calling this function.
@param key The key to locate.
@param pFoundValue Pointer to store the value if a matching
key was found.
@return `true` if the value was found.
*/
bool lookupValueByKey (KeyType const& key, ValueType* pFoundValue)
{
bool found;
std::pair <typename values_t::iterator, typename values_t::iterator> result =
std::equal_range (m_values.begin (), m_values.end (), key, FindCompare ());
if (result.first != result.second)
{
*pFoundValue = *result.first;
found = true;
}
else
{
found = false;
}
return found;
}
private:
values_t m_values;
};
#endif

View File

@@ -1,495 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SORTEDSET_BEASTHEADER
#define BEAST_SORTEDSET_BEASTHEADER
#include "beast_ArrayAllocationBase.h"
#include "../threads/beast_CriticalSection.h"
#if BEAST_MSVC
#pragma warning (push)
#pragma warning (disable: 4512)
#endif
//==============================================================================
/**
Holds a set of unique primitive objects, such as ints or doubles.
A set can only hold one item with a given value, so if for example it's a
set of integers, attempting to add the same integer twice will do nothing
the second time.
Internally, the list of items is kept sorted (which means that whatever
kind of primitive type is used must support the ==, <, >, <= and >= operators
to determine the order), and searching the set for known values is very fast
because it uses a binary-chop method.
Note that if you're using a class or struct as the element type, it must be
capable of being copied or moved with a straightforward memcpy, rather than
needing construction and destruction code.
To make all the set's methods thread-safe, pass in "CriticalSection" as the templated
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
@see Array, OwnedArray, SharedObjectArray, StringArray, CriticalSection
*/
template <class ElementType, class TypeOfCriticalSectionToUse = DummyCriticalSection>
class SortedSet
{
public:
//==============================================================================
/** Creates an empty set. */
SortedSet() noexcept
{
}
/** Creates a copy of another set.
@param other the set to copy
*/
SortedSet (const SortedSet& other)
: data (other.data)
{
}
/** Destructor. */
~SortedSet() noexcept
{
}
/** Copies another set over this one.
@param other the set to copy
*/
SortedSet& operator= (const SortedSet& other) noexcept
{
data = other.data;
return *this;
}
//==============================================================================
/** Compares this set to another one.
Two sets are considered equal if they both contain the same set of elements.
@param other the other set to compare with
*/
bool operator== (const SortedSet<ElementType>& other) const noexcept
{
return data == other.data;
}
/** Compares this set to another one.
Two sets are considered equal if they both contain the same set of elements.
@param other the other set to compare with
*/
bool operator!= (const SortedSet<ElementType>& other) const noexcept
{
return ! operator== (other);
}
//==============================================================================
/** Removes all elements from the set.
This will remove all the elements, and free any storage that the set is
using. To clear it without freeing the storage, use the clearQuick()
method instead.
@see clearQuick
*/
void clear() noexcept
{
data.clear();
}
/** Removes all elements from the set without freeing the array's allocated storage.
@see clear
*/
void clearQuick() noexcept
{
data.clearQuick();
}
//==============================================================================
/** Returns the current number of elements in the set.
*/
inline int size() const noexcept
{
return data.size();
}
/** Returns one of the elements in the set.
If the index passed in is beyond the range of valid elements, this
will return zero.
If you're certain that the index will always be a valid element, you
can call getUnchecked() instead, which is faster.
@param index the index of the element being requested (0 is the first element in the set)
@see getUnchecked, getFirst, getLast
*/
inline ElementType operator[] (const int index) const noexcept
{
return data [index];
}
/** Returns one of the elements in the set, without checking the index passed in.
Unlike the operator[] method, this will try to return an element without
checking that the index is within the bounds of the set, so should only
be used when you're confident that it will always be a valid index.
@param index the index of the element being requested (0 is the first element in the set)
@see operator[], getFirst, getLast
*/
inline ElementType getUnchecked (const int index) const noexcept
{
return data.getUnchecked (index);
}
/** Returns a direct reference to one of the elements in the set, without checking the index passed in.
This is like getUnchecked, but returns a direct reference to the element, so that
you can alter it directly. Obviously this can be dangerous, so only use it when
absolutely necessary.
@param index the index of the element being requested (0 is the first element in the array)
*/
inline ElementType& getReference (const int index) const noexcept
{
return data.getReference (index);
}
/** Returns the first element in the set, or 0 if the set is empty.
@see operator[], getUnchecked, getLast
*/
inline ElementType getFirst() const noexcept
{
return data.getFirst();
}
/** Returns the last element in the set, or 0 if the set is empty.
@see operator[], getUnchecked, getFirst
*/
inline ElementType getLast() const noexcept
{
return data.getLast();
}
//==============================================================================
/** Returns a pointer to the first element in the set.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ElementType* begin() const noexcept
{
return data.begin();
}
/** Returns a pointer to the element which follows the last element in the set.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline ElementType* end() const noexcept
{
return data.end();
}
//==============================================================================
/** Finds the index of the first element which matches the value passed in.
This will search the set for the given object, and return the index
of its first occurrence. If the object isn't found, the method will return -1.
@param elementToLookFor the value or object to look for
@returns the index of the object, or -1 if it's not found
*/
int indexOf (const ElementType& elementToLookFor) const noexcept
{
const ScopedLockType lock (data.getLock());
int s = 0;
int e = data.size();
for (;;)
{
if (s >= e)
return -1;
if (elementToLookFor == data.getReference (s))
return s;
const int halfway = (s + e) / 2;
if (halfway == s)
return -1;
else if (elementToLookFor < data.getReference (halfway))
e = halfway;
else
s = halfway;
}
}
/** Returns true if the set contains at least one occurrence of an object.
@param elementToLookFor the value or object to look for
@returns true if the item is found
*/
bool contains (const ElementType& elementToLookFor) const noexcept
{
return indexOf (elementToLookFor) >= 0;
}
//==============================================================================
/** Adds a new element to the set, (as long as it's not already in there).
Note that if a matching element already exists, the new value will be assigned
to the existing one using operator=, so that if there are any differences between
the objects which were not recognised by the object's operator==, then the
set will always contain a copy of the most recently added one.
@param newElement the new object to add to the set
@returns true if the value was added, or false if it already existed
@see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray
*/
bool add (const ElementType& newElement) noexcept
{
const ScopedLockType lock (getLock());
int s = 0;
int e = data.size();
while (s < e)
{
ElementType& elem = data.getReference (s);
if (newElement == elem)
{
elem = newElement; // force an update in case operator== permits differences.
return false;
}
const int halfway = (s + e) / 2;
const bool isBeforeHalfway = (newElement < data.getReference (halfway));
if (halfway == s)
{
if (! isBeforeHalfway)
++s;
break;
}
else if (isBeforeHalfway)
e = halfway;
else
s = halfway;
}
data.insert (s, newElement);
return true;
}
/** Adds elements from an array to this set.
@param elementsToAdd the array of elements to add
@param numElementsToAdd how many elements are in this other array
@see add
*/
void addArray (const ElementType* elementsToAdd,
int numElementsToAdd) noexcept
{
const ScopedLockType lock (getLock());
while (--numElementsToAdd >= 0)
add (*elementsToAdd++);
}
/** Adds elements from another set to this one.
@param setToAddFrom the set from which to copy the elements
@param startIndex the first element of the other set to start copying from
@param numElementsToAdd how many elements to add from the other set. If this
value is negative or greater than the number of available elements,
all available elements will be copied.
@see add
*/
template <class OtherSetType>
void addSet (const OtherSetType& setToAddFrom,
int startIndex = 0,
int numElementsToAdd = -1) noexcept
{
const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock());
{
const ScopedLockType lock2 (getLock());
bassert (this != &setToAddFrom);
if (this != &setToAddFrom)
{
if (startIndex < 0)
{
bassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
numElementsToAdd = setToAddFrom.size() - startIndex;
if (numElementsToAdd > 0)
addArray (&setToAddFrom.data.getReference (startIndex), numElementsToAdd);
}
}
}
//==============================================================================
/** Removes an element from the set.
This will remove the element at a given index.
If the index passed in is out-of-range, nothing will happen.
@param indexToRemove the index of the element to remove
@returns the element that has been removed
@see removeValue, removeRange
*/
ElementType remove (const int indexToRemove) noexcept
{
return data.remove (indexToRemove);
}
/** Removes an item from the set.
This will remove the given element from the set, if it's there.
@param valueToRemove the object to try to remove
@see remove, removeRange
*/
void removeValue (const ElementType valueToRemove) noexcept
{
const ScopedLockType lock (getLock());
data.remove (indexOf (valueToRemove));
}
/** Removes any elements which are also in another set.
@param otherSet the other set in which to look for elements to remove
@see removeValuesNotIn, remove, removeValue, removeRange
*/
template <class OtherSetType>
void removeValuesIn (const OtherSetType& otherSet) noexcept
{
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
const ScopedLockType lock2 (getLock());
if (this == &otherSet)
{
clear();
}
else if (otherSet.size() > 0)
{
for (int i = data.size(); --i >= 0;)
if (otherSet.contains (data.getReference (i)))
remove (i);
}
}
/** Removes any elements which are not found in another set.
Only elements which occur in this other set will be retained.
@param otherSet the set in which to look for elements NOT to remove
@see removeValuesIn, remove, removeValue, removeRange
*/
template <class OtherSetType>
void removeValuesNotIn (const OtherSetType& otherSet) noexcept
{
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
const ScopedLockType lock2 (getLock());
if (this != &otherSet)
{
if (otherSet.size() <= 0)
{
clear();
}
else
{
for (int i = data.size(); --i >= 0;)
if (! otherSet.contains (data.getReference (i)))
remove (i);
}
}
}
/** This swaps the contents of this array with those of another array.
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
because it just swaps their internal pointers.
*/
template <class OtherSortedSetType>
void swapWith (OtherSortedSetType& otherSet) noexcept
{
data.swapWith (otherSet.data);
}
//==============================================================================
/** Reduces the amount of storage being used by the set.
Sets typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads() noexcept
{
data.minimiseStorageOverheads();
}
/** Increases the set's internal storage to hold a minimum number of elements.
Calling this before adding a large known number of elements means that
the set won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
*/
void ensureStorageAllocated (const int minNumElements)
{
data.ensureStorageAllocated (minNumElements);
}
//==============================================================================
/** Returns the CriticalSection that locks this array.
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
an object of ScopedLockType as an RAII lock for it.
*/
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data.getLock(); }
/** Returns the type of scoped lock to use for locking this array */
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
private:
//==============================================================================
Array <ElementType, TypeOfCriticalSectionToUse> data;
};
#if BEAST_MSVC
#pragma warning (pop)
#endif
#endif // BEAST_SORTEDSET_BEASTHEADER

View File

@@ -1,334 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#if 0
#include <iostream>
//------------------------------------------------------------------------------
//
// Windows structured exception handling
//
#if BEAST_MSVC
#include <windows.h>
namespace vf
{
namespace
{
//
// While this object is in scope, any Windows SEH
// exceptions will be caught and re-thrown as an Error object.
//
class ScopedPlatformExceptionCatcher : public Uncopyable
{
public:
ScopedPlatformExceptionCatcher ()
{
//s_mutex.enter ();
if (++s_count == 1)
s_sehPrev = ::SetUnhandledExceptionFilter (sehFilter);
//s_mutex.exit ();
}
~ScopedPlatformExceptionCatcher ()
{
//s_mutex.enter ();
if (--s_count == 0)
SetUnhandledExceptionFilter (s_sehPrev);
//s_mutex.exit ();
}
static LONG WINAPI sehFilter (_EXCEPTION_POINTERS* ei)
{
EXCEPTION_RECORD* er = ei->ExceptionRecord;
if (er->ExceptionCode == EXCEPTION_BREAKPOINT ||
er->ExceptionCode == EXCEPTION_SINGLE_STEP)
{
// pass through
}
else
{
String s;
switch (er->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
s = TRANS ("an access violation occurred");
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
s = TRANS ("array bounds were exceeded");
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
s = TRANS ("memory access was unaligned");
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
s = TRANS ("a floating point operation produced a denormal");
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
s = TRANS ("a floating point divide by zero was attempted");
break;
case EXCEPTION_FLT_INEXACT_RESULT:
s = TRANS ("the floating point operation was unrepresentable");
break;
case EXCEPTION_FLT_INVALID_OPERATION:
s = TRANS ("the floating point operation was invalid");
break;
case EXCEPTION_FLT_OVERFLOW:
s = TRANS ("the floating point operation overflowed");
break;
case EXCEPTION_FLT_STACK_CHECK:
s = TRANS ("a stack check resulted from a floating point operation");
break;
case EXCEPTION_FLT_UNDERFLOW:
s = TRANS ("the floating point operation underflowed");
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
s = TRANS ("an invalid instruction was received");
break;
case EXCEPTION_IN_PAGE_ERROR:
s = TRANS ("a virtual paging error occurred");
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
s = TRANS ("an integer divide by zero was attempted");
break;
case EXCEPTION_INT_OVERFLOW:
s = TRANS ("an integer operation overflowed");
break;
case EXCEPTION_INVALID_DISPOSITION:
s = TRANS ("the exception handler returned an invalid disposition");
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
s = TRANS ("a non-continuable exception occurred");
break;
case EXCEPTION_PRIV_INSTRUCTION:
s = TRANS ("a privileged instruction was attempted");
break;
case EXCEPTION_STACK_OVERFLOW:
s = TRANS ("the stack overflowed");
break;
default:
s = TRANS ("an unknown system exception of code ");
s << String ((unsigned int)er->ExceptionCode);
s << " " << TRANS ("occurred");
break;
}
Throw (Error ().fail (__FILE__, __LINE__, s, Error::platform));
}
return s_sehPrev (ei);
}
private:
static int s_count;
static CriticalSection s_mutex;
static LPTOP_LEVEL_EXCEPTION_FILTER s_sehPrev;
};
CriticalSection ScopedPlatformExceptionCatcher::s_mutex;
int ScopedPlatformExceptionCatcher::s_count = 0;
LPTOP_LEVEL_EXCEPTION_FILTER ScopedPlatformExceptionCatcher::s_sehPrev = 0;
}
}
//------------------------------------------------------------------------------
#else
// TODO: POSIX SIGNAL HANDLER
#pragma message(BEAST_FILEANDLINE_ "Missing class ScopedPlatformExceptionCatcher")
namespace vf
{
namespace
{
class ScopedPlatformExceptionCatcher
{
public:
// Missing
};
}
END_BEAST_NAMESPACE
#endif
#endif
//------------------------------------------------------------------------------
#if 0
bool CatchAny (Function <void (void)> f, bool returnFromException)
{
bool caughtException = true; // assume the worst
try
{
//ScopedPlatformExceptionCatcher platformExceptionCatcher;
f ();
caughtException = false;
}
catch (Error& e)
{
if (!returnFromException)
{
JUCEApplication* app = JUCEApplication::getInstance ();
if (app)
{
app->unhandledException (
&e,
e.getSourceFilename (),
e.getLineNumber ());
}
else
{
std::cout << e.what ();
std::unexpected ();
}
}
}
catch (std::exception& e)
{
if (!returnFromException)
{
JUCEApplication* app = JUCEApplication::getInstance ();
if (app)
{
app->unhandledException (&e, __FILE__, __LINE__);
}
else
{
std::cout << e.what ();
std::unexpected ();
}
}
}
catch (...)
{
if (!returnFromException)
{
JUCEApplication* app = JUCEApplication::getInstance ();
if (app)
{
app->unhandledException (0, __FILE__, __LINE__);
}
else
{
std::unexpected ();
}
}
}
return caughtException;
}
#endif
//------------------------------------------------------------------------------
void ProtectedCall::DefaultHandler::onException (ProtectedCall::Exception const&) const
{
}
Static::Storage <Atomic <ProtectedCall::Handler const*>, ProtectedCall>
ProtectedCall::s_handler;
void ProtectedCall::setHandler (Handler const& handler)
{
s_handler->set (&handler);
}
void ProtectedCall::call (Call& c)
{
static DefaultHandler defaultHandler;
Handler const* handler = s_handler->get ();
if (handler == nullptr)
handler = &defaultHandler;
try
{
c ();
}
catch (...)
{
Exception e;
handler->onException (e);
}
}
//------------------------------------------------------------------------------
class ProtectedCallTests : public UnitTest
{
public:
ProtectedCallTests () : UnitTest ("ProtectedCall", "beast", runManual)
{
}
void runTest ()
{
beginTestCase ("backtrace");
String const s = SystemStats::getStackBacktrace ();
logMessage (s);
pass ();
}
};
static ProtectedCallTests protectedCallTests;

View File

@@ -1,163 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_PROTECTEDCALL_H_INCLUDED
#define BEAST_PROTECTEDCALL_H_INCLUDED
/** Call a function in a protected exception context.
This is for intercepting unhandled exceptions, reporting on the extended
information provided by @ref Throw, and calling a customizable unhandled
exception callback. Some implementations will also catch native exceptions
such as memory violations or segmentation faults.
An unhandled exception should terminate the process with a non zero
return code.
To use this, construct an instance with your funtion and arguments as
parameters. For example:
@code
extern void funcThatMightThrow (int numberOfTimes);
ProtectedCall (&funcThatMightThrow, 3);
@endcode
*/
class ProtectedCall
{
public:
struct Exception
{
};
/** This receives the unhandled exception. */
struct Handler
{
/** Called when an uhandled exception is thrown.
@note This can be called from multiple threads, which is
why it is const.
*/
virtual void onException (Exception const& e) const = 0;
};
/** The default handler writes to std::cerr makes the process exit. */
class DefaultHandler : public Handler
{
void onException (Exception const& e) const;
};
static void setHandler (Handler const& handler);
public:
#if BEAST_VARIADIC_MAX >= 1
template <class Fn>
explicit ProtectedCall (Fn f)
{ callf (functional::bind (f)); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <class Fn, class T1>
ProtectedCall (Fn f, T1 t1)
{ callf (functional::bind (f, t1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <class Fn, class T1, class T2>
ProtectedCall (Fn f, T1 t1, T2 t2)
{ callf (functional::bind (f, t1, t2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <class Fn, class T1, class T2, class T3>
ProtectedCall (Fn f, T1 t1, T2 t2, T3 t3)
{ callf (functional::bind (f, t1, t2, t3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <class Fn, class T1, class T2, class T3, class T4>
ProtectedCall (Fn f, T1 t1, T2 t2, T3 t3, T4 t4)
{ callf (functional::bind (f, t1, t2, t3, t4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <class Fn, class T1, class T2, class T3, class T4, class T5>
ProtectedCall (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{ callf (functional::bind (f, t1, t2, t3, t4, t5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6>
ProtectedCall (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{ callf (functional::bind (f, t1, t2, t3, t4, t5, t6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
ProtectedCall (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{ callf (functional::bind (f, t1, t2, t3, t4, t5, t6, t7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
ProtectedCall (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{ callf (functional::bind (f, t1, t2, t3, t4, t5, t6, t7, t8)); }
#endif
private:
struct Call
{
virtual void operator() () = 0;
};
template <class Functor>
struct CallType : public Call
{
public:
explicit CallType (Functor f)
: m_f (f)
{
}
void operator() ()
{
m_f ();
}
private:
Functor m_f;
};
template <class Functor>
void callf (Functor f)
{
CallType <Functor> wrapper (f);
call (wrapper);
}
void call (Call& call);
private:
static Static::Storage <Atomic <Handler const*>, ProtectedCall> s_handler;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,269 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_EXPRESSION_BEASTHEADER
#define BEAST_EXPRESSION_BEASTHEADER
#include "../memory/beast_SharedObject.h"
#include "../containers/beast_Array.h"
#include "../memory/beast_ScopedPointer.h"
//==============================================================================
/**
A class for dynamically evaluating simple numeric expressions.
This class can parse a simple C-style string expression involving floating point
numbers, named symbols and functions. The basic arithmetic operations of +, -, *, /
are supported, as well as parentheses, and any alphanumeric identifiers are
assumed to be named symbols which will be resolved when the expression is
evaluated.
Expressions which use identifiers and functions require a subclass of
Expression::Scope to be supplied when evaluating them, and this object
is expected to be able to resolve the symbol names and perform the functions that
are used.
*/
class BEAST_API Expression
{
public:
//==============================================================================
/** Creates a simple expression with a value of 0. */
Expression();
/** Destructor. */
~Expression();
/** Creates a simple expression with a specified constant value. */
explicit Expression (double constant);
/** Creates a copy of an expression. */
Expression (const Expression& other);
/** Copies another expression. */
Expression& operator= (const Expression& other);
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
Expression (Expression&& other) noexcept;
Expression& operator= (Expression&& other) noexcept;
#endif
/** Creates an expression by parsing a string.
If there's a syntax error in the string, this will throw a ParseError exception.
@throws ParseError
*/
explicit Expression (const String& stringToParse);
/** Returns a string version of the expression. */
String toString() const;
/** Returns an expression which is an addtion operation of two existing expressions. */
Expression operator+ (const Expression& other) const;
/** Returns an expression which is a subtraction operation of two existing expressions. */
Expression operator- (const Expression& other) const;
/** Returns an expression which is a multiplication operation of two existing expressions. */
Expression operator* (const Expression& other) const;
/** Returns an expression which is a division operation of two existing expressions. */
Expression operator/ (const Expression& other) const;
/** Returns an expression which performs a negation operation on an existing expression. */
Expression operator-() const;
/** Returns an Expression which is an identifier reference. */
static Expression symbol (const String& symbol);
/** Returns an Expression which is a function call. */
static Expression function (const String& functionName, const Array<Expression>& parameters);
/** Returns an Expression which parses a string from a character pointer, and updates the pointer
to indicate where it finished.
The pointer is incremented so that on return, it indicates the character that follows
the end of the expression that was parsed.
If there's a syntax error in the string, this will throw a ParseError exception.
@throws ParseError
*/
static Expression parse (String::CharPointerType& stringToParse);
//==============================================================================
/** When evaluating an Expression object, this class is used to resolve symbols and
perform functions that the expression uses.
*/
class BEAST_API Scope
{
public:
Scope();
virtual ~Scope();
/** Returns some kind of globally unique ID that identifies this scope. */
virtual String getScopeUID() const;
/** Returns the value of a symbol.
If the symbol is unknown, this can throw an Expression::EvaluationError exception.
The member value is set to the part of the symbol that followed the dot, if there is
one, e.g. for "foo.bar", symbol = "foo" and member = "bar".
@throws Expression::EvaluationError
*/
virtual Expression getSymbolValue (const String& symbol) const;
/** Executes a named function.
If the function name is unknown, this can throw an Expression::EvaluationError exception.
@throws Expression::EvaluationError
*/
virtual double evaluateFunction (const String& functionName,
const double* parameters, int numParameters) const;
/** Used as a callback by the Scope::visitRelativeScope() method.
You should never create an instance of this class yourself, it's used by the
expression evaluation code.
*/
class Visitor
{
public:
virtual ~Visitor() {}
virtual void visit (const Scope&) = 0;
};
/** Creates a Scope object for a named scope, and then calls a visitor
to do some kind of processing with this new scope.
If the name is valid, this method must create a suitable (temporary) Scope
object to represent it, and must call the Visitor::visit() method with this
new scope.
*/
virtual void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
};
/** Evaluates this expression, without using a Scope.
Without a Scope, no symbols can be used, and only basic functions such as sin, cos, tan,
min, max are available.
To find out about any errors during evaluation, use the other version of this method which
takes a String parameter.
*/
double evaluate() const;
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
or functions that it uses.
To find out about any errors during evaluation, use the other version of this method which
takes a String parameter.
*/
double evaluate (const Scope& scope) const;
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
or functions that it uses.
*/
double evaluate (const Scope& scope, String& evaluationError) const;
/** Attempts to return an expression which is a copy of this one, but with a constant adjusted
to make the expression resolve to a target value.
E.g. if the expression is "x + 10" and x is 5, then asking for a target value of 8 will return
the expression "x + 3". Obviously some expressions can't be reversed in this way, in which
case they might just be adjusted by adding a constant to the original expression.
@throws Expression::EvaluationError
*/
Expression adjustedToGiveNewResult (double targetValue, const Scope& scope) const;
/** Represents a symbol that is used in an Expression. */
struct Symbol
{
Symbol (const String& scopeUID, const String& symbolName);
bool operator== (const Symbol&) const noexcept;
bool operator!= (const Symbol&) const noexcept;
String scopeUID; /**< The unique ID of the Scope that contains this symbol. */
String symbolName; /**< The name of the symbol. */
};
/** Returns a copy of this expression in which all instances of a given symbol have been renamed. */
Expression withRenamedSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope) const;
/** Returns true if this expression makes use of the specified symbol.
If a suitable scope is supplied, the search will dereference and recursively check
all symbols, so that it can be determined whether this expression relies on the given
symbol at any level in its evaluation. If the scope parameter is null, this just checks
whether the expression contains any direct references to the symbol.
@throws Expression::EvaluationError
*/
bool referencesSymbol (const Symbol& symbol, const Scope& scope) const;
/** Returns true if this expression contains any symbols. */
bool usesAnySymbols() const;
/** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */
void findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const;
//==============================================================================
/** An exception that can be thrown by Expression::parse(). */
class ParseError : public std::exception
{
public:
ParseError (const String& message);
String description;
};
//==============================================================================
/** Expression type.
@see Expression::getType()
*/
enum Type
{
constantType,
functionType,
operatorType,
symbolType
};
/** Returns the type of this expression. */
Type getType() const noexcept;
/** If this expression is a symbol, function or operator, this returns its identifier. */
String getSymbolOrFunction() const;
/** Returns the number of inputs to this expression.
@see getInput
*/
int getNumInputs() const;
/** Retrieves one of the inputs to this expression.
@see getNumInputs
*/
Expression getInput (int index) const;
private:
//==============================================================================
class Term;
struct Helpers;
friend class Term;
friend struct Helpers;
friend class ScopedPointer<Term>;
friend class SharedObjectPtr<Term>;
SharedObjectPtr<Term> term;
explicit Expression (Term*);
};
#endif // BEAST_EXPRESSION_BEASTHEADER

View File

@@ -1,387 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_INTERVAL_BEASTHEADER
#define BEAST_INTERVAL_BEASTHEADER
/** A half-open interval.
This represents the half-open interval [begin, end) over the scalar
type of template parameter `Ty`. It may also be considered as the
specification of a subset of a 1-dimensional Euclidean space.
@tparam Ty A scalar numerical type.
*/
template <class Ty>
class Interval
{
public:
typedef Ty value_type;
/** The empty interval.
*/
static const Interval none;
/** Create an uninitialized interval.
*/
Interval ()
{
}
/** Create an interval with the specified values.
*/
Interval (Ty begin, Ty end)
: m_begin (begin)
, m_end (end)
{
}
/** Create an interval from another interval.
*/
Interval (Interval const& other)
: m_begin (other.m_begin)
, m_end (other.m_end)
{
}
/** Assign from another interval.
@param other The interval to assign from.
@return A reference to this interval.
*/
Interval& operator= (const Interval& other)
{
m_begin = other.m_begin;
m_end = other.m_end;
return *this;
}
/** Compare an interval for equality.
Empty intervals are always equal to other empty intervals.
@param rhs The other interval to compare.
@return `true` if this interval is equal to the specified interval.
*/
bool operator== (Interval const& rhs) const
{
return (empty () && rhs.empty ()) ||
(m_begin == rhs.m_begin && m_end == rhs.m_end);
}
/** Compare an interval for inequality.
@param rhs The other interval to compare.
@return `true` if this interval is not equal to the specified interval.
*/
bool operator!= (Interval const& rhs) const
{
return !this->operator== (rhs);
}
/** Get the starting value of the interval.
@return The starting point of the interval.
*/
Ty begin () const
{
return m_begin;
}
/** Get the ending value of the interval.
@return The ending point of the interval.
*/
Ty end () const
{
return m_end;
}
/** Get the Lebesque measure.
@return The Lebesque measure.
*/
Ty length () const
{
return empty () ? Ty () : (end () - begin ());
}
//Ty count () const { return length (); } // sugar
//Ty distance () const { return length (); } // sugar
/** Determine if the interval is empty.
@return `true` if the interval is empty.
*/
bool empty () const
{
return m_begin >= m_end;
}
/** Determine if the interval is non-empty.
@return `true` if the interval is not empty.
*/
bool notEmpty () const
{
return m_begin < m_end;
}
/** Set the starting point of the interval.
@param v The starting point.
*/
void setBegin (Ty v)
{
m_begin = v;
}
/** Set the ending point of the interval.
@param v The ending point.
*/
void setEnd (Ty v)
{
m_end = v;
}
/** Set the ending point relative to the starting point.
@param v The length of the resulting interval.
*/
void setLength (Ty v)
{
m_end = m_begin + v;
}
/** Determine if a value is contained in the interval.
@param v The value to check.
@return `true` if this interval contains `v`.
*/
bool contains (Ty v) const
{
return notEmpty () && v >= m_begin && v < m_end;
}
/** Determine if this interval intersects another interval.
@param other The other interval.
@return `true` if the intervals intersect.
*/
template <class To>
bool intersects (Interval <To> const& other) const
{
return notEmpty () && other.notEmpty () &&
end () > other.begin () && begin () < other.end ();
}
/** Determine if this interval adjoins another interval.
An interval is adjoint to another interval if and only if the union of the
intervals is a single non-empty half-open subset.
@param other The other interval.
@return `true` if the intervals are adjoint.
*/
template <class To>
bool adjoins (Interval <To> const& other) const
{
return (empty () != other.empty ()) ||
(notEmpty () && end () >= other.begin ()
&& begin () <= other.end ());
}
/** Determine if this interval is disjoint from another interval.
@param other The other interval.
@return `true` if the intervals are disjoint.
*/
bool disjoint (Interval const& other) const
{
return !intersects (other);
}
/** Determine if this interval is a superset of another interval.
An interval A is a superset of interval B if B is empty or if A fully
contains B.
@param other The other interval.
@return `true` if this is a superset of `other`.
*/
template <class To>
bool superset_of (Interval <To> const& other) const
{
return other.empty () ||
(notEmpty () && begin () <= other.begin ()
&& end () >= other.end ());
}
/** Determine if this interval is a proper superset of another interval.
An interval A is a proper superset of interval B if A is a superset of
B and A is not equal to B.
@param other The other interval.
@return `true` if this interval is a proper superset of `other`.
*/
template <class To>
bool proper_superset_of (Interval <To> const& other) const
{
return this->superset_of (other) && this->operator != (other);
}
/** Determine if this interval is a subset of another interval.
@param other The other interval.
@return `true` if this interval is a subset of `other`.
*/
template <class To>
bool subset_of (Interval <To> const& other) const
{
return other.superset_of (*this);
}
/** Determine if this interval is a proper subset of another interval.
@param other The other interval.
@return `true` if this interval is a proper subset of `other`.
*/
template <class To>
bool proper_subset_of (Interval <To> const& other) const
{
return other.proper_superset_of (*this);
}
/** Return the intersection of this interval with another interval.
@param other The other interval.
@return The intersection of the intervals.
*/
template <class To>
Interval intersection (Interval <To> const& other) const
{
return Interval (std::max (begin (), other.begin ()),
std::min (end (), other.end ()));
}
/** Determine the smallest interval that contains both intervals.
@param other The other interval.
@return The simple union of the intervals.
*/
template <class To>
Interval simple_union (Interval <To> const& other) const
{
return Interval (
std::min (other.normalized ().begin (), normalized ().begin ()),
std::max (other.normalized ().end (), normalized ().end ()));
}
/** Calculate the single-interval union.
The result is empty if the union cannot be represented as a
single half-open interval.
@param other The other interval.
@return The simple union of the intervals.
*/
template <class To>
Interval single_union (Interval <To> const& other) const
{
if (empty ())
return other;
else if (other.empty ())
return *this;
else if (end () < other.begin () || begin () > other.end ())
return none;
else
return Interval (std::min (begin (), other.begin ()),
std::max (end (), other.end ()));
}
/** Determine if the interval is correctly ordered.
@return `true` if the interval is correctly ordered.
*/
bool normal () const
{
return end () >= begin ();
}
/** Return a normalized interval.
@return The normalized interval.
*/
Interval normalized () const
{
if (normal ())
return *this;
else
return Interval (end (), begin ());
}
/** Clamp a value to the interval.
@param v The value to clamp.
@return The clamped result.
*/
template <typename Tv>
Ty clamp (Tv v) const
{
// These conditionals are carefully ordered so
// that if m_begin == m_end, value is assigned m_begin.
if (v > end ())
v = end () - (std::numeric_limits <Tv>::is_integer ? 1 :
std::numeric_limits <Tv>::epsilon ());
if (v < begin ())
v = begin ();
return v;
}
private:
Ty m_begin;
Ty m_end;
};
template <typename Ty>
const Interval<Ty> Interval<Ty>::none = Interval<Ty> (Ty (), Ty ());
#endif

View File

@@ -1,83 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ATOMICCOUNTER_BEASTHEADER
#define BEAST_ATOMICCOUNTER_BEASTHEADER
/*============================================================================*/
/**
A thread safe usage counter.
This provides a simplified interface to an atomic integer suitable for
measuring reference or usage counts. The counter is signaled when the
count is non zero.
@ingroup beast_core
*/
class BEAST_API AtomicCounter
{
public:
/** Create a new counter.
@param initialValue An optional starting usage count (default is 0).
*/
AtomicCounter (int initialValue = 0) noexcept
:
m_value (initialValue)
{
}
/** Increment the usage count.
@return `true` if the counter became signaled.
*/
inline bool addref () noexcept
{
return (++m_value) == 1;
}
/** Decrements the usage count.
@return `true` if the counter became non-signaled.
*/
inline bool release () noexcept
{
// Unfortunately, AllocatorWithoutTLS breaks this assert
//bassert (isSignaled ());
return (--m_value) == 0;
}
/** Determine if the counter is signaled.
Note that another thread can cause the counter to become reset after
this function returns true.
@return `true` if the counter was signaled.
*/
inline bool isSignaled () const noexcept
{
return m_value.get () > 0;
}
private:
Atomic <int> m_value;
};
#endif

View File

@@ -1,102 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ATOMICFLAG_BEASTHEADER
#define BEAST_ATOMICFLAG_BEASTHEADER
/*============================================================================*/
/**
A thread safe flag.
This provides a simplified interface to an atomic integer suitable for
representing a flag. The flag is signaled when on, else it is considered
reset.
@ingroup beast_core
*/
class BEAST_API AtomicFlag
{
public:
/** Create an AtomicFlag in the reset state. */
AtomicFlag () noexcept
:
m_value (0)
{
}
/** Signal the flag.
If two or more threads simultaneously attempt to signal the flag,
only one will receive a true return value.
@return true if the flag was previously reset.
*/
inline bool trySignal () noexcept
{
return m_value.compareAndSetBool (1, 0);
}
/** Signal the flag.
The flag must be in the reset state. Only one thread may
call this at a time.
*/
inline void signal () noexcept
{
#if BEAST_DEBUG
const bool success = m_value.compareAndSetBool (1, 0);
bassert (success);
#else
m_value.set (1);
#endif
}
/** Reset the flag.
The flag must be in the signaled state. Only one thread may
call this at a time. Usually it is the thread that was successful
in a previous call to trySignal().
*/
inline void reset () noexcept
{
#if BEAST_DEBUG
const bool success = m_value.compareAndSetBool (0, 1);
bassert (success);
#else
m_value.set (0);
#endif
}
/** Check if the AtomicFlag is signaled
The signaled status may change immediately after this call
returns. The caller must synchronize.
@return true if the flag was signaled.
*/
inline bool isSignaled () const noexcept
{
return m_value.get () == 1;
}
private:
Atomic <int> m_value;
};
#endif

View File

@@ -1,133 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ATOMICPOINTER_BEASTHEADER
#define BEAST_ATOMICPOINTER_BEASTHEADER
/*============================================================================*/
/**
A thread safe pointer.
This provides a simplified interface to an atomic pointer suitable
for building containers or composite classes. Operator overloads
allow access to the underlying pointer using natural C++ syntax.
@ingroup beast_core
*/
template <class P>
class AtomicPointer
{
public:
/** Create a pointer.
@param initialValue An optional starting value (default is null).
*/
explicit AtomicPointer (P* const initialValue = nullptr) noexcept
:
m_value (initialValue)
{
}
/** Retrieve the pointer value */
inline P* get () const noexcept
{
return m_value.get ();
}
/** Obtain a pointer to P through type conversion.
The caller must synchronize access to P.
@return A pointer to P.
*/
inline operator P* () const noexcept
{
return get ();
}
/** Dereference operator
The caller must synchronize access to P.
@return A reference to P.
*/
inline P& operator* () const noexcept
{
return &get ();
}
/** Member selection
The caller must synchronize access to P.
@return A pointer to P.
*/
inline P* operator-> () const noexcept
{
return get ();
}
inline void set (P* p)
{
m_value.set (p);
}
/** Atomically assign a new pointer
@param newValue The new value to assign.
*/
inline void operator= (P* newValue) noexcept
{
set (newValue);
}
/** Atomically assign a new pointer and return the old value.
@param newValue The new value to assign.
@return The previous value.
*/
inline P* exchange (P* newValue)
{
return m_value.exchange (newValue);
}
/** Conditionally perform an atomic assignment.
The current value is compared with oldValue and atomically
set to newValue if the comparison is equal.
The caller is responsible for handling the ABA problem.
@param newValue The new value to assign.
@param oldValue The matching old value.
@return true if the assignment was performed.
*/
inline bool compareAndSet (P* newValue, P* oldValue)
{
return m_value.compareAndSetBool (newValue, oldValue);
}
private:
Atomic <P*> m_value;
};
#endif

View File

@@ -1,101 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ATOMICSTATE_BEASTHEADER
#define BEAST_ATOMICSTATE_BEASTHEADER
/*============================================================================*/
/**
A thread safe state variable.
This provides a simplified interface to an integer used to control atomic
state transitions. A state is distinguished by a single integer value.
@ingroup beast_core
*/
class BEAST_API AtomicState
{
public:
/** Create a new state with an optional starting value.
@param initialState The initial state.
*/
explicit AtomicState (const int initialState = 0) noexcept
:
m_value (initialState)
{
}
/** Retrieve the current state.
This converts the object to an integer reflecting the current state.
Note that other threads may change the value immediately after this
function returns. The caller is responsible for synchronizing.
@return The state at the time of the call.
*/
inline operator int () const
{
return m_value.get ();
}
/** Attempt a state transition.
The current state is compared to `from`, and if the comparison is
successful the state becomes `to`. The entire operation is atomic.
@param from The current state, for comparison.
@param to The desired new state.
@return true if the state transition succeeded.
*/
inline bool tryChangeState (const int from, const int to) noexcept
{
return m_value.compareAndSetBool (to, from);
}
/** Perform a state transition.
This attempts to change the state and generates a diagnostic on
failure. This routine can be used instead of tryChangeState()
when program logic requires that the state change must succeed.
@param from The required current state.
@param to The new state.
*/
inline void changeState (const int from, const int to) noexcept
{
#if BEAST_DEBUG
const bool success = tryChangeState (from, to);
bassert (success);
#else
tryChangeState (from, to);
#endif
}
private:
Atomic <int> m_value;
};
#endif

View File

@@ -1,126 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_BYTESWAP_H_INCLUDED
#define BEAST_BYTESWAP_H_INCLUDED
namespace detail
{
/** Specialized helper class template for swapping bytes.
Normally you won't use this directly, use the helper function
byteSwap instead. You can specialize this class for your
own user defined types, as was done for uint24.
@see swapBytes, uint24
*/
template <typename IntegralType>
struct SwapBytes
{
inline IntegralType operator() (IntegralType value) const noexcept
{
return ByteOrder::swap (value);
}
};
// Specializations for signed integers
template <>
struct SwapBytes <int16>
{
inline int16 operator() (int16 value) const noexcept
{
return static_cast <int16> (ByteOrder::swap (static_cast <uint16> (value)));
}
};
template <>
struct SwapBytes <int32>
{
inline int32 operator() (int32 value) const noexcept
{
return static_cast <int32> (ByteOrder::swap (static_cast <uint32> (value)));
}
};
template <>
struct SwapBytes <int64>
{
inline int64 operator() (int64 value) const noexcept
{
return static_cast <int64> (ByteOrder::swap (static_cast <uint64> (value)));
}
};
}
//------------------------------------------------------------------------------
/** Returns a type with the bytes swapped.
Little endian becomes big endian and vice versa. The underlying
type must be an integral type or behave like one.
*/
template <class IntegralType>
inline IntegralType swapBytes (IntegralType value) noexcept
{
return detail::SwapBytes <IntegralType> () (value);
}
/** Returns the machine byte-order value to little-endian byte order. */
template <typename IntegralType>
inline IntegralType toLittleEndian (IntegralType value) noexcept
{
#if BEAST_LITTLE_ENDIAN
return value;
#else
return swapBytes (value);
#endif
}
/** Returns the machine byte-order value to big-endian byte order. */
template <typename IntegralType>
inline IntegralType toBigEndian (IntegralType value) noexcept
{
#if BEAST_LITTLE_ENDIAN
return swapBytes (value);
#else
return value;
#endif
}
/** Returns the machine byte-order value to network byte order. */
template <typename IntegralType>
inline IntegralType toNetworkByteOrder (IntegralType value) noexcept
{
return toBigEndian (value);
}
/** Converts from network byte order to machine byte order. */
template <typename IntegralType>
inline IntegralType fromNetworkByteOrder (IntegralType value) noexcept
{
#if BEAST_LITTLE_ENDIAN
return swapBytes (value);
#else
return value;
#endif
}
#endif

View File

@@ -1,126 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_RECYCLEDOBJECTPOOL_H_INCLUDED
#define BEAST_RECYCLEDOBJECTPOOL_H_INCLUDED
/** A pool of objects which may be recycled.
This is a thread safe pool of objects that get re-used. It is
primarily designed to eliminate the need for many memory allocations
and frees when temporary buffers are needed for operations.
To use it, first declare a structure containing the information
that you want to recycle. Then when you want to use a recycled object
put a ScopedItem on your stack:
@code
struct StdString
{
std::string data;
};
RecycledObjectPool <StdString> pool;
void foo ()
{
RecycledObjectPool <StdString>::ScopedItem item;
item.getObject ().data = "text";
}
@endcode
*/
template <class Object>
class RecycledObjectPool
{
public:
struct Item : Object, LockFreeStack <Item>::Node, LeakChecked <Item>
{
};
class ScopedItem
{
public:
explicit ScopedItem (RecycledObjectPool <Object>& pool)
: m_pool (pool)
, m_item (pool.get ())
{
}
~ScopedItem ()
{
m_pool.release (m_item);
}
Object& getObject () noexcept
{
return *m_item;
}
private:
RecycledObjectPool <Object>& m_pool;
Item* const m_item;
};
public:
RecycledObjectPool () noexcept
{
}
~RecycledObjectPool ()
{
for (;;)
{
Item* const item = m_stack.pop_front ();
if (item != nullptr)
delete item;
else
break;
}
}
private:
Item* get ()
{
Item* item = m_stack.pop_front ();
if (item == nullptr)
{
item = new Item;
if (item == nullptr)
Throw (std::bad_alloc ());
}
return item;
}
void release (Item* item) noexcept
{
m_stack.push_front (item);
}
private:
LockFreeStack <Item> m_stack;
};
#endif

View File

@@ -1,390 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
#define BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
#include "beast_Atomic.h"
//==============================================================================
/**
Adds reference-counting to an object.
To add reference-counting to a class, derive it from this class, and
use the SharedObjectPtr class to point to it.
e.g. @code
class MyClass : public SharedObject
{
void foo();
// This is a neat way of declaring a typedef for a pointer class,
// rather than typing out the full templated name each time..
typedef SharedObjectPtr<MyClass> Ptr;
};
MyClass::Ptr p = new MyClass();
MyClass::Ptr p2 = p;
p = nullptr;
p2->foo();
@endcode
Once a new SharedObject has been assigned to a pointer, be
careful not to delete the object manually.
This class uses an Atomic<int> value to hold the reference count, so that it
the pointers can be passed between threads safely. For a faster but non-thread-safe
version, use SingleThreadedSharedObject instead.
@see SharedObjectPtr, SharedObjectArray, SingleThreadedSharedObject
*/
class BEAST_API SharedObject : public Uncopyable
{
public:
//==============================================================================
/** Increments the object's reference count.
This is done automatically by the smart pointer, but is public just
in case it's needed for nefarious purposes.
*/
inline void incReferenceCount() noexcept
{
++refCount;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will be deleted.
*/
inline void decReferenceCount() noexcept
{
bassert (getReferenceCount() > 0);
if (--refCount == 0)
delete this;
}
/** Returns the object's current reference count. */
inline int getReferenceCount() const noexcept { return refCount.get(); }
protected:
//==============================================================================
/** Creates the reference-counted object (with an initial ref count of zero). */
SharedObject()
{
}
/** Destructor. */
virtual ~SharedObject()
{
// it's dangerous to delete an object that's still referenced by something else!
bassert (getReferenceCount() == 0);
}
/** Resets the reference count to zero without deleting the object.
You should probably never need to use this!
*/
void resetReferenceCount() noexcept
{
refCount = 0;
}
private:
//==============================================================================
Atomic <int> refCount;
};
//==============================================================================
/**
Adds reference-counting to an object.
This is effectively a version of the SharedObject class, but which
uses a non-atomic counter, and so is not thread-safe (but which will be more
efficient).
For more details on how to use it, see the SharedObject class notes.
@see SharedObject, SharedObjectPtr, SharedObjectArray
*/
class BEAST_API SingleThreadedSharedObject : public Uncopyable
{
public:
//==============================================================================
/** Increments the object's reference count.
This is done automatically by the smart pointer, but is public just
in case it's needed for nefarious purposes.
*/
inline void incReferenceCount() noexcept
{
++refCount;
}
/** Decreases the object's reference count.
If the count gets to zero, the object will be deleted.
*/
inline void decReferenceCount() noexcept
{
bassert (getReferenceCount() > 0);
if (--refCount == 0)
delete this;
}
/** Returns the object's current reference count. */
inline int getReferenceCount() const noexcept { return refCount; }
protected:
//==============================================================================
/** Creates the reference-counted object (with an initial ref count of zero). */
SingleThreadedSharedObject() : refCount (0) {}
/** Destructor. */
virtual ~SingleThreadedSharedObject()
{
// it's dangerous to delete an object that's still referenced by something else!
bassert (getReferenceCount() == 0);
}
private:
//==============================================================================
int refCount;
};
//==============================================================================
/**
A smart-pointer class which points to a reference-counted object.
The template parameter specifies the class of the object you want to point to - the easiest
way to make a class reference-countable is to simply make it inherit from SharedObject,
but if you need to, you could roll your own reference-countable class by implementing a pair of
mathods called incReferenceCount() and decReferenceCount().
When using this class, you'll probably want to create a typedef to abbreviate the full
templated name - e.g.
@code typedef SharedObjectPtr<MyClass> MyClassPtr;@endcode
@see SharedObject, SharedObjectArray
*/
template <class SharedObjectClass>
class SharedObjectPtr
{
public:
/** The class being referenced by this pointer. */
typedef SharedObjectClass ReferencedType;
//==============================================================================
/** Creates a pointer to a null object. */
inline SharedObjectPtr() noexcept
: referencedObject (nullptr)
{
}
/** Creates a pointer to an object.
This will increment the object's reference-count if it is non-null.
*/
inline SharedObjectPtr (SharedObjectClass* const refCountedObject) noexcept
: referencedObject (refCountedObject)
{
if (refCountedObject != nullptr)
refCountedObject->incReferenceCount();
}
/** Copies another pointer.
This will increment the object's reference-count (if it is non-null).
*/
inline SharedObjectPtr (const SharedObjectPtr& other) noexcept
: referencedObject (other.referencedObject)
{
if (referencedObject != nullptr)
referencedObject->incReferenceCount();
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
/** Takes-over the object from another pointer. */
inline SharedObjectPtr (SharedObjectPtr&& other) noexcept
: referencedObject (other.referencedObject)
{
other.referencedObject = nullptr;
}
#endif
/** Copies another pointer.
This will increment the object's reference-count (if it is non-null).
*/
template <class DerivedClass>
inline SharedObjectPtr (const SharedObjectPtr<DerivedClass>& other) noexcept
: referencedObject (static_cast <SharedObjectClass*> (other.get()))
{
if (referencedObject != nullptr)
referencedObject->incReferenceCount();
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
SharedObjectPtr& operator= (const SharedObjectPtr& other)
{
return operator= (other.referencedObject);
}
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
template <class DerivedClass>
SharedObjectPtr& operator= (const SharedObjectPtr<DerivedClass>& other)
{
return operator= (static_cast <SharedObjectClass*> (other.get()));
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
/** Takes-over the object from another pointer. */
SharedObjectPtr& operator= (SharedObjectPtr&& other)
{
std::swap (referencedObject, other.referencedObject);
return *this;
}
#endif
/** Changes this pointer to point at a different object.
The reference count of the old object is decremented, and it might be
deleted if it hits zero. The new object's count is incremented.
*/
SharedObjectPtr& operator= (SharedObjectClass* const newObject)
{
if (referencedObject != newObject)
{
if (newObject != nullptr)
newObject->incReferenceCount();
SharedObjectClass* const oldObject = referencedObject;
referencedObject = newObject;
if (oldObject != nullptr)
oldObject->decReferenceCount();
}
return *this;
}
/** Destructor.
This will decrement the object's reference-count, and may delete it if it
gets to zero.
*/
inline ~SharedObjectPtr()
{
if (referencedObject != nullptr)
referencedObject->decReferenceCount();
}
/** Returns the object that this pointer references.
The pointer returned may be zero, of course.
*/
inline operator SharedObjectClass*() const noexcept
{
return referencedObject;
}
// the -> operator is called on the referenced object
inline SharedObjectClass* operator->() const noexcept
{
return referencedObject;
}
/** Returns the object that this pointer references.
The pointer returned may be zero, of course.
*/
inline SharedObjectClass* get() const noexcept
{
return referencedObject;
}
/** Returns the object that this pointer references.
The pointer returned may be zero, of course.
*/
inline SharedObjectClass* getObject() const noexcept
{
return referencedObject;
}
private:
//==============================================================================
SharedObjectClass* referencedObject;
};
/** Compares two SharedObjectPointers. */
template <class SharedObjectClass>
bool operator== (const SharedObjectPtr<SharedObjectClass>& object1, SharedObjectClass* const object2) noexcept
{
return object1.get() == object2;
}
/** Compares two SharedObjectPointers. */
template <class SharedObjectClass>
bool operator== (const SharedObjectPtr<SharedObjectClass>& object1, const SharedObjectPtr<SharedObjectClass>& object2) noexcept
{
return object1.get() == object2.get();
}
/** Compares two SharedObjectPointers. */
template <class SharedObjectClass>
bool operator== (SharedObjectClass* object1, SharedObjectPtr<SharedObjectClass>& object2) noexcept
{
return object1 == object2.get();
}
/** Compares two SharedObjectPointers. */
template <class SharedObjectClass>
bool operator!= (const SharedObjectPtr<SharedObjectClass>& object1, const SharedObjectClass* object2) noexcept
{
return object1.get() != object2;
}
/** Compares two SharedObjectPointers. */
template <class SharedObjectClass>
bool operator!= (const SharedObjectPtr<SharedObjectClass>& object1, SharedObjectPtr<SharedObjectClass>& object2) noexcept
{
return object1.get() != object2.get();
}
/** Compares two SharedObjectPointers. */
template <class SharedObjectClass>
bool operator!= (SharedObjectClass* object1, SharedObjectPtr<SharedObjectClass>& object2) noexcept
{
return object1 != object2.get();
}
#endif // BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER

View File

@@ -1,172 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_STATICOBJECT_BEASTHEADER
#define BEAST_STATICOBJECT_BEASTHEADER
//
// A full suite of thread-safe objects designed for static storage duration.
//
// Wraps an object with a thread-safe initialization preamble so that it can
// properly exist with static storage duration.
//
// Implementation notes:
//
// This is accomplished by omitting the constructor and relying on the C++
// specification that plain data types with static storage duration are filled
// with zeroes before any other initialization code executes.
//
// Spec: N2914=09-0104
//
// [3.6.2] Initialization of non-local objects
//
// Objects with static storage duration (3.7.1) or thread storage
// duration (3.7.2) shall be zero-initialized (8.5) before any
// other initialization takes place.
//
// Requirements:
//
// Object must be constructible without parameters.
// The StaticObject must be declared with static storage duration or
// the behavior is undefined.
//
// Usage example:
//
// Object* getInstance ()
// {
// static StaticObject <Object> instance;
// return instance->getObject ();
// }
//
namespace Static
{
//------------------------------------------------------------------------------
// Holds an object with static storage duration.
// The owner determines if and when the object is constructed and destroyed.
// Caller is responsible for synchronization.
//
template <class ObjectType, class Tag>
class Storage
{
public:
static inline void construct ()
{
new (getObjectPtr ()) ObjectType;
}
static inline void destroy ()
{
getObjectPtr ()->~ObjectType ();
}
static inline ObjectType* getObjectPtr ()
{
return reinterpret_cast <ObjectType*> (s_storage);
}
static inline ObjectType& getObject ()
{
return *getObjectPtr ();
}
inline ObjectType* operator-> () const
{
return getObjectPtr ();
}
inline ObjectType& operator* () const
{
return getObject ();
}
inline operator ObjectType* () const
{
return getObjectPtr ();
}
// TODO: Crashes on iOS if not accessed before usage
static char s_storage [sizeof (ObjectType)];
private:
};
template <class ObjectType, class Tag>
char Storage <ObjectType, Tag>::s_storage [sizeof (ObjectType)];
//------------------------------------------------------------------------------
// Provides a thread safe flag for indicating if and when
// initialization is required for an object with static storage duration.
//
class Initializer
{
public:
// If the condition is not initialized, the first caller will
// receive true, while concurrent callers get blocked until
// initialization completes.
//
bool beginConstruction ()
{
bool needsInitialization = false;
if (m_state.get () != stateInitialized)
{
if (m_state.compareAndSetBool (stateInitializing, stateUninitialized))
{
needsInitialization = true;
}
else
{
SpinDelay delay;
do
{
delay.pause ();
}
while (m_state.get () != stateInitialized);
}
}
return needsInitialization;
}
// Called to signal that the initialization is complete
//
void endConstruction ()
{
m_state.set (stateInitialized);
}
private:
enum
{
stateUninitialized = 0, // must be zero
stateInitializing,
stateInitialized
};
Atomic <int> m_state;
};
}
#endif

View File

@@ -1,207 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_WEAKREFERENCE_BEASTHEADER
#define BEAST_WEAKREFERENCE_BEASTHEADER
#include "beast_SharedObject.h"
//==============================================================================
/**
This class acts as a pointer which will automatically become null if the object
to which it points is deleted.
To accomplish this, the source object needs to cooperate by performing a couple of simple tasks.
It must embed a WeakReference::Master object, which stores a shared pointer object, and must clear
this master pointer in its destructor.
E.g.
@code
class MyObject
{
public:
MyObject()
{
// If you're planning on using your WeakReferences in a multi-threaded situation, you may choose
// to create a WeakReference to the object here in the constructor, which will pre-initialise the
// embedded object, avoiding an (extremely unlikely) race condition that could occur if multiple
// threads overlap while creating the first WeakReference to it.
}
~MyObject()
{
// This will zero all the references - you need to call this in your destructor.
masterReference.clear();
}
private:
// You need to embed a variable of this type, with the name "masterReference" inside your object. If the
// variable is not public, you should make your class a friend of WeakReference<MyObject> so that the
// WeakReference class can access it.
WeakReference<MyObject>::Master masterReference;
friend class WeakReference<MyObject>;
};
// Here's an example of using a pointer..
MyObject* n = new MyObject();
WeakReference<MyObject> myObjectRef = n;
MyObject* pointer1 = myObjectRef; // returns a valid pointer to 'n'
delete n;
MyObject* pointer2 = myObjectRef; // returns a null pointer
@endcode
@see WeakReference::Master
*/
template <class ObjectType, class ReferenceCountingType = SharedObject>
class WeakReference
{
public:
/** Creates a null SafePointer. */
inline WeakReference() noexcept {}
/** Creates a WeakReference that points at the given object. */
WeakReference (ObjectType* const object) : holder (getRef (object)) {}
/** Creates a copy of another WeakReference. */
WeakReference (const WeakReference& other) noexcept : holder (other.holder) {}
/** Copies another pointer to this one. */
WeakReference& operator= (const WeakReference& other) { holder = other.holder; return *this; }
/** Copies another pointer to this one. */
WeakReference& operator= (ObjectType* const newObject) { holder = getRef (newObject); return *this; }
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
WeakReference (WeakReference&& other) noexcept : holder (static_cast <SharedRef&&> (other.holder)) {}
WeakReference& operator= (WeakReference&& other) noexcept { holder = static_cast <SharedRef&&> (other.holder); return *this; }
#endif
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
ObjectType* get() const noexcept { return holder != nullptr ? holder->get() : nullptr; }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
operator ObjectType*() const noexcept { return get(); }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
ObjectType* operator->() noexcept { return get(); }
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
const ObjectType* operator->() const noexcept { return get(); }
/** This returns true if this reference has been pointing at an object, but that object has
since been deleted.
If this reference was only ever pointing at a null pointer, this will return false. Using
operator=() to make this refer to a different object will reset this flag to match the status
of the reference from which you're copying.
*/
bool wasObjectDeleted() const noexcept { return holder != nullptr && holder->get() == nullptr; }
bool operator== (ObjectType* const object) const noexcept { return get() == object; }
bool operator!= (ObjectType* const object) const noexcept { return get() != object; }
//==============================================================================
/** This class is used internally by the WeakReference class - don't use it directly
in your code!
@see WeakReference
*/
class SharedPointer
: public ReferenceCountingType
, public Uncopyable
{
public:
explicit SharedPointer (ObjectType* const obj) noexcept : owner (obj) {}
inline ObjectType* get() const noexcept { return owner; }
void clearPointer() noexcept { owner = nullptr; }
private:
ObjectType* volatile owner;
};
typedef SharedObjectPtr<SharedPointer> SharedRef;
//==============================================================================
/**
This class is embedded inside an object to which you want to attach WeakReference pointers.
See the WeakReference class notes for an example of how to use this class.
@see WeakReference
*/
class Master : public Uncopyable
{
public:
Master() noexcept {}
~Master()
{
// You must remember to call clear() in your source object's destructor! See the notes
// for the WeakReference class for an example of how to do this.
bassert (sharedPointer == nullptr || sharedPointer->get() == nullptr);
}
/** The first call to this method will create an internal object that is shared by all weak
references to the object.
*/
SharedPointer* getSharedPointer (ObjectType* const object)
{
if (sharedPointer == nullptr)
{
sharedPointer = new SharedPointer (object);
}
else
{
// You're trying to create a weak reference to an object that has already been deleted!!
bassert (sharedPointer->get() != nullptr);
}
return sharedPointer;
}
/** The object that owns this master pointer should call this before it gets destroyed,
to zero all the references to this object that may be out there. See the WeakReference
class notes for an example of how to do this.
*/
void clear()
{
if (sharedPointer != nullptr)
sharedPointer->clearPointer();
}
private:
SharedRef sharedPointer;
};
private:
SharedRef holder;
static inline SharedPointer* getRef (ObjectType* const o)
{
return (o != nullptr) ? o->masterReference.getSharedPointer (o) : nullptr;
}
};
#endif // BEAST_WEAKREFERENCE_BEASTHEADER

View File

@@ -1,170 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "()V") \
METHOD (toString, "toString", "()Ljava/lang/String;") \
DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer");
#undef JNI_CLASS_MEMBERS
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (release, "release", "()V") \
METHOD (read, "read", "([BI)I") \
METHOD (getPosition, "getPosition", "()J") \
METHOD (getTotalLength, "getTotalLength", "()J") \
METHOD (isExhausted, "isExhausted", "()Z") \
METHOD (setPosition, "setPosition", "(J)Z") \
DECLARE_JNI_CLASS (HTTPStream, BEAST_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream");
#undef JNI_CLASS_MEMBERS
//==============================================================================
void MACAddress::findAllAddresses (Array<MACAddress>& result)
{
// TODO
}
bool Process::openEmailWithAttachments (const String& targetEmailAddress,
const String& emailSubject,
const String& bodyText,
const StringArray& filesToAttach)
{
// TODO
return false;
}
//==============================================================================
class WebInputStream
: public InputStream
, LeakChecked <WebInputStream>
{
public:
//==============================================================================
WebInputStream (String address, bool isPost, const MemoryBlock& postData,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers, int timeOutMs, StringPairArray* responseHeaders)
{
if (! address.contains ("://"))
address = "http://" + address;
JNIEnv* env = getEnv();
jbyteArray postDataArray = 0;
if (postData.getSize() > 0)
{
postDataArray = env->NewByteArray (postData.getSize());
env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData());
}
LocalRef<jobject> responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor));
stream = GlobalRef (env->CallStaticObjectMethod (BeastAppActivity,
BeastAppActivity.createHTTPStream,
javaString (address).get(),
(jboolean) isPost,
postDataArray,
javaString (headers).get(),
(jint) timeOutMs,
responseHeaderBuffer.get()));
if (postDataArray != 0)
env->DeleteLocalRef (postDataArray);
if (stream != 0)
{
StringArray headerLines;
{
LocalRef<jstring> headersString ((jstring) env->CallObjectMethod (responseHeaderBuffer.get(),
StringBuffer.toString));
headerLines.addLines (beastString (env, headersString));
}
if (responseHeaders != 0)
{
for (int i = 0; i < headerLines.size(); ++i)
{
const String& header = headerLines[i];
const String key (header.upToFirstOccurrenceOf (": ", false, false));
const String value (header.fromFirstOccurrenceOf (": ", false, false));
const String previousValue ((*responseHeaders) [key]);
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
}
}
}
}
~WebInputStream()
{
if (stream != 0)
stream.callVoidMethod (HTTPStream.release);
}
//==============================================================================
bool isExhausted() { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); }
int64 getTotalLength() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; }
int64 getPosition() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; }
bool setPosition (int64 wantedPos) { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); }
int read (void* buffer, int bytesToRead)
{
bassert (buffer != nullptr && bytesToRead >= 0);
if (stream == nullptr)
return 0;
JNIEnv* env = getEnv();
jbyteArray javaArray = env->NewByteArray (bytesToRead);
int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead);
if (numBytes > 0)
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast <jbyte*> (buffer));
env->DeleteLocalRef (javaArray);
return numBytes;
}
//==============================================================================
GlobalRef stream;
};
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
{
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
progressCallback, progressCallbackContext,
headers, timeOutMs, responseHeaders));
return wi->stream != 0 ? wi.release() : nullptr;
}

View File

@@ -1,455 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
void MACAddress::findAllAddresses (Array<MACAddress>& result)
{
ifaddrs* addrs = nullptr;
if (getifaddrs (&addrs) == 0)
{
for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next)
{
sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
if (sto->ss_family == AF_LINK)
{
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
#ifndef IFT_ETHER
#define IFT_ETHER 6
#endif
if (sadd->sdl_type == IFT_ETHER)
result.addIfNotAlreadyThere (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
}
}
freeifaddrs (addrs);
}
}
bool Process::openEmailWithAttachments (const String& /* targetEmailAddress */,
const String& /* emailSubject */,
const String& /* bodyText */,
const StringArray& /* filesToAttach */)
{
bassertfalse; // xxx todo
return false;
}
//==============================================================================
class WebInputStream
: public InputStream
, LeakChecked <WebInputStream>
{
public:
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
: socketHandle (-1), levelsOfRedirection (0),
address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
{
createConnection (progressCallback, progressCallbackContext);
if (responseHeaders != nullptr && ! isError())
{
for (int i = 0; i < headerLines.size(); ++i)
{
const String& headersEntry = headerLines[i];
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
const String previousValue ((*responseHeaders) [key]);
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
}
}
}
~WebInputStream()
{
closeSocket();
}
//==============================================================================
bool isError() const { return socketHandle < 0; }
bool isExhausted() { return finished; }
int64 getPosition() { return position; }
int64 getTotalLength()
{
//xxx to do
return -1;
}
int read (void* buffer, int bytesToRead)
{
if (finished || isError())
return 0;
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);
struct timeval tv;
tv.tv_sec = bmax (1, timeOutMs / 1000);
tv.tv_usec = 0;
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return 0; // (timeout)
const int bytesRead = bmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
if (bytesRead == 0)
finished = true;
position += bytesRead;
return bytesRead;
}
bool setPosition (int64 wantedPos)
{
if (isError())
return false;
if (wantedPos != position)
{
finished = false;
if (wantedPos < position)
{
closeSocket();
position = 0;
createConnection (0, 0);
}
skipNextBytes (wantedPos - position);
}
return true;
}
//==============================================================================
private:
int socketHandle, levelsOfRedirection;
StringArray headerLines;
String address, headers;
MemoryBlock postData;
int64 position;
bool finished;
const bool isPost;
const int timeOutMs;
void closeSocket()
{
if (socketHandle >= 0)
close (socketHandle);
socketHandle = -1;
levelsOfRedirection = 0;
}
void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
{
closeSocket();
uint32 timeOutTime = Time::getMillisecondCounter();
if (timeOutMs == 0)
timeOutTime += 60000;
else if (timeOutMs < 0)
timeOutTime = 0xffffffff;
else
timeOutTime += timeOutMs;
String hostName, hostPath;
int hostPort;
if (! decomposeURL (address, hostName, hostPath, hostPort))
return;
String serverName, proxyName, proxyPath;
int proxyPort = 0;
int port = 0;
const String proxyURL (getenv ("http_proxy"));
if (proxyURL.startsWithIgnoreCase ("http://"))
{
if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
return;
serverName = proxyName;
port = proxyPort;
}
else
{
serverName = hostName;
port = hostPort;
}
struct addrinfo hints;
zerostruct (hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
struct addrinfo* result = nullptr;
if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0)
return;
socketHandle = socket (result->ai_family, result->ai_socktype, 0);
if (socketHandle == -1)
{
freeaddrinfo (result);
return;
}
int receiveBufferSize = 16384;
setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
#if BEAST_MAC
setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
#endif
if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1)
{
closeSocket();
freeaddrinfo (result);
return;
}
freeaddrinfo (result);
{
const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort,
hostPath, address, headers, postData, isPost));
if (! sendHeader (socketHandle, requestHeader, timeOutTime, progressCallback, progressCallbackContext))
{
closeSocket();
return;
}
}
String responseHeader (readResponse (socketHandle, timeOutTime));
if (responseHeader.isNotEmpty())
{
headerLines = StringArray::fromLines (responseHeader);
const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
.substring (0, 3).getIntValue();
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
String location (findHeaderItem (headerLines, "Location:"));
if (statusCode >= 300 && statusCode < 400 && location.isNotEmpty())
{
if (! location.startsWithIgnoreCase ("http://"))
location = "http://" + location;
if (++levelsOfRedirection <= 3)
{
address = location;
createConnection (progressCallback, progressCallbackContext);
return;
}
}
else
{
levelsOfRedirection = 0;
return;
}
}
closeSocket();
}
//==============================================================================
static String readResponse (const int socketHandle, const uint32 timeOutTime)
{
int bytesRead = 0, numConsecutiveLFs = 0;
MemoryBlock buffer (1024, true);
while (numConsecutiveLFs < 2 && bytesRead < 32768
&& Time::getMillisecondCounter() <= timeOutTime)
{
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);
struct timeval tv;
tv.tv_sec = bmax (1, (int) (timeOutTime - Time::getMillisecondCounter()) / 1000);
tv.tv_usec = 0;
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return String::empty; // (timeout)
buffer.ensureSize (bytesRead + 8, true);
char* const dest = (char*) buffer.getData() + bytesRead;
if (recv (socketHandle, dest, 1, 0) == -1)
return String::empty;
const char lastByte = *dest;
++bytesRead;
if (lastByte == '\n')
++numConsecutiveLFs;
else if (lastByte != '\r')
numConsecutiveLFs = 0;
}
const String header (CharPointer_UTF8 ((const char*) buffer.getData()));
if (header.startsWithIgnoreCase ("HTTP/"))
return header.trimEnd();
return String::empty;
}
static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value)
{
if (! headers.containsIgnoreCase (key))
dest << "\r\n" << key << ' ' << value;
}
static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port)
{
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
if (port > 0)
dest << ':' << port;
}
static MemoryBlock createRequestHeader (const String& hostName, const int hostPort,
const String& proxyName, const int proxyPort,
const String& hostPath, const String& originalURL,
const String& userHeaders, const MemoryBlock& postData,
const bool isPost)
{
MemoryOutputStream header;
if (proxyName.isEmpty())
writeHost (header, isPost, hostPath, hostName, hostPort);
else
writeHost (header, isPost, originalURL, proxyName, proxyPort);
writeValueIfNotPresent (header, userHeaders, "User-Agent:", "BEAST/" BEAST_STRINGIFY(BEAST_MAJOR_VERSION)
"." BEAST_STRINGIFY(BEAST_MINOR_VERSION)
"." BEAST_STRINGIFY(BEAST_BUILDNUMBER));
writeValueIfNotPresent (header, userHeaders, "Connection:", "Close");
if (isPost)
writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize()));
header << "\r\n" << userHeaders
<< "\r\n" << postData;
return header.getMemoryBlock();
}
static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
{
size_t totalHeaderSent = 0;
while (totalHeaderSent < requestHeader.getSize())
{
if (Time::getMillisecondCounter() > timeOutTime)
return false;
const int numToSend = bmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
return false;
totalHeaderSent += numToSend;
if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
return false;
}
return true;
}
static bool decomposeURL (const String& url, String& host, String& path, int& port)
{
if (! url.startsWithIgnoreCase ("http://"))
return false;
const int nextSlash = url.indexOfChar (7, '/');
int nextColon = url.indexOfChar (7, ':');
if (nextColon > nextSlash && nextSlash > 0)
nextColon = -1;
if (nextColon >= 0)
{
host = url.substring (7, nextColon);
if (nextSlash >= 0)
port = url.substring (nextColon + 1, nextSlash).getIntValue();
else
port = url.substring (nextColon + 1).getIntValue();
}
else
{
port = 80;
if (nextSlash >= 0)
host = url.substring (7, nextSlash);
else
host = url.substring (7);
}
if (nextSlash >= 0)
path = url.substring (nextSlash);
else
path = "/";
return true;
}
static String findHeaderItem (const StringArray& lines, const String& itemName)
{
for (int i = 0; i < lines.size(); ++i)
if (lines[i].startsWithIgnoreCase (itemName))
return lines[i].substring (itemName.length()).trim();
return String::empty;
}
};
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
{
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
progressCallback, progressCallbackContext,
headers, timeOutMs, responseHeaders));
return wi->isError() ? nullptr : wi.release();
}

View File

@@ -1,457 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
void MACAddress::findAllAddresses (Array<MACAddress>& result)
{
const int s = socket (AF_INET, SOCK_DGRAM, 0);
if (s != -1)
{
char buf [1024];
struct ifconf ifc;
ifc.ifc_len = sizeof (buf);
ifc.ifc_buf = buf;
ioctl (s, SIOCGIFCONF, &ifc);
for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
{
struct ifreq ifr;
strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
{
result.addIfNotAlreadyThere (MACAddress ((const uint8*) ifr.ifr_hwaddr.sa_data));
}
}
close (s);
}
}
bool Process::openEmailWithAttachments (const String& /* targetEmailAddress */,
const String& /* emailSubject */,
const String& /* bodyText */,
const StringArray& /* filesToAttach */)
{
bassertfalse; // xxx todo
return false;
}
//==============================================================================
class WebInputStream
: public InputStream
, LeakChecked <WebInputStream>
{
public:
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
: socketHandle (-1), levelsOfRedirection (0),
address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
{
createConnection (progressCallback, progressCallbackContext);
if (responseHeaders != nullptr && ! isError())
{
for (int i = 0; i < headerLines.size(); ++i)
{
const String& headersEntry = headerLines[i];
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
const String previousValue ((*responseHeaders) [key]);
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
}
}
}
~WebInputStream()
{
closeSocket();
}
//==============================================================================
bool isError() const { return socketHandle < 0; }
bool isExhausted() { return finished; }
int64 getPosition() { return position; }
int64 getTotalLength()
{
//xxx to do
return -1;
}
int read (void* buffer, int bytesToRead)
{
if (finished || isError())
return 0;
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);
struct timeval tv;
tv.tv_sec = bmax (1, timeOutMs / 1000);
tv.tv_usec = 0;
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return 0; // (timeout)
const int bytesRead = bmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
if (bytesRead == 0)
finished = true;
position += bytesRead;
return bytesRead;
}
bool setPosition (int64 wantedPos)
{
if (isError())
return false;
if (wantedPos != position)
{
finished = false;
if (wantedPos < position)
{
closeSocket();
position = 0;
createConnection (0, 0);
}
skipNextBytes (wantedPos - position);
}
return true;
}
//==============================================================================
private:
int socketHandle, levelsOfRedirection;
StringArray headerLines;
String address, headers;
MemoryBlock postData;
int64 position;
bool finished;
const bool isPost;
const int timeOutMs;
void closeSocket()
{
if (socketHandle >= 0)
close (socketHandle);
socketHandle = -1;
levelsOfRedirection = 0;
}
void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
{
closeSocket();
uint32 timeOutTime = Time::getMillisecondCounter();
if (timeOutMs == 0)
timeOutTime += 60000;
else if (timeOutMs < 0)
timeOutTime = 0xffffffff;
else
timeOutTime += timeOutMs;
String hostName, hostPath;
int hostPort;
if (! decomposeURL (address, hostName, hostPath, hostPort))
return;
String serverName, proxyName, proxyPath;
int proxyPort = 0;
int port = 0;
const String proxyURL (getenv ("http_proxy"));
if (proxyURL.startsWithIgnoreCase ("http://"))
{
if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
return;
serverName = proxyName;
port = proxyPort;
}
else
{
serverName = hostName;
port = hostPort;
}
struct addrinfo hints;
zerostruct (hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
struct addrinfo* result = nullptr;
if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0)
return;
socketHandle = socket (result->ai_family, result->ai_socktype, 0);
if (socketHandle == -1)
{
freeaddrinfo (result);
return;
}
int receiveBufferSize = 16384;
setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
#if BEAST_MAC
setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
#endif
if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1)
{
closeSocket();
freeaddrinfo (result);
return;
}
freeaddrinfo (result);
{
const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort,
hostPath, address, headers, postData, isPost));
if (! sendHeader (socketHandle, requestHeader, timeOutTime, progressCallback, progressCallbackContext))
{
closeSocket();
return;
}
}
String responseHeader (readResponse (socketHandle, timeOutTime));
if (responseHeader.isNotEmpty())
{
headerLines = StringArray::fromLines (responseHeader);
const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
.substring (0, 3).getIntValue();
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
String location (findHeaderItem (headerLines, "Location:"));
if (statusCode >= 300 && statusCode < 400 && location.isNotEmpty())
{
if (! location.startsWithIgnoreCase ("http://"))
location = "http://" + location;
if (++levelsOfRedirection <= 3)
{
address = location;
createConnection (progressCallback, progressCallbackContext);
return;
}
}
else
{
levelsOfRedirection = 0;
return;
}
}
closeSocket();
}
//==============================================================================
static String readResponse (const int socketHandle, const uint32 timeOutTime)
{
int bytesRead = 0, numConsecutiveLFs = 0;
MemoryBlock buffer (1024, true);
while (numConsecutiveLFs < 2 && bytesRead < 32768
&& Time::getMillisecondCounter() <= timeOutTime)
{
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);
struct timeval tv;
tv.tv_sec = bmax (1, (int) (timeOutTime - Time::getMillisecondCounter()) / 1000);
tv.tv_usec = 0;
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return String::empty; // (timeout)
buffer.ensureSize (bytesRead + 8, true);
char* const dest = (char*) buffer.getData() + bytesRead;
if (recv (socketHandle, dest, 1, 0) == -1)
return String::empty;
const char lastByte = *dest;
++bytesRead;
if (lastByte == '\n')
++numConsecutiveLFs;
else if (lastByte != '\r')
numConsecutiveLFs = 0;
}
const String header (CharPointer_UTF8 ((const char*) buffer.getData()));
if (header.startsWithIgnoreCase ("HTTP/"))
return header.trimEnd();
return String::empty;
}
static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value)
{
if (! headers.containsIgnoreCase (key))
dest << "\r\n" << key << ' ' << value;
}
static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port)
{
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
if (port > 0)
dest << ':' << port;
}
static MemoryBlock createRequestHeader (const String& hostName, const int hostPort,
const String& proxyName, const int proxyPort,
const String& hostPath, const String& originalURL,
const String& userHeaders, const MemoryBlock& postData,
const bool isPost)
{
MemoryOutputStream header;
if (proxyName.isEmpty())
writeHost (header, isPost, hostPath, hostName, hostPort);
else
writeHost (header, isPost, originalURL, proxyName, proxyPort);
writeValueIfNotPresent (header, userHeaders, "User-Agent:", "BEAST/" BEAST_STRINGIFY(BEAST_MAJOR_VERSION)
"." BEAST_STRINGIFY(BEAST_MINOR_VERSION)
"." BEAST_STRINGIFY(BEAST_BUILDNUMBER));
writeValueIfNotPresent (header, userHeaders, "Connection:", "Close");
if (isPost)
writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize()));
header << "\r\n" << userHeaders
<< "\r\n" << postData;
return header.getMemoryBlock();
}
static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
{
size_t totalHeaderSent = 0;
while (totalHeaderSent < requestHeader.getSize())
{
if (Time::getMillisecondCounter() > timeOutTime)
return false;
const int numToSend = bmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
return false;
totalHeaderSent += numToSend;
if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
return false;
}
return true;
}
static bool decomposeURL (const String& url, String& host, String& path, int& port)
{
if (! url.startsWithIgnoreCase ("http://"))
return false;
const int nextSlash = url.indexOfChar (7, '/');
int nextColon = url.indexOfChar (7, ':');
if (nextColon > nextSlash && nextSlash > 0)
nextColon = -1;
if (nextColon >= 0)
{
host = url.substring (7, nextColon);
if (nextSlash >= 0)
port = url.substring (nextColon + 1, nextSlash).getIntValue();
else
port = url.substring (nextColon + 1).getIntValue();
}
else
{
port = 80;
if (nextSlash >= 0)
host = url.substring (7, nextSlash);
else
host = url.substring (7);
}
if (nextSlash >= 0)
path = url.substring (nextSlash);
else
path = "/";
return true;
}
static String findHeaderItem (const StringArray& lines, const String& itemName)
{
for (int i = 0; i < lines.size(); ++i)
if (lines[i].startsWithIgnoreCase (itemName))
return lines[i].substring (itemName.length()).trim();
return String::empty;
}
};
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
{
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
progressCallback, progressCallbackContext,
headers, timeOutMs, responseHeaders));
return wi->isError() ? nullptr : wi.release();
}

View File

@@ -1,428 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
void MACAddress::findAllAddresses (Array<MACAddress>& result)
{
ifaddrs* addrs = nullptr;
if (getifaddrs (&addrs) == 0)
{
for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next)
{
sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
if (sto->ss_family == AF_LINK)
{
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
#ifndef IFT_ETHER
#define IFT_ETHER 6
#endif
if (sadd->sdl_type == IFT_ETHER)
result.addIfNotAlreadyThere (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
}
}
freeifaddrs (addrs);
}
}
//==============================================================================
bool Process::openEmailWithAttachments (const String& targetEmailAddress,
const String& emailSubject,
const String& bodyText,
const StringArray& filesToAttach)
{
#if BEAST_IOS
//xxx probably need to use MFMailComposeViewController
bassertfalse;
return false;
#else
BEAST_AUTORELEASEPOOL
{
String script;
script << "tell application \"Mail\"\r\n"
"set newMessage to make new outgoing message with properties {subject:\""
<< emailSubject.replace ("\"", "\\\"")
<< "\", content:\""
<< bodyText.replace ("\"", "\\\"")
<< "\" & return & return}\r\n"
"tell newMessage\r\n"
"set visible to true\r\n"
"set sender to \"sdfsdfsdfewf\"\r\n"
"make new to recipient at end of to recipients with properties {address:\""
<< targetEmailAddress
<< "\"}\r\n";
for (int i = 0; i < filesToAttach.size(); ++i)
{
script << "tell content\r\n"
"make new attachment with properties {file name:\""
<< filesToAttach[i].replace ("\"", "\\\"")
<< "\"} at after the last paragraph\r\n"
"end tell\r\n";
}
script << "end tell\r\n"
"end tell\r\n";
NSAppleScript* s = [[NSAppleScript alloc] initWithSource: beastStringToNS (script)];
NSDictionary* error = nil;
const bool ok = [s executeAndReturnError: &error] != nil;
[s release];
return ok;
}
#endif
}
//==============================================================================
class URLConnectionState
: public Thread
, LeakChecked <URLConnectionState>
, public Uncopyable
{
public:
URLConnectionState (NSURLRequest* req)
: Thread ("http connection"),
contentLength (-1),
delegate (nil),
request ([req retain]),
connection (nil),
data ([[NSMutableData data] retain]),
headers (nil),
initialised (false),
hasFailed (false),
hasFinished (false)
{
static DelegateClass cls;
delegate = [cls.createInstance() init];
DelegateClass::setState (delegate, this);
}
~URLConnectionState()
{
stop();
[connection release];
[data release];
[request release];
[headers release];
[delegate release];
}
bool start (URL::OpenStreamProgressCallback* callback, void* context)
{
startThread();
while (isThreadRunning() && ! initialised)
{
if (callback != nullptr)
callback (context, -1, (int) [[request HTTPBody] length]);
Thread::sleep (1);
}
return connection != nil && ! hasFailed;
}
void stop()
{
[connection cancel];
stopThread (10000);
}
int read (char* dest, int numBytes)
{
int numDone = 0;
while (numBytes > 0)
{
const int available = bmin (numBytes, (int) [data length]);
if (available > 0)
{
const ScopedLock sl (dataLock);
[data getBytes: dest length: (NSUInteger) available];
[data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0];
numDone += available;
numBytes -= available;
dest += available;
}
else
{
if (hasFailed || hasFinished)
break;
Thread::sleep (1);
}
}
return numDone;
}
void didReceiveResponse (NSURLResponse* response)
{
{
const ScopedLock sl (dataLock);
[data setLength: 0];
}
initialised = true;
contentLength = [response expectedContentLength];
[headers release];
headers = nil;
if ([response isKindOfClass: [NSHTTPURLResponse class]])
headers = [[((NSHTTPURLResponse*) response) allHeaderFields] retain];
}
void didFailWithError (NSError* error)
{
DBG (nsStringToBeast ([error description])); (void) error;
hasFailed = true;
initialised = true;
signalThreadShouldExit();
}
void didReceiveData (NSData* newData)
{
const ScopedLock sl (dataLock);
[data appendData: newData];
initialised = true;
}
void didSendBodyData (int /*totalBytesWritten*/, int /*totalBytesExpected*/)
{
}
void finishedLoading()
{
hasFinished = true;
initialised = true;
signalThreadShouldExit();
}
void run() override
{
connection = [[NSURLConnection alloc] initWithRequest: request
delegate: delegate];
while (! threadShouldExit())
{
BEAST_AUTORELEASEPOOL
{
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
}
}
}
int64 contentLength;
CriticalSection dataLock;
NSObject* delegate;
NSURLRequest* request;
NSURLConnection* connection;
NSMutableData* data;
NSDictionary* headers;
bool initialised, hasFailed, hasFinished;
private:
//==============================================================================
struct DelegateClass : public ObjCClass <NSObject>
{
DelegateClass() : ObjCClass <NSObject> ("BEASTAppDelegate_")
{
addIvar <URLConnectionState*> ("state");
addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@");
addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@");
addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@");
addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:totalBytesExpectedToWrite:),
connectionDidSendBodyData, "v@:@iii");
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@");
registerClass();
}
static void setState (id self, URLConnectionState* state) { object_setInstanceVariable (self, "state", state); }
static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (self, "state"); }
private:
static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
{
getState (self)->didReceiveResponse (response);
}
static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
{
getState (self)->didFailWithError (error);
}
static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
{
getState (self)->didReceiveData (newData);
}
static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
{
getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected);
}
static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
{
getState (self)->finishedLoading();
}
};
};
//==============================================================================
class WebInputStream
: public InputStream
, LeakChecked <WebInputStream>
{
public:
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
: address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
{
BEAST_AUTORELEASEPOOL
{
createConnection (progressCallback, progressCallbackContext);
if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil)
{
NSEnumerator* enumerator = [connection->headers keyEnumerator];
NSString* key;
while ((key = [enumerator nextObject]) != nil)
responseHeaders->set (nsStringToBeast (key),
nsStringToBeast ((NSString*) [connection->headers objectForKey: key]));
}
}
}
//==============================================================================
bool isError() const { return connection == nullptr; }
int64 getTotalLength() { return connection == nullptr ? -1 : connection->contentLength; }
bool isExhausted() { return finished; }
int64 getPosition() { return position; }
int read (void* buffer, int bytesToRead)
{
bassert (buffer != nullptr && bytesToRead >= 0);
if (finished || isError())
return 0;
BEAST_AUTORELEASEPOOL
{
const int bytesRead = connection->read (static_cast <char*> (buffer), bytesToRead);
position += bytesRead;
if (bytesRead == 0)
finished = true;
return bytesRead;
}
}
bool setPosition (int64 wantedPos)
{
if (wantedPos != position)
{
finished = false;
if (wantedPos < position)
{
connection = nullptr;
position = 0;
createConnection (0, 0);
}
skipNextBytes (wantedPos - position);
}
return true;
}
private:
ScopedPointer<URLConnectionState> connection;
String address, headers;
MemoryBlock postData;
int64 position;
bool finished;
const bool isPost;
const int timeOutMs;
void createConnection (URL::OpenStreamProgressCallback* progressCallback,
void* progressCallbackContext)
{
bassert (connection == nullptr);
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: beastStringToNS (address)]
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)];
if (req != nil)
{
[req setHTTPMethod: nsStringLiteral (isPost ? "POST" : "GET")];
//[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
StringArray headerLines;
headerLines.addLines (headers);
headerLines.removeEmptyStrings (true);
for (int i = 0; i < headerLines.size(); ++i)
{
const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim());
const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim());
if (key.isNotEmpty() && value.isNotEmpty())
[req addValue: beastStringToNS (value) forHTTPHeaderField: beastStringToNS (key)];
}
if (isPost && postData.getSize() > 0)
[req setHTTPBody: [NSData dataWithBytes: postData.getData()
length: postData.getSize()]];
connection = new URLConnectionState (req);
if (! connection->start (progressCallback, progressCallbackContext))
connection = nullptr;
}
}
};
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
{
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
progressCallback, progressCallbackContext,
headers, timeOutMs, responseHeaders));
return wi->isError() ? nullptr : wi.release();
}

View File

@@ -1,464 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef INTERNET_FLAG_NEED_FILE
#define INTERNET_FLAG_NEED_FILE 0x00000010
#endif
#ifndef INTERNET_OPTION_DISABLE_AUTODIAL
#define INTERNET_OPTION_DISABLE_AUTODIAL 70
#endif
//==============================================================================
class WebInputStream
: public InputStream
, LeakChecked <WebInputStream>
{
public:
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
: connection (0), request (0),
address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
{
createConnection (progressCallback, progressCallbackContext);
if (responseHeaders != nullptr && ! isError())
{
DWORD bufferSizeBytes = 4096;
for (;;)
{
HeapBlock<char> buffer ((size_t) bufferSizeBytes);
if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0))
{
StringArray headersArray;
headersArray.addLines (reinterpret_cast <const WCHAR*> (buffer.getData()));
for (int i = 0; i < headersArray.size(); ++i)
{
const String& header = headersArray[i];
const String key (header.upToFirstOccurrenceOf (": ", false, false));
const String value (header.fromFirstOccurrenceOf (": ", false, false));
const String previousValue ((*responseHeaders) [key]);
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
}
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break;
}
}
}
~WebInputStream()
{
close();
}
//==============================================================================
bool isError() const { return request == 0; }
bool isExhausted() { return finished; }
int64 getPosition() { return position; }
int64 getTotalLength()
{
if (! isError())
{
DWORD index = 0, result = 0, size = sizeof (result);
if (HttpQueryInfo (request, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &result, &size, &index))
return (int64) result;
}
return -1;
}
int read (void* buffer, int bytesToRead)
{
bassert (buffer != nullptr && bytesToRead >= 0);
DWORD bytesRead = 0;
if (! (finished || isError()))
{
InternetReadFile (request, buffer, (DWORD) bytesToRead, &bytesRead);
position += bytesRead;
if (bytesRead == 0)
finished = true;
}
return (int) bytesRead;
}
bool setPosition (int64 wantedPos)
{
if (isError())
return false;
if (wantedPos != position)
{
finished = false;
position = (int64) InternetSetFilePointer (request, (LONG) wantedPos, 0, FILE_BEGIN, 0);
if (position == wantedPos)
return true;
if (wantedPos < position)
{
close();
position = 0;
createConnection (0, 0);
}
skipNextBytes (wantedPos - position);
}
return true;
}
private:
//==============================================================================
HINTERNET connection, request;
String address, headers;
MemoryBlock postData;
int64 position;
bool finished;
const bool isPost;
int timeOutMs;
void close()
{
if (request != 0)
{
InternetCloseHandle (request);
request = 0;
}
if (connection != 0)
{
InternetCloseHandle (connection);
connection = 0;
}
}
void createConnection (URL::OpenStreamProgressCallback* progressCallback,
void* progressCallbackContext)
{
static HINTERNET sessionHandle = InternetOpen (_T("beast"), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
close();
if (sessionHandle != 0)
{
// break up the url..
const int fileNumChars = 65536;
const int serverNumChars = 2048;
const int usernameNumChars = 1024;
const int passwordNumChars = 1024;
HeapBlock<TCHAR> file (fileNumChars), server (serverNumChars),
username (usernameNumChars), password (passwordNumChars);
URL_COMPONENTS uc = { 0 };
uc.dwStructSize = sizeof (uc);
uc.lpszUrlPath = file;
uc.dwUrlPathLength = fileNumChars;
uc.lpszHostName = server;
uc.dwHostNameLength = serverNumChars;
uc.lpszUserName = username;
uc.dwUserNameLength = usernameNumChars;
uc.lpszPassword = password;
uc.dwPasswordLength = passwordNumChars;
if (InternetCrackUrl (address.toWideCharPointer(), 0, 0, &uc))
openConnection (uc, sessionHandle, progressCallback, progressCallbackContext);
}
}
void openConnection (URL_COMPONENTS& uc, HINTERNET sessionHandle,
URL::OpenStreamProgressCallback* progressCallback,
void* progressCallbackContext)
{
int disable = 1;
InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable));
if (timeOutMs == 0)
timeOutMs = 30000;
else if (timeOutMs < 0)
timeOutMs = -1;
applyTimeout (sessionHandle, INTERNET_OPTION_CONNECT_TIMEOUT);
applyTimeout (sessionHandle, INTERNET_OPTION_RECEIVE_TIMEOUT);
applyTimeout (sessionHandle, INTERNET_OPTION_SEND_TIMEOUT);
applyTimeout (sessionHandle, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT);
applyTimeout (sessionHandle, INTERNET_OPTION_DATA_SEND_TIMEOUT);
const bool isFtp = address.startsWithIgnoreCase ("ftp:");
connection = InternetConnect (sessionHandle, uc.lpszHostName, uc.nPort,
uc.lpszUserName, uc.lpszPassword,
isFtp ? (DWORD) INTERNET_SERVICE_FTP
: (DWORD) INTERNET_SERVICE_HTTP,
0, 0);
if (connection != 0)
{
if (isFtp)
request = FtpOpenFile (connection, uc.lpszUrlPath, GENERIC_READ,
FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_NEED_FILE, 0);
else
openHTTPConnection (uc, progressCallback, progressCallbackContext);
}
}
void applyTimeout (HINTERNET sessionHandle, const DWORD option)
{
InternetSetOption (sessionHandle, option, &timeOutMs, sizeof (timeOutMs));
}
void openHTTPConnection (URL_COMPONENTS& uc, URL::OpenStreamProgressCallback* progressCallback,
void* progressCallbackContext)
{
const TCHAR* mimeTypes[] = { _T("*/*"), nullptr };
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES;
if (address.startsWithIgnoreCase ("https:"))
flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 -
// IE7 seems to automatically work out when it's https)
request = HttpOpenRequest (connection, isPost ? _T("POST") : _T("GET"),
uc.lpszUrlPath, 0, 0, mimeTypes, flags, 0);
if (request != 0)
{
INTERNET_BUFFERS buffers = { 0 };
buffers.dwStructSize = sizeof (INTERNET_BUFFERS);
buffers.lpcszHeader = headers.toWideCharPointer();
buffers.dwHeadersLength = (DWORD) headers.length();
buffers.dwBufferTotal = (DWORD) postData.getSize();
if (HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0))
{
int bytesSent = 0;
for (;;)
{
const int bytesToDo = bmin (1024, (int) postData.getSize() - bytesSent);
DWORD bytesDone = 0;
if (bytesToDo > 0
&& ! InternetWriteFile (request,
static_cast <const char*> (postData.getData()) + bytesSent,
(DWORD) bytesToDo, &bytesDone))
{
break;
}
if (bytesToDo == 0 || (int) bytesDone < bytesToDo)
{
if (HttpEndRequest (request, 0, 0, 0))
return;
break;
}
bytesSent += bytesDone;
if (progressCallback != nullptr
&& ! progressCallback (progressCallbackContext, bytesSent, (int) postData.getSize()))
break;
}
}
}
close();
}
};
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
{
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
progressCallback, progressCallbackContext,
headers, timeOutMs, responseHeaders));
return wi->isError() ? nullptr : wi.release();
}
//==============================================================================
struct GetAdaptersInfoHelper
{
bool callGetAdaptersInfo()
{
DynamicLibrary dll ("iphlpapi.dll");
BEAST_LOAD_WINAPI_FUNCTION (dll, GetAdaptersInfo, getAdaptersInfo, DWORD, (PIP_ADAPTER_INFO, PULONG))
if (getAdaptersInfo == nullptr)
return false;
adapterInfo.malloc (1);
ULONG len = sizeof (IP_ADAPTER_INFO);
if (getAdaptersInfo (adapterInfo, &len) == ERROR_BUFFER_OVERFLOW)
adapterInfo.malloc (len, 1);
return getAdaptersInfo (adapterInfo, &len) == NO_ERROR;
}
HeapBlock<IP_ADAPTER_INFO> adapterInfo;
};
namespace MACAddressHelpers
{
void getViaGetAdaptersInfo (Array<MACAddress>& result)
{
GetAdaptersInfoHelper gah;
if (gah.callGetAdaptersInfo())
{
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
if (adapter->AddressLength >= 6)
result.addIfNotAlreadyThere (MACAddress (adapter->Address));
}
}
void getViaNetBios (Array<MACAddress>& result)
{
DynamicLibrary dll ("netapi32.dll");
BEAST_LOAD_WINAPI_FUNCTION (dll, Netbios, NetbiosCall, UCHAR, (PNCB))
if (NetbiosCall != 0)
{
LANA_ENUM enums = { 0 };
{
NCB ncb = { 0 };
ncb.ncb_command = NCBENUM;
ncb.ncb_buffer = (unsigned char*) &enums;
ncb.ncb_length = sizeof (LANA_ENUM);
NetbiosCall (&ncb);
}
for (int i = 0; i < enums.length; ++i)
{
NCB ncb2 = { 0 };
ncb2.ncb_command = NCBRESET;
ncb2.ncb_lana_num = enums.lana[i];
if (NetbiosCall (&ncb2) == 0)
{
NCB ncb = { 0 };
memcpy (ncb.ncb_callname, "* ", NCBNAMSZ);
ncb.ncb_command = NCBASTAT;
ncb.ncb_lana_num = enums.lana[i];
struct ASTAT
{
ADAPTER_STATUS adapt;
NAME_BUFFER NameBuff [30];
};
ASTAT astat;
zerostruct (astat);
ncb.ncb_buffer = (unsigned char*) &astat;
ncb.ncb_length = sizeof (ASTAT);
if (NetbiosCall (&ncb) == 0 && astat.adapt.adapter_type == 0xfe)
result.addIfNotAlreadyThere (MACAddress (astat.adapt.adapter_address));
}
}
}
}
}
void MACAddress::findAllAddresses (Array<MACAddress>& result)
{
MACAddressHelpers::getViaGetAdaptersInfo (result);
MACAddressHelpers::getViaNetBios (result);
}
void IPAddress::findAllAddresses (Array<IPAddress>& result)
{
result.addIfNotAlreadyThere (IPAddress::local());
GetAdaptersInfoHelper gah;
if (gah.callGetAdaptersInfo())
{
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
{
IPAddress ip (adapter->IpAddressList.IpAddress.String);
if (ip != IPAddress::any())
result.addIfNotAlreadyThere (ip);
}
}
}
//==============================================================================
bool Process::openEmailWithAttachments (const String& targetEmailAddress,
const String& emailSubject,
const String& bodyText,
const StringArray& filesToAttach)
{
DynamicLibrary dll ("MAPI32.dll");
BEAST_LOAD_WINAPI_FUNCTION (dll, MAPISendMail, mapiSendMail,
ULONG, (LHANDLE, ULONG, lpMapiMessage, ::FLAGS, ULONG))
if (mapiSendMail == nullptr)
return false;
MapiMessage message = { 0 };
message.lpszSubject = (LPSTR) emailSubject.toRawUTF8();
message.lpszNoteText = (LPSTR) bodyText.toRawUTF8();
MapiRecipDesc recip = { 0 };
recip.ulRecipClass = MAPI_TO;
String targetEmailAddress_ (targetEmailAddress);
if (targetEmailAddress_.isEmpty())
targetEmailAddress_ = " "; // (Windows Mail can't deal with a blank address)
recip.lpszName = (LPSTR) targetEmailAddress_.toRawUTF8();
message.nRecipCount = 1;
message.lpRecips = &recip;
HeapBlock <MapiFileDesc> files;
files.calloc ((size_t) filesToAttach.size());
message.nFileCount = (ULONG) filesToAttach.size();
message.lpFiles = files;
for (int i = 0; i < filesToAttach.size(); ++i)
{
files[i].nPosition = (ULONG) -1;
files[i].lpszPathName = (LPSTR) filesToAttach[i].toRawUTF8();
}
return mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS;
}

View File

@@ -1,144 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
IPAddress::IPAddress() noexcept
{
address[0] = 0; address[1] = 0;
address[2] = 0; address[3] = 0;
}
IPAddress::IPAddress (const uint8 bytes[4]) noexcept
{
address[0] = bytes[0]; address[1] = bytes[1];
address[2] = bytes[2]; address[3] = bytes[3];
}
IPAddress::IPAddress (uint8 a0, uint8 a1, uint8 a2, uint8 a3) noexcept
{
address[0] = a0; address[1] = a1;
address[2] = a2; address[3] = a3;
}
IPAddress::IPAddress (uint32 n) noexcept
{
address[0] = (n >> 24);
address[1] = (n >> 16) & 255;
address[2] = (n >> 8) & 255;
address[3] = (n & 255);
}
IPAddress::IPAddress (const String& adr)
{
StringArray tokens;
tokens.addTokens (adr, ".", String::empty);
for (int i = 0; i < 4; ++i)
address[i] = (uint8) tokens[i].getIntValue();
}
String IPAddress::toString() const
{
String s ((int) address[0]);
for (int i = 1; i < 4; ++i)
s << '.' << (int) address[i];
return s;
}
IPAddress IPAddress::any() noexcept { return IPAddress(); }
IPAddress IPAddress::broadcast() noexcept { return IPAddress (255, 255, 255, 255); }
IPAddress IPAddress::local() noexcept { return IPAddress (127, 0, 0, 1); }
bool IPAddress::operator== (const IPAddress& other) const noexcept
{
return address[0] == other.address[0]
&& address[1] == other.address[1]
&& address[2] == other.address[2]
&& address[3] == other.address[3];
}
bool IPAddress::operator!= (const IPAddress& other) const noexcept
{
return ! operator== (other);
}
#if ! BEAST_WINDOWS
static void addAddress (const sockaddr_in* addr_in, Array<IPAddress>& result)
{
in_addr_t addr = addr_in->sin_addr.s_addr;
if (addr != INADDR_NONE)
result.addIfNotAlreadyThere (IPAddress (ntohl (addr)));
}
static void findIPAddresses (int sock, Array<IPAddress>& result)
{
ifconf cfg;
HeapBlock<char> buffer;
size_t bufferSize = 1024;
do
{
bufferSize *= 2;
buffer.calloc (bufferSize);
cfg.ifc_len = bufferSize;
cfg.ifc_buf = buffer;
if (ioctl (sock, SIOCGIFCONF, &cfg) < 0 && errno != EINVAL)
return;
} while (bufferSize < cfg.ifc_len + 2 * (IFNAMSIZ + sizeof (struct sockaddr_in6)));
#if BEAST_MAC || BEAST_IOS
while (cfg.ifc_len >= (int) (IFNAMSIZ + sizeof (struct sockaddr_in)))
{
if (cfg.ifc_req->ifr_addr.sa_family == AF_INET) // Skip non-internet addresses
addAddress ((const sockaddr_in*) &cfg.ifc_req->ifr_addr, result);
cfg.ifc_len -= IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
cfg.ifc_buf += IFNAMSIZ + cfg.ifc_req->ifr_addr.sa_len;
}
#else
for (size_t i = 0; i < cfg.ifc_len / sizeof (struct ifreq); ++i)
{
const ifreq& item = cfg.ifc_req[i];
if (item.ifr_addr.sa_family == AF_INET)
addAddress ((const sockaddr_in*) &item.ifr_addr, result);
}
#endif
}
void IPAddress::findAllAddresses (Array<IPAddress>& result)
{
const int sock = socket (AF_INET, SOCK_DGRAM, 0); // a dummy socket to execute the IO control
if (sock >= 0)
{
findIPAddresses (sock, result);
::close (sock);
}
}
#endif

View File

@@ -1,77 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_IPADDRESS_BEASTHEADER
#define BEAST_IPADDRESS_BEASTHEADER
//==============================================================================
/**
An IPV4 address.
*/
class BEAST_API IPAddress
{
public:
//==============================================================================
/** Populates a list of all the IP addresses that this machine is using. */
static void findAllAddresses (Array<IPAddress>& results);
//==============================================================================
/** Creates a null address (0.0.0.0). */
IPAddress() noexcept;
/** Creates an address from 4 bytes. */
explicit IPAddress (const uint8 bytes[4]) noexcept;
/** Creates an address from 4 bytes. */
IPAddress (uint8 address1, uint8 address2, uint8 address3, uint8 address4) noexcept;
/** Creates an address from a packed 32-bit integer, where the MSB is
the first number in the address, and the LSB is the last.
*/
explicit IPAddress (uint32 asNativeEndian32Bit) noexcept;
/** Parses a string IP address of the form "a.b.c.d". */
explicit IPAddress (const String& address);
/** Returns a dot-separated string in the form "1.2.3.4" */
String toString() const;
/** Returns an address meaning "any" (0.0.0.0) */
static IPAddress any() noexcept;
/** Returns an address meaning "broadcast" (255.255.255.255) */
static IPAddress broadcast() noexcept;
/** Returns an address meaning "localhost" (127.0.0.1) */
static IPAddress local() noexcept;
bool operator== (const IPAddress& other) const noexcept;
bool operator!= (const IPAddress& other) const noexcept;
/** The elements of the IP address. */
uint8 address[4];
};
#endif // BEAST_IPADDRESS_BEASTHEADER

View File

@@ -1,468 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
URL::URL()
{
}
URL::URL (const String& url_)
: url (url_)
{
int i = url.indexOfChar ('?');
if (i >= 0)
{
do
{
const int nextAmp = url.indexOfChar (i + 1, '&');
const int equalsPos = url.indexOfChar (i + 1, '=');
if (equalsPos > i + 1)
{
if (nextAmp < 0)
{
addParameter (removeEscapeChars (url.substring (i + 1, equalsPos)),
removeEscapeChars (url.substring (equalsPos + 1)));
}
else if (nextAmp > 0 && equalsPos < nextAmp)
{
addParameter (removeEscapeChars (url.substring (i + 1, equalsPos)),
removeEscapeChars (url.substring (equalsPos + 1, nextAmp)));
}
}
i = nextAmp;
}
while (i >= 0);
url = url.upToFirstOccurrenceOf ("?", false, false);
}
}
URL::URL (const URL& other)
: url (other.url),
postData (other.postData),
parameterNames (other.parameterNames),
parameterValues (other.parameterValues),
filesToUpload (other.filesToUpload),
mimeTypes (other.mimeTypes)
{
}
URL& URL::operator= (const URL& other)
{
url = other.url;
postData = other.postData;
parameterNames = other.parameterNames;
parameterValues = other.parameterValues;
filesToUpload = other.filesToUpload;
mimeTypes = other.mimeTypes;
return *this;
}
bool URL::operator== (const URL& other) const
{
return url == other.url
&& postData == other.postData
&& parameterNames == other.parameterNames
&& parameterValues == other.parameterValues
&& filesToUpload == other.filesToUpload
&& mimeTypes == other.mimeTypes;
}
bool URL::operator!= (const URL& other) const
{
return ! operator== (other);
}
URL::~URL()
{
}
namespace URLHelpers
{
static String getMangledParameters (const URL& url)
{
bassert (url.getParameterNames().size() == url.getParameterValues().size());
String p;
for (int i = 0; i < url.getParameterNames().size(); ++i)
{
if (i > 0)
p << '&';
p << URL::addEscapeChars (url.getParameterNames()[i], true)
<< '='
<< URL::addEscapeChars (url.getParameterValues()[i], true);
}
return p;
}
static int findEndOfScheme (const String& url)
{
int i = 0;
while (CharacterFunctions::isLetterOrDigit (url[i])
|| url[i] == '+' || url[i] == '-' || url[i] == '.')
++i;
return url[i] == ':' ? i + 1 : 0;
}
static int findStartOfNetLocation (const String& url)
{
int start = findEndOfScheme (url);
while (url[start] == '/')
++start;
return start;
}
static int findStartOfPath (const String& url)
{
return url.indexOfChar (findStartOfNetLocation (url), '/') + 1;
}
static void createHeadersAndPostData (const URL& url, String& headers, MemoryBlock& postData)
{
MemoryOutputStream data (postData, false);
if (url.getFilesToUpload().size() > 0)
{
// need to upload some files, so do it as multi-part...
const String boundary (String::toHexString (Random::getSystemRandom().nextInt64()));
headers << "Content-Type: multipart/form-data; boundary=" << boundary << "\r\n";
data << "--" << boundary;
for (int i = 0; i < url.getParameterNames().size(); ++i)
{
data << "\r\nContent-Disposition: form-data; name=\""
<< url.getParameterNames() [i]
<< "\"\r\n\r\n"
<< url.getParameterValues() [i]
<< "\r\n--"
<< boundary;
}
for (int i = 0; i < url.getFilesToUpload().size(); ++i)
{
const File file (url.getFilesToUpload().getAllValues() [i]);
const String paramName (url.getFilesToUpload().getAllKeys() [i]);
data << "\r\nContent-Disposition: form-data; name=\"" << paramName
<< "\"; filename=\"" << file.getFileName() << "\"\r\n";
const String mimeType (url.getMimeTypesOfUploadFiles()
.getValue (paramName, String::empty));
if (mimeType.isNotEmpty())
data << "Content-Type: " << mimeType << "\r\n";
data << "Content-Transfer-Encoding: binary\r\n\r\n"
<< file << "\r\n--" << boundary;
}
data << "--\r\n";
}
else
{
data << getMangledParameters (url)
<< url.getPostData();
// just a short text attachment, so use simple url encoding..
headers << "Content-Type: application/x-www-form-urlencoded\r\nContent-length: "
<< (int) data.getDataSize() << "\r\n";
}
}
static void concatenatePaths (String& path, const String& suffix)
{
if (! path.endsWithChar ('/'))
path << '/';
if (suffix.startsWithChar ('/'))
path += suffix.substring (1);
else
path += suffix;
}
}
void URL::addParameter (const String& name, const String& value)
{
parameterNames.add (name);
parameterValues.add (value);
}
String URL::toString (const bool includeGetParameters) const
{
if (includeGetParameters && parameterNames.size() > 0)
return url + "?" + URLHelpers::getMangledParameters (*this);
return url;
}
bool URL::isWellFormed() const
{
//xxx TODO
return url.isNotEmpty();
}
String URL::getDomain() const
{
const int start = URLHelpers::findStartOfNetLocation (url);
const int end1 = url.indexOfChar (start, '/');
const int end2 = url.indexOfChar (start, ':');
const int end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max()
: ((end1 < 0 || end2 < 0) ? bmax (end1, end2)
: bmin (end1, end2));
return url.substring (start, end);
}
String URL::getSubPath() const
{
const int startOfPath = URLHelpers::findStartOfPath (url);
return startOfPath <= 0 ? String::empty
: url.substring (startOfPath);
}
String URL::getScheme() const
{
return url.substring (0, URLHelpers::findEndOfScheme (url) - 1);
}
int URL::getPort() const
{
const int colonPos = url.indexOfChar (URLHelpers::findStartOfNetLocation (url), ':');
return colonPos > 0 ? url.substring (colonPos + 1).getIntValue() : 0;
}
URL URL::withNewSubPath (const String& newPath) const
{
const int startOfPath = URLHelpers::findStartOfPath (url);
URL u (*this);
if (startOfPath > 0)
u.url = url.substring (0, startOfPath);
URLHelpers::concatenatePaths (u.url, newPath);
return u;
}
URL URL::getChildURL (const String& subPath) const
{
URL u (*this);
URLHelpers::concatenatePaths (u.url, subPath);
return u;
}
//==============================================================================
bool URL::isProbablyAWebsiteURL (const String& possibleURL)
{
const char* validProtocols[] = { "http:", "ftp:", "https:" };
for (int i = 0; i < numElementsInArray (validProtocols); ++i)
if (possibleURL.startsWithIgnoreCase (validProtocols[i]))
return true;
if (possibleURL.containsChar ('@')
|| possibleURL.containsChar (' '))
return false;
const String topLevelDomain (possibleURL.upToFirstOccurrenceOf ("/", false, false)
.fromLastOccurrenceOf (".", false, false));
return topLevelDomain.isNotEmpty() && topLevelDomain.length() <= 3;
}
bool URL::isProbablyAnEmailAddress (const String& possibleEmailAddress)
{
const int atSign = possibleEmailAddress.indexOfChar ('@');
return atSign > 0
&& possibleEmailAddress.lastIndexOfChar ('.') > (atSign + 1)
&& (! possibleEmailAddress.endsWithChar ('.'));
}
//==============================================================================
InputStream* URL::createInputStream (const bool usePostCommand,
OpenStreamProgressCallback* const progressCallback,
void* const progressCallbackContext,
const String& extraHeaders,
const int timeOutMs,
StringPairArray* const responseHeaders) const
{
String headers;
MemoryBlock headersAndPostData;
if (usePostCommand)
URLHelpers::createHeadersAndPostData (*this, headers, headersAndPostData);
headers += extraHeaders;
if (! headers.endsWithChar ('\n'))
headers << "\r\n";
return createNativeStream (toString (! usePostCommand), usePostCommand, headersAndPostData,
progressCallback, progressCallbackContext,
headers, timeOutMs, responseHeaders);
}
//==============================================================================
bool URL::readEntireBinaryStream (MemoryBlock& destData,
const bool usePostCommand) const
{
const ScopedPointer <InputStream> in (createInputStream (usePostCommand));
if (in != nullptr)
{
in->readIntoMemoryBlock (destData);
return true;
}
return false;
}
String URL::readEntireTextStream (const bool usePostCommand) const
{
const ScopedPointer <InputStream> in (createInputStream (usePostCommand));
if (in != nullptr)
return in->readEntireStreamAsString();
return String::empty;
}
XmlElement* URL::readEntireXmlStream (const bool usePostCommand) const
{
return XmlDocument::parse (readEntireTextStream (usePostCommand));
}
//==============================================================================
URL URL::withParameter (const String& parameterName,
const String& parameterValue) const
{
URL u (*this);
u.addParameter (parameterName, parameterValue);
return u;
}
URL URL::withFileToUpload (const String& parameterName,
const File& fileToUpload,
const String& mimeType) const
{
bassert (mimeType.isNotEmpty()); // You need to supply a mime type!
URL u (*this);
u.filesToUpload.set (parameterName, fileToUpload.getFullPathName());
u.mimeTypes.set (parameterName, mimeType);
return u;
}
URL URL::withPOSTData (const String& postData_) const
{
URL u (*this);
u.postData = postData_;
return u;
}
const StringPairArray& URL::getFilesToUpload() const
{
return filesToUpload;
}
const StringPairArray& URL::getMimeTypesOfUploadFiles() const
{
return mimeTypes;
}
//==============================================================================
String URL::removeEscapeChars (const String& s)
{
String result (s.replaceCharacter ('+', ' '));
if (! result.containsChar ('%'))
return result;
// We need to operate on the string as raw UTF8 chars, and then recombine them into unicode
// after all the replacements have been made, so that multi-byte chars are handled.
Array<char> utf8 (result.toRawUTF8(), (int) result.getNumBytesAsUTF8());
for (int i = 0; i < utf8.size(); ++i)
{
if (utf8.getUnchecked(i) == '%')
{
const int hexDigit1 = CharacterFunctions::getHexDigitValue ((beast_wchar) (uint8) utf8 [i + 1]);
const int hexDigit2 = CharacterFunctions::getHexDigitValue ((beast_wchar) (uint8) utf8 [i + 2]);
if (hexDigit1 >= 0 && hexDigit2 >= 0)
{
utf8.set (i, (char) ((hexDigit1 << 4) + hexDigit2));
utf8.removeRange (i + 1, 2);
}
}
}
return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size());
}
String URL::addEscapeChars (const String& s, const bool isParameter)
{
const CharPointer_UTF8 legalChars (isParameter ? "_-.*!'()"
: ",$_-.*!'()");
Array<char> utf8 (s.toRawUTF8(), (int) s.getNumBytesAsUTF8());
for (int i = 0; i < utf8.size(); ++i)
{
const char c = utf8.getUnchecked(i);
if (! (CharacterFunctions::isLetterOrDigit (c)
|| legalChars.indexOf ((beast_wchar) c) >= 0))
{
utf8.set (i, '%');
utf8.insert (++i, "0123456789abcdef" [((uint8) c) >> 4]);
utf8.insert (++i, "0123456789abcdef" [c & 15]);
}
}
return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size());
}
//==============================================================================
bool URL::launchInDefaultBrowser() const
{
String u (toString (true));
if (u.containsChar ('@') && ! u.containsChar (':'))
u = "mailto:" + u;
return Process::openDocument (u, String::empty);
}

View File

@@ -1,344 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_URL_BEASTHEADER
#define BEAST_URL_BEASTHEADER
#include "../text/beast_StringPairArray.h"
#include "../files/beast_File.h"
class InputStream;
class XmlElement;
//==============================================================================
/**
Represents a URL and has a bunch of useful functions to manipulate it.
This class can be used to launch URLs in browsers, and also to create
InputStreams that can read from remote http or ftp sources.
*/
class BEAST_API URL : LeakChecked <URL>
{
public:
//==============================================================================
/** Creates an empty URL. */
URL();
/** Creates a URL from a string. */
URL (const String& url);
/** Creates a copy of another URL. */
URL (const URL& other);
/** Destructor. */
~URL();
/** Copies this URL from another one. */
URL& operator= (const URL& other);
/** Compares two URLs.
All aspects of the URLs must be identical for them to match, including any parameters,
upload files, etc.
*/
bool operator== (const URL&) const;
bool operator!= (const URL&) const;
//==============================================================================
/** Returns a string version of the URL.
If includeGetParameters is true and any parameters have been set with the
withParameter() method, then the string will have these appended on the
end and url-encoded.
*/
String toString (bool includeGetParameters) const;
/** True if it seems to be valid. */
bool isWellFormed() const;
/** Returns just the domain part of the URL.
E.g. for "http://www.xyz.com/foobar", this will return "www.xyz.com".
*/
String getDomain() const;
/** Returns the path part of the URL.
E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar".
*/
String getSubPath() const;
/** Returns the scheme of the URL.
E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't
include the colon).
*/
String getScheme() const;
/** Attempts to read a port number from the URL.
@returns the port number, or 0 if none is explicitly specified.
*/
int getPort() const;
/** Returns a new version of this URL that uses a different sub-path.
E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with
"bar", it'll return "http://www.xyz.com/bar?x=1".
*/
URL withNewSubPath (const String& newPath) const;
/** Returns a new URL that refers to a sub-path relative to this one.
E.g. if the URL is "http://www.xyz.com/foo" and you call this with
"bar", it'll return "http://www.xyz.com/foo/bar". Note that there's no way for
this method to know whether the original URL is a file or directory, so it's
up to you to make sure it's a directory. It also won't attempt to be smart about
the content of the childPath string, so if this string is an absolute URL, it'll
still just get bolted onto the end of the path.
@see File::getChildFile
*/
URL getChildURL (const String& subPath) const;
//==============================================================================
/** Returns a copy of this URL, with a GET or POST parameter added to the end.
Any control characters in the value will be encoded.
e.g. calling "withParameter ("amount", "some fish") for the url "www.fish.com"
would produce a new url whose toString(true) method would return
"www.fish.com?amount=some+fish".
@see getParameterNames, getParameterValues
*/
URL withParameter (const String& parameterName,
const String& parameterValue) const;
/** Returns a copy of this URl, with a file-upload type parameter added to it.
When performing a POST where one of your parameters is a binary file, this
lets you specify the file.
Note that the filename is stored, but the file itself won't actually be read
until this URL is later used to create a network input stream.
*/
URL withFileToUpload (const String& parameterName,
const File& fileToUpload,
const String& mimeType) const;
/** Returns an array of the names of all the URL's parameters.
E.g. for the url "www.fish.com?type=haddock&amount=some+fish", this array would
contain two items: "type" and "amount".
You can call getParameterValues() to get the corresponding value of each
parameter. Note that the list can contain multiple parameters with the same name.
@see getParameterValues, withParameter
*/
const StringArray& getParameterNames() const noexcept { return parameterNames; }
/** Returns an array of the values of all the URL's parameters.
E.g. for the url "www.fish.com?type=haddock&amount=some+fish", this array would
contain two items: "haddock" and "some fish".
The values returned will have been cleaned up to remove any escape characters.
You can call getParameterNames() to get the corresponding name of each
parameter. Note that the list can contain multiple parameters with the same name.
@see getParameterNames, withParameter
*/
const StringArray& getParameterValues() const noexcept { return parameterValues; }
/** Returns the set of files that should be uploaded as part of a POST operation.
This is the set of files that were added to the URL with the withFileToUpload()
method.
*/
const StringPairArray& getFilesToUpload() const;
/** Returns the set of mime types associated with each of the upload files.
*/
const StringPairArray& getMimeTypesOfUploadFiles() const;
/** Returns a copy of this URL, with a block of data to send as the POST data.
If you're setting the POST data, be careful not to have any parameters set
as well, otherwise it'll all get thrown in together, and might not have the
desired effect.
If the URL already contains some POST data, this will replace it, rather
than being appended to it.
This data will only be used if you specify a post operation when you call
createInputStream().
*/
URL withPOSTData (const String& postData) const;
/** Returns the data that was set using withPOSTData(). */
const String& getPostData() const noexcept { return postData; }
//==============================================================================
/** Tries to launch the system's default browser to open the URL.
Returns true if this seems to have worked.
*/
bool launchInDefaultBrowser() const;
//==============================================================================
/** Takes a guess as to whether a string might be a valid website address.
This isn't foolproof!
*/
static bool isProbablyAWebsiteURL (const String& possibleURL);
/** Takes a guess as to whether a string might be a valid email address.
This isn't foolproof!
*/
static bool isProbablyAnEmailAddress (const String& possibleEmailAddress);
//==============================================================================
/** This callback function can be used by the createInputStream() method.
It allows your app to receive progress updates during a lengthy POST operation. If you
want to continue the operation, this should return true, or false to abort.
*/
typedef bool (OpenStreamProgressCallback) (void* context, int bytesSent, int totalBytes);
/** Attempts to open a stream that can read from this URL.
@param usePostCommand if true, it will try to do use a http 'POST' to pass
the paramters, otherwise it'll encode them into the
URL and do a 'GET'.
@param progressCallback if this is non-zero, it lets you supply a callback function
to keep track of the operation's progress. This can be useful
for lengthy POST operations, so that you can provide user feedback.
@param progressCallbackContext if a callback is specified, this value will be passed to
the function
@param extraHeaders if not empty, this string is appended onto the headers that
are used for the request. It must therefore be a valid set of HTML
header directives, separated by newlines.
@param connectionTimeOutMs if 0, this will use whatever default setting the OS chooses. If
a negative number, it will be infinite. Otherwise it specifies a
time in milliseconds.
@param responseHeaders if this is non-zero, all the (key, value) pairs received as headers
in the response will be stored in this array
@returns an input stream that the caller must delete, or a null pointer if there was an
error trying to open it.
*/
InputStream* createInputStream (bool usePostCommand,
OpenStreamProgressCallback* progressCallback = nullptr,
void* progressCallbackContext = nullptr,
const String& extraHeaders = String::empty,
int connectionTimeOutMs = 0,
StringPairArray* responseHeaders = nullptr) const;
//==============================================================================
/** Tries to download the entire contents of this URL into a binary data block.
If it succeeds, this will return true and append the data it read onto the end
of the memory block.
@param destData the memory block to append the new data to
@param usePostCommand whether to use a POST command to get the data (uses
a GET command if this is false)
@see readEntireTextStream, readEntireXmlStream
*/
bool readEntireBinaryStream (MemoryBlock& destData,
bool usePostCommand = false) const;
/** Tries to download the entire contents of this URL as a string.
If it fails, this will return an empty string, otherwise it will return the
contents of the downloaded file. If you need to distinguish between a read
operation that fails and one that returns an empty string, you'll need to use
a different method, such as readEntireBinaryStream().
@param usePostCommand whether to use a POST command to get the data (uses
a GET command if this is false)
@see readEntireBinaryStream, readEntireXmlStream
*/
String readEntireTextStream (bool usePostCommand = false) const;
/** Tries to download the entire contents of this URL and parse it as XML.
If it fails, or if the text that it reads can't be parsed as XML, this will
return 0.
When it returns a valid XmlElement object, the caller is responsibile for deleting
this object when no longer needed.
@param usePostCommand whether to use a POST command to get the data (uses
a GET command if this is false)
@see readEntireBinaryStream, readEntireTextStream
*/
XmlElement* readEntireXmlStream (bool usePostCommand = false) const;
//==============================================================================
/** Adds escape sequences to a string to encode any characters that aren't
legal in a URL.
E.g. any spaces will be replaced with "%20".
This is the opposite of removeEscapeChars().
If isParameter is true, it means that the string is going to be used
as a parameter, so it also encodes '$' and ',' (which would otherwise
be legal in a URL.
@see removeEscapeChars
*/
static String addEscapeChars (const String& stringToAddEscapeCharsTo,
bool isParameter);
/** Replaces any escape character sequences in a string with their original
character codes.
E.g. any instances of "%20" will be replaced by a space.
This is the opposite of addEscapeChars().
@see addEscapeChars
*/
static String removeEscapeChars (const String& stringToRemoveEscapeCharsFrom);
private:
//==============================================================================
String url, postData;
StringArray parameterNames, parameterValues;
StringPairArray filesToUpload, mimeTypes;
void addParameter (const String&, const String&);
static InputStream* createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
OpenStreamProgressCallback* progressCallback,
void* progressCallbackContext, const String& headers,
const int timeOutMs, StringPairArray* responseHeaders);
};
#endif // BEAST_URL_BEASTHEADER

View File

@@ -1,367 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
Thread::Thread (const String& threadName_)
: threadName (threadName_),
threadHandle (nullptr),
threadId (0),
threadPriority (5),
affinityMask (0),
shouldExit (false)
{
}
Thread::~Thread()
{
/* If your thread class's destructor has been called without first stopping the thread, that
means that this partially destructed object is still performing some work - and that's
probably a Bad Thing!
To avoid this type of nastiness, always make sure you call stopThread() before or during
your subclass's destructor.
*/
fatal_assert (! isThreadRunning());
}
//==============================================================================
// Use a ref-counted object to hold this shared data, so that it can outlive its static
// shared pointer when threads are still running during static shutdown.
struct CurrentThreadHolder : public SharedObject
{
CurrentThreadHolder() noexcept {}
typedef SharedObjectPtr <CurrentThreadHolder> Ptr;
ThreadLocalValue<Thread*> value;
};
static char currentThreadHolderLock [sizeof (SpinLock)]; // (statically initialised to zeros).
static SpinLock* castToSpinLockWithoutAliasingWarning (void* s)
{
return static_cast<SpinLock*> (s);
}
static CurrentThreadHolder::Ptr getCurrentThreadHolder()
{
static CurrentThreadHolder::Ptr currentThreadHolder;
SpinLock::ScopedLockType lock (*castToSpinLockWithoutAliasingWarning (currentThreadHolderLock));
if (currentThreadHolder == nullptr)
currentThreadHolder = new CurrentThreadHolder();
return currentThreadHolder;
}
void Thread::threadEntryPoint()
{
const CurrentThreadHolder::Ptr currentThreadHolder (getCurrentThreadHolder());
currentThreadHolder->value = this;
BEAST_TRY
{
if (threadName.isNotEmpty())
setCurrentThreadName (threadName);
if (startSuspensionEvent.wait (10000))
{
bassert (getCurrentThreadId() == threadId);
if (affinityMask != 0)
setCurrentThreadAffinityMask (affinityMask);
run();
}
}
BEAST_CATCH_ALL_ASSERT
currentThreadHolder->value.releaseCurrentThreadStorage();
closeThreadHandle();
}
// used to wrap the incoming call from the platform-specific code
void BEAST_API beast_threadEntryPoint (void* userData)
{
ProtectedCall (&Thread::threadEntryPoint, static_cast <Thread*> (userData));
}
//==============================================================================
void Thread::startThread()
{
const ScopedLock sl (startStopLock);
shouldExit = false;
if (threadHandle == nullptr)
{
launchThread();
setThreadPriority (threadHandle, threadPriority);
startSuspensionEvent.signal();
}
}
void Thread::startThread (const int priority)
{
const ScopedLock sl (startStopLock);
if (threadHandle == nullptr)
{
threadPriority = priority;
startThread();
}
else
{
setPriority (priority);
}
}
bool Thread::isThreadRunning() const
{
return threadHandle != nullptr;
}
Thread* Thread::getCurrentThread()
{
return getCurrentThreadHolder()->value.get();
}
//==============================================================================
void Thread::signalThreadShouldExit()
{
shouldExit = true;
}
bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
{
// Doh! So how exactly do you expect this thread to wait for itself to stop??
bassert (getThreadId() != getCurrentThreadId() || getCurrentThreadId() == 0);
const uint32 timeoutEnd = Time::getMillisecondCounter() + (uint32) timeOutMilliseconds;
while (isThreadRunning())
{
if (timeOutMilliseconds >= 0 && Time::getMillisecondCounter() > timeoutEnd)
return false;
sleep (2);
}
return true;
}
bool Thread::stopThread (const int timeOutMilliseconds)
{
bool cleanExit = true;
// agh! You can't stop the thread that's calling this method! How on earth
// would that work??
bassert (getCurrentThreadId() != getThreadId());
const ScopedLock sl (startStopLock);
if (isThreadRunning())
{
signalThreadShouldExit();
notify();
if (timeOutMilliseconds != 0)
{
cleanExit = waitForThreadToExit (timeOutMilliseconds);
}
if (isThreadRunning())
{
bassert (! cleanExit);
// very bad karma if this point is reached, as there are bound to be
// locks and events left in silly states when a thread is killed by force..
killThread();
threadHandle = nullptr;
threadId = 0;
cleanExit = false;
}
else
{
cleanExit = true;
}
}
return cleanExit;
}
//==============================================================================
bool Thread::setPriority (const int newPriority)
{
// NB: deadlock possible if you try to set the thread prio from the thread itself,
// so using setCurrentThreadPriority instead in that case.
if (getCurrentThreadId() == getThreadId())
return setCurrentThreadPriority (newPriority);
const ScopedLock sl (startStopLock);
if (setThreadPriority (threadHandle, newPriority))
{
threadPriority = newPriority;
return true;
}
return false;
}
bool Thread::setCurrentThreadPriority (const int newPriority)
{
return setThreadPriority (0, newPriority);
}
void Thread::setAffinityMask (const uint32 newAffinityMask)
{
affinityMask = newAffinityMask;
}
//==============================================================================
bool Thread::wait (const int timeOutMilliseconds) const
{
return defaultEvent.wait (timeOutMilliseconds);
}
void Thread::notify() const
{
defaultEvent.signal();
}
//==============================================================================
void SpinLock::enter() const noexcept
{
if (! tryEnter())
{
for (int i = 20; --i >= 0;)
if (tryEnter())
return;
while (! tryEnter())
Thread::yield();
}
}
//==============================================================================
class AtomicTests : public UnitTest
{
public:
AtomicTests() : UnitTest ("Atomic", "beast") {}
void runTest()
{
beginTestCase ("Misc");
char a1[7];
expect (numElementsInArray(a1) == 7);
int a2[3];
expect (numElementsInArray(a2) == 3);
expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211));
beginTestCase ("int");
AtomicTester <int>::testInteger (*this);
beginTestCase ("unsigned int");
AtomicTester <unsigned int>::testInteger (*this);
beginTestCase ("int32");
AtomicTester <int32>::testInteger (*this);
beginTestCase ("uint32");
AtomicTester <uint32>::testInteger (*this);
beginTestCase ("long");
AtomicTester <long>::testInteger (*this);
beginTestCase ("void*");
AtomicTester <void*>::testInteger (*this);
beginTestCase ("int*");
AtomicTester <int*>::testInteger (*this);
beginTestCase ("float");
AtomicTester <float>::testFloat (*this);
#if ! BEAST_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms
beginTestCase ("int64");
AtomicTester <int64>::testInteger (*this);
beginTestCase ("uint64");
AtomicTester <uint64>::testInteger (*this);
beginTestCase ("double");
AtomicTester <double>::testFloat (*this);
#endif
}
template <typename Type>
class AtomicTester
{
public:
AtomicTester() {}
static void testInteger (UnitTest& test)
{
Atomic<Type> a, b;
a.set ((Type) 10);
test.expect (a.value == (Type) 10);
test.expect (a.get() == (Type) 10);
a += (Type) 15;
test.expect (a.get() == (Type) 25);
a.memoryBarrier();
a -= (Type) 5;
test.expect (a.get() == (Type) 20);
test.expect (++a == (Type) 21);
++a;
test.expect (--a == (Type) 21);
test.expect (a.get() == (Type) 21);
a.memoryBarrier();
testFloat (test);
}
static void testFloat (UnitTest& test)
{
Atomic<Type> a, b;
a = (Type) 21;
a.memoryBarrier();
/* These are some simple test cases to check the atomics - let me know
if any of these assertions fail on your system!
*/
test.expect (a.get() == (Type) 21);
test.expect (a.compareAndSetValue ((Type) 100, (Type) 50) == (Type) 21);
test.expect (a.get() == (Type) 21);
test.expect (a.compareAndSetValue ((Type) 101, a.get()) == (Type) 21);
test.expect (a.get() == (Type) 101);
test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
test.expect (a.get() == (Type) 101);
test.expect (a.compareAndSetBool ((Type) 200, a.get()));
test.expect (a.get() == (Type) 200);
test.expect (a.exchange ((Type) 300) == (Type) 200);
test.expect (a.get() == (Type) 300);
b = a;
test.expect (b.get() == a.get());
}
};
};
static AtomicTests atomicTests;

View File

@@ -1,375 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
ThreadPoolJob::ThreadPoolJob (const String& name)
: jobName (name),
pool (nullptr),
shouldStop (false),
isActive (false),
shouldBeDeleted (false)
{
}
ThreadPoolJob::~ThreadPoolJob()
{
// you mustn't delete a job while it's still in a pool! Use ThreadPool::removeJob()
// to remove it first!
bassert (pool == nullptr || ! pool->contains (this));
}
String ThreadPoolJob::getJobName() const
{
return jobName;
}
void ThreadPoolJob::setJobName (const String& newName)
{
jobName = newName;
}
void ThreadPoolJob::signalJobShouldExit()
{
shouldStop = true;
}
//==============================================================================
class ThreadPool::ThreadPoolThread
: public Thread
, LeakChecked <ThreadPoolThread>
{
public:
ThreadPoolThread (ThreadPool& pool_)
: Thread ("Pool"),
pool (pool_)
{
}
void run() override
{
while (! threadShouldExit())
{
if (! pool.runNextJob())
wait (500);
}
}
private:
ThreadPool& pool;
};
//==============================================================================
ThreadPool::ThreadPool (const int numThreads)
{
bassert (numThreads > 0); // not much point having a pool without any threads!
createThreads (numThreads);
}
ThreadPool::ThreadPool()
{
createThreads (SystemStats::getNumCpus());
}
ThreadPool::~ThreadPool()
{
removeAllJobs (true, 5000);
stopThreads();
}
void ThreadPool::createThreads (int numThreads)
{
for (int i = bmax (1, numThreads); --i >= 0;)
threads.add (new ThreadPoolThread (*this));
for (int i = threads.size(); --i >= 0;)
threads.getUnchecked(i)->startThread();
}
void ThreadPool::stopThreads()
{
for (int i = threads.size(); --i >= 0;)
threads.getUnchecked(i)->signalThreadShouldExit();
for (int i = threads.size(); --i >= 0;)
threads.getUnchecked(i)->stopThread (500);
}
void ThreadPool::addJob (ThreadPoolJob* const job, const bool deleteJobWhenFinished)
{
bassert (job != nullptr);
bassert (job->pool == nullptr);
if (job->pool == nullptr)
{
job->pool = this;
job->shouldStop = false;
job->isActive = false;
job->shouldBeDeleted = deleteJobWhenFinished;
{
const ScopedLock sl (lock);
jobs.add (job);
}
for (int i = threads.size(); --i >= 0;)
threads.getUnchecked(i)->notify();
}
}
int ThreadPool::getNumJobs() const
{
return jobs.size();
}
ThreadPoolJob* ThreadPool::getJob (const int index) const
{
const ScopedLock sl (lock);
return jobs [index];
}
bool ThreadPool::contains (const ThreadPoolJob* const job) const
{
const ScopedLock sl (lock);
return jobs.contains (const_cast <ThreadPoolJob*> (job));
}
bool ThreadPool::isJobRunning (const ThreadPoolJob* const job) const
{
const ScopedLock sl (lock);
return jobs.contains (const_cast <ThreadPoolJob*> (job)) && job->isActive;
}
bool ThreadPool::waitForJobToFinish (const ThreadPoolJob* const job,
const int timeOutMs) const
{
if (job != nullptr)
{
const uint32 start = Time::getMillisecondCounter();
while (contains (job))
{
if (timeOutMs >= 0 && Time::getMillisecondCounter() >= start + (uint32) timeOutMs)
return false;
jobFinishedSignal.wait (2);
}
}
return true;
}
bool ThreadPool::removeJob (ThreadPoolJob* const job,
const bool interruptIfRunning,
const int timeOutMs)
{
bool dontWait = true;
OwnedArray<ThreadPoolJob> deletionList;
if (job != nullptr)
{
const ScopedLock sl (lock);
if (jobs.contains (job))
{
if (job->isActive)
{
if (interruptIfRunning)
job->signalJobShouldExit();
dontWait = false;
}
else
{
jobs.removeFirstMatchingValue (job);
addToDeleteList (deletionList, job);
}
}
}
return dontWait || waitForJobToFinish (job, timeOutMs);
}
bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, const int timeOutMs,
ThreadPool::JobSelector* selectedJobsToRemove)
{
Array <ThreadPoolJob*> jobsToWaitFor;
{
OwnedArray<ThreadPoolJob> deletionList;
{
const ScopedLock sl (lock);
for (int i = jobs.size(); --i >= 0;)
{
ThreadPoolJob* const job = jobs.getUnchecked(i);
if (selectedJobsToRemove == nullptr || selectedJobsToRemove->isJobSuitable (job))
{
if (job->isActive)
{
jobsToWaitFor.add (job);
if (interruptRunningJobs)
job->signalJobShouldExit();
}
else
{
jobs.remove (i);
addToDeleteList (deletionList, job);
}
}
}
}
}
const uint32 start = Time::getMillisecondCounter();
for (;;)
{
for (int i = jobsToWaitFor.size(); --i >= 0;)
{
ThreadPoolJob* const job = jobsToWaitFor.getUnchecked (i);
if (! isJobRunning (job))
jobsToWaitFor.remove (i);
}
if (jobsToWaitFor.size() == 0)
break;
if (timeOutMs >= 0 && Time::getMillisecondCounter() >= start + (uint32) timeOutMs)
return false;
jobFinishedSignal.wait (20);
}
return true;
}
StringArray ThreadPool::getNamesOfAllJobs (const bool onlyReturnActiveJobs) const
{
StringArray s;
const ScopedLock sl (lock);
for (int i = 0; i < jobs.size(); ++i)
{
const ThreadPoolJob* const job = jobs.getUnchecked(i);
if (job->isActive || ! onlyReturnActiveJobs)
s.add (job->getJobName());
}
return s;
}
bool ThreadPool::setThreadPriorities (const int newPriority)
{
bool ok = true;
for (int i = threads.size(); --i >= 0;)
if (! threads.getUnchecked(i)->setPriority (newPriority))
ok = false;
return ok;
}
ThreadPoolJob* ThreadPool::pickNextJobToRun()
{
OwnedArray<ThreadPoolJob> deletionList;
{
const ScopedLock sl (lock);
for (int i = 0; i < jobs.size(); ++i)
{
ThreadPoolJob* job = jobs[i];
if (job != nullptr && ! job->isActive)
{
if (job->shouldStop)
{
jobs.remove (i);
addToDeleteList (deletionList, job);
--i;
continue;
}
job->isActive = true;
return job;
}
}
}
return nullptr;
}
bool ThreadPool::runNextJob()
{
ThreadPoolJob* const job = pickNextJobToRun();
if (job == nullptr)
return false;
ThreadPoolJob::JobStatus result = ThreadPoolJob::jobHasFinished;
BEAST_TRY
{
result = job->runJob();
}
BEAST_CATCH_ALL_ASSERT
OwnedArray<ThreadPoolJob> deletionList;
{
const ScopedLock sl (lock);
if (jobs.contains (job))
{
job->isActive = false;
if (result != ThreadPoolJob::jobNeedsRunningAgain || job->shouldStop)
{
jobs.removeFirstMatchingValue (job);
addToDeleteList (deletionList, job);
jobFinishedSignal.signal();
}
else
{
// move the job to the end of the queue if it wants another go
jobs.move (jobs.indexOf (job), -1);
}
}
}
return true;
}
void ThreadPool::addToDeleteList (OwnedArray<ThreadPoolJob>& deletionList, ThreadPoolJob* const job) const
{
job->shouldStop = true;
job->pool = nullptr;
if (job->shouldBeDeleted)
deletionList.add (job);
}

View File

@@ -1,309 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_THREADPOOL_BEASTHEADER
#define BEAST_THREADPOOL_BEASTHEADER
#include "beast_Thread.h"
#include "../text/beast_StringArray.h"
#include "../containers/beast_Array.h"
#include "../containers/beast_OwnedArray.h"
class ThreadPool;
class ThreadPoolThread;
//==============================================================================
/**
A task that is executed by a ThreadPool object.
A ThreadPool keeps a list of ThreadPoolJob objects which are executed by
its threads.
The runJob() method needs to be implemented to do the task, and if the code that
does the work takes a significant time to run, it must keep checking the shouldExit()
method to see if something is trying to interrupt the job. If shouldExit() returns
true, the runJob() method must return immediately.
@see ThreadPool, Thread
*/
class BEAST_API ThreadPoolJob : LeakChecked <ThreadPoolJob>, public Uncopyable
{
public:
//==============================================================================
/** Creates a thread pool job object.
After creating your job, add it to a thread pool with ThreadPool::addJob().
*/
explicit ThreadPoolJob (const String& name);
/** Destructor. */
virtual ~ThreadPoolJob();
//==============================================================================
/** Returns the name of this job.
@see setJobName
*/
String getJobName() const;
/** Changes the job's name.
@see getJobName
*/
void setJobName (const String& newName);
//==============================================================================
/** These are the values that can be returned by the runJob() method.
*/
enum JobStatus
{
jobHasFinished = 0, /**< indicates that the job has finished and can be
removed from the pool. */
jobNeedsRunningAgain /**< indicates that the job would like to be called
again when a thread is free. */
};
/** Peforms the actual work that this job needs to do.
Your subclass must implement this method, in which is does its work.
If the code in this method takes a significant time to run, it must repeatedly check
the shouldExit() method to see if something is trying to interrupt the job.
If shouldExit() ever returns true, the runJob() method must return immediately.
If this method returns jobHasFinished, then the job will be removed from the pool
immediately. If it returns jobNeedsRunningAgain, then the job will be left in the
pool and will get a chance to run again as soon as a thread is free.
@see shouldExit()
*/
virtual JobStatus runJob() = 0;
//==============================================================================
/** Returns true if this job is currently running its runJob() method. */
bool isRunning() const noexcept { return isActive; }
/** Returns true if something is trying to interrupt this job and make it stop.
Your runJob() method must call this whenever it gets a chance, and if it ever
returns true, the runJob() method must return immediately.
@see signalJobShouldExit()
*/
bool shouldExit() const noexcept { return shouldStop; }
/** Calling this will cause the shouldExit() method to return true, and the job
should (if it's been implemented correctly) stop as soon as possible.
@see shouldExit()
*/
void signalJobShouldExit();
//==============================================================================
private:
friend class ThreadPool;
friend class ThreadPoolThread;
String jobName;
ThreadPool* pool;
bool shouldStop, isActive, shouldBeDeleted;
};
//==============================================================================
/**
A set of threads that will run a list of jobs.
When a ThreadPoolJob object is added to the ThreadPool's list, its runJob() method
will be called by the next pooled thread that becomes free.
@see ThreadPoolJob, Thread
*/
class BEAST_API ThreadPool : LeakChecked <ThreadPool>, public Uncopyable
{
public:
//==============================================================================
/** Creates a thread pool.
Once you've created a pool, you can give it some jobs by calling addJob().
@param numberOfThreads the number of threads to run. These will be started
immediately, and will run until the pool is deleted.
*/
ThreadPool (int numberOfThreads);
/** Creates a thread pool with one thread per CPU core.
Once you've created a pool, you can give it some jobs by calling addJob().
If you want to specify the number of threads, use the other constructor; this
one creates a pool which has one thread for each CPU core.
@see SystemStats::getNumCpus()
*/
ThreadPool();
/** Destructor.
This will attempt to remove all the jobs before deleting, but if you want to
specify a timeout, you should call removeAllJobs() explicitly before deleting
the pool.
*/
~ThreadPool();
//==============================================================================
/** A callback class used when you need to select which ThreadPoolJob objects are suitable
for some kind of operation.
@see ThreadPool::removeAllJobs
*/
class BEAST_API JobSelector
{
public:
virtual ~JobSelector() {}
/** Should return true if the specified thread matches your criteria for whatever
operation that this object is being used for.
Any implementation of this method must be extremely fast and thread-safe!
*/
virtual bool isJobSuitable (ThreadPoolJob* job) = 0;
};
//==============================================================================
/** Adds a job to the queue.
Once a job has been added, then the next time a thread is free, it will run
the job's ThreadPoolJob::runJob() method. Depending on the return value of the
runJob() method, the pool will either remove the job from the pool or add it to
the back of the queue to be run again.
If deleteJobWhenFinished is true, then the job object will be owned and deleted by
the pool when not needed - if you do this, make sure that your object's destructor
is thread-safe.
If deleteJobWhenFinished is false, the pointer will be used but not deleted, and
the caller is responsible for making sure the object is not deleted before it has
been removed from the pool.
*/
void addJob (ThreadPoolJob* job,
bool deleteJobWhenFinished);
/** Tries to remove a job from the pool.
If the job isn't yet running, this will simply remove it. If it is running, it
will wait for it to finish.
If the timeout period expires before the job finishes running, then the job will be
left in the pool and this will return false. It returns true if the job is sucessfully
stopped and removed.
@param job the job to remove
@param interruptIfRunning if true, then if the job is currently busy, its
ThreadPoolJob::signalJobShouldExit() method will be called to try
to interrupt it. If false, then if the job will be allowed to run
until it stops normally (or the timeout expires)
@param timeOutMilliseconds the length of time this method should wait for the job to finish
before giving up and returning false
*/
bool removeJob (ThreadPoolJob* job,
bool interruptIfRunning,
int timeOutMilliseconds);
/** Tries to remove all jobs from the pool.
@param interruptRunningJobs if true, then all running jobs will have their ThreadPoolJob::signalJobShouldExit()
methods called to try to interrupt them
@param timeOutMilliseconds the length of time this method should wait for all the jobs to finish
before giving up and returning false
@param selectedJobsToRemove if this is non-zero, the JobSelector object is asked to decide which
jobs should be removed. If it is zero, all jobs are removed
@returns true if all jobs are successfully stopped and removed; false if the timeout period
expires while waiting for one or more jobs to stop
*/
bool removeAllJobs (bool interruptRunningJobs,
int timeOutMilliseconds,
JobSelector* selectedJobsToRemove = nullptr);
/** Returns the number of jobs currently running or queued.
*/
int getNumJobs() const;
/** Returns one of the jobs in the queue.
Note that this can be a very volatile list as jobs might be continuously getting shifted
around in the list, and this method may return 0 if the index is currently out-of-range.
*/
ThreadPoolJob* getJob (int index) const;
/** Returns true if the given job is currently queued or running.
@see isJobRunning()
*/
bool contains (const ThreadPoolJob* job) const;
/** Returns true if the given job is currently being run by a thread.
*/
bool isJobRunning (const ThreadPoolJob* job) const;
/** Waits until a job has finished running and has been removed from the pool.
This will wait until the job is no longer in the pool - i.e. until its
runJob() method returns ThreadPoolJob::jobHasFinished.
If the timeout period expires before the job finishes, this will return false;
it returns true if the job has finished successfully.
*/
bool waitForJobToFinish (const ThreadPoolJob* job,
int timeOutMilliseconds) const;
/** Returns a list of the names of all the jobs currently running or queued.
If onlyReturnActiveJobs is true, only the ones currently running are returned.
*/
StringArray getNamesOfAllJobs (bool onlyReturnActiveJobs) const;
/** Changes the priority of all the threads.
This will call Thread::setPriority() for each thread in the pool.
May return false if for some reason the priority can't be changed.
*/
bool setThreadPriorities (int newPriority);
private:
//==============================================================================
Array <ThreadPoolJob*> jobs;
class ThreadPoolThread;
friend class ThreadPoolThread;
friend class OwnedArray <ThreadPoolThread>;
OwnedArray <ThreadPoolThread> threads;
CriticalSection lock;
WaitableEvent jobFinishedSignal;
bool runNextJob();
ThreadPoolJob* pickNextJobToRun();
void addToDeleteList (OwnedArray<ThreadPoolJob>&, ThreadPoolJob*) const;
void createThreads (int numThreads);
void stopThreads();
// Note that this method has changed, and no longer has a parameter to indicate
// whether the jobs should be deleted - see the new method for details.
void removeAllJobs (bool, int, bool);
};
#endif // BEAST_THREADPOOL_BEASTHEADER

Some files were not shown because too many files have changed in this diff Show More