Compare commits

..

60 Commits

Author SHA1 Message Date
liukegang
19035c90e9 [bugfix] rm duplication process dimension 2019-06-11 21:15:29 +08:00
David Aurelio
19fd066507 Pass layout context for Event::LayoutPassStart
Summary: Adds the layout context pointer when publishing `Event::LayoutPassStart`.

Reviewed By: SidharthGuglani

Differential Revision: D15754425

fbshipit-source-id: 6295ae1ebec9eab72a79c43bc1cb0e05a6d7ae68
2019-06-11 01:41:22 -07:00
David Aurelio
204e849218 rm YogaEventListener
Reviewed By: SidharthGuglani

Differential Revision: D15742456

fbshipit-source-id: b90a221e177e936e141c582500dccf0ac38027c2
2019-06-11 01:41:22 -07:00
Aditya Sharat
8ff13c922a Back out "[litho] Adds check to unset a YogaNode's parent during reconciliation."
Summary: Removes `unsetOwner` from Yoga. This was temporarily for patching a crash.

Reviewed By: colriot

Differential Revision: D15737613

fbshipit-source-id: 8ab93ecf7ffb913df6207fe5db47a8cc93eded2c
2019-06-10 06:57:05 -07:00
Sidharth Guglani
af219f8836 add node layout event and pass it java layer
Summary: Listen to NodeLayout event and passes this event callback to java layer along with the information whether layout or measure was done in this pass

Reviewed By: davidaurelio

Differential Revision: D15696021

fbshipit-source-id: 8c5ca69330a9baca26b77052d4965cc67fe97c75
2019-06-10 01:51:53 -07:00
Aditya Sharat
e33123f955 Adds check to unset a YogaNode's parent during reconciliation.
Summary: Adds check to unset a YogaNode's parent during reconciliation.

Reviewed By: davidaurelio

Differential Revision: D15714899

fbshipit-source-id: 6e2c2a28106574d062fec722c9a051acea87d0b6
2019-06-07 09:28:24 -07:00
Sidharth Guglani
755fa07b39 add node measure event and passing the callback to java layer
Summary: Adds measure event and its listener initial code structure

Reviewed By: davidaurelio

Differential Revision: D15600738

fbshipit-source-id: d15764e0b64edb170fcb15e0912ecce5f7e53595
2019-06-06 21:03:24 -07:00
Sidharth Guglani
2701d80078 passing layout context and getting local reference from it
Summary: We are passing layout context from yoga as event data for Layout Pass End event and it is being then used to get the local reference of node so that we can pass it as method parameter to java layer

Reviewed By: davidaurelio

Differential Revision: D15619640

fbshipit-source-id: 5f6c29d9e6acb73a8d87f8e0cb1577d35a271aeb
2019-06-06 21:03:24 -07:00
Sidharth Guglani
c393ed1381 moved PtrJNode map to YGJtypes.h and passing layout context as data in LayoutPassEnd Event
Summary: Move PtrJNodeMap to header file so that it can be accessed in events subscribers outside yoga

Reviewed By: davidaurelio

Differential Revision: D15619629

