I used lualite to wrap the following object in lua:
class SpriteComponent : public Component
{
public:
SpriteComponent();
std::string name() const;
std::string textureId() const;
void setTextureId(const std::string& id);
int spriteCoordX() const;
void setSpriteCoordX(int value);
int spriteCoordY() const;
void setSpriteCoordY(int value);
};
The binding code:
module(L,
class_<SpriteComponent>("SpriteComponent")
.constructor("new")
.def("name", &SpriteComponent::name)
.property("textureId",
&SpriteComponent::textureId, &SpriteComponent::setTextureId)
.property("spriteCoordX",
&SpriteComponent::spriteCoordX, &SpriteComponent::setSpriteCoordX)
.property("spriteCoordY",
&SpriteComponent::spriteCoordY, &SpriteComponent::setSpriteCoordY)
);
Is there a way (either on the lua side or the C++ side) to get a list of properties? If I list the pairs in the resulting table, I only get name and __instance.
local o = SpriteComponent.new()
for key,value in pairs(o) do
print("found member " .. key);
end
I even tried some of these table printers, but no luck.
I'm the author of lualite. I wrote the library to be minimalist and fast and did not foresee the need for reflection :) Anyway, what you are looking for can be found as 2 static members:
static ::std::unordered_map<char const*, detail::map_member_info_type,
detail::unordered_hash, detail::unordered_eq> getters_;
static ::std::unordered_map<char const*, detail::map_member_info_type,
detail::unordered_hash, detail::unordered_eq> setters_;
the char const* is the name of the property, the value being a map_member_info_type, which are essentially two pointers, one to a lualite stub, the other to the C++ member function.
struct map_member_info_type
{
lua_CFunction callback;
member_func_type func;
};
If you like, I can make both members public. The way properties work is as follows:
A default getter is (usually) set in the wrapped class's instance table:
lua_pushcclosure(L, default_getter<C>, 2);
rawsetfield(L, -2, "__index");
This points to the default getter:
template <class C>
int default_getter(lua_State* const L)
{
assert(2 == lua_gettop(L));
auto const i(lualite::class_<C>::getters_.find(lua_tostring(L, 2)));
return lualite::class_<C>::getters_.end() == i
? 0
: (lua_pushlightuserdata(L, &i->second.func),
lua_replace(L, lua_upvalueindex(2)),
(i->second.callback)(L));
}
which looks for the name of the property (which is on the stack). That could be anything really and if it does not find the name, it returns 0, otherwise, it forwards the call to the lualite stub made for the member function, which then handles the arguments and the return value(s).
If you could tolerate having to list the property names in your Lua code, this could be a solution:
local GetPropertyList
do -- to make `property_names` "private" to GetPropertyList
property_names = {
["SpriteComponent"] = { "textureId", "spriteCoordX", "spriteCoordY" },
-- property names for other components, e.g.
["AnotherComponentName"] = { "propName1", "propName2" },
}
function GetPropertyList( object ) --[[local]]
local component_name = object:name()
local prop_names = property_names[component_name]
if not prop_names then
error( "unsupported component" )
end
local res = {}
for _, p_name in ipairs( prop_names ) do
local p_val = object[p_name]
res[ #res + 1 ] = p_val
-- or use this if you want a key-value map:
-- res[p_name] = p_val
end
return res
end -- function
end -- do
for k, v in pairs( GetPropertyList(o) ) do
print( k, v )
end
Related
I have the following method I wish to unit test:
public class Board
{
public static BoardElement RandomElement(List<BoardElement> elements)
{
int index = Random.Next(elements.Count);
return elements[index];
}
}
This method calls Random.Next(elements.Count).
I tried to create a mock of Random so that Random.Next(int maxValue) returns a controlled integer regardless of the int maxValue passed:
Random.Setup(random => random.Next(It.IsAny<int>())).Returns(randomInt);
The whole test function is as follows:
[Theory]
[MemberData(nameof(TestData.RandomElement_TestData), MemberType = typeof(TestData))]
private static void Test_RandomElement(List<BoardElement> elements, int randomInt)
{
Mock<Random> Random = new Mock<Random>();
Random.Setup(random => random.Next(It.IsAny<int>())).Returns(randomInt);
BoardElement element = Board.RandomElement(elements);
Assert.Equal(elements[randomInt], element);
}
Is there a way to setup Random.Next to return a controlled integer regardless of where it is called?
The pure virtual class
class ConfigGetter {
public:
virtual const std::string Get(const char *name,
const char *default_value) const = 0;
};
The mock
class MockConfigGetter : public engine::ConfigGetter {
public:
MOCK_CONST_METHOD2(Get, const std::string(const char *, const char *));
};
Test case
TEST(ConfigTest, NormalString) {
NiceMock<MockConfigGetter> getter;
EXPECT_CALL(getter, Get("SERVER_LISTEN_PORT", ""))
.WillRepeatedly(Return("80"));
// Pass
ASSERT_EQ("80", getter.Get("SERVER_LISTEN_PORT", ""));
// GetNewConfig internal call getter->Get("SERVER_LISTEN_PORT", "")
auto f = engine::GetNewConfig(&getter);
ASSERT_NE(f, nullptr);
// Failure
ASSERT_EQ(80, f->listen_port);
}
And good mock reports:
Unexpected mock function call - returning default value.
Function call: Get(0x556fb6ea4860 pointing to "SERVER_LISTEN_PORT", 0x556fb6ea4843 pointing to "")
Returns: ""
Google Mock tried the following 1 expectation, but it didn't match:
/home/phillip/projects/engine-test/src/config/config-test.cpp:26: EXPECT_CALL(getter, Get("SERVER_LISTEN_PORT", ""))...
Expected arg #0: is equal to 0x556fb6ea2878 pointing to "SERVER_LISTEN_PORT"
Actual: 0x556fb6ea4860 pointing to "SERVER_LISTEN_PORT"
Expected arg #1: is equal to 0x556fb6ea27bc pointing to ""
Actual: 0x556fb6ea4843 pointing to ""
Expected: to be called any number of times
Actual: called twice - satisfied and active
arg0 and arg1 is exactly the same as EXPECT_CALL. I don't know why the second call fail to match.
This happens because gmock compares values of arguments, i.e. pointers. To compare strings you need to add corresponding matchers, i.e.
EXPECT_CALL(getter, Get(StrEq("SERVER_LISTEN_PORT"), StrEq("")))
.WillRepeatedly(Return("80"));
In my Unreal Engine project, which uses GameplayAbilitySystem and the default server->client architecture, the client gets notified of an attribute value changes that happened on the server.
Additionally, I'm trying to get not only the new value, but also the amount the value changed (delta = new value - old value). This should be possible using the attribute value change delegate, since it contains FOnAttributeChangeData with its members NewValue and OldValue.
On the server, both values are correct. However, on the client, FOnAttributeChangeData::NewValue == FOnAttributeChangeData::OldValue and both have the value being identical to NewValue on the server.
This is because the delegate is called after the replication happened ...
UPROPERTY(ReplicatedUsing=OnRep_MyAttribute)
FGameplayAttributeData MyAttribute;
void UAttributeSetBase::OnRep_MyAttribute()
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MyAttribute);
}
(this is default GAS setup of ActionRPG)
... so the client has no knowledge about the value it had before replication.
How do I get the value of the attribute, which it had before it got updated by the server?
How do I forward this value to the delegate?
Getting the old value (question 1)
UnrealEngine OnRep functions provide the previous state of an replicated variable as first parameter in the OnRep function. So add the parameter
void UAttributeSetBase::OnRep_MyAttribute(const FGameplayAttributeData& Previous)
{
const auto PreviousValue = Previous.GetCurrentValue(); // See below for possible usage.
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MyAttribute);
}
Thanks #Dan from Unreal GAS discord channel.
Forward the value to the delegate (question 2)
Idea
When your goal is to not modify the UE4 source code, one possibility is to cache the previous value within the attribute set, so you are able to access it from outside.
Cache that value for each attribute in the attribute set OnRep function.
Use the cached value in the delegate, but only if it is valid. Since the value is assigned within the OnRep function, it won't exist on the server. This is perfectly fine since we want to retain the behaviour on the server, which uses FOnAttributeChangeData::OldValue (which has the correct value only on the server).
Example implementation
Caching the previous value
AttributeSetBase.h:
// Wrapper for a TMap. If you need thread safety, use another container or allocator.
class CachePreviousDataFromReplication
{
TMap<FName, FGameplayAttributeData> CachedPreviousData;
public:
void Add(const FName, const FGameplayAttributeData&);
auto Find(const FName) const -> const FGameplayAttributeData*;
};
class YOUR_API UAttributeSetBase : public UAttributeSet
{
// ...
private:
UFUNCTION() void OnRep_MyAttribute(const FGameplayAttributeData& Previous);
// ...
private:
CachePreviousDataFromReplication CachedDataFromReplication;
public:
// \param[in] AttributeName Use GET_MEMBER_NAME_CHECKED() to retrieve the name.
auto GetPreviousDataFromReplication(const FName AttributeName) const -> const FGameplayAttributeData*;
}
AttributeSetBase.cpp:
void CachePreviousDataFromReplication::Add(const FName AttributeName, const FGameplayAttributeData& AttributeData)
{
this->CachedPreviousData.Add(AttributeName, AttributeData);
}
auto CachePreviousDataFromReplication::Find(const FName AttributeName) const -> const FGameplayAttributeData*
{
return CachedPreviousData.Find(AttributeName);
}
void UAttributeSetBase::OnRep_MyAttribute(const FGameplayAttributeData& Previous)
{
CachedDataFromReplication.Add(GET_MEMBER_NAME_CHECKED(UAttributeSetBase, MyAttribute), Previous); // Add this to every OnRep function.
GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MyAttribute);
}
auto UAttributeSetBase::GetPreviousDataFromReplication(const FName AttributeName) const -> const FGameplayAttributeData*
{
return CachedDataFromReplication.Find(AttributeName);
}
Accessing the previous value in the delegate
ACharacterBase.h:
class YOUR_API ACharacterBase : public ACharacter, public IAbilitySystemInterface
{
// ...
void OnMyAttributeValueChange(const FOnAttributeChangeData& Data); // The callback to be registered within GAS.
// ...
}
ACharacterBase.cpp:
void ACharacterBase::OnMyAttributeValueChange(const FOnAttributeChangeData& Data)
{
// This delegate is fired either from
// 1. `SetBaseAttributeValueFromReplication` or from
// 2. `InternalUpdateNumericalAttribute`
// #1 is called on clients, after the attribute has changed its value. This implies,
// that the previous value is not present on the client anymore. Therefore, the
// value of `Data.OldValue` is erroneously identical to `Data.NewValue`.
// In that case (and only in that case), the previous value is retrieved from a cache
// in the AttributeSet. This cache will be only present on client, after it had
// received an update from replication.
auto deltaValue = 0.f;
if (Data.NewValue == Data.OldValue)
{
const auto attributeName = GET_MEMBER_NAME_CHECKED(UAttributeSetBase, MyAttribute);
if (auto previousData = AttributeSetComponent->GetPreviousDataFromReplication(attributeName))
{
// This will be called on the client, when coming from replication.
deltaValue = Data.NewValue - previousData->GetCurrentValue();
}
}
else
{
// This might be called on the server or clients, when coming from
// `InternalUpdateNumericalAttribute`.
deltaValue = Data.NewValue - Data.OldValue;
}
// Use deltaValue as you like.
}
In below code snippet I do require to instantiate the object through factory method in order to call the selected adapter (i.e. adapterTwovalue)but while calling through factory method i am not able to get the desire results. When we assign static declared object's address (i.e adapter = &at) it works but with factory i usually get the blank output.
I tried as well with (adapter = new adapterTwo()) to instantiate the object but output string is giving blank results. As per my requirement i need to populate the all the getters in connect function which is pure virtual function to frame the response.Anybody can suggest how to achieve this using factory method.
#include <iostream>
using namespace std;
class IAdapter
{
public:
enum FactoryList { AdapterOnevalue = 0, AdapterTwovalue };
virtual void connect() = 0;
static IAdapter* CreateList(FactoryList);
virtual ~IAdapter() {}
};
class LibraryOne
{
string property;
public:
void SetConnection(string property)
{
this->property = property;
}
string getConnection()const
{
return property;
}
};
//LibraryTwo
class LibraryTwo
{
string broker;
public:
void SetBroker(string broker1)
{
this->broker = broker1;
}
string getBroker() const
{
return broker;
}
};
//adapterOne
class AdapterOne : public IAdapter
{
LibraryOne one;
string constring;
public:
void SetClientconnection(string constring)
{
one.SetConnection(constring);
}
string GetClientconnection()
{
return one.getConnection();
}
void connect()
{
constring = GetClientconnection();
}
};
//Adapter to use library two
class AdapterTwo : public IAdapter
{
LibraryTwo two;
string brokerstring;
public:
void SetClientbroker(string constring)
{
two.SetBroker(constring);
}
string GetClientbroker()
{
return two.getBroker();
}
void connect()
{
string constring = GetClientbroker();
cout << "final value=" << constring;
}
};
IAdapter* IAdapter::CreateList(FactoryList SelectList)
{
IAdapter *ListObject;
switch (SelectList)
{
case AdapterOnevalue:
ListObject = new AdapterOne();
break;
case AdapterTwovalue:
ListObject = new AdapterTwo();
break;
default:
ListObject = NULL;
}
return ListObject;
}
int main()
{
IAdapter *adapter = 0;
//LibraryTwo obj;
AdapterTwo at;
at.SetClientbroker("amqp");
//cout << at.GetClientbroker();
//adapter = &at; it works
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);//it doesn't work
//Just do the operation now
adapter->connect();
return 0;
}
You can see the complete solution in below share link.
http://coliru.stacked-crooked.com/a/d8b9d32a1fa989c9
Here is the explanation.
(1) setClientBroker() or all other adapters related setter functionality needs to be implement as a virtual function in Interface with default parameter value " " (blank string).
(2) you need to always use override keyword (c++11) feature in derive class for setters so that compiler will cross check during compilation whether proper virtual method is being overridden or not.
(3) instead of using local raw pointer , always use smart pointer . below is the
implementation link for the same.
http://coliru.stacked-crooked.com/a/2feea991ee90d4a2
With your code I expect the output: final value=.
It will not print final value=amqp cause you need to call SetClientbroker("amqp") on the right adapter object (adapter in your example).
Anyway, I would think about putting a virtual method SetString in the base class, so you could simply do:
int main()
{
IAdapter *adapter = 0;
//LibraryTwo obj;
//AdapterTwo at;
//at.SetClientbroker("amqp");
//cout << at.GetClientbroker();
//adapter = &at; it works
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);//it doesn't work
//Just do the operation now
adapter->SetString("amqp");//<---------
adapter->connect();
return 0;
}
EDIT after the comment:
You need to cast the object, at this point (as suggested by #Aconcagua).
But IMHO it's not elegant at all. I think you are going to loose the benefits gained with the factory method.
IAdapter* adapter = nullptr;
AdapterTwo at;
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);
You have created two independent objects here (as calling new within createList): at and the one adapter points to.
AdapterTwo at;
at.SetClientbroker("amqp");
Now sure you get the expected output if you let adapter point to at, but how could the other object be aware of the string you set in the first one?
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);
adapter->SetClientbroker("amqp"); // (*) !!!
You need to set the broker at the other object, too. As being different objects, you even can set the brokers independently:
AdapterTwo at;
at.SetClientbroker("amqp");
IAdapter* adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);
adapter->SetClientbroker("aconcagua"); // (*) !!!
Output now would be (if you called connect on both objects):
final value=amqp
final value=aconcagua
Only: The marked lines ((*)) won't compile as your base class does not provide the appropriate setter!
There are now different solutions for this problem. You could, for instance, just cast the object:
// if you are REALLY 100% sure the object is of appropriate type:
static_cast<AdapterTwo*>(adapter)->setClientBroker("...");
// if NOT:
AdapterTwo* a2 = dynamic_cast<AdapterTwo*>(adapter);
if(a2)
a2->setClientBroker("...");
else
// appropriate error handling
You could find a more generic name for the set/get Broker/ClientConnection functions, have them already pure virtual within IAdapter and override them in the two implementing adapter classes, so you could then just call adapter->setXYZ("ampq");. [Edit: according to your comment to the question, not an option in the given case]
My personal favourite is providing an additional parameter to your createList function such that the setter would already be called within the factory - possibly with appropriate default: empty string, if you opt for a std::string parameter, or nullptr in case of char const*. You'd only call the setter if the parameter is not matching the default, of course... Alternatively, you could have two overloads.
As I come from a JS background this is how I'd call a function by name stored in a variable:
var obj = {
foobar: function(param) {
// do something
}
};
var key = "foobar";
obj[key](123);
Now I would like to recreate this in Swift, for example:
struct obj = {
func foobar(param) {
// do something
}
}
let key:String = "foobar"
obj[key](123)
The above code unfortunately gives Type 'obj.Type' has no subscript members
Is there any way to call functions by names in a Struct, Class or a Dictionary (if it's even possible to store functions in Dicts?)
EDIT - MORE CONTEXT:
I have a user-supplied array of things say:
let arr = ["apples", "oranges", "pears"]
but this array can be as long as 20 items. Based on each item of the array I need to perform certain action. So I iterate over the array:
for (key, _) in arr {
if (key == "apples") {
handleApples()
}
if (key == "oranges") {
handleOranges()
}
// and so on...
}
Sure, I can have a function with a simple switch that would consist of 20 cases but that's far from ideal. What if my array grows to say 100 items?
I was hoping to achieve something similar to this:
for (key, _) in arr {
myClass[key]()
}
Is there any way to call functions by names in a Struct, Class or a Dictionary (if it's even possible to store functions in Dicts?)
Yes you can store a function into a dictionary
Let's define a function type
typealias FuncType = () -> ()
and 2 functions
func func0() {
print("Apples")
}
func func1() {
print("Oranges")
}
Now we can create a dictionary where the key is String and the value is FuncType
let dict : [String:FuncType] = [
"Apples" : func0,
"Oranges" : func1
]
And of course we can invoke a function stored into the dictionary
dict["Apples"]?() // prints "Apples"
I think this might be what you're looking for:
var obj: [String: Int] = {
// do something, like call foobar(param) that's defined outside of the variable
// or just manipulate data directly in here
return ["foobar": 123]
// or whatever dictionary you want that matches the type you defined for obj
}()
Kind of tough to give you a better answer without you posting the kind of output or behavior you're looking for.