Query result value / reference

Mar 17, 2014 at 12:08 PM
Dear all,

I have a database of objects, and I am using CPPLINQ to select some items based upon given properties. In order to spare some memory, I would like to know wether it possible for a CPPLINQ query to return elements by reference instead of by value ?
Coordinator
Mar 17, 2014 at 7:58 PM
cpplinq tries to return references when it's safe to do so but some operations (such as select) return by value.

Perhaps you can post some code and we can take a look to see if there's something we can do?

Mårten
Mar 18, 2014 at 8:02 AM
Edited Mar 18, 2014 at 8:04 AM
Dear Marten,

I am using a vector of "Component" as a database, and I am using CPPLINQ to retrieve some "Component" based upon given properties. These properties does not changed as soon as the vector is built (by serialization from a binary file) - therefore, I would like to know how to make CPPLINQ return "Components" as const reference to avoid unnecessary copies and waste of memory. To give you a better insight, here are some sample code:

--> "Component" used to store informations
template<typename T>
class ComponentData
{
private:
//Serialized Data
    // Scalar properties
    double m_MolecularWeight;
    double m_NormalBoilingPoint;
    double m_CriticalTemperature;
    double m_CriticalPressure;
....
public:
    ComponentData(){};
    ~ComponentData(){};

    T Get_MolecularWeight() const
    {
        return m_MolecularWeight;
    }

    const std::string Get_CASN() const
    {
        return m_CASN;
    }
....
}
--> The database itself
template<typename T>
class ComponentDatabase
{
private:
    ComponentDatabase(const ComponentDatabase& that) = delete;
        std::vector<ComponentData<T>> m_Database;

public:
    ComponentDatabase(std::string a_PathToDB);  // The constructor will load data from a binarized file
...
        std::vector<ComponentData<T>> Find_MW(const T a_LowerMW, const T a_UpperMW) const;
}
--> Here's the detail of Find_MW:
template<typename T>
std::vector<ComponentData<T>> ComponentDatabase<T>::Find_MW(const T a_LowerMW, const T a_UpperMW) const
{
    return cpplinq::from(m_Database)
        >> cpplinq::where([a_LowerMW, a_UpperMW](ComponentData<DOUBLE> cmp){return cmp.Get_MolecularWeight() > a_LowerMW &&   cmp.Get_MolecularWeight() < a_UpperMW; })
        >> cpplinq::to_vector();
}
--> An example of CPPLINQ query:
auto cmps = vComponentDatabase.Find_MW(100.0, 101.1);  // I would like at this point to have a vector (or any else container) of ComponentData references.
Thank you for your support and giving us access to LINQ :)
Coordinator
Mar 19, 2014 at 7:35 PM
Hi.

Been thinking. STL supports something called std::reference_wrapper<>. The intention of this is to wrap reference into a value type that can be stored in STL containers.

I introduced a new ref range operator that allows converting ranges into a range of std::reference_wrapper<>

For example:
            std::vector<std::reference_wrapper<customer const>> ref_result =
                    from_array (customers)
                >>  ref ()
                >>  to_vector ()
                ;

            auto index = 0U;
            for (auto customer : ref_result)
            {
                if (!TEST_ASSERT (customers[index].id, customer.get ().id))
                {
                    printf ("    @index:%u\n", index);
                }

                ++index;
            }

            TEST_ASSERT (count_of_customers, ref_result.size ());
This shouldn't invoke the .ctor of the customer class.

You can find the operator in the branch: mrange__ref_range

I need to verify that the ref range operator in the cpplinq supported compilers before I dare merge it into master but it would help me if you could verify that this solves your issue.

Regards,
Mårten
Mar 20, 2014 at 9:00 AM
Dear Marten,

I'm glad to say that using branch mrange__ref_range and ref() operator is working perfectly ! If you need me to test some features, please let me know.

Regards,

Jean-Pierre
Coordinator
Mar 20, 2014 at 1:49 PM
Thanks for testing. Glad it resolved your issue.

Note that the ref() operator is only valid after operators that return references (such as where()). ref() operator tests this with a static_assert in order to minimize the risk of doing it wrong.

As soon as I have this verified for our supported compilers I will merge this to master.

This probably warrants a new release of cpplinq as well (been holding that off long enough now).
Coordinator
Mar 20, 2014 at 7:10 PM
Hi.

I read up on compiler support for reference wrapper.

I think it is safe to merge to master and have done so. So if you grab the latest from master you should have ref ()
Mar 21, 2014 at 10:34 AM
Hello Marten,

A quick word to say that master branch solved my issue under VisualStudioExpress 2013.

Thanks.
Coordinator
Mar 21, 2014 at 11:51 AM
Thanks good to know.
Coordinator
Mar 23, 2014 at 10:27 AM
Edited Mar 23, 2014 at 10:27 AM
FYI: There's a new release now: https://cpplinq.codeplex.com/releases/view/119967

This contains amongst other things the ref () range operator. I listed you in "Thanks to" section.

I've also updated the documentation to include ref (): https://cpplinq.codeplex.com/wikipage?title=Cpplinq%20Query%20Operators

PS. Please rate the release (good or bad) after you tested it.