// bdljsn_location.h                                                  -*-C++-*-
#ifndef INCLUDED_BDLJSN_LOCATION
#define INCLUDED_BDLJSN_LOCATION

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a value-semantic type for location in a JSON document.
//
//@CLASSES:
//  bdljsn::Location: position in a JSON document
//
//@SEE_ALSO: bdljsn_jsonutil, bdljsn_json
//
//@DESCRIPTION: This component provides a single, unconstrained
// (value-semantic) attribute class, 'bdljsn::Location', that is used to
// describe a location in a (JSON) document.  Location is expressed by the
// 'offset' (attrbute) in bytes from the start of the document.  See
// {'jsonutil'} for utilities that may provide 'bdljsn::Location' values when
// reporting error states.
//
///Attributes
///----------
//..
//  Name                Type           Default
//  ------------------  -------------  -------
//  offset              bsl::uint64_t  0
//..
//: o 'offset': the offset into the JSON document
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Syntax
///- - - - - - - - - - - -
// This example exercises each of the methods of the 'bdljsn::Location' class.
//
// First, create a 'bdljsn::Location' object (having the default value):
//..
//  bdljsn::Location locationA;
//  assert(0 == locationA.offset());
//..
// Then, set 'locationA' to some other offset:
//..
//  locationA.setOffset(1);
//  assert(1 == locationA.offset());
//..
// Next, use the value constructor to create a second location having the same
// offset as the first:
//..
//      bdljsn::Location locationB(1);
//      assert(1         == locationB.offset());
//      assert(locationA == locationB);
//..
// Then, set the second location to the maximum offset:
//..
//  const bsl::uint64_t maxOffset = bsl::numeric_limits<bsl::uint64_t>::max();
//
//  locationB.setOffset(maxOffset);
//  assert(maxOffset == locationB.offset());
//..
// Next, create another 'Location` that is a copy of the one at 'maxOffset':
//..
//  bdljsn::Location locationC(locationB);
//  assert(locationB == locationC);
//..
// Then, set the first location back to the default state:
//..
//  locationA.reset();
//  assert(0                  == locationA.offset());
//  assert(bdljsn::Location() == locationA);
//..
//  Next, print the value of each:
//..
//  bsl::cout << locationA << "\n"
//            << locationB << bsl::endl;
//
//  bsl::cout << "\n";
//
//  locationC.print(bsl::cout, 2, 3);
//..
// and observe:
//..
//   0
//   18446744073709551615
//
//        [
//           offset = 18446744073709551615
//        ]
//..
// Finally, set each location equal to the first:
//..
//  locationC = locationB = locationA;
//  assert(0 == locationA.offset());
//  assert(0 == locationB.offset());
//  assert(0 == locationC.offset());
//..

#include <bdlscm_version.h>

#include <bslalg_swaputil.h>

#include <bslmf_isbitwisemoveable.h>
#include <bslmf_nestedtraitdeclaration.h>

#include <bslh_hash.h>

#include <bsl_cstdint.h> // 'bsl::uint64_t'
#include <bsl_iosfwd.h>

namespace BloombergLP {
namespace bdljsn {

                               // ==============
                               // class Location
                               // ==============

class Location {
    // This unconstrained (value-semantic) attribute class specifies a location
    // in a (JSON) document.  See the {Attributes} section under {DESCRIPTION}
    // in the component-level documentation for information on the class
    // attributes.  Note that the class invariants are identically the
    // constraints on the individual attributes.

    // DATA
    bsl::uint64_t d_offset; // offset in bytes into a document

    // FRIENDS
    template <class HASHALG>
    friend void hashAppend(HASHALG& hashAlg , const Location& );
    friend void swap(Location& , Location& );

  public:
    BSLMF_NESTED_TRAIT_DECLARATION(Location, bslmf::IsBitwiseMoveable);

    // CREATORS
    Location();
        // Create a 'Location' object having the default value, 0.

    explicit Location(bsl::uint64_t offset);
        // Create a 'Location' object having the specified 'offset'.

    Location(const Location& original);
        // Create a 'Location' object having the same value as the specified
        // 'original' object.

    //! ~Location() = default;
        // Destroy this object.

    // MANIPULATORS
    Location& operator=(const Location& rhs);
        // Assign to this object the value of the specified 'rhs' object.

    void reset();
        // Reset this object to the default value (i.e., its value upon default
        // construction).