fbshipit-source-id: 1bf213efd38ec7bcac6a38070f21fa837c5f17da
2019-06-06 21:03:23 -07:00
Rain ⁣
a4bdd9cd9b standardize C-like MIT copyright headers throughout fbsource
Summary:
`/*` is the standard throughout open source code. For example, Firefox uses single /*: https://hg.mozilla.org/mozilla-central/file/21d22b2f541258d3d1cf96c7ba5ad73e96e616b5/gfx/ipc/CompositorWidgetVsyncObserver.cpp#l3

In addition, Rust considers `/**` to be a doc comment (similar to Javadoc) and having such a comment at the beginning of the file causes `rustc` to barf.

Note that some JavaScript tooling requires `/**`. This is OK since JavaScript files were not covered by the linter in the first place, but it would be good to have that tooling fixed too.

Reviewed By: zertosh

Differential Revision: D15640366

fbshipit-source-id: b4ed4599071516364d6109720750d6a43304c089
2019-06-06 19:44:16 -07:00
Joshua Gross
4a4325afb6 Revert D15602627: [yoga] moved PtrJNode map to YGJtypes.h and passing layout context as data in LayoutPassEnd Event
Differential Revision:
D15602627

Original commit changeset: bb5bd5bbf8dc

fbshipit-source-id: 5ae08826eb706c3794c36738cb9625f82b58641e
2019-06-03 19:57:53 -07:00
Joshua Gross
586eb6102a Revert D15602923: [yoga] passing layout context and getting local reference from it
Differential Revision:
D15602923

Original commit changeset: 54b25956af09

fbshipit-source-id: 8ce26a7f00d76bd5ade18f32ad14d943118a6f31
2019-06-03 19:57:53 -07:00
Sidharth Guglani
b1e6793460 passing layout context and getting local reference from it
Summary: We are passing layout context from yoga as event data for Layout Pass End event and it is being then used to get the local reference of node so that we can pass it as method parameter to java layer

Reviewed By: davidaurelio

Differential Revision: D15602923

fbshipit-source-id: 54b25956af098700cea25c4f7f8ffe0b9117432c
2019-06-03 16:01:51 -07:00
Sidharth Guglani
8b17459254 moved PtrJNode map to YGJtypes.h and passing layout context as data in LayoutPassEnd Event
Summary: Move PtrJNodeMap to header file so that it can be accessed in events subscribers outside yoga

Reviewed By: davidaurelio

Differential Revision: D15602627

fbshipit-source-id: bb5bd5bbf8dcb279f5f87a4fd7287909d4e895d8
2019-06-03 16:01:50 -07:00
David Aurelio
195c166efe Back out "[Yoga] Remove comparison to YGUndefined *and* 0.0f"
Summary: Original commit changeset: 13c8f24e1bc8

Reviewed By: fabiomassimo

Differential Revision: D15583502

fbshipit-source-id: efc6175f6c4925a383fea723195c073f49e2eff1
2019-05-31 15:56:50 -07:00
David Aurelio
0908d3a173 Data structure for exclusive writing
Summary:
Adds a data structure that holds a series of values that can be *borrowed* for exclusive writing.
That means, that only a single consumer can write to any value owned by the data structure.

In addition, the data structure exposes read access via iteration over all contained values.

A typical use case would be a counter with thread-local values that are accumulated by readers in other parts of a programm. The design carefully avoids the use of atomics or locks for reading and writing. This approach avoids cache flushes and bus sync between cores.

Borrowing and returning a value go through a central lock to guarantee the consistency of the underlying data structure.

Values are allocated in a `std::forward_list`, which typically should avoid two values in the same cache line -- in that case, writing to one value would still cause cache flushing on other cores. An alternative approach would be to allocate values continuously on cache line boundaries (with padding between them). We can still change the code if the current approach turns out to be too naive (non-deterministic).

Reviewed By: SidharthGuglani

Differential Revision: D15535018

fbshipit-source-id: 212ac88bba9682a4c9d4326b46de0ee2fb5d9a7e
2019-05-31 09:43:43 -07:00
David Aurelio
f304990656 Use atomic list for event subscribers
Summary:
Replace the *copy on write* vector with an atomic pointer to a linked list.

This allows to publish without locking a mutex, at the cost of the slower traversal of a linked list (a vector has better locality).

At the moment, the typical use case is to have one subscriber, meaning that the afforementioned slower traversal is not a problem.

Adding subscribers is implemented as atomic *compare and swap.*

Reviewed By: SidharthGuglani

Differential Revision: D15546964

fbshipit-source-id: 41bfa41f1ac6be5c9b6bf4288ea3271ee995877e
2019-05-31 01:26:42 -07:00
David Aurelio
cea3865c74 Deprecate YGNode::setConfig
Summary:
We want to phase out usage of config pointers on nodes. Setting configs is no longer needed, as a config is unly used during construction.

Here we deprecate the setter, as it is no longer working as it used to (e.g. changing `useWebDefaults` after a node is constructed).

Reviewed By: SidharthGuglani

Differential Revision: D15416474

fbshipit-source-id: a2cc06cad0c5148cecce056ece5f141b3defe9a9
2019-05-29 07:50:11 -07:00
David Aurelio
b74c0d4766 Remove comparison to YGUndefined *and* 0.0f
Summary: Removes a check introduced in D6969537, comparing `totalFlexGrowFactors` and `resolveFlexGrow` to both `0.0` *and* undefined.

Reviewed By: SidharthGuglani

Differential Revision: D15431425

fbshipit-source-id: 13c8f24e1bc8c49496097a6aa78e20ee5d3964a7
2019-05-22 09:44:36 -07:00
David Aurelio
54e863cef2 Remove YGNode::setAndPropogateUseLegacyFlag
Summary:
`YGNode::setAndPropogateUseLegacyFlag` was only used for debugging purposes.
Here, we replace it with a free function in `Yoga.cpp`.

Now that we have events, the diffing functionality should go into a separate debugging package and be implemented in terms of an event listener. Let's do that as soon as we can support multiple listeners.

Reviewed By: SidharthGuglani

Differential Revision: D15316863

fbshipit-source-id: db929eba7c2de8aa1550e362dd2c175929c0070e
2019-05-21 06:06:37 -07:00
David Aurelio
1938792517 YGNode: Field for web defaults
Summary:
In order to remove the config pointer from nodes, we have to keep track of whether the node is using web defaults.
This information fits into one bit that we can place in padding (i.e. no extra memory needed).

This allows us to get rid of config usage withing `YGNode` with some exceptions:

- `iterChildrenAfterCloningIfNeeded` -- this function will simply receive the configuration, or the cloning callback.
- `setAndPropogateUseLegacyFlag` -- will be removed in D15316863
- in `YGNode::reset` -- will go away utomatically once we remove the config pointer

Reviewed By: SidharthGuglani

Differential Revision: D15391536

fbshipit-source-id: 0fa0d0805c6862bd741fe4a7d9b637ed534f56a4
2019-05-20 10:51:38 -07:00
Sidharth Guglani
aa71dbb5bd mutex lock while accessing event subscribers vector for thread safety
Summary: Using Mutex lock_guard mechanism when writing to subscribers and when accessing them in publish to make a copy

Reviewed By: davidaurelio

Differential Revision: D15391679

fbshipit-source-id: 16713ff28ce1762a5ca4c48c152897a92417e80b
2019-05-19 23:34:41 -07:00
David Aurelio
8dc46c0a87 YGNode: one byte of private storage
Summary:
Adds one byte of private storage to `YGNode`, intended to be used by Yoga itself.

This is in previously unused alignment space, and won’t cause more memory to be allocated.

Reviewed By: SidharthGuglani

Differential Revision: D15296732

fbshipit-source-id: 3caf0a3cd506e4e324e51c31869c69be5781d476
2019-05-16 11:47:30 -07:00
David Aurelio
1180afed9c Fix style property bits
Summary: Style bits had overlap, because `dimensionBit` was set with an incorrect increment.

Reviewed By: SidharthGuglani

Differential Revision: D15335134

fbshipit-source-id: 370e1a73547d76b0e26bc6ab67acb96d33ddf180
2019-05-16 11:47:30 -07:00
Sidharth Guglani
1562bce9b4 use shared_ptr for subscribers vector in event system
Summary:
using shared_ptr for vector of subscribers
Further changes in commit stack support the mutiple subscribers in event system

Reviewed By: davidaurelio

Differential Revision: D15352512

fbshipit-source-id: fac7f4268abf9ca4277734aca2f21cd711eb7d6e
2019-05-15 09:01:06 -07:00
Sidharth Guglani
a9514513a7 use vector for subscribers in event system
Summary:
Replaced global event subscriber with a vector of subscriber functions
Further changes in commit stack support the mutiple subscribers in event system

Reviewed By: davidaurelio

Differential Revision: D15352451

fbshipit-source-id: 7ca6f0943735bf1f76a906c23e15e14ae3c5f42c
2019-05-15 09:01:04 -07:00
Sidharth Guglani
cf809b8e8b added listener in flipper plugin for yoga
Summary:
Adds YogaEventListener interface and it's implementation which will be used in flipper for events coming from Yoga
After this diff , we will start getting layout calculate events in flipper listener

Reviewed By: davidaurelio

Differential Revision: D15316928

fbshipit-source-id: da3a53374a52386037b553d460038d988b0162c2
2019-05-15 01:18:11 -07:00
Yadong Wen
d7ff5c0689 Remove c++1y compiler flag
Reviewed By: meyering

Differential Revision: D15326600

fbshipit-source-id: 837f454ccf27299bc9360174bf54e48e4209bb52
2019-05-14 13:48:02 -07:00
David Aurelio
e3156279fc Travis: Fix C++ compilation
Summary:
@public

Removes the usage of C++14 features, and enforces C++11 via compiler flags.

Reviewed By: SidharthGuglani

Differential Revision: D15334938

fbshipit-source-id: 011764b5f226fef6a35e0c7c1dd170a39ae2261e
2019-05-14 07:45:31 -07:00
gengjiawen
0ce42d83e0 add missing gradle script for windows
Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/885

Differential Revision: D15334309

Pulled By: davidaurelio

fbshipit-source-id: c594c0216a967c776606443a50f14e81da228d64
2019-05-14 06:24:18 -07:00
Shawn Presser
afc1108659 Fix cmake build / update CMakeLists.txt to use C++11 (#887)
Summary:
On MacOS, the following steps result in build errors:

```
mkdir build
cd build
cmake ..
make
```

The problem is that yogacore uses C++11 features (`constexpr`) but C++11 isn't specified in CMakeLists.txt.

This PR solves the poblem by adding the following code to the bottom of CMakeLists.txt:

```
set_target_properties(yogacore PROPERTIES CXX_STANDARD 11)
```

This solution was derived from https://stackoverflow.com/questions/45688522/how-to-enable-c17-in-cmake
Pull Request resolved: https://github.com/facebook/yoga/pull/887

Differential Revision: D15334282

Pulled By: davidaurelio

fbshipit-source-id: a599d8a8f555f7f9cd8dc333e12dc2387d5b2d7a
2019-05-14 05:28:19 -07:00
David Aurelio
a15bf6e701 Publish events for layout pass
Summary:
Adds `LayoutPassStart` and `LayoutPassEnd` events.

The existing `NodeLayout` event in isolation is not as useful as it could be. Having events that mark start and end of a layout pass are a useful addition.

Differential Revision: D15305467

fbshipit-source-id: 14af6f65e698fb1e3112eb2ffd87a74d31df4840
2019-05-10 19:05:07 -07:00
Sidharth Guglani
74fc37efc8 move event files to yoga/events folder
Summary: Moved events files to yoga/events for better code structure

Reviewed By: davidaurelio

Differential Revision: D15198566

fbshipit-source-id: 74d451011841d59fae5a1c637f9c33a7d2d1f87e
2019-05-09 07:46:10 -07:00
David Aurelio
5824dbda66 Publish event when visiting nodes during layout
Summary:
@public

Publish an event when visiting nodes during layouts.

Reviewed By: SidharthGuglani

Differential Revision: D15206965

fbshipit-source-id: c201f084b1d4186bc64560b8033be965f2549236
2019-05-09 04:31:25 -07:00
David Aurelio
e96a09e5ff **breaking:** remove YGNodeGetInstanceCount
Summary:
@public

`YGNodeGetInstanceCount` was only ever meant for tests, and caused data races in multi-threaded environments.

It was completely replaced with event-based counting for tests.

Here we remove public API around the counter, and the counter itself.

Reviewed By: SidharthGuglani

Differential Revision: D15174857

fbshipit-source-id: 228e85da565bac9e8485121e956a2e41910b11c8
2019-05-09 04:31:24 -07:00
David Aurelio
9e20dfeea1 Switch tests to test utility for counting nodes
Summary:
@public
replaces the global node counter with the event-based one for all tests.

Reviewed By: SidharthGuglani

Differential Revision: D15174856

fbshipit-source-id: f4401d502bdbaf3b6e4632a4d985aac260cb35a8
2019-05-09 04:31:24 -07:00
David Aurelio
6e04631862 Add test utilities for C++ and Java
Summary:
@public

Test utility on top of the new event system that maintains a counter of instantiated nodes. Meant to replace the global node counter.

Reviewed By: SidharthGuglani

Differential Revision: D15174855

fbshipit-source-id: 6998472f95a09b8da652257a26596164bdcf43d6
2019-05-09 04:31:23 -07:00
David Aurelio
88b23ebb3d Publish events for node allocation and deallocation
Summary:
@public

Publish two events, `NodeAllocation` and `NodeDeallocation`, in the same places where the global node counter is changed.

Reviewed By: SidharthGuglani

Differential Revision: D15174858

fbshipit-source-id: 6e4e9add88513b9e987189ca5035d76da2a1de55
2019-05-09 04:31:23 -07:00
David Aurelio
018916403e Reduce measure cache size to 8
Summary:
@public

Reduces measure cache size to a number that is enough for 95% of nodes, according to our (FB-internal) measurements.

Node size: 776b -> 584b

Reviewed By: SidharthGuglani

Differential Revision: D15183567

fbshipit-source-id: 9ae8cc78074271a015e7618b931ba0356de87a0c
2019-05-09 03:24:31 -07:00
Adrian Zgorzalek
af38fd31f8 Upgrade prettier to 1.17.0
Summary:
Run `js1 upgrade prettier 1.17.0` and `xplat/js/scripts/update-oss-yarn-lockfile.sh` and `hg revert -r .^ xplat/js/rome`

allow-large-files

Reviewed By: zackargyle, pvdz

Differential Revision: D15164375

fbshipit-source-id: 2fe68733dfa93ea64a67d170ba2f80c5af086917
2019-05-07 12:39:46 -07:00
David Aurelio
1e0ebdae2f Remove API to constrain measure cache size
Summary: We conducted an experiment with different measure cache sizes. This has now been deallocatedi (D15183473). Remove the necessary APIs.

Reviewed By: SidharthGuglani

Differential Revision: D15183486

fbshipit-source-id: a38fa5a3ab0321c2521265f7d1cd6b495efd76cf
2019-05-03 05:54:40 -07:00
David Aurelio
1adbafe950 Fix YGConfig constructors
Summary:
@public

`YGConfig::YGConfig(YGConfig*)` was not initializing the same fields as the default constructors.

Here, we make the default constructor delegate to the more specialized one to remove duplication.

Reviewed By: SidharthGuglani

Differential Revision: D15164599

fbshipit-source-id: 27247709091b7664386057d09ac67d481877871f
2019-05-03 05:01:32 -07:00
David Aurelio
e51ca95713 Add foundations for event system
Summary:
@public

We want to enable tooling, instrumentation, and statistics within Yoga without coupling these functionalities to our core code.

This commit introduces the foundations of a simple, global event system.
For the time being, we will only support a single subscriber. Should we require more than one, we can add support for it later.

Reviewed By: SidharthGuglani

Differential Revision: D15153678

fbshipit-source-id: 7d96f4c8def646a6a1b3908f946e7f81a6dba9c3
2019-05-01 17:08:02 -07:00
David Aurelio
a803421739 YGStyle: Make getters/setters template args of BitfieldRef
Summary:
@public

Makes bitfield getters/setters part of the bitfield ref template.
Since we introduced the tracking bit as template parameter in D14933022, every bitfield ref is an individual class anyway, and having function pointers doesn’t potentially lead to less code generation anyway.

Furthermore, this change can (in the absence of tracking bits) avoid less specialized templates dealing with refs, and to dynamic dispatch as a consequence.

Reviewed By: SidharthGuglani

Differential Revision: D15085495

fbshipit-source-id: 0dd70fa05e9d43a29e38a619cddb642c9ca3f7ab
2019-05-01 06:52:55 -07:00
David Aurelio
011c1964a0 Track which style properties have been set on YGStyle
Summary:
@public

In order to optimise property storage, we have to know how style properties are used in our apps.
Here, we add a bitmask that allows us to track which properties are set explicitely, and use that for our analysis.

Reviewed By: SidharthGuglani

Differential Revision: D14933022

fbshipit-source-id: 1ab8af562b14baba1d02057e527aa36d5c9a7823
2019-05-01 06:52:55 -07:00
David Aurelio
05d205cf89 Deduplicate updateStyle overloads
Summary:
@public

The extra overload of `updateStyle` introduced in D15078961 can also handle `BitfieldRef`.
That means that we can remove the more specific implementation previously introduced for `BitfieldRef`

Reviewed By: SidharthGuglani

Differential Revision: D15081069

fbshipit-source-id: 98f1f3478627974c5273c85d268ca07350f303d7
2019-05-01 06:52:54 -07:00
David Aurelio
0a4f7bd558 YGStyle: mutable accessors return Ref instances
Summary:
@public

Change style property accessors to return `Ref` instances instead of references to `CompactValue`.

This will allow to track assignments to properties later on, e.g. for instrumentation or dynamic property storage.

Reviewed By: SidharthGuglani

Differential Revision: D15078961

fbshipit-source-id: 259f05f7d30f093c04bf333c5bd4fb3601b8e933
2019-05-01 06:52:54 -07:00
David Aurelio
cea862a6bf Expose the value type used by YGStyle as ValueRepr
Summary:
@public

Adds `YGStyle::ValueRepr` to make code depending on the actual type easier to write.

So far, we have treated `yoga::detail::CompactValue` as an implementation detail, and that’s what it’s supposed to stay.

React Native Fabric has one value conversion overload that depends on that type, though, and used `decltype(YGStyle{}.margin()[0])` until now.
That’s problematic for two reasons:

- we want to constrain the parameter of `operator[](...)` to enum types, making the `0` unsuitable
- we want to return the non-const overload of the operator to return a custom `Ref` type, which is not the type needed by Fabric.

Making the storage type explicit allows to write more forward-compatible code.

Reviewed By: SidharthGuglani

Differential Revision: D15078960

fbshipit-source-id: 932c27ef2f2cdc6ce965b79894268170f0ccdce5
2019-04-29 09:23:18 -07:00
David Aurelio
cc02a20c9e More constness
Summary:
@public

Some `YGNode*` passed as `const YGNode*`, some const refs to sub-objects introduced.
This helps selecting the desired methods in more places, i.e. `const` overloads of accessors on `YGStyle`.

Reviewed By: SidharthGuglani

Differential Revision: D15078963

fbshipit-source-id: 5013721d6edcc68f42f4504f5c331da647a294bd
2019-04-29 09:23:17 -07:00
David Aurelio
98fda9c587 YGFloatOptional: Move binary operators to free functions
Summary:
@public

Having binary operators as member functions has disadvantages:

- the left hand side cannot be converted to `YGFloatOptional` implicitly (which we need for `YGStyle` refs)
- Operators are not necessarily commutative.

By moving these operators into free functions, and adding overloads for both variants if one operand is `float`, we get these properties.

Reviewed By: SidharthGuglani

Differential Revision: D15078962

fbshipit-source-id: 2e228a2ef90a8083c91788caa9eedfd4d140677f
2019-04-29 09:23:16 -07:00
David Aurelio
2eed95f3e4 YGNodeToString: take const ref to node style
Summary:
@public

Takes a const reference to the style of the printed node once, instead of using repeated calls to `node->getStyle()`.
Makes the code a bit shorter, and ensures that we are operating on `const YGStyle&`, which helps selecting the correct methods further up the stack.

Reviewed By: SidharthGuglani

Differential Revision: D14999094

fbshipit-source-id: 814f06b7e3179ac8cfb43d79fbec48ee4115d6e3
2019-04-26 02:15:06 -07:00
David Aurelio
e5d3baca81 Introduce YGNodeConstRef
Summary:
@public

Introduces `YGNodeConstRef` as `const YGNode*`, i.e. a pointer to a constant `YGNode`.
We also use it for all style getters, which will avoid casts to `const YGNode*` in diffs up the stack.

We should use this pointer type for all functions that do not modify the underlying node.

Reviewed By: SidharthGuglani

Differential Revision: D14999095

fbshipit-source-id: 61cc53bb35e787a12ae12e70438d84c0a4983752
2019-04-23 10:10:24 -07:00
David Aurelio
dee93017f7 YGStyle: wrap all fields into accessors
Summary:
@public

In order to encapsulate property access on `YGStyle`, as a first measure we wrap all fields with accessors.

This will e.g. enable dynamic property storage and instrumentation in the future.

All accessors have a `const` version that allows direct access via `const&`. For mutation, bit fields are wrapped with a custom reference object.

This style allows for the least amount of changes in client code. Property access simply needs appended parens, eg `style.direction` becomes `style.direction`.

Reviewed By: shergin

Differential Revision: D14999096

fbshipit-source-id: fbf29f7ddab520513d4618f5e70094c4f6330b30
2019-04-23 08:17:18 -07:00
David Aurelio
e167642672 Yoga.h: clean up const / extern
Summary:
@public

Remove unnecessary `const` and `extern` specifiers from `Yoga.h`.

- Function declarations are `extern` by default
- The removed `const` specifiers for pass-by-valye parameters are only meaningful for the *definition* of functions, not for the declaration.
In this specific case, I found `const YGNodeRef` particularly confusing, as it is a `typedef` for a pointer type. `const` does not refer to the pointed-to object, but to the parameter itself, i.e. `const YGNodeRef` is `YGNode * const`, and not `const YGNode *`.

Reviewed By: SidharthGuglani

Differential Revision: D14999097

fbshipit-source-id: 8350870cb67f4a34722f796c4f4a2fc7dde41b99
2019-04-23 08:17:16 -07:00
David Aurelio
e9bb1efb03 Code formatting: allow short inline methods on one line
Summary:
@public

This allows short methods defined in class declarations to occupy a single line.
The change makes class declarations more readable.

Reviewed By: SidharthGuglani

Differential Revision: D14950012

fbshipit-source-id: 1321949475184181c6cceb86613f730e430763e2
2019-04-16 07:12:58 -07:00
David Aurelio
3f7d03b443 Define all style getters/setters explicitely
Summary:
@public

For better grepping, we define all `YGNodeStyle...` accessors explicitely. This also replaces all macros with a set of templates that can easily be updated when we switch to style accessors on `YGNode`.

Transitioning to a consistent set of templates also allowed to end up with a single *needs update* / *do update* / *mark dirty* block.

The new template code also takes full advantage of the properties of `YGOptional` (constructor call with *not a number* creates an empty optional) and `detail::CompactValue` (conversions of *auto* and *undefined* are always well-formed) to get rid of some additional code:

Removed `NAN` check:
```
 _YGNodeStyleSetFlex:
 	pushq	%rbp
 	movq	%rsp, %rbp
 	movss	0x34(%rdi), %xmm1
 	ucomiss	%xmm0, %xmm1
 	jne	0x____
 	jnp	0x____
 	ucomiss	%xmm0, %xmm0
 	jnp	0x____
 	ucomiss	%xmm1, %xmm1
 	jnp	0x____
 	popq	%rbp
 	retq
-	ucomiss	%xmm0, %xmm0
-	movd	%xmm0, %eax
-	movl	$0x7fc00000, %ecx
-	cmovnpl	%eax, %ecx
-	movl	%ecx, 0x34(%rdi)
+	movss	%xmm0, 0x34(%rdi)
 	popq	%rbp
 	jmp	0x____
-	nopw	%cs:(%rax,%rax)
-	nop
+	nopw	(%rax,%rax)
```

Removed well-formedness check:
```
 _YGNodeStyleGetPosition:
 	pushq	%rbp
 	movq	%rsp, %rbp
 	movl	%esi, %eax
 	movl	0x68(%rdi,%rax,4), %ecx
+	xorl	%eax, %eax
 	movq	(%rip), %rcx
 	movl	(%rcx), %eax
 	movl	0x4(%rcx), %ecx
-	movq	%rcx, %rdx
-	shlq	$0x20, %rdx
+	shlq	$0x20, %rcx
 	movl	%eax, %eax
-	orq	%rdx, %rax
-	cmpl	$0x3, %ecx
-	je	0x____
-	testl	%ecx, %ecx
-	jne	0x____
-	movl	$0x7fc00000, %ecx
-	jmp	0x____
-	movq	%rax, %rcx
-	movabsq	$-0x100000000, %rdx
-	andq	%rax, %rdx
-	movl	%ecx, %eax
-	orq	%rdx, %rax
+	orq	%rcx, %rax
 	popq	%rbp
 	retq
 	nopw	(%rax,%rax)
```

Reviewed By: SidharthGuglani

Differential Revision: D14911973

fbshipit-source-id: db6eef65f8fdaf70875f7fe8799919ca88bd50ee
2019-04-15 10:51:44 -07:00
Sidharth Guglani
ffce716557 Use only 4 edges for margin, padding, border in YGLayout
Summary:
We were using four edges for margin, padding and border. This diff changes the array size in YGLayout for margin, padding, border to reduce YGNode size and corresponding changes while we are setting values in YGLayout.
Reduces the YGNode size by 24 bytes

Reviewed By: davidaurelio

Differential Revision: D14892666

fbshipit-source-id: 94013d5183ee869901267c4c9941fd94fa05d848
2019-04-15 05:41:59 -07:00
Andres Suarez
fcfb19e9cf Enable black for xplat/yoga
Summary:
This directory was excluded from Black formatting in D14888843 when Black
was turned on for all of `xplat/`. Since there aren't a lot of `.py` files in
this directory, the opt-out is being removed, and the outstanding issues fixed.

Reviewed By: d16r

Differential Revision: D14889104

fbshipit-source-id: 440077c1efcb4c653151bca1da5636212978add5
2019-04-11 05:24:34 -07:00
David Aurelio
c5f105a7b6 JNI: set language level to C++11
Summary:
@public

compiler flags were pushed to C++14, but we don’t currently have any code that requires it. Setting to `-std=c++11` in order to fix the OSS build.

Reviewed By: SidharthGuglani

Differential Revision: D14833737

fbshipit-source-id: df2cd7da8c7124e89863c90d7b77bcf86c495618
2019-04-09 03:12:32 -07:00
David Aurelio
b062d23947 Add -SNAPSHOT to gradle version
Summary:
@public

needed for snapshot releases off of master.

Reviewed By: colriot

Differential Revision: D14833415

fbshipit-source-id: f3b1fb1c41318a9b8f634cd16d37d5e2d050398f
2019-04-08 10:57:18 -07:00
129 changed files with 2887 additions and 1499 deletions

View File

@@ -9,7 +9,7 @@ AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None

17
BUCK
View File

@@ -9,21 +9,17 @@ GMOCK_OVERRIDE_FLAGS = [
"-Wno-inconsistent-missing-override",
]
COMPILER_FLAGS = LIBRARY_COMPILER_FLAGS + [
"-std=c++1y",
]
TEST_COMPILER_FLAGS = BASE_COMPILER_FLAGS + GMOCK_OVERRIDE_FLAGS + [
"-std=c++1y",
"-DDEBUG",
"-DYG_ENABLE_EVENTS",
]
yoga_cxx_library(
name = "yoga",
srcs = glob(["yoga/*.cpp"]),
srcs = glob(["yoga/**/*.cpp"]),
header_namespace = "",
exported_headers = subdir_glob([("", "yoga/*.h")]),
compiler_flags = COMPILER_FLAGS,
exported_headers = subdir_glob([("", "yoga/**/*.h")]),
compiler_flags = LIBRARY_COMPILER_FLAGS,
soname = "libyogacore.$(ext)",
tests = [":YogaTests"],
visibility = ["PUBLIC"],
@@ -34,9 +30,9 @@ yoga_cxx_library(
yoga_cxx_library(
name = "yogaForDebug",
srcs = glob(["yoga/*.cpp"]),
srcs = glob(["yoga/**/*.cpp"]),
header_namespace = "",
exported_headers = subdir_glob([("", "yoga/*.h")]),
exported_headers = subdir_glob([("", "yoga/**/*.h")]),
compiler_flags = TEST_COMPILER_FLAGS,
soname = "libyogacore.$(ext)",
tests = [":YogaTests"],
@@ -55,6 +51,7 @@ yoga_cxx_test(
visibility = ["PUBLIC"],
deps = [
":yogaForDebug",
yoga_dep("testutil:testutil"),
GTEST_TARGET,
],
)

View File

@@ -13,3 +13,4 @@ file(GLOB yogacore_SRC yoga/*.cpp)
add_library(yogacore STATIC ${yogacore_SRC})
target_link_libraries(yogacore android log)
set_target_properties(yogacore PROPERTIES CXX_STANDARD 11)

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -12,7 +12,7 @@ load(
"yoga_dep",
)
COMPILER_FLAGS = BASE_COMPILER_FLAGS + ["-std=c++14"]
COMPILER_FLAGS = BASE_COMPILER_FLAGS + ["-std=c++11"]
fb_native.csharp_library(
name = "yogalibnet46",

View File

@@ -43,9 +43,6 @@ namespace Facebook.Yoga
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGConfigFree(IntPtr node);
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int YGNodeGetInstanceCount();
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int YGConfigGetInstanceCount();

View File

@@ -673,10 +673,5 @@ namespace Facebook.Yoga
return _children != null ? ((IEnumerable<YogaNode>)_children).GetEnumerator() :
System.Linq.Enumerable.Empty<YogaNode>().GetEnumerator();
}
public static int GetInstanceCount()
{
return Native.YGNodeGetInstanceCount();
}
}
}

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,3 +1,9 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Yoga.rc

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

286
enums.py
View File

@@ -3,107 +3,57 @@
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import, division, print_function, unicode_literals
import os
ENUMS = {
'Direction': [
'Inherit',
'LTR',
'RTL',
"Direction": ["Inherit", "LTR", "RTL"],
"Unit": ["Undefined", "Point", "Percent", "Auto"],
"FlexDirection": ["Column", "ColumnReverse", "Row", "RowReverse"],
"Justify": [
"FlexStart",
"Center",
"FlexEnd",
"SpaceBetween",
"SpaceAround",
"SpaceEvenly",
],
'Unit': [
'Undefined',
'Point',
'Percent',
'Auto',
"Overflow": ["Visible", "Hidden", "Scroll"],
"Align": [
"Auto",
"FlexStart",
"Center",
"FlexEnd",
"Stretch",
"Baseline",
"SpaceBetween",
"SpaceAround",
],
'FlexDirection': [
'Column',
'ColumnReverse',
'Row',
'RowReverse',
"PositionType": ["Relative", "Absolute"],
"Display": ["Flex", "None"],
"Wrap": ["NoWrap", "Wrap", "WrapReverse"],
"MeasureMode": ["Undefined", "Exactly", "AtMost"],
"Dimension": ["Width", "Height"],
"Edge": [
"Left",
"Top",
"Right",
"Bottom",
"Start",
"End",
"Horizontal",
"Vertical",
"All",
],
'Justify': [
'FlexStart',
'Center',
'FlexEnd',
'SpaceBetween',
'SpaceAround',
'SpaceEvenly',
],
'Overflow': [
'Visible',
'Hidden',
'Scroll',
],
'Align': [
'Auto',
'FlexStart',
'Center',
'FlexEnd',
'Stretch',
'Baseline',
'SpaceBetween',
'SpaceAround',
],
'PositionType': [
'Relative',
'Absolute',
],
'Display': [
'Flex',
'None',
],
'Wrap': [
'NoWrap',
'Wrap',
'WrapReverse',
],
'MeasureMode': [
'Undefined',
'Exactly',
'AtMost',
],
'Dimension': [
'Width',
'Height',
],
'Edge': [
'Left',
'Top',
'Right',
'Bottom',
'Start',
'End',
'Horizontal',
'Vertical',
'All',
],
'NodeType': [
'Default',
'Text',
],
'LogLevel': [
'Error',
'Warn',
'Info',
'Debug',
'Verbose',
'Fatal',
],
'ExperimentalFeature': [
"NodeType": ["Default", "Text"],
"LogLevel": ["Error", "Warn", "Info", "Debug", "Verbose", "Fatal"],
"ExperimentalFeature": [
# Mimic web flex-basis behavior.
'WebFlexBasis',
],
'PrintOptions': [
('Layout', 1),
('Style', 2),
('Children', 4),
"WebFlexBasis"
],
"PrintOptions": [("Layout", 1), ("Style", 2), ("Children", 4)],
}
LICENSE = """/**
@@ -115,23 +65,25 @@ LICENSE = """/**
"""
def to_java_upper(symbol):
symbol = str(symbol)
out = ''
out = ""
for i in range(0, len(symbol)):
c = symbol[i]
if str.istitle(c) and i is not 0 and not str.istitle(symbol[i - 1]):
out += '_'
out += "_"
out += c.upper()
return out
def to_log_lower(symbol):
symbol = str(symbol)
out = ''
out = ""
for i in range(0, len(symbol)):
c = symbol[i]
if str.istitle(c) and i is not 0 and not str.istitle(symbol[i - 1]):
out += '-'
out += "-"
out += c.lower()
return out
@@ -139,114 +91,128 @@ def to_log_lower(symbol):
root = os.path.dirname(os.path.abspath(__file__))
# write out C & Objective-C headers
with open(root + '/yoga/YGEnums.h', 'w') as f:
with open(root + "/yoga/YGEnums.h", "w") as f:
f.write(LICENSE)
f.write('#pragma once\n\n')
f.write("#pragma once\n\n")
f.write('#include "YGMacros.h"\n\n')
f.write('YG_EXTERN_C_BEGIN\n\n')
f.write("YG_EXTERN_C_BEGIN\n\n")
for name, values in sorted(ENUMS.items()):
f.write('#define YG%sCount %s\n' % (name, len(values)))
f.write('typedef YG_ENUM_BEGIN(YG%s) {\n' % name)
f.write("#define YG%sCount %s\n" % (name, len(values)))
f.write("typedef YG_ENUM_BEGIN(YG%s) {\n" % name)
for value in values:
if isinstance(value, tuple):
f.write(' YG%s%s = %d,\n' % (name, value[0], value[1]))
f.write(" YG%s%s = %d,\n" % (name, value[0], value[1]))
else:
f.write(' YG%s%s,\n' % (name, value))
f.write('} YG_ENUM_END(YG%s);\n' % name)
f.write('WIN_EXPORT const char *YG%sToString(const YG%s value);\n' % (name, name))
f.write('\n')
f.write('YG_EXTERN_C_END\n')
f.write(" YG%s%s,\n" % (name, value))
f.write("} YG_ENUM_END(YG%s);\n" % name)
f.write(
"WIN_EXPORT const char *YG%sToString(const YG%s value);\n" % (name, name)
)
f.write("\n")
f.write("YG_EXTERN_C_END\n")
# write out C body for printing
with open(root + '/yoga/YGEnums.cpp', 'w') as f:
with open(root + "/yoga/YGEnums.cpp", "w") as f:
f.write(LICENSE)
f.write('#include "YGEnums.h"\n\n')
for name, values in sorted(ENUMS.items()):
f.write('const char *YG%sToString(const YG%s value){\n' % (name, name))
f.write(' switch(value){\n')
f.write("const char *YG%sToString(const YG%s value){\n" % (name, name))
f.write(" switch(value){\n")
for value in values:
if isinstance(value, tuple):
f.write(' case YG%s%s:\n' % (name, value[0]))
f.write(" case YG%s%s:\n" % (name, value[0]))
f.write(' return "%s";\n' % to_log_lower(value[0]))
else:
f.write(' case YG%s%s:\n' % (name, value))
f.write(" case YG%s%s:\n" % (name, value))
f.write(' return "%s";\n' % to_log_lower(value))
f.write(' }\n')
f.write(" }\n")
f.write(' return "unknown";\n')
f.write('}\n\n')
f.write("}\n\n")
# write out java files
for name, values in sorted(ENUMS.items()):
with open(root + '/java/com/facebook/yoga/Yoga%s.java' % name, 'w') as f:
f.write(LICENSE.replace('/**', '/*', 1))
f.write('package com.facebook.yoga;\n\n')
f.write('import com.facebook.proguard.annotations.DoNotStrip;\n\n')
f.write('@DoNotStrip\n')
f.write('public enum Yoga%s {\n' % name)
with open(root + "/java/com/facebook/yoga/Yoga%s.java" % name, "w") as f:
f.write(LICENSE.replace("/**", "/*", 1))
f.write("package com.facebook.yoga;\n\n")
f.write("import com.facebook.proguard.annotations.DoNotStrip;\n\n")
f.write("@DoNotStrip\n")
f.write("public enum Yoga%s {\n" % name)
if len(values) > 0:
for value in values:
if isinstance(value, tuple):
f.write(' %s(%d)' % (to_java_upper(value[0]), value[1]))
f.write(" %s(%d)" % (to_java_upper(value[0]), value[1]))
else:
f.write(' %s(%d)' % (to_java_upper(value), values.index(value)))
f.write(" %s(%d)" % (to_java_upper(value), values.index(value)))
if values.index(value) is len(values) - 1:
f.write(';\n')
f.write(";\n")
else:
f.write(',\n')
f.write(",\n")
else:
f.write('__EMPTY(-1);')
f.write('\n')
f.write(' private int mIntValue;\n')
f.write('\n')
f.write(' Yoga%s(int intValue) {\n' % name)
f.write(' mIntValue = intValue;\n')
f.write(' }\n')
f.write('\n')
f.write(' public int intValue() {\n')
f.write(' return mIntValue;\n')
f.write(' }\n')
f.write('\n')
f.write(' public static Yoga%s fromInt(int value) {\n' % name)
f.write(' switch (value) {\n')
f.write("__EMPTY(-1);")
f.write("\n")
f.write(" private int mIntValue;\n")
f.write("\n")
f.write(" Yoga%s(int intValue) {\n" % name)
f.write(" mIntValue = intValue;\n")
f.write(" }\n")
f.write("\n")
f.write(" public int intValue() {\n")
f.write(" return mIntValue;\n")
f.write(" }\n")
f.write("\n")
f.write(" public static Yoga%s fromInt(int value) {\n" % name)
f.write(" switch (value) {\n")
for value in values:
if isinstance(value, tuple):
f.write(' case %d: return %s;\n' % (value[1], to_java_upper(value[0])))
f.write(
" case %d: return %s;\n" % (value[1], to_java_upper(value[0]))
)
else:
f.write(' case %d: return %s;\n' % (values.index(value), to_java_upper(value)))
f.write(' default: throw new IllegalArgumentException("Unknown enum value: " + value);\n')
f.write(' }\n')
f.write(' }\n')
f.write('}\n')
f.write(
" case %d: return %s;\n"
% (values.index(value), to_java_upper(value))
)
f.write(
' default: throw new IllegalArgumentException("Unknown enum value: " + value);\n'
)
f.write(" }\n")
f.write(" }\n")
f.write("}\n")
# write out csharp files
for name, values in sorted(ENUMS.items()):
with open(root + '/csharp/Facebook.Yoga/Yoga%s.cs' % name, 'w') as f:
with open(root + "/csharp/Facebook.Yoga/Yoga%s.cs" % name, "w") as f:
f.write(LICENSE)
f.write('namespace Facebook.Yoga\n{\n')
f.write("namespace Facebook.Yoga\n{\n")
if isinstance(next(iter(values or []), None), tuple):
f.write(' [System.Flags]\n')
f.write(' public enum Yoga%s\n {\n' % name)
f.write(" [System.Flags]\n")
f.write(" public enum Yoga%s\n {\n" % name)
for value in values:
if isinstance(value, tuple):
f.write(' %s = %d,\n' % (value[0], value[1]))
f.write(" %s = %d,\n" % (value[0], value[1]))
else:
f.write(' %s,\n' % value)
f.write(' }\n')
f.write('}\n')
f.write(" %s,\n" % value)
f.write(" }\n")
f.write("}\n")
# write out javascript file
with open(root + '/javascript/sources/YGEnums.js', 'w') as f:
with open(root + "/javascript/sources/YGEnums.js", "w") as f:
f.write(LICENSE)
f.write('module.exports = {\n\n')
f.write("module.exports = {\n\n")
for name, values in sorted(ENUMS.items()):
f.write(' %s_COUNT: %s,\n' % (to_java_upper(name), len(values)))
f.write(" %s_COUNT: %s,\n" % (to_java_upper(name), len(values)))
base = 0
for value in values:
if isinstance(value, tuple):
f.write(' %s_%s: %d,\n' % (to_java_upper(name), to_java_upper(value[0]), value[1]))
f.write(
" %s_%s: %d,\n"
% (to_java_upper(name), to_java_upper(value[0]), value[1])
)
base = value[1] + 1
else:
f.write(' %s_%s: %d,\n' % (to_java_upper(name), to_java_upper(value), base))
f.write(
" %s_%s: %d,\n" % (to_java_upper(name), to_java_upper(value), base)
)
base += 1
f.write('\n')
f.write('};\n')
f.write("\n")
f.write("};\n")

View File

@@ -9,7 +9,7 @@
org.gradle.jvmargs=-Xmx1536M
VERSION_NAME=1.14.0
VERSION_NAME=1.14.0-SNAPSHOT
POM_URL=https://github.com/facebook/yoga
POM_SCM_URL=https://github.com/facebook/yoga.git
POM_SCM_CONNECTION=scm:git:https://github.com/facebook/yoga.git

84
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -3,13 +3,18 @@
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "CXX_LIBRARY_WHITELIST", "FBJNI_JAVA_TARGET", "FBJNI_TARGET", "INFER_ANNOTATIONS_TARGET", "JNI_TARGET", "JSR_305_TARGET", "JUNIT_TARGET", "PROGRUARD_ANNOTATIONS_TARGET", "SOLOADER_TARGET", "yoga_cxx_library", "yoga_dep", "yoga_java_binary", "yoga_java_library", "yoga_java_test")
load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "CXX_LIBRARY_WHITELIST", "FBJNI_JAVA_TARGET", "FBJNI_TARGET", "INFER_ANNOTATIONS_TARGET", "JNI_TARGET", "JSR_305_TARGET", "JUNIT_TARGET", "PROGRUARD_ANNOTATIONS_TARGET", "SOLOADER_TARGET", "yoga_cxx_lib", "yoga_cxx_library", "yoga_dep", "yoga_java_binary", "yoga_java_library", "yoga_java_test")
CXX_LIBRARY_WHITELIST_FOR_TESTS = CXX_LIBRARY_WHITELIST + [
yoga_cxx_lib("testutil:jni"),
yoga_cxx_lib("testutil:testutil"),
]
yoga_cxx_library(
name = "jni",
srcs = glob(["jni/*.cpp"]),
headers = glob(["jni/*.h"]),
header_namespace = "",
header_namespace = "yoga/java",
exported_headers = glob(["jni/*.h"]),
allow_jni_merging = True,
compiler_flags = [
"-fno-omit-frame-pointer",
@@ -18,7 +23,7 @@ yoga_cxx_library(
"-Wall",
"-Werror",
"-Os",
"-std=c++14",
"-std=c++11",
],
platforms = ANDROID,
preprocessor_flags = [
@@ -55,11 +60,12 @@ yoga_java_library(
yoga_java_test(
name = "tests",
srcs = glob(["tests/**/*.java"]),
cxx_library_whitelist = CXX_LIBRARY_WHITELIST,
cxx_library_whitelist = CXX_LIBRARY_WHITELIST_FOR_TESTS,
use_cxx_libraries = True,
visibility = ["PUBLIC"],
deps = [
":java",
yoga_dep("testutil:java"),
JUNIT_TARGET,
],
)

View File

@@ -28,7 +28,6 @@ public class YogaNative {
// YGNode related
static native int jni_YGNodeGetInstanceCount();
static native long jni_YGNodeNew(boolean useBatchingForLayoutOutputs);
static native long jni_YGNodeNewWithConfig(long configPointer, boolean useBatchingForLayoutOutputs);
static native void jni_YGNodeFree(long nativePointer);

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
@@ -75,34 +75,6 @@ const short int LAYOUT_BORDER_START_INDEX = 14;
bool useBatchingForLayoutOutputs;
class PtrJNodeMap {
using JNodeArray = JArrayClass<JYogaNode::javaobject>;
std::map<YGNodeRef, size_t> ptrsToIdxs_;
alias_ref<JNodeArray> javaNodes_;
public:
PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {}
PtrJNodeMap(
alias_ref<JArrayLong> nativePointers,
alias_ref<JNodeArray> javaNodes)
: javaNodes_{javaNodes} {
auto pin = nativePointers->pinCritical();
auto ptrs = pin.get();
for (size_t i = 0, n = pin.size(); i < n; ++i) {
ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i;
}
}
local_ref<JYogaNode> ref(YGNodeRef node) {
auto idx = ptrsToIdxs_.find(node);
if (idx == ptrsToIdxs_.end()) {
return local_ref<JYogaNode>{};
} else {
return javaNodes_->getElement(idx->second);
}
}
};
namespace {
union YGNodeContext {
@@ -135,18 +107,14 @@ public:
node->setContext(context.asVoidPtr);
}
bool has(Edge edge) {
return (edges_ & edge) == edge;
}
bool has(Edge edge) { return (edges_ & edge) == edge; }
YGNodeEdges& add(Edge edge) {
edges_ |= edge;
return *this;
}
int get() {
return edges_;
}
int get() { return edges_; }
};
struct YogaValue {
@@ -942,10 +910,6 @@ void jni_YGNodeSetStyleInputs(
YGNodeSetStyleInputs(_jlong2YGNodeRef(nativePointer), result, size);
}
jint jni_YGNodeGetInstanceCount() {
return YGNodeGetInstanceCount();
}
jlong jni_YGNodeStyleGetMargin(jlong nativePointer, jint edge) {
YGNodeRef yogaNodeRef = _jlong2YGNodeRef(nativePointer);
if (!YGNodeEdges{yogaNodeRef}.has(YGNodeEdges::MARGIN)) {
@@ -1109,7 +1073,6 @@ jint JNI_OnLoad(JavaVM* vm, void*) {
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxHeightPercent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAspectRatio),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAspectRatio),
YGMakeCriticalNativeMethod(jni_YGNodeGetInstanceCount),
YGMakeCriticalNativeMethod(jni_YGNodePrint),
YGMakeNativeMethod(jni_YGNodeClone),
YGMakeNativeMethod(jni_YGNodeSetStyleInputs),

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
@@ -6,6 +6,11 @@
*/
#include <fb/fbjni.h>
#include <yoga/YGValue.h>
#include <yoga/Yoga.h>
#include <map>
using namespace facebook::jni;
using namespace std;
struct JYogaNode : public facebook::jni::JavaClass<JYogaNode> {
static constexpr auto kJavaDescriptor = "Lcom/facebook/yoga/YogaNodeJNIBase;";
@@ -28,3 +33,31 @@ struct JYogaLogger : public facebook::jni::JavaClass<JYogaLogger> {
facebook::jni::alias_ref<JYogaLogLevel>,
jstring);
};
class PtrJNodeMap {
using JNodeArray = JArrayClass<JYogaNode::javaobject>;
std::map<YGNodeRef, size_t> ptrsToIdxs_;
alias_ref<JNodeArray> javaNodes_;
public:
PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {}
PtrJNodeMap(
alias_ref<JArrayLong> nativePointers,
alias_ref<JNodeArray> javaNodes)
: javaNodes_{javaNodes} {
auto pin = nativePointers->pinCritical();
auto ptrs = pin.get();
for (size_t i = 0, n = pin.size(); i < n; ++i) {
ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i;
}
}
local_ref<JYogaNode> ref(YGNodeRef node) {
auto idx = ptrsToIdxs_.find(node);
if (idx == ptrsToIdxs_.end()) {
return local_ref<JYogaNode>{};
} else {
return javaNodes_->getElement(idx->second);
}
}
};

View File

@@ -31,9 +31,9 @@ public class YogaNodeTest {
@Test
public void testInit() {
final int refCount = YogaNative.jni_YGNodeGetInstanceCount();
TestUtil.startCountingNodes();
final YogaNode node = createNode();
assertEquals(refCount + 1, YogaNative.jni_YGNodeGetInstanceCount());
assertEquals(1, TestUtil.stopCountingNodes());
}
@Test
@@ -254,7 +254,7 @@ public class YogaNodeTest {
root_child0_child0_child0.setFlexShrink(1);
root_child0_child0.addChildAt(root_child0_child0_child0, 0);
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
assertFalse(((YogaNodeJNIBase) root).getDoesLegacyStretchFlagAffectsLayout());
assertTrue(((YogaNodeJNIBase) root).getDoesLegacyStretchFlagAffectsLayout());
}
@Test

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,13 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include <yoga/Yoga.h>
#include "./global.hh"
unsigned getInstanceCount(void) {
return YGNodeGetInstanceCount();
}

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -32,7 +32,7 @@ yoga_cxx_library(
"-Wall",
"-Werror",
"-Wno-unused-parameter",
"-std=c++14",
"-std=c++11",
],
platforms = (ANDROID,),
visibility = ["PUBLIC"],

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

147
tests/EventsTest.cpp Normal file
View File

@@ -0,0 +1,147 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <yoga/Yoga.h>
#include <yoga/event/event.h>
#include <yoga/YGNode.h>
#include <yoga/testutil/testutil.h>
#include <algorithm>
#include <functional>
#include <memory>
#include <vector>
namespace facebook {
namespace yoga {
namespace test {
struct EventArgs {
const YGNode* node;
Event::Type type;
std::unique_ptr<void, std::function<void(void*)>> dataPtr;
template <Event::Type E>
const Event::TypedData<E>& data() {
return *static_cast<Event::TypedData<E>*>(dataPtr.get());
}
};
class EventTest : public ::testing::Test {
ScopedEventSubscription subscription = {&EventTest::listen};
static void listen(const YGNode&, Event::Type, Event::Data);
public:
static std::vector<EventArgs> events;
static EventArgs& lastEvent() { return events.back(); }
void TearDown() override;
};
TEST_F(EventTest, new_node_has_event) {
auto c = YGConfigGetDefault();
auto n = YGNodeNew();
ASSERT_EQ(lastEvent().node, n);
ASSERT_EQ(lastEvent().type, Event::NodeAllocation);
ASSERT_EQ(lastEvent().data<Event::NodeAllocation>().config, c);
YGNodeFree(n);
}
TEST_F(EventTest, new_node_with_config_event) {
auto c = YGConfigNew();
auto n = YGNodeNewWithConfig(c);
ASSERT_EQ(lastEvent().node, n);
ASSERT_EQ(lastEvent().type, Event::NodeAllocation);
ASSERT_EQ(lastEvent().data<Event::NodeAllocation>().config, c);
YGNodeFree(n);
YGConfigFree(c);
}
TEST_F(EventTest, clone_node_event) {
auto c = YGConfigNew();
auto n = YGNodeNewWithConfig(c);
auto clone = YGNodeClone(n);
ASSERT_EQ(lastEvent().node, clone);
ASSERT_EQ(lastEvent().type, Event::NodeAllocation);
ASSERT_EQ(lastEvent().data<Event::NodeAllocation>().config, c);
YGNodeFree(n);
YGNodeFree(clone);
YGConfigFree(c);
}
TEST_F(EventTest, free_node_event) {
auto c = YGConfigNew();
auto n = YGNodeNewWithConfig(c);
YGNodeFree(n);
ASSERT_EQ(lastEvent().node, n);
ASSERT_EQ(lastEvent().type, Event::NodeDeallocation);
ASSERT_EQ(lastEvent().data<Event::NodeDeallocation>().config, c);
YGConfigFree(c);
}
TEST_F(EventTest, layout_events) {
auto root = YGNodeNew();
auto child = YGNodeNew();
YGNodeInsertChild(root, child, 0);
YGNodeCalculateLayout(root, 123, 456, YGDirectionLTR);
ASSERT_EQ(events[2].node, root);
ASSERT_EQ(events[2].type, Event::NodeLayout);
ASSERT_EQ(events[3].node, child);
ASSERT_EQ(events[3].type, Event::NodeLayout);
YGNodeFreeRecursive(root);
}
namespace {
template <Event::Type E>
EventArgs createArgs(const YGNode& node, const Event::Data& data) {
using Data = Event::TypedData<E>;
auto deleteData = [](void* x) { delete static_cast<Data*>(x); };
return {&node, E, {new Data{data.get<E>()}, deleteData}};
}
} // namespace
void EventTest::listen(const YGNode& node, Event::Type type, Event::Data data) {
switch (type) {
case Event::NodeAllocation:
events.push_back(createArgs<Event::NodeAllocation>(node, data));
break;
case Event::NodeDeallocation:
events.push_back(createArgs<Event::NodeDeallocation>(node, data));
break;
case Event::NodeLayout:
events.push_back(createArgs<Event::NodeLayout>(node, data));
break;
case Event::LayoutPassStart:
break;
case Event::LayoutPassEnd:
break;
case Event::NodeMeasure:
break;
}
}
void EventTest::TearDown() {
events.clear();
}
std::vector<EventArgs> EventTest::events{};
} // namespace test
} // namespace yoga
} // namespace facebook

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
@@ -20,12 +20,8 @@ struct ConfigCloningTest : public ::testing::Test {
void TearDown() override;
static YGNode clonedNode;
static YGNodeRef cloneNode(YGNodeRef, YGNodeRef, int) {
return &clonedNode;
}
static YGNodeRef doNotClone(YGNodeRef, YGNodeRef, int) {
return nullptr;
}
static YGNodeRef cloneNode(YGNodeRef, YGNodeRef, int) { return &clonedNode; }
static YGNodeRef doNotClone(YGNodeRef, YGNodeRef, int) { return nullptr; }
};
TEST_F(ConfigCloningTest, uses_values_provided_by_cloning_callback) {

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,14 +1,19 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <yoga/testutil/testutil.h>
#include <yoga/YGNode.h>
#include <yoga/Yoga.h>
using facebook::yoga::test::TestUtil;
TEST(YogaTest, assert_layout_trees_are_same) {
TestUtil::startCountingNodes();
YGConfig* config = YGConfigNew();
YGConfigSetUseLegacyStretchBehaviour(config, true);
const YGNodeRef root1 = YGNodeNewWithConfig(config);
@@ -30,12 +35,12 @@ TEST(YogaTest, assert_layout_trees_are_same) {
YGNodeInsertChild(root1_child0_child0, root1_child0_child0_child0, 0);
const int32_t cal1_configInstanceCount = YGConfigGetInstanceCount();
const int32_t cal1_nodeInstanceCount = YGNodeGetInstanceCount();
const int32_t cal1_nodeInstanceCount = TestUtil::nodeCount();
YGNodeCalculateLayout(root1, YGUndefined, YGUndefined, YGDirectionLTR);
ASSERT_EQ(YGConfigGetInstanceCount(), cal1_configInstanceCount);
ASSERT_EQ(YGNodeGetInstanceCount(), cal1_nodeInstanceCount);
ASSERT_EQ(TestUtil::nodeCount(), cal1_nodeInstanceCount);
const YGNodeRef root2 = YGNodeNewWithConfig(config);
YGNodeStyleSetWidth(root2, 500);
@@ -56,12 +61,12 @@ TEST(YogaTest, assert_layout_trees_are_same) {
YGNodeInsertChild(root2_child0_child0, root2_child0_child0_child0, 0);
const int32_t cal2_configInstanceCount = YGConfigGetInstanceCount();
const int32_t cal2_nodeInstanceCount = YGNodeGetInstanceCount();
const int32_t cal2_nodeInstanceCount = TestUtil::nodeCount();
YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
ASSERT_EQ(YGConfigGetInstanceCount(), cal2_configInstanceCount);
ASSERT_EQ(YGNodeGetInstanceCount(), cal2_nodeInstanceCount);
ASSERT_EQ(TestUtil::nodeCount(), cal2_nodeInstanceCount);
ASSERT_TRUE(YGNodeLayoutGetDidUseLegacyFlag(root1));
ASSERT_TRUE(YGNodeLayoutGetDidUseLegacyFlag(root2));
@@ -70,12 +75,12 @@ TEST(YogaTest, assert_layout_trees_are_same) {
YGNodeStyleSetAlignItems(root2, YGAlignFlexEnd);
const int32_t cal3_configInstanceCount = YGConfigGetInstanceCount();
const int32_t cal3_nodeInstanceCount = YGNodeGetInstanceCount();
const int32_t cal3_nodeInstanceCount = TestUtil::nodeCount();
YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
ASSERT_EQ(YGConfigGetInstanceCount(), cal3_configInstanceCount);
ASSERT_EQ(YGNodeGetInstanceCount(), cal3_nodeInstanceCount);
ASSERT_EQ(TestUtil::stopCountingNodes(), cal3_nodeInstanceCount);
ASSERT_FALSE(root1->isLayoutTreeEqualToNode(*root2));

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,13 +1,16 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <yoga/testutil/testutil.h>
#include <yoga/Yoga.h>
#include <yoga/YGNode.h>
using facebook::yoga::test::TestUtil;
TEST(YogaTest, cloning_shared_root) {
const YGConfigRef config = YGConfigNew();
@@ -220,7 +223,7 @@ TEST(YogaTest, cloning_two_levels) {
}
TEST(YogaTest, cloning_and_freeing) {
const int32_t initialInstanceCount = YGNodeGetInstanceCount();
TestUtil::startCountingNodes();
const YGConfigRef config = YGConfigNew();
@@ -249,7 +252,7 @@ TEST(YogaTest, cloning_and_freeing) {
YGConfigFree(config);
ASSERT_EQ(initialInstanceCount, YGNodeGetInstanceCount());
ASSERT_EQ(0, TestUtil::stopCountingNodes());
}
TEST(YogaTest, mixed_shared_and_owned_children) {

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -0,0 +1,391 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include <cstdint>
#include <type_traits>
#include <gtest/gtest.h>
#include <yoga/YGEnums.h>
#include <yoga/YGStyle.h>
#include <yoga/YGValue.h>
#include <utility>
using AssignedProps =
std::remove_reference<decltype(YGStyle{}.assignedProps())>::type;
namespace {
constexpr AssignedProps setBits(int from, int n) {
return n > 0 ? (setBits(from, n - 1) | AssignedProps{1ull << (from + n - 1)})
: 0;
}
} // namespace
#define ACCESSOR_TESTS_1(NAME, X) \
style.NAME() = X; \
ASSERT_EQ(style.NAME(), X); \
ASSERT_EQ(style.assignedProps(), AssignedProps{1ull << YGStyle::NAME##Bit});
#define ACCESSOR_TESTS_2(NAME, X, ...) \
ACCESSOR_TESTS_1(NAME, X); \
ACCESSOR_TESTS_1(NAME, __VA_ARGS__);
#define ACCESSOR_TESTS_3(NAME, X, ...) \
ACCESSOR_TESTS_1(NAME, X); \
ACCESSOR_TESTS_2(NAME, __VA_ARGS__);
#define ACCESSOR_TESTS_4(NAME, X, ...) \
ACCESSOR_TESTS_1(NAME, X); \
ACCESSOR_TESTS_3(NAME, __VA_ARGS__);
#define ACCESSOR_TESTS_5(NAME, X, ...) \
ACCESSOR_TESTS_1(NAME, X); \
ACCESSOR_TESTS_4(NAME, __VA_ARGS__)
#define ACCESSOR_TESTS_N(a, b, c, d, e, COUNT, ...) ACCESSOR_TESTS_##COUNT
#define ACCESSOR_TESTS(...) ACCESSOR_TESTS_N(__VA_ARGS__, 5, 4, 3, 2, 1)
#define INDEX_ACCESSOR_TESTS_1(NAME, IDX, X) \
{ \
auto style = YGStyle{}; \
style.NAME()[IDX] = X; \
ASSERT_EQ(style.NAME()[IDX], X); \
ASSERT_EQ( \
style.assignedProps(), \
AssignedProps{1ull << (YGStyle::NAME##Bit + IDX)}); \
auto asArray = decltype(std::declval<const YGStyle&>().NAME()){X}; \
style.NAME() = asArray; \
ASSERT_EQ(static_cast<decltype(asArray)>(style.NAME()), asArray); \
ASSERT_EQ( \
style.assignedProps(), \
AssignedProps{setBits( \
YGStyle::NAME##Bit, \
facebook::yoga::enums::count<decltype(IDX)>())}); \
}
#define INDEX_ACCESSOR_TESTS_2(NAME, IDX, X, Y) \
INDEX_ACCESSOR_TESTS_1(NAME, IDX, X) \
INDEX_ACCESSOR_TESTS_1(NAME, IDX, Y)
#define INDEX_ACCESSOR_TESTS_3(NAME, IDX, X, ...) \
INDEX_ACCESSOR_TESTS_1(NAME, IDX, X) \
INDEX_ACCESSOR_TESTS_2(NAME, IDX, __VA_ARGS__)
#define INDEX_ACCESSOR_TESTS_4(NAME, IDX, X, ...) \
INDEX_ACCESSOR_TESTS_1(NAME, IDX, X) \
INDEX_ACCESSOR_TESTS_3(NAME, IDX, __VA_ARGS__)
#define INDEX_ACCESSOR_TESTS_5(NAME, IDX, X, ...) \
INDEX_ACCESSOR_TESTS_1(NAME, IDX, X) \
INDEX_ACCESSOR_TESTS_4(NAME, IDX, __VA_ARGS__)
#define INDEX_ACCESSOR_TESTS_N(a, b, c, d, e, COUNT, ...) \
INDEX_ACCESSOR_TESTS_##COUNT
#define INDEX_ACCESSOR_TESTS(...) \
INDEX_ACCESSOR_TESTS_N(__VA_ARGS__, 5, 4, 3, 2, 1)
// test macro for up to 5 values. If more are needed, extend the macros above.
#define ACCESSOR_TEST(NAME, DEFAULT_VAL, ...) \
TEST(YGStyle, style_##NAME##_access) { \
auto style = YGStyle{}; \
ASSERT_EQ(style.NAME(), DEFAULT_VAL); \
ACCESSOR_TESTS(__VA_ARGS__)(NAME, __VA_ARGS__) \
}
#define INDEX_ACCESSOR_TEST(NAME, DEFAULT_VAL, IDX, ...) \
TEST(YGStyle, style_##NAME##_access) { \
ASSERT_EQ(YGStyle{}.NAME()[IDX], DEFAULT_VAL); \
ASSERT_EQ(YGStyle{}.assignedProps(), 0); \
INDEX_ACCESSOR_TESTS(__VA_ARGS__)(NAME, IDX, __VA_ARGS__) \
}
namespace facebook {
namespace yoga {
using CompactValue = detail::CompactValue;
ACCESSOR_TEST(
direction,
YGDirectionInherit,
YGDirectionLTR,
YGDirectionRTL,
YGDirectionInherit);
ACCESSOR_TEST(
flexDirection,
YGFlexDirectionColumn,
YGFlexDirectionColumnReverse,
YGFlexDirectionRowReverse,
YGFlexDirectionRow)
ACCESSOR_TEST(
justifyContent,
YGJustifyFlexStart,
YGJustifyFlexEnd,
YGJustifySpaceAround,
YGJustifyFlexStart,
YGJustifySpaceEvenly)
ACCESSOR_TEST(
alignContent,
YGAlignFlexStart,
YGAlignAuto,
YGAlignFlexStart,
YGAlignCenter,
YGAlignFlexEnd,
YGAlignStretch)
ACCESSOR_TEST(
alignItems,
YGAlignStretch,
YGAlignFlexStart,
YGAlignFlexEnd,
YGAlignBaseline,
YGAlignSpaceBetween,
YGAlignSpaceAround)
ACCESSOR_TEST(
alignSelf,
YGAlignAuto,
YGAlignFlexStart,
YGAlignCenter,
YGAlignAuto,
YGAlignFlexEnd,
YGAlignStretch)
ACCESSOR_TEST(
positionType,
YGPositionTypeRelative,
YGPositionTypeAbsolute,
YGPositionTypeRelative)
ACCESSOR_TEST(
flexWrap,
YGWrapNoWrap,
YGWrapWrap,
YGWrapWrapReverse,
YGWrapNoWrap)
ACCESSOR_TEST(
overflow,
YGOverflowVisible,
YGOverflowHidden,
YGOverflowScroll,
YGOverflowVisible)
ACCESSOR_TEST(display, YGDisplayFlex, YGDisplayNone, YGDisplayFlex)
ACCESSOR_TEST(
flex,
YGFloatOptional{},
YGFloatOptional{123.45f},
YGFloatOptional{-9.87f},
YGFloatOptional{})
ACCESSOR_TEST(
flexGrow,
YGFloatOptional{},
YGFloatOptional{123.45f},
YGFloatOptional{-9.87f},
YGFloatOptional{})
ACCESSOR_TEST(
flexShrink,
YGFloatOptional{},
YGFloatOptional{123.45f},
YGFloatOptional{-9.87f},
YGFloatOptional{})
ACCESSOR_TEST(
flexBasis,
CompactValue::ofAuto(),
CompactValue::ofUndefined(),
CompactValue::ofAuto(),
CompactValue::of<YGUnitPoint>(7777.77f),
CompactValue::of<YGUnitPercent>(-100.0f))
INDEX_ACCESSOR_TEST(
position,
CompactValue::ofUndefined(),
YGEdgeBottom,
CompactValue::ofAuto(),
CompactValue::ofUndefined(),
CompactValue::of<YGUnitPoint>(7777.77f),
CompactValue::of<YGUnitPercent>(-100.0f))
INDEX_ACCESSOR_TEST(
margin,
CompactValue::ofUndefined(),
YGEdgeTop,
CompactValue::ofAuto(),
CompactValue::ofUndefined(),
CompactValue::of<YGUnitPoint>(7777.77f),
CompactValue::of<YGUnitPercent>(-100.0f))
INDEX_ACCESSOR_TEST(
padding,
CompactValue::ofUndefined(),
YGEdgeAll,
CompactValue::of<YGUnitPoint>(7777.77f),
CompactValue::ofUndefined(),
CompactValue::of<YGUnitPercent>(-100.0f))
INDEX_ACCESSOR_TEST(
border,
CompactValue::ofUndefined(),
YGEdgeHorizontal,
CompactValue::of<YGUnitPoint>(-7777.77f),
CompactValue::ofUndefined())
INDEX_ACCESSOR_TEST(
dimensions,
CompactValue::ofAuto(),
YGDimensionWidth,
CompactValue::ofUndefined(),
CompactValue::ofAuto(),
CompactValue::of<YGUnitPoint>(7777.77f),
CompactValue::of<YGUnitPercent>(-100.0f))
INDEX_ACCESSOR_TEST(
minDimensions,
CompactValue::ofUndefined(),
YGDimensionHeight,
CompactValue::ofAuto(),
CompactValue::ofUndefined(),
CompactValue::of<YGUnitPoint>(7777.77f),
CompactValue::of<YGUnitPercent>(-100.0f))
INDEX_ACCESSOR_TEST(
maxDimensions,
CompactValue::ofUndefined(),
YGDimensionHeight,
CompactValue::ofAuto(),
CompactValue::ofUndefined(),
CompactValue::of<YGUnitPoint>(7777.77f),
CompactValue::of<YGUnitPercent>(-100.0f))
ACCESSOR_TEST(
aspectRatio,
YGFloatOptional{},
YGFloatOptional{-123.45f},
YGFloatOptional{9876.5f},
YGFloatOptional{0.0f},
YGFloatOptional{});
TEST(YGStyle, set_properties_default_to_0) {
ASSERT_EQ(YGStyle{}.assignedProps(), AssignedProps{0});
}
TEST(YGStyle, set_properties_reflects_all_set_properties) {
auto style = YGStyle{};
style.direction() = YGDirectionRTL;
style.justifyContent() = YGJustifySpaceAround;
style.flexWrap() = YGWrapWrap;
style.padding()[YGEdgeVertical] = YGValue{1, YGUnitPoint};
style.minDimensions()[YGDimensionHeight] = YGValue{1, YGUnitPercent};
style.aspectRatio() = YGFloatOptional{1.23};
ASSERT_EQ(
style.assignedProps(),
AssignedProps{1ull << YGStyle::directionBit |
1ull << YGStyle::justifyContentBit |
1ull << YGStyle::flexWrapBit |
1ull << (YGStyle::paddingBit + YGEdgeVertical) |
1ull << (YGStyle::minDimensionsBit + YGDimensionHeight) |
1ull << YGStyle::aspectRatioBit});
}
TEST(YGStyle, directionBit) {
constexpr auto directionBit = YGStyle::directionBit;
ASSERT_EQ(directionBit, 0);
}
TEST(YGStyle, flexDirectionBit) {
constexpr auto flexDirectionBit = YGStyle::flexDirectionBit;
ASSERT_EQ(flexDirectionBit, 1);
}
TEST(YGStyle, justifyContentBit) {
constexpr auto justifyContentBit = YGStyle::justifyContentBit;
ASSERT_EQ(justifyContentBit, 2);
}
TEST(YGStyle, alignContentBit) {
constexpr auto alignContentBit = YGStyle::alignContentBit;
ASSERT_EQ(alignContentBit, 3);
}
TEST(YGStyle, alignItemsBit) {
constexpr auto alignItemsBit = YGStyle::alignItemsBit;
ASSERT_EQ(alignItemsBit, 4);
}
TEST(YGStyle, alignSelfBit) {
constexpr auto alignSelfBit = YGStyle::alignSelfBit;
ASSERT_EQ(alignSelfBit, 5);
}
TEST(YGStyle, positionTypeBit) {
constexpr auto positionTypeBit = YGStyle::positionTypeBit;
ASSERT_EQ(positionTypeBit, 6);
}
TEST(YGStyle, flexWrapBit) {
constexpr auto flexWrapBit = YGStyle::flexWrapBit;
ASSERT_EQ(flexWrapBit, 7);
}
TEST(YGStyle, overflowBit) {
constexpr auto overflowBit = YGStyle::overflowBit;
ASSERT_EQ(overflowBit, 8);
}
TEST(YGStyle, displayBit) {
constexpr auto displayBit = YGStyle::displayBit;
ASSERT_EQ(displayBit, 9);
}
TEST(YGStyle, flexBit) {
constexpr auto flexBit = YGStyle::flexBit;
ASSERT_EQ(flexBit, 10);
}
TEST(YGStyle, flexGrowBit) {
constexpr auto flexGrowBit = YGStyle::flexGrowBit;
ASSERT_EQ(flexGrowBit, 11);
}
TEST(YGStyle, flexShrinkBit) {
constexpr auto flexShrinkBit = YGStyle::flexShrinkBit;
ASSERT_EQ(flexShrinkBit, 12);
}
TEST(YGStyle, flexBasisBit) {
constexpr auto flexBasisBit = YGStyle::flexBasisBit;
ASSERT_EQ(flexBasisBit, 13);
}
TEST(YGStyle, marginBit) {
constexpr auto marginBit = YGStyle::marginBit;
ASSERT_EQ(marginBit, 14);
}
TEST(YGStyle, positionBit) {
constexpr auto positionBit = YGStyle::positionBit;
ASSERT_EQ(positionBit, 23);
}
TEST(YGStyle, paddingBit) {
constexpr auto paddingBit = YGStyle::paddingBit;
ASSERT_EQ(paddingBit, 32);
}
TEST(YGStyle, borderBit) {
constexpr auto borderBit = YGStyle::borderBit;
ASSERT_EQ(borderBit, 41);
}
TEST(YGStyle, dimensionsBit) {
constexpr auto dimensionsBit = YGStyle::dimensionsBit;
ASSERT_EQ(dimensionsBit, 50);
}
TEST(YGStyle, maxDimensionsBit) {
constexpr auto maxDimensionsBit = YGStyle::maxDimensionsBit;
ASSERT_EQ(maxDimensionsBit, 52);
}
TEST(YGStyle, minDimensionsBit) {
constexpr auto minDimensionsBit = YGStyle::minDimensionsBit;
ASSERT_EQ(minDimensionsBit, 54);
}
TEST(YGStyle, aspectRatioBit) {
constexpr auto aspectRatioBit = YGStyle::aspectRatioBit;
ASSERT_EQ(aspectRatioBit, 56);
}
TEST(YGStyle, numStyles) {
constexpr auto numStyles = YGStyle::numStyles;
ASSERT_EQ(numStyles, 57);
}
} // namespace yoga
} // namespace facebook

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

View File

@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE

37
testutil/BUCK Normal file
View File

@@ -0,0 +1,37 @@
load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID", "FBJNI_TARGET", "LIBRARY_COMPILER_FLAGS", "SOLOADER_TARGET", "yoga_cxx_library", "yoga_dep", "yoga_java_library")
yoga_cxx_library(
name = "testutil",
srcs = ["testutil.cpp"],
header_namespace = "yoga/testutil",
exported_headers = ["testutil.h"],
compiler_flags = LIBRARY_COMPILER_FLAGS,
soname = "libyoga_testutil.$(ext)",
visibility = ["PUBLIC"],
deps = [yoga_dep(":yoga")],
)
yoga_java_library(
name = "java",
srcs = ["TestUtil.java"],
source = "1.7",
target = "1.7",
visibility = ["PUBLIC"],
deps = [
":jni",
SOLOADER_TARGET,
],
)
yoga_cxx_library(
name = "jni",
srcs = ["jni.cpp"],
compiler_flags = LIBRARY_COMPILER_FLAGS,
platforms = ANDROID,
soname = "libyoga_testutil_jni.$(ext)",
visibility = ["PUBLIC"],
deps = [
":testutil",
FBJNI_TARGET,
],
)

19
testutil/TestUtil.java Normal file
View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.yoga;
import com.facebook.soloader.SoLoader;
class TestUtil {
static {
SoLoader.loadLibrary("yoga_testutil_jni");
}
static native void startCountingNodes();
static native int nodeCount();
static native int stopCountingNodes();
}

38
testutil/jni.cpp Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include <fb/fbjni.h>
#include <yoga/testutil/testutil.h>
using namespace facebook;
namespace {
void startCountingNodes(jni::alias_ref<jclass>) {
yoga::test::TestUtil::startCountingNodes();
}
jint nodeCount(jni::alias_ref<jclass>) {
return yoga::test::TestUtil::nodeCount();
}
jint stopCountingNodes(jni::alias_ref<jclass>) {
return yoga::test::TestUtil::stopCountingNodes();
}
} // namespace
jint JNI_OnLoad(JavaVM* vm, void*) {
return jni::initialize(vm, [] {
jni::registerNatives(
"com/facebook/yoga/TestUtil",
{
makeNativeMethod("startCountingNodes", startCountingNodes),
makeNativeMethod("nodeCount", nodeCount),
makeNativeMethod("stopCountingNodes", stopCountingNodes),
});
});
}

65
testutil/testutil.cpp Normal file
View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include "testutil.h"
#include <yoga/YGNode.h>
#include <yoga/event/event.h>
namespace facebook {
namespace yoga {
namespace test {
int nodeInstanceCount = 0;
namespace {
void yogaEventSubscriber(
const YGNode& node,
Event::Type eventType,
const Event::Data& eventData) {
switch (eventType) {
case Event::NodeAllocation:
nodeInstanceCount++;
break;
case Event::NodeDeallocation:
nodeInstanceCount--;
break;
default:
break;
}
}
} // namespace
void TestUtil::startCountingNodes() {
nodeInstanceCount = 0;
Event::subscribe(yogaEventSubscriber);
}
int TestUtil::nodeCount() {
return nodeInstanceCount;
}
int TestUtil::stopCountingNodes() {
Event::reset();
auto prev = nodeInstanceCount;
nodeInstanceCount = 0;
return prev;
}
ScopedEventSubscription::ScopedEventSubscription(
std::function<Event::Subscriber>&& s) {
Event::subscribe(std::move(s));
}
ScopedEventSubscription::~ScopedEventSubscription() {
Event::reset();
}
} // namespace test
} // namespace yoga
} // namespace facebook

30
testutil/testutil.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#pragma once
#include <yoga/event/event.h>
#include <functional>
namespace facebook {
namespace yoga {
namespace test {
struct TestUtil {
static void startCountingNodes();
static int nodeCount();
static int stopCountingNodes();
};
struct ScopedEventSubscription {
ScopedEventSubscription(std::function<Event::Subscriber>&&);
~ScopedEventSubscription();
};
} // namespace test
} // namespace yoga
} // namespace facebook

View File

@@ -58,6 +58,7 @@ BASE_COMPILER_FLAGS = [
"-Wall",
"-Werror",
"-O2",
"-std=c++11",
]
LIBRARY_COMPILER_FLAGS = BASE_COMPILER_FLAGS + [
@@ -148,6 +149,9 @@ def _single_subdir_glob(dirpath, glob_pattern, exclude = None, prefix = None):
def yoga_dep(dep):
return "//" + dep
def yoga_cxx_lib(lib):
return yoga_dep(lib)
def yoga_android_aar(*args, **kwargs):
native.android_aar(*args, **kwargs)

30
util/BUCK Normal file
View File

@@ -0,0 +1,30 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
load("//tools/build_defs/oss:yoga_defs.bzl", "GTEST_TARGET", "LIBRARY_COMPILER_FLAGS", "yoga_cxx_library", "yoga_cxx_test")
_TESTS = glob(["*Test.cpp"])
yoga_cxx_library(
name = "util",
srcs = glob(
["*.cpp"],
exclude = _TESTS,
),
header_namespace = "yoga/util",
exported_headers = glob(["*.h"]),
compiler_flags = LIBRARY_COMPILER_FLAGS,
tests = [":test"],
visibility = ["PUBLIC"],
)
yoga_cxx_test(
name = "test",
srcs = _TESTS,
compiler_flags = LIBRARY_COMPILER_FLAGS,
deps = [
":util",
GTEST_TARGET,
],
)

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include "SingleWriterValueList.h"
namespace facebook {
namespace yoga {
namespace detail {
void* FreeList::getRaw() {
if (free_.size() == 0)
return nullptr;
auto ptr = free_.top();
free_.pop();
return ptr;
}
void FreeList::put(std::mutex& mutex, void* ptr) {
std::lock_guard<std::mutex> lock{mutex};
free_.push(ptr);
}
FreeList::FreeList() = default;
FreeList::~FreeList() = default;
} // namespace detail
} // namespace yoga
} // namespace facebook

View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include <forward_list>
#include <memory>
#include <mutex>
#include <stack>
#include <type_traits>
#include <utility>
namespace facebook {
namespace yoga {
namespace detail {
class FreeList {
std::stack<void*> free_;
void* getRaw();
public:
FreeList();
~FreeList();
void put(std::mutex&, void*);
template <typename T>
T* get() {
return static_cast<T*>(getRaw());
}
};
} // namespace detail
/// SingleWriterValueList is a data structure that holds a list of values. Each
/// value can be borrowed for exclusive writing, and will not be exposed to
/// another borrower until returned.
/// Additionaly, the whole list of values can be accessed for reading via const
/// iterators. Read consistency depends on CPU internals, i.e. whether values
/// are written to memory atomically.
///
/// A typical usage scenario would be a set of threads, where each thread
/// borrows a value for lock free writing, e.g. as a thread local variable. This
/// avoids the usage of atomics, or locking of shared memory, which both can
/// lead to increased latency due to CPU cache flushes and waits.
///
/// Values are heap allocated (via forward_list), which typically will avoid
/// multiple values being allocated in the same CPU cache line, which would also
/// lead to cache flushing.
///
/// SingleWriterValueList never deallocates, to guarantee the validity of
/// references and iterators. However, memory returned by a borrower can be
/// borrowed again.
///
/// SingleWriterValueList supports return policies as second template parameter,
/// i.e. an optional mutation of values after a borrower returns them. The
/// default policy is to do nothing. SingleWriterValueList::resetPolicy is a
/// convenience method that will move assign the default value of a type.
///
/// Example:
///
/// static SingleWriterValueList<int> counters;
/// thread_local auto localCounter = counters.borrow();
///
/// /* per thread */
/// localCounter =+ n;
///
/// /* anywhere */
/// std::accumulate(counters.begin(), counters.end(), 0);
///
template <typename T, void (*ReturnPolicy)(T&) = nullptr>
class SingleWriterValueList {
std::forward_list<T> values_{};
std::mutex acquireMutex_{};
detail::FreeList freeValuesList_{};
T* allocValue() {
values_.emplace_front();
return &values_.front();
}
void returnRef(T* value) {
if (ReturnPolicy != nullptr) {
ReturnPolicy(*value);
}
freeValuesList_.put(acquireMutex_, value);
}
public:
using const_iterator = decltype(values_.cbegin());
/// RAII representation of a single value, borrowed for exclusive writing.
/// Instances cannot be copied, and will return the borrowed value to the
/// owner upon destruction.
class Borrowed {
T* value_;
SingleWriterValueList* owner_;
public:
Borrowed(T* value, SingleWriterValueList* owner)
: value_{value}, owner_{owner} {}
~Borrowed() {
if (owner_ != nullptr && value_ != nullptr) {
owner_->returnRef(value_);
}
}
Borrowed(Borrowed&& other) = default;
Borrowed& operator=(Borrowed&& other) = default;
// no copies allowed
Borrowed(const Borrowed&) = delete;
Borrowed& operator=(const Borrowed&) = delete;
T& get() { return *value_; }
T& operator*() { return get(); }
};
Borrowed borrow() {
std::lock_guard<std::mutex> lock{acquireMutex_};
T* value = freeValuesList_.get<T>();
return {value != nullptr ? value : allocValue(), this};
}
const_iterator cbegin() const { return values_.cbegin(); };
const_iterator cend() const { return values_.cend(); };
const_iterator begin() const { return cbegin(); };
const_iterator end() const { return cend(); };
static void resetPolicy(T& value) { value = std::move(T{}); }
};
} // namespace yoga
} // namespace facebook

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <yoga/util/SingleWriterValueList.h>
#include <numeric>
#include <type_traits>
#include <unordered_set>
namespace facebook {
namespace yoga {
static_assert(
!std::is_copy_constructible<SingleWriterValueList<int>>::value,
"SingleWriterValueList must not be copyable");
static_assert(
!std::is_copy_assignable<SingleWriterValueList<int>>::value,
"SingleWriterValueList must not be copyable");
static_assert(
!std::is_copy_constructible<SingleWriterValueList<int>::Borrowed>::value,
"SingleWriterValueList::Borrowed must not be copyable");
static_assert(
!std::is_copy_assignable<SingleWriterValueList<int>::Borrowed>::value,
"SingleWriterValueList::Borrowed must not be copyable");
static_assert(
std::is_move_constructible<SingleWriterValueList<int>::Borrowed>::value,
"SingleWriterValueList::Borrowed must be movable");
static_assert(
std::is_move_assignable<SingleWriterValueList<int>::Borrowed>::value,
"SingleWriterValueList::Borrowed must be movable");
TEST(SingleWriterValueList, borrowsAreExclusive) {
SingleWriterValueList<int> x{};
auto a = x.borrow();
auto b = x.borrow();
ASSERT_NE(&a.get(), &b.get());
}
TEST(SingleWriterValueList, borrowsSupportDereference) {
SingleWriterValueList<int> x{};
auto a = x.borrow();
*a = 123;
ASSERT_EQ(*a, 123);
}
TEST(SingleWriterValueList, borrowsHaveGetMethod) {
SingleWriterValueList<int> x{};
auto a = x.borrow();
a.get() = 123;
ASSERT_EQ(a.get(), 123);
}
TEST(SingleWriterValueList, exposesBorrowsViaIterator) {
SingleWriterValueList<int> x{};
auto a = x.borrow();
auto b = x.borrow();
*a = 12;
*b = 34;
int sum = 0;
for (auto& i : x) {
sum += i;
}
ASSERT_EQ(sum, 12 + 34);
}
TEST(SingleWriterValueList, exposesBorrowsViaConstIterator) {
SingleWriterValueList<int> x{};
auto a = x.borrow();
auto b = x.borrow();
*a = 12;
*b = 34;
ASSERT_EQ(std::accumulate(x.cbegin(), x.cend(), 0), 12 + 34);
}
TEST(SingleWriterValueList, doesNotDeallocateReturnedBorrows) {
SingleWriterValueList<int> x{};
std::unordered_set<const int*> values;
{
auto a = x.borrow();
auto b = x.borrow();
values.insert(&a.get());
values.insert(&b.get());
}
auto it = x.begin();
ASSERT_NE(it, x.end());
ASSERT_NE(values.find(&*it), values.end());
ASSERT_NE(++it, x.end());
ASSERT_NE(values.find(&*it), values.end());
}
TEST(SingleWriterValueList, reusesReturnedBorrows) {
SingleWriterValueList<int> x{};
int* firstBorrow;
{
auto a = x.borrow();
firstBorrow = &a.get();
}
auto b = x.borrow();
ASSERT_EQ(&b.get(), firstBorrow);
}
TEST(SingleWriterValueList, keepsValuesAfterReturning) {
SingleWriterValueList<int> x{};
{
auto a = x.borrow();
*a = 123;
}
ASSERT_EQ(*x.begin(), 123);
}
static void addOne(int& v) {
v += 1;
}
TEST(SingleWriterValueList, allowsCustomReturnPolicy) {
SingleWriterValueList<int, addOne> x{};
{
auto a = x.borrow();
*a = 123;
}
ASSERT_EQ(*x.begin(), 124);
}
TEST(SingleWriterValueList, hasConvenienceResetPolicy) {
SingleWriterValueList<int, SingleWriterValueList<int>::resetPolicy> x{};
{
auto a = x.borrow();
*a = 123;
}
ASSERT_EQ(*x.begin(), 0);
}
} // namespace yoga
} // namespace facebook

View File

@@ -32,6 +32,6 @@
"develop": "gatsby develop"
},
"devDependencies": {
"prettier": "1.16.4"
"prettier": "1.17.0"
}
}

View File

@@ -6978,10 +6978,10 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
prettier@1.16.4:
version "1.16.4"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717"
integrity sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==
prettier@1.17.0:
version "1.17.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.17.0.tgz#53b303676eed22cc14a9f0cec09b477b3026c008"
integrity sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw==
pretty-bytes@^4.0.2:
version "4.0.2"

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