    void setOffset(bsl::uint64_t value);
        // Set the "offset" attribute of this object to the specified 'value'.

                                  // Aspects

    void swap(Location& other);
        // Efficiently exchange the value of this object with the value of the
        // specified 'other' object.  This method provides the no-throw
        // exception-safety guarantee.

    // ACCESSORS
    bsl::uint64_t offset() const;
        // Return the 'offset' attribute of this object.

                                  // Aspects

    bsl::ostream& print(bsl::ostream& stream,
                        int           level = 0,
                        int           spacesPerLevel = 4) const;
        // Format this object to the specified output 'stream' at the
        // optionally specified indentation 'level' and return a reference to
        // the modifiable 'stream'.  If 'level' is specified, optionally
        // specify 'spacesPerLevel', the number of spaces per indentation level
        // for this and all of its nested objects.  Each line is indented by
        // the absolute value of 'level * spacesPerLevel'.  If 'level' is
        // negative, suppress indentation of the first line.  If
        // 'spacesPerLevel' is negative, suppress line breaks and format the
        // entire output on one line.  If 'stream' is initially invalid, this
        // operation has no effect.  Note that a trailing newline is provided
        // in multiline mode only.
};

// FREE OPERATORS
inline
bool operator==(const Location& lhs, const Location& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' attribute objects have
    // the same value, and 'false' otherwise.  Two attribute objects have the
    // same value if each respective attribute has the same value.

inline
bool operator!=(const Location& lhs, const Location& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' attribute objects do not
    // have the same value, and 'false' otherwise.  Two attribute objects do
    // not have the same value if one or more respective attributes differ in
    // values.

bsl::ostream& operator<<(bsl::ostream& stream, const Location& object);
    // Write the value of the specified 'object' to the specified output
    // 'stream' in a single-line format, and return a non-'const' reference to
    // 'stream'.  If 'stream' is not valid on entry, this operation has no
    // effect.  Note that this human-readable format is not fully specified and
    // can change without notice.  Also note that this method has the same
    // behavior as 'object.print(stream, 0, -1)', but with the attribute names
    // elided.

// FREE FUNCTIONS
template <class HASHALG>
void hashAppend(HASHALG& hashAlg, const Location& object);
    // Pass the specified 'object' to the specified 'hashAlg'.  This function
    // integrates with the 'bslh' modular hashing system and effectively
    // provides a 'bsl::hash' specialization for 'Location'.

void swap(Location& a, Location& b);
    // Exchange the values of the specified 'a' and 'b' objects.  This function
    // provides the no-throw exception-safety guarantee.

// ============================================================================
//                         INLINE DEFINITIONS
// ============================================================================

                               // --------------
                               // class Location
                               // --------------

// CREATORS
inline
Location::Location()
: d_offset(0)
{
}

inline
Location::Location(bsl::uint64_t offset)
: d_offset(offset)
{
}

inline
Location::Location(const Location& original)
: d_offset(original.d_offset)
{
}

// MANIPULATORS
inline
Location& Location::operator=(const Location& rhs)
{
    d_offset = rhs.d_offset;

    return *this;
}

inline
void Location::reset()
{
    d_offset = 0;
}

inline
void Location::setOffset(bsl::uint64_t value)
{
    d_offset = value;
}

                                  // Aspects

inline
void Location::swap(Location& other)
{
    bslalg::SwapUtil::swap(&d_offset,&other.d_offset);
}

// ACCESSORS
inline
bsl::uint64_t Location::offset() const
{
    return d_offset;
}

}  // close package namespace

// FREE OPERATORS
inline
bool bdljsn::operator==(const bdljsn::Location& lhs,
                        const bdljsn::Location& rhs)
{
    return lhs.offset() == rhs.offset();
}

inline
bool bdljsn::operator!=(const bdljsn::Location& lhs,
                        const bdljsn::Location& rhs)
{
    return lhs.offset() != rhs.offset();
}

// FREE FUNCTIONS
template <class HASHALG>
inline
void bdljsn::hashAppend(HASHALG& hashAlg, const Location& object)
{
    using ::BloombergLP::bslh::hashAppend;
    hashAppend(hashAlg, object.d_offset);
}

inline
void bdljsn::swap(Location& a, Location& b)
{
    bslalg::SwapUtil::swap(&a.d_offset, &b.d_offset);
}

}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2022 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